Files
gh-giuseppe-trisciuoglio-de…/skills/spring-boot/spring-boot-actuator/references/loggers.md
2025-11-29 18:28:30 +08:00

11 KiB

Loggers Endpoint

Spring Boot Actuator includes the ability to view and configure the log levels of your application at runtime. You can view either the entire list or an individual logger's configuration, which is made up of both the explicitly configured logging level as well as the effective logging level given to it by the logging framework. These levels can be one of:

  • TRACE
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL
  • OFF
  • null

null indicates that there is no explicit configuration.

Viewing Logger Configuration

View All Loggers

To view the configuration of all loggers:

GET /actuator/loggers

Response example:

{
  "levels": ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"],
  "loggers": {
    "ROOT": {
      "configuredLevel": "INFO",
      "effectiveLevel": "INFO"
    },
    "com.example": {
      "configuredLevel": null,
      "effectiveLevel": "INFO"
    },
    "com.example.MyClass": {
      "configuredLevel": "DEBUG",
      "effectiveLevel": "DEBUG"
    }
  }
}

View Specific Logger

To view the configuration of a specific logger:

GET /actuator/loggers/com.example.MyClass

Response example:

{
  "configuredLevel": "DEBUG",
  "effectiveLevel": "DEBUG"
}

Configuring a Logger

To configure a given logger, POST a partial entity to the resource's URI, as the following example shows:

POST /actuator/loggers/com.example.MyClass
Content-Type: application/json

{
    "configuredLevel": "DEBUG"
}

Tip

To "reset" the specific level of the logger (and use the default configuration instead), you can pass a value of null as the configuredLevel.

Reset Logger Level

To reset a logger to its default level:

POST /actuator/loggers/com.example.MyClass
Content-Type: application/json

{
    "configuredLevel": null
}

Configuration Examples

Enable Debug Logging for Specific Package

curl -X POST http://localhost:8080/actuator/loggers/com.example.service \
  -H "Content-Type: application/json" \
  -d '{"configuredLevel": "DEBUG"}'

Enable Trace Logging for Spring Security

curl -X POST http://localhost:8080/actuator/loggers/org.springframework.security \
  -H "Content-Type: application/json" \
  -d '{"configuredLevel": "TRACE"}'

Set Root Logger Level

curl -X POST http://localhost:8080/actuator/loggers/ROOT \
  -H "Content-Type: application/json" \
  -d '{"configuredLevel": "WARN"}'

Programmatic Logger Management

You can also manage loggers programmatically in your application:

@RestController
public class LoggerController {

    private final LoggingSystem loggingSystem;

    public LoggerController(LoggingSystem loggingSystem) {
        this.loggingSystem = loggingSystem;
    }

    @PostMapping("/admin/logger/{name}")
    public void setLogLevel(@PathVariable String name, @RequestBody LogLevelRequest request) {
        LogLevel level = request.getLevel() != null ? 
            LogLevel.valueOf(request.getLevel().toUpperCase()) : null;
        loggingSystem.setLogLevel(name, level);
    }

    public static class LogLevelRequest {
        private String level;
        
        public String getLevel() { return level; }
        public void setLevel(String level) { this.level = level; }
    }
}

Conditional Logging

Environment-based Configuration

logging:
  level:
    com.example: ${LOGGING_LEVEL_EXAMPLE:INFO}
    org.springframework.web: ${LOGGING_LEVEL_WEB:WARN}
    org.hibernate.SQL: ${LOGGING_LEVEL_SQL:WARN}
    org.hibernate.type.descriptor.sql: ${LOGGING_LEVEL_SQL_PARAMS:WARN}

---
spring:
  config:
    activate:
      on-profile: development
logging:
  level:
    com.example: DEBUG
    org.hibernate.SQL: DEBUG
    org.hibernate.type.descriptor.sql: TRACE

---
spring:
  config:
    activate:
      on-profile: production
logging:
  level:
    root: WARN
    com.example: INFO

Feature Toggle Logging

@Component
public class FeatureLoggingController {

    private final LoggingSystem loggingSystem;
    private final Environment environment;

    public FeatureLoggingController(LoggingSystem loggingSystem, Environment environment) {
        this.loggingSystem = loggingSystem;
        this.environment = environment;
    }

    @EventListener
    public void handleFeatureToggleChange(FeatureToggleEvent event) {
        if ("debug-logging".equals(event.getFeatureName())) {
            if (event.isEnabled()) {
                enableDebugLogging();
            } else {
                disableDebugLogging();
            }
        }
    }

    private void enableDebugLogging() {
        loggingSystem.setLogLevel("com.example.service", LogLevel.DEBUG);
        loggingSystem.setLogLevel("com.example.repository", LogLevel.DEBUG);
    }

    private void disableDebugLogging() {
        loggingSystem.setLogLevel("com.example.service", null);
        loggingSystem.setLogLevel("com.example.repository", null);
    }
}

Security Considerations

Securing the Loggers Endpoint

@Configuration
public class LoggersSecurityConfig {

    @Bean
    @Order(1)
    public SecurityFilterChain loggersSecurityFilterChain(HttpSecurity http) throws Exception {
        return http
            .requestMatcher(EndpointRequest.to("loggers"))
            .authorizeHttpRequests(requests -> 
                requests.anyRequest().hasRole("ADMIN"))
            .httpBasic(withDefaults())
            .build();
    }
}

Read-only Access

To provide read-only access to the loggers endpoint:

management:
  endpoint:
    loggers:
      access: read-only

Or configure programmatically:

@Configuration
public class LoggersAccessConfig {

    @Bean
    @Order(1)
    public SecurityFilterChain loggersSecurityFilterChain(HttpSecurity http) throws Exception {
        return http
            .requestMatcher(EndpointRequest.to("loggers"))
            .authorizeHttpRequests(requests -> 
                requests
                    .requestMatchers(HttpMethod.GET).hasRole("LOGGER_READER")
                    .requestMatchers(HttpMethod.POST).hasRole("LOGGER_ADMIN")
                    .anyRequest().denyAll())
            .httpBasic(withDefaults())
            .build();
    }
}

OpenTelemetry Integration

By default, logging via OpenTelemetry is not configured. You have to provide the location of the OpenTelemetry logs endpoint to configure it:

management:
  otlp:
    logging:
      endpoint: "https://otlp.example.com:4318/v1/logs"

Note

The OpenTelemetry Logback appender and Log4j appender are not part of Spring Boot. For more details, see the OpenTelemetry Logback appender or the OpenTelemetry Log4j2 appender in the OpenTelemetry Java instrumentation GitHub repository.

Tip

You have to configure the appender in your logback-spring.xml or log4j2-spring.xml configuration to get OpenTelemetry logging working.

The OpenTelemetryAppender for both Logback and Log4j requires access to an OpenTelemetry instance to function properly. This instance must be set programmatically during application startup:

@Component
public class OpenTelemetryAppenderInitializer {

    public OpenTelemetryAppenderInitializer(OpenTelemetry openTelemetry) {
        // Configure Logback appender
        if (LoggerFactory.getILoggerFactory() instanceof LoggerContext) {
            LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
            context.getStatusManager().add(new OnConsoleStatusListener());
            
            OpenTelemetryAppender appender = new OpenTelemetryAppender();
            appender.setContext(context);
            appender.setOpenTelemetry(openTelemetry);
            appender.start();
            
            ch.qos.logback.classic.Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME);
            rootLogger.addAppender(appender);
        }
    }
}

Best Practices

  1. Monitor Performance: Changing log levels at runtime can impact application performance
  2. Security: Always secure the loggers endpoint in production environments
  3. Audit Changes: Log when log levels are changed and by whom
  4. Temporary Changes: Consider making runtime log level changes temporary
  5. Documentation: Document the purpose of different log levels in your application
  6. Testing: Test your application with different log levels to ensure it performs well
  7. Correlation IDs: Use correlation IDs to track requests across log entries

Audit Log Level Changes

@Component
public class LoggerAuditListener {

    private static final Logger logger = LoggerFactory.getLogger(LoggerAuditListener.class);

    @EventListener
    public void handleLoggerConfigurationChange(LoggerConfigurationChangeEvent event) {
        String username = getCurrentUsername();
        logger.info("Logger level changed: logger={}, oldLevel={}, newLevel={}, user={}", 
                   event.getLoggerName(), 
                   event.getOldLevel(), 
                   event.getNewLevel(), 
                   username);
    }

    private String getCurrentUsername() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return auth != null ? auth.getName() : "system";
    }
}

Temporary Log Level Changes

@Component
public class TemporaryLogLevelManager {

    private final LoggingSystem loggingSystem;
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private final Map<String, LogLevel> originalLevels = new ConcurrentHashMap<>();

    public TemporaryLogLevelManager(LoggingSystem loggingSystem) {
        this.loggingSystem = loggingSystem;
    }

    public void setTemporaryLogLevel(String loggerName, LogLevel level, Duration duration) {
        // Store original level
        LoggerConfiguration config = loggingSystem.getLoggerConfiguration(loggerName);
        originalLevels.put(loggerName, config.getConfiguredLevel());
        
        // Set new level
        loggingSystem.setLogLevel(loggerName, level);
        
        // Schedule reset
        scheduler.schedule(() -> resetLogLevel(loggerName), duration.toMillis(), TimeUnit.MILLISECONDS);
    }

    private void resetLogLevel(String loggerName) {
        LogLevel originalLevel = originalLevels.remove(loggerName);
        loggingSystem.setLogLevel(loggerName, originalLevel);
    }
}