skip to content

What does the Spring Boot Actuator `loggers` endpoint let you do, and how do you use it?

level: juniorimportance: must knowfreq 55%

answer

  1. GET lists configuredLevel + effectiveLevel
  2. POST {configuredLevel:DEBUG} = live change, no restart
  3. POST {configuredLevel:null} = reset to inherit
  4. backed by LoggingSystem abstraction
  5. must expose via exposure.include=loggers

basics

~20 s

The /actuator/loggers endpoint shows the log levels of your application. A GET lists loggers and their levels; a POST with a JSON body like {"configuredLevel":"DEBUG"} changes a logger's level at runtime without restarting the app.

solid answer

~40 s

The Actuator `loggers` endpoint exposes and controls logging levels at runtime. `GET /actuator/loggers` returns all known loggers with their `configuredLevel` (explicitly set, may be null) and `effectiveLevel` (what actually applies after inheritance). `GET /actuator/loggers/{name}` inspects one logger, e.g. `com.myapp`. `POST /actuator/loggers/{name}` with body `{"configuredLevel":"DEBUG"}` raises or lowers that logger's level live — no restart needed. Sending `{"configuredLevel":null}` resets it to inherit from its parent. This is invaluable for debugging production: turn on DEBUG for one package to capture detail, then reset. To enable it you expose the endpoint via `management.endpoints.web.exposure.include=loggers` (it is enabled but not web-exposed by default). It works through Spring's `LoggingSystem` abstraction over Logback/Log4j2/JUL.

code

java · 20 lines
java
// application.yml equivalent (properties form):
// management.endpoints.web.exposure.include=loggers

// Inspect one logger:
//   GET http://localhost:8080/actuator/loggers/com.myapp
//   -> { "configuredLevel": null, "effectiveLevel": "INFO" }

// Turn on DEBUG at runtime (returns 204 No Content):
//   POST http://localhost:8080/actuator/loggers/com.myapp
//   Content-Type: application/json
//   { "configuredLevel": "DEBUG" }

// Reset back to inheriting from parent:
//   POST http://localhost:8080/actuator/loggers/com.myapp
//   { "configuredLevel": null }

// curl form of the change:
//   curl -X POST http://localhost:8080/actuator/loggers/com.myapp \
//        -H 'Content-Type: application/json' \
//        -d '{"configuredLevel":"DEBUG"}'

go deeper

for a junior

Know that GET reads levels and POST {configuredLevel:LEVEL} changes them live without restart, and that you must expose the endpoint.

for a middle

Explain configuredLevel vs effectiveLevel, the null reset, and that it is non-persistent and returns 204.

for a senior

Tie it to the LoggingSystem abstraction, logger groups, and the security implications of a state-changing endpoint.

for a principal

Frame it as an operational debugging tool and reason about its non-persistence, blast radius, and how to govern access in production.

## What the endpoint is Spring Boot Actuator ships a built-in endpoint with id `loggers` that lets you **read and change log levels of a running application over HTTP** — without editing config files or restarting the process. ### Terms defined - **Logger**: a named channel that log statements are attached to. Loggers are hierarchical by dotted name — `com.myapp.service.OrderService` is a child of `com.myapp.service`, which is a child of `com.myapp`, under the special `ROOT` logger. - **Log level**: a threshold — `TRACE < DEBUG < INFO < WARN < ERROR < OFF`. A statement logs only if its level is at least the logger's effective level. - **configuredLevel**: the level *explicitly* set on a logger. It can be `null`, meaning nothing was set directly on it. - **effectiveLevel**: the level that *actually applies* — resolved by walking up the hierarchy to the nearest ancestor that has a configured level. If `com.myapp` is set to `DEBUG` and `com.myapp.service` has no configured level, the service logger's effectiveLevel is `DEBUG` (inherited). ### Reading levels - `GET /actuator/loggers` returns a JSON document with two parts: `levels` (the array of available level names) and `loggers` (a map of every known logger name to `{configuredLevel, effectiveLevel}`). It also includes any logger `groups`. - `GET /actuator/loggers/com.myapp` returns just that one logger's `{configuredLevel, effectiveLevel}`. ### Changing levels (the key feature) - `POST /actuator/loggers/com.myapp` with JSON body `{"configuredLevel":"DEBUG"}` sets that logger to DEBUG **immediately and live**. Child loggers that inherit will now also emit DEBUG. - `POST` with body `{"configuredLevel":null}` (or an empty body) **clears** the configured level so the logger reverts to inheriting from its parent. - The POST returns HTTP 204 No Content on success. ### How it works under the hood Spring Boot does not talk to Logback/Log4j2/JUL directly here. It uses the **`org.springframework.boot.logging.LoggingSystem`** abstraction. `LoggersEndpoint` calls `LoggingSystem.setLogLevel(name, level)` and `getLoggerConfigurations()`. `LoggingSystem` has concrete implementations — `LogbackLoggingSystem`, `Log4J2LoggingSystem`, `JavaLoggingSystem` — auto-selected based on what's on the classpath (Logback is the Spring Boot default). So the same endpoint works uniformly regardless of backend. ### Enabling / exposing it - The endpoint is **enabled by default** but, like most endpoints, **not exposed over the web by default** (only `health` is web-exposed out of the box). Expose it with `management.endpoints.web.exposure.include=loggers` (or `*`). - It is exposed over JMX by default in older versions; on the web you must opt in. ### Logger groups You can define a **logger group** in config — `logging.group.web=org.springframework.web,org.springframework.http` — then `POST /actuator/loggers/web {"configuredLevel":"DEBUG"}` sets the level for all members at once. Spring predefines two groups: `web` and `sql`. ### Edge cases & gotchas - **Changes are in-memory and non-persistent**: they are lost on restart. The endpoint intentionally does not rewrite `application.yml`. - **A POST can create a logger entry** for a name that wasn't previously listed; it becomes a configured logger from then on. - **Case-insensitive level names** are accepted, but use the canonical uppercase. - **Security**: this is a state-changing, sensitive endpoint. Anyone who can POST can flip your app to TRACE and flood logs (a DoS / info-leak vector). Protect it with Spring Security; never expose it unauthenticated on a public port. - **`null` configuredLevel vs `OFF`**: `null` means "inherit"; `OFF` means "explicitly silence". They are different states. ### When to use it Primarily **live production debugging**: a customer hits an intermittent bug, you raise `com.myapp.payments` to DEBUG, reproduce, capture the detail, then POST `null` to reset — all without a deploy or restart. Also useful in tests and demos.

  • Does a level change made through the endpoint survive an application restart?
    No. The change is applied in memory via LoggingSystem and is not written back to any config file, so it is lost on restart. To make it permanent you must update static config (e.g. logging.level in application.yml).
  • What HTTP status does a successful POST return?
    204 No Content — there is no response body; the change is applied to the running LoggingSystem.

saying these in an interview costs you the question

  • Thinking the change is written back to application.yml and persists across restarts
  • Claiming the loggers endpoint is web-exposed by default (only health is)
  • Confusing GET (read) with the POST that actually changes the level
  • Saying you must restart the app for a new level to take effect

context