A Comprehensive Guide to Logging using YAML for Spring Boot 3

Logging is crucial in any Java application, especially when building production-grade systems using Spring Boot. This guide will take you from the basics of setting up logging configurations in YAML to more advanced topics, ensuring your system is production-ready.

1. Basic Logging Levels

  • TRACE: Most detailed information. Rarely used in production.
  • DEBUG: Detailed information on application flow. Useful for debugging.
  • INFO: General information about application events (e.g., startup).
  • WARN: An indication of potential issues.
  • ERROR: Error events that might disrupt functionality.
  • FATAL: Critical issues causing the application to stop.

2. Setting Up Basic Logging in application.yml

When using YAML for configuration in Spring Boot, you can define logging settings directly in the application.yml file. Here’s how you can set the root logging level:

logging:
  level:
    ROOT: INFO

The above configuration sets the default logging level to INFO for all packages. If you want to specify different logging levels for specific packages or classes, you can extend it as follows:

logging:
  level:
    com.example: DEBUG
    org.springframework: WARN
    com.example.service.MyService: ERROR

This configuration sets DEBUG for the com.example package, WARN for org.springframework, and ERROR for the specific class MyService within the com.example.service package.

3. Configuring a Rolling File Appender

Logging everything to the console is useful during development, but in production, logs should be persisted to files. A rolling file appender is commonly used to manage log files efficiently. You can set this up in application.yml like this:

logging:
  file:
    path: /logs/application.log
  logback:
    rollingpolicy:
      max-file-size: 10MB
      file-name-pattern: /logs/archived/application-%d{yyyy-MM-dd}.%i.log
      max-history: 30

Explanation:

  • path: Defines where the log file is stored.
  • rollingpolicy: Manages log file rotation based on size and date.
  • max-file-size: The maximum size a single log file can reach before rotation.
  • file-name-pattern: The pattern for archived log files.
  • max-history: The number of days log files are retained.

4. Advanced Log Configuration by Package

For more granular control, you can set different logging levels per package:

logging:
  level:
    ROOT: WARN
    com.filenet.wcm: ERROR
    de.mycompany: DEBUG

This sets ERROR for com.filenet.wcm and DEBUG for de.mycompany. The root level remains at WARN, and any sub-package logging levels override it as needed.

Common Pitfall: Ensure the syntax follows YAML’s indentation rules. Incorrect spacing can cause parsing errors.

5. Logging Incoming HTTP Requests

To log incoming HTTP requests in Spring Boot, you can use CommonsRequestLoggingFilter:

logging:
  level:
    org.springframework.web.filter.CommonsRequestLoggingFilter: DEBUG

Java Configuration:

@Configuration
public class RequestLoggingFilterConfig {

    @Bean
    public CommonsRequestLoggingFilter logFilter() {
        CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
        filter.setIncludeQueryString(true);
        filter.setIncludePayload(true);
        filter.setMaxPayloadLength(10000);
        filter.setIncludeHeaders(false);
        filter.setAfterMessagePrefix("REQUEST DATA : ");
        return filter;
    }
}

This setup logs the query string and payload for each request. It’s especially useful for debugging HTTP calls.

6. Implementing a Custom Log Format

Customizing log formats can enhance readability and make logs more informative:

logging:
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n"

This configuration formats logs with a timestamp, log level, thread name, logger name, and the message. You can adjust the pattern to suit your needs.

7. Adding Log Filters

Log filters control what gets logged based on specific criteria. This is particularly helpful when you need to filter out noisy logs:

logging:
  level:
    org.hibernate: INFO
    org.hibernate.SQL: DEBUG
    org.hibernate.type: TRACE

This example sets the SQL queries to DEBUG level and TRACE for Hibernate type information. Fine-tuning these levels helps reduce log noise while retaining essential information.

8. Integrating Logback-Spring.xml for Advanced Configuration

For scenarios that require more advanced logging setups, you can use logback-spring.xml instead of YAML. Here’s a basic setup:

logback-spring.xml:

<configuration>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/archived/application-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d %-5level [%thread] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="FILE"/>
    </root>
</configuration>

Switching to XML allows for greater flexibility, like adding multiple appenders or custom log filters.

9. Best Practices for Production-Ready Logging

  1. Use Proper Log Levels: Set different levels for development (DEBUG) and production (WARN or ERROR) to prevent log flooding in production.
  2. Centralize Logs: Use centralized logging tools (e.g., ELK stack, Graylog) to aggregate logs from different services and make analysis easier.
  3. Configure Log Rotation: Prevent disk space exhaustion by implementing proper log rotation policies.
  4. Avoid Sensitive Data: Ensure logs don’t contain sensitive information like passwords, API keys, or personally identifiable information (PII).

10. Dynamic Log Level Changes Without Restarting

Spring Boot allows changing log levels dynamically through Actuator. Add spring-boot-starter-actuator as a dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Enable the logging endpoint in application.yml:

management:
  endpoints:
    web:
      exposure:
        include: loggers

Now, you can update log levels via HTTP POST:

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

Conclusion

By following these steps, you can set up a robust logging system that provides the right amount of information without overwhelming your logs. Fine-tune your configurations based on your development and production needs, ensuring your application remains efficient and easy to debug.