Skip to main content

Management Logging — Logback & Log4j2 Backends

The juneau-rest-server-management-logging module ships opt-in LogBackend adapters that let the /loggers management endpoint drive Logback or Log4j2 instead of the built-in java.util.logging default.

Background: the /loggers endpoint​

The /loggers runtime log-level management endpoint is built into juneau-rest-server — no extra module is needed to expose it. It surfaces as:

MethodPathEffect
GET/loggersLists all known loggers and their configured levels (empty string = inherited).
GET/loggers/{name}Returns one logger's configured level. 404 if not registered.
PUT / POST/loggers/{name}Sets a logger's level at runtime. Disabled by default — see below.

Wire the endpoint into your resource using one of two forms:

Mixin (adds /loggers paths directly to the host resource):

@Rest(mixins = LoggersMixin.class)
public class MyRestServlet extends BasicRestServlet { ... }

Child resource (mounts at /loggers as a sub-resource):

@Rest(children = LoggersResource.class)
public class RootResources extends BasicRestServlet { ... }

The default backend is java.util.logging. That is the only backend shipped in core juneau-rest-server, which keeps the module dependency-free. juneau-rest-server-management-logging is only needed when your application logs through Logback or Log4j2.

Maven dependency​

<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-rest-server-management-logging</artifactId>
<version>${juneau.version}</version>
</dependency>

Both logback-classic and log4j-core are declared provided in this module — they never leak as transitive dependencies. Declare whichever backend runtime you use in your own POM, at the version you want.

Choosing a backend​

Default — java.util.logging (no extra module)​

JulLogBackend is the default. When no LoggersSettings bean is registered, the endpoint drives JUL automatically. Level names are JUL-standard: FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, OFF, ALL. The root logger is addressed as "ROOT".

Logback​

@Bean
public LoggersSettings loggersSettings() {
return LoggersSettings.create()
.backend(new LogbackLogBackend())
.build();
}

LogbackLogBackend drives the concrete Logback LoggerContext — not the SLF4J facade. An SLF4J → Logback binding routes here because the emitting backend is Logback.

Level names are Logback-standard: TRACE, DEBUG, INFO, WARN, ERROR, OFF. A logger whose own level is not set returns an empty string (inherited from ancestor). The root logger is addressed as "ROOT".

Constructor options:

// Uses the SLF4J-bound LoggerContext (fails fast if SLF4J is not bound to Logback).
new LogbackLogBackend()

// Explicit LoggerContext — for tests or multi-context setups.
new LogbackLogBackend(loggerContext)

Log4j2​

@Bean
public LoggersSettings loggersSettings() {
return LoggersSettings.create()
.backend(new Log4j2LogBackend())
.build();
}

Log4j2LogBackend drives the Log4j2 LoggerContext / Configuration. An SLF4J → Log4j2 binding routes here because the emitting backend is Log4j2.

Level names are Log4j2-standard: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF, ALL. Unlike JUL and Logback, every LoggerConfig in the configuration carries a concrete level — there is no "inherited / no own level" sentinel, so reads return a level name (never an empty string) for configured loggers, and null for names that have no LoggerConfig. The root logger is addressed as "ROOT".

Constructor options:

// Uses the current LoggerContext (LogManager.getContext(false)).
new Log4j2LogBackend()

// Explicit LoggerContext — for tests or multi-context setups.
new Log4j2LogBackend(loggerContext)

Enabling write access​

The GET (read) endpoints are always exposed. The PUT / POST set-level endpoints are deny-by-default — they respond 403 Forbidden unless the registered LoggersSettings bean explicitly enables writes:

@Bean
public LoggersSettings loggersSettings() {
return LoggersSettings.create()
.enableWrite() // opt in to PUT/POST /loggers/{name}
.backend(new LogbackLogBackend()) // omit to keep JUL
.build();
}

The mutating endpoints should be protected with an auth guard — see Logging / Debugging for how to layer guards on management endpoints.

Changes made via the set-level endpoints are process-lifetime-only: they do not rewrite the backend's configuration file and are lost on restart.

Implementing a custom backend​

LogBackend is a plain three-method interface:

public interface LogBackend {
Map<String,String> getLevels();
String getLevel(String name);
void setLevel(String name, String level);
}

Implement it directly to drive any backend Juneau does not ship an adapter for (Dropwizard Metrics, system-property bridges, …):

@Bean
public LoggersSettings loggersSettings() {
return LoggersSettings.create()
.enableWrite()
.backend(new MyCustomBackend())
.build();
}

The endpoint never auto-detects a backend from the classpath — it only drives what the registered LoggersSettings bean declares, consistent with Juneau's explicit-over-magic posture.

Level-name reference​

BackendLevel names
JUL (JulLogBackend)FINEST FINER FINE CONFIG INFO WARNING SEVERE OFF ALL
Logback (LogbackLogBackend)TRACE DEBUG INFO WARN ERROR OFF
Log4j2 (Log4j2LogBackend)TRACE DEBUG INFO WARN ERROR FATAL OFF ALL

All backends accept "ROOT" as the name for the root logger. A blank or null level clears the logger's own level so it inherits from its ancestor (JUL and Logback); Log4j2 resets to the parent logger's configured level.

See also​