{"record":{"id":"dbafee51d8222c49","repo":"apache/pulsar","slug":"proxy-doesn-t-have-logging-level-2","errorCode":null,"errorMessage":"Proxy doesn't have logging level 2","messagePattern":"Proxy doesn't have logging level 2","errorType":"http","errorClass":"RestException","httpStatus":412,"severity":"warning","filePath":"pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java","lineNumber":105,"sourceCode":"            stats.add(new ConnectionStats(requestRate, byteRate, inboundChannel, outboundChannel));\n        });\n        return stats;\n    }\n\n    @GET\n    @Path(\"/topics\")\n    @Operation(summary = \"Proxy topic stats api\")\n    @ApiResponses(value = {\n            @ApiResponse(responseCode = \"200\", description = \"Proxy topic stats api\",\n                    content = @Content(schema = @Schema(type = \"object\"),\n                            additionalPropertiesSchema = @Schema(implementation = Map.class))),\n            @ApiResponse(responseCode = \"412\", description = \"Proxy logging should be > 2 to capture topic stats\"),\n            @ApiResponse(responseCode = \"503\", description = \"Proxy service is not initialized\") })\n    public Map<String, TopicStats> topics() {\n        throwIfNotSuperUser(\"topics\");\n        Optional<Integer> logLevel = proxyService().getConfiguration().getProxyLogLevel();\n        if (!logLevel.isPresent() || logLevel.get() < 2) {\n            throw new RestException(Status.PRECONDITION_FAILED, \"Proxy doesn't have logging level 2\");\n        }\n        return proxyService().getTopicStats();\n    }\n\n    @POST\n    @Path(\"/logging/{logLevel}\")\n    @Operation(hidden = true, summary = \"Change proxy logging level dynamically\",\n            description = \"It only changes the log level in memory; change it in the config file to persist the change\")\n    @ApiResponses(value = { @ApiResponse(responseCode = \"412\", description = \"Proxy log level can be [0-2]\"), })\n    public void updateProxyLogLevel(@PathParam(\"logLevel\") int logLevel) {\n        throwIfNotSuperUser(\"updateProxyLogLevel\");\n        if (logLevel < 0 || logLevel > 2) {\n            throw new RestException(Status.PRECONDITION_FAILED, \"Proxy log level can be only [0-2]\");\n        }\n        proxyService().setProxyLogLevel(logLevel);\n    }\n\n    @GET","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java#L87-L123","documentation":"The proxy REST /topics stats endpoint only captures topic-level stats when the proxy's dynamic log level is >= 2, because topic stats collection piggybacks on verbose logging machinery. ProxyStats.topics enforces this precondition with HTTP 412 when proxyLogLevel is absent or below 2.","triggerScenarios":"GET /admin/v2/proxy-stats/topics (via ProxyStats.topics) while getConfiguration().getProxyLogLevel() is unset or < 2 — e.g. before anyone called POST /logging/{logLevel} or the config file has no proxyLogLevel entry.","commonSituations":"Monitoring/scraping tools querying topic stats on a fresh proxy whose proxyLogLevel defaults below 2; operators forgetting to raise the log level after restart; automated dashboards hitting the endpoint on a proxy configured with proxyLogLevel=1.","solutions":["Raise the proxy log level first: POST /admin/v2/proxy-stats/logging/2 (requires superuser role)","Set proxyLogLevel=2 in the proxy configuration file so it survives restarts","If only aggregate metrics are needed, use the /metrics endpoint instead of topic-level stats","Ensure the client authenticating to the REST endpoint has superuser permissions so the request reaches the log-level check"],"exampleFix":"// before\nproxyLogLevel=1\n\n// after\nproxyLogLevel=2","handlingStrategy":"validation","validationCode":"Integer logLevel = proxyConfig.getProxyLogLevel().orElse(0);\nif (logLevel < 2) {\n    // raise first, then query\n    admin.postProxyLogLevel(2);\n}\nMap<String, TopicStats> stats = admin.getTopics();","typeGuard":"boolean topicStatsEnabled(ProxyConfiguration cfg) {\n    return cfg.getProxyLogLevel().map(l -> l >= 2).orElse(false);\n}","tryCatchPattern":"try {\n    return proxyStats.topics();\n} catch (RestException e) {\n    if (e.getResponseStatus() == 412) {\n        proxyStats.updateProxyLogLevel(2);\n        return proxyStats.topics();\n    }\n    throw e;\n}","preventionTips":["Set proxyLogLevel=2 in the proxy config when topic-level stats are needed","Raise the level via POST /logging/2 after every proxy restart (in-memory change)","Have monitoring scrapers handle 412 by enabling level 2 first instead of failing the scrape","Use /metrics endpoint when topic-level granularity is not required"],"tags":["pulsar-proxy","rest-api","logging","precondition","stats"],"backgroundTag":"precondition-failed","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}