Logback Configuration in Spring Boot: Multi‑Env, Dynamic Levels, Async, Masking, MDC & Trace Integration

This guide walks through a complete Logback setup for Spring Boot, covering multi‑environment profiles, runtime log‑level changes via Actuator, async appender tuning, structured JSON output, sensitive‑data masking, MDC‑based distributed tracing, exception stack filtering, performance metrics and best‑practice recommendations.

Programmer1970
Programmer1970
Programmer1970
Logback Configuration in Spring Boot: Multi‑Env, Dynamic Levels, Async, Masking, MDC & Trace Integration

Logback Core Configuration

Use logback-spring.xml together with Spring profiles to isolate logging settings per environment.

<configuration>
  <!-- Development -->
  <springProfile name="dev">
    <root level="DEBUG">
      <appender-ref ref="CONSOLE"/>
    </root>
    <logger name="com.example" level="TRACE" additivity="false">
      <appender-ref ref="CONSOLE"/>
    </logger>
  </springProfile>

  <!-- Production -->
  <springProfile name="prod">
    <root level="INFO">
      <appender-ref ref="ASYNC_FILE"/>
      <appender-ref ref="ELK"/>
    </root>
    <logger name="com.example.payment" level="WARN" additivity="false">
      <appender-ref ref="PAYMENT_FILE"/>
    </logger>
  </springProfile>
</configuration>

Dynamic Log Level Management

Spring Boot Actuator exposes /actuator/loggers to view and modify logger levels at runtime.

# application.yml
management:
  endpoint:
    loggers:
      enabled: true
  endpoints:
    web:
      exposure:
        include: loggers

Typical API calls: GET /actuator/loggers – list all loggers. GET /actuator/loggers/com.example.payment – fetch current level. POST /actuator/loggers/com.example.payment with {"configuredLevel":"DEBUG"} – change level. POST /actuator/loggers/com.example.payment with {"configuredLevel":null} – reset to default.

Async Logging Optimization

Configure AsyncAppender to move I/O off the application thread. Key parameters are queueSize, discardingThreshold, neverBlock and maxFlushTime.

<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
  <queueSize>4096</queueSize>
  <discardingThreshold>819</discardingThreshold>
  <neverBlock>true</neverBlock>
  <maxFlushTime>1000</maxFlushTime>
  <appender-ref ref="FILE"/>
</appender>

Log Format and Rolling Policy

A fixed‑length pattern reduces parsing overhead.

<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
  <layout class="ch.qos.logback.classic.PatternLayout">
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%5.5thread] %-5level %40.40logger{39} %4line : %msg%n</pattern>
  </layout>
  <charset>UTF-8</charset>
</encoder>

Rolling policy uses SizeAndTimeBasedRollingPolicy with maxFileSize 256 MB, maxHistory 7 days, totalSizeCap 10 GB and immediateFlush set to false for production.

Structured Logging with Logstash Encoder

JSON output simplifies ingestion by log‑analysis platforms.

<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>logs/structured.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <fileNamePattern>logs/structured-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxFileSize>128MB</maxFileSize>
    <maxHistory>30</maxHistory>
  </rollingPolicy>
  <encoder class="net.logstash.logback.encoder.LogstashEncoder">
    <customFields>{"app_name":"${spring.application.name}","env":"${spring.profiles.active}"}</customFields>
    <timestampPattern>yyyy-MM-dd'T'HH:mm:ss.SSSZ</timestampPattern>
    <includeMdc>true</includeMdc>
  </encoder>
</appender>

Sensitive Data Masking

A custom ClassicConverter masks credit‑card numbers, phone numbers and email addresses before they are written.

public class SensitiveDataConverter extends ClassicConverter {
  private static final Pattern CREDIT_CARD_PATTERN = Pattern.compile("\\b(?:\\d[ -]*?){15,16}\\b");
  private static final Pattern PHONE_PATTERN = Pattern.compile("(\\d{3})\\d{4}(\\d{4})");
  private static final Pattern EMAIL_PATTERN = Pattern.compile("(?<=@)[^@]+(?=\\.[^.]+$)");

  @Override
  public String convert(ILoggingEvent event) {
    String message = event.getFormattedMessage();
    message = CREDIT_CARD_PATTERN.matcher(message).replaceAll("****-****-****-****");
    message = PHONE_PATTERN.matcher(message).replaceAll("$1****$2");
    message = EMAIL_PATTERN.matcher(message).replaceAll("***");
    return message;
  }
}

Register the converter in logback-spring.xml and use %sensitive in the pattern.

MDC and Distributed Tracing

Trace identifiers are propagated via MDC so every log line carries the request context.

public class TraceIdInterceptor implements HandlerInterceptor {
  private static final String TRACE_ID = "traceId";

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    String traceId = request.getHeader("X-Trace-Id");
    if (traceId == null || traceId.isEmpty()) {
      traceId = UUID.randomUUID().toString().replace("-", "");
    }
    MDC.put(TRACE_ID, traceId);
    return true;
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    MDC.remove(TRACE_ID);
  }
}

For async tasks, a TaskDecorator copies the MDC map.

public class MdcTaskDecorator implements TaskDecorator {
  @Override
  public Runnable decorate(Runnable runnable) {
    Map<String, String> contextMap = MDC.getCopyOfContextMap();
    return () -> {
      if (contextMap != null) {
        MDC.setContextMap(contextMap);
      }
      try {
        runnable.run();
      } finally {
        MDC.clear();
      }
    };
  }
}

Exception Stack Enhancement

Filter noisy packages from stack traces and use a custom ThrowableConverter to keep only relevant frames.

<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
  <pattern>%d{ISO8601} [%thread] %-5level %logger - %msg%n%ex{full, sun.reflect, org.springframework, org.apache.catalina, org.apache.coyote, org.apache.tomcat, java.lang.reflect.Method, com.netflix, feign, org.hibernate}</pattern>
</encoder>

Performance Monitoring

Key metrics to watch:

Log write throughput (events/sec).

Async queue depth and discarding threshold.

Log file size growth rate.

Error‑log proportion.

Latency of critical operations.

Micrometer bridge example:

@Configuration
public class LoggingMetricsConfig {
  @Bean
  public MicrometerBridge micrometerBridge() {
    return new MicrometerBridge();
  }
}

public class MicrometerBridge implements LoggingEventAware {
  private final Counter asyncQueueSize;
  private final Timer logProcessingTime;

  public MicrometerBridge() {
    MeterRegistry registry = Metrics.globalRegistry;
    this.asyncQueueSize = registry.counter("log.async.queue.size");
    this.logProcessingTime = registry.timer("log.processing.time");
  }

  @Override
  public void beforeLogEvent(ILoggingEvent event) {
    // optional pre‑log metrics
  }

  @Override
  public void afterLogEvent(ILoggingEvent event) {
    logProcessingTime.record(event.getTimeStamp() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
  }
}

Prometheus alert for high error rate:

groups:
- name: logging-alerts
  rules:
  - alert: HighErrorRate
    expr: sum(rate(logback_events_total{level="error"}[5m])) by (app) > 10
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "High error rate on {{ $labels.app }}"
      description: "Error rate is {{ $value }} errors/sec"

Best‑Practice Summary

Use logback-spring.xml with Spring profiles for environment isolation.

Enable AsyncAppender in production to avoid blocking the application thread.

Set log levels per environment (DEBUG for dev, INFO/WARN for prod).

Prefer JSON structured logs for downstream analysis platforms.

Implement a unified masking converter to protect sensitive data.

Propagate trace identifiers via MDC for full‑stack tracing.

Monitor key log‑system metrics and configure alerts.

Plan storage capacity based on observed log growth rates.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Performance MonitoringloggingSpring BootLogbackData MaskingMDCAsyncAppender
Programmer1970
Written by

Programmer1970

Formerly called 'Code to 35'. Add our main WeChat ID to access a wealth of shared resources (algorithms, interview prep, tech stacks: Java, Python, Go, big data). We mainly share serious development techniques, focusing on output-driven input. Occasionally we post life snippets and gossip. Our aim is to attract precise traffic and test advertising opportunities.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.