1. Overview of log framework and introduction of SLF4j
1.1 Why logging frameworks are needed
Logging is a crucial component in software development. Imagine you are developing an e-commerce system:
- When a user fails to place an order, you need to know the specific reason.
- When there is a bottleneck in system performance, you need to track time-consuming operations
- When there is a problem with the production environment, you need to troubleshoot the root cause of the error
Without a good logging system, it is like groping in the dark and cannot quickly locate and solve problems.
1.2 Comparison of mainstream log frameworks
Frame Name | type | Features | Applicable scenarios |
---|---|---|---|
Log4j | accomplish | Produced by Apache, powerful functions and flexible configuration | Traditional Java Projects |
Log4j2 | accomplish | Log4j upgraded version, better performance and supports asynchronous | High performance requirements system |
Logback | accomplish | SLF4j native implementation, excellent performance | Spring Boot default |
JUL () | accomplish | JDK built-in, simple functions | When restricted by small applications or JDK environments |
SLF4j | Facade | Provide a unified interface and is not responsible for specific implementation | Scenarios that require flexibly switching log implementations |
1.3 The core value of SLF4j
SLF4j (Simple Logging Facade for Java) is a log facade, not a specific log implementation. It is similar to JDBC, providing a unified API, and the underlying layer can connect to different database drivers.
Advantages of facade mode:
- Decoupling: Business code does not rely on specific log implementation
- flexible: The underlying log framework can be switched at any time
- unified: Use a consistent logging API in your project
2. Spring Boot default log configuration
2.1 Log selection for Spring Boot
Spring Boot uses SLF4j + Logback combination by default:
- SLF4j: Provide a unified logging API
- Logback: As the default implementation of SLF4j, the performance is better than Log4j
2.2 Basic usage examples
import org.; import org.; @RestController public class OrderController { // Use SLF4j's LoggerFactory to get the Logger instance private static final Logger logger = (); @GetMapping("/order/{id}") public String getOrder(@PathVariable String id) { // Different levels of logging ("Track order inquiry,OrderID: {}", id); // The most detailed log ("Debugging information-OrderID: {}", id); // Debugging information ("查询Order,OrderID: {}", id); // Business information ("Order查询参数过长,ID: {}", id); // Warning message if(() > 20) { ("OrderIDException of format: {}", id); // error message throw new IllegalArgumentException("Illegal Order ID"); } return "Order Details"; } }
2.3 Detailed explanation of log level
SLF4j defines 6 log levels (from low to high):
level | meaning | Use scenarios | Whether to output by default |
---|---|---|---|
TRACE | track | The most detailed log information, record every step of the program execution | no |
DEBUG | debug | Debugging information, use in the development stage | no |
INFO | information | Important business process information | yes |
WARN | warn | Potential problems do not affect system operation | yes |
ERROR | mistake | Error message affects some functions | yes |
FATAL | fatal | Serious error causing system crash | Yes (Logback does not have this level and will be mapped to ERROR) |
3. Detailed explanation of SLF4j configuration file
3.1 Default configuration and customization
Spring Boot will look for the following log configuration files under classpath by default:
-
(recommend)
Why is it recommended to use?
Because it supports the Profile feature of Spring Boot, different configurations can be loaded according to different environments.
3.2 Complete configuration file analysis
Here is a complete oneExample, we parse in segments:
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="30 seconds"> <!-- Define variables --> <property name="LOG_HOME" value="./logs" /> <property name="APP_NAME" value="my-application" /> <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:} [%thread] %-5level %logger{36} - %msg%n" /> <!-- Console output --> <appender name="CONSOLE" class=""> <encoder> <pattern>${LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> <!-- The console outputs onlyINFOLevels above --> <filter class=""> <level>INFO</level> </filter> </appender> <!-- Scroll file output --> <appender name="FILE" class=""> <file>${LOG_HOME}/${APP_NAME}.log</file> <encoder> <pattern>${LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> <!-- Scrolling strategy --> <rollingPolicy class=""> <!-- Scroll by date and size --> <fileNamePattern>${LOG_HOME}/${APP_NAME}-%d{yyyy-MM-dd}.%</fileNamePattern> <!-- Maximum single file100MB --> <maxFileSize>100MB</maxFileSize> <!-- reserve30Day Log --> <maxHistory>30</maxHistory> <!-- The total size does not exceed5GB --> <totalSizeCap>5GB</totalSizeCap> </rollingPolicy> </appender> <!-- Asynchronous logs --> <appender name="ASYNC" class=""> <!-- Threshold for not losing logs,default256 --> <queueSize>512</queueSize> <!-- Add additionalappender --> <appender-ref ref="FILE" /> </appender> <!-- Log level settings --> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="ASYNC" /> </root> <!-- Specific package/Class log level --> <logger name="" level="DEBUG" /> <logger name="" level="WARN" /> <!-- Production environment specific configuration --> <springProfile name="prod"> <root level="WARN"> <appender-ref ref="CONSOLE" /> <appender-ref ref="ASYNC" /> </root> </springProfile> <!-- Development environment specific configuration --> <springProfile name="dev"> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> </root> </springProfile> </configuration>
3.3 Detailed explanation of configuration elements
3.3.1 Properties
<property name="LOG_HOME" value="./logs" />
property | illustrate | Example Values | necessity |
---|---|---|---|
name | Attribute name | LOG_HOME | Required |
value | Attribute value | ./logs | Required |
scope | Scope | context/system | Optional |
3.3.2 Output source (Appender)
1. Console output (ConsoleAppender)
<appender name="CONSOLE" class=""> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender>
2. File output (RollingFileAppender)
<appender name="FILE" class=""> <file>${LOG_HOME}/${APP_NAME}.log</file> <rollingPolicy class=""> <fileNamePattern>${LOG_HOME}/${APP_NAME}-%d{yyyy-MM-dd}.%</fileNamePattern> <maxFileSize>100MB</maxFileSize> <maxHistory>30</maxHistory> </rollingPolicy> </appender>
Comparison of scrolling strategies
Strategy | illustrate | Applicable scenarios |
---|---|---|
TimeBasedRollingPolicy | Scroll by time | Logs need to be split by day/hour |
SizeBasedTriggeringPolicy | Scroll by size | Need to limit the size of a single log file |
SizeAndTimeBasedRollingPolicy | Dual strategy of time and size | Split by time and size |
3.3.3 Log format (Pattern)
The log format consists of converters, commonly used converters:
Strategy | illustrate | Applicable scenarios |
---|---|---|
TimeBasedRollingPolicy | Scroll by time | Logs need to be split by day/hour |
SizeBasedTriggeringPolicy | Scroll by size | Need to limit the size of a single log file |
SizeAndTimeBasedRollingPolicy | Dual strategy of time and size | Split by time and size |
3.3.4 Filter
<filter class=""> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
Commonly used filters:
Filter class | Function | parameter |
---|---|---|
LevelFilter | Precise matching level | level, onMatch, onMismatch |
ThresholdFilter | Threshold filtering, record only if it is above or equal to this level | level |
EvaluatorFilter | Use expression filtering | evaluator |
3.3.5 Asynchronous logs (AsyncAppender)
<appender name="ASYNC" class=""> <queueSize>512</queueSize> <discardingThreshold>0</discardingThreshold> <appender-ref ref="FILE" /> </appender>
Parameter description
parameter | illustrate | default value | Suggested value |
---|---|---|---|
queueSize | Queue size | 256 | 512-2048 |
discardingThreshold | When the remaining queue capacity is less than this value, discard the TRACE/DEBUG log | queueSize/5 | 0(Don't discard) |
includeCallerData | Whether to include caller information | false | Production environment false (performance considerations) |
4. Advanced features and best practices
4.1 MDC (Mapped Diagnostic Context)
MDC is used to save thread context information in logs and is very suitable for web request tracking.
Example: Add a request ID to the log
import org.; @RestController public class OrderController { @GetMapping("/order/{id}") public String getOrder(@PathVariable String id) { // Set the MDC value ("requestId", ().toString()); ("userId", "user123"); try { ("Inquiry of orders: {}", id); // Business logic... return "Order details"; } finally { // Clear MDC (); } } }
Reference to MDC in logback configuration
<pattern>%d{yyyy-MM-dd HH:mm:} [%thread] [%X{requestId}] %-5level %logger{36} - %msg%n</pattern>
4.2 Log performance optimization
Parameterized log
Avoid string splicing and use placeholders:
// Not recommended("User " + userId + " login from " + ip); // recommend("User {} login from {}", userId, ip);
isXXXEnabled judgment
For high overhead logs:
if(()) { ("Large data: {}", expensiveOperation()); }
Asynchronous logs
As in the previous example, use AsyncAppender to reduce I/O blocking
4.3 Multi-environment configuration
Use Spring Profile to implement differentiated configuration in the environment:
<!-- Development Environment --> <springProfile name="dev"> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> </root> </springProfile> <!-- Production environment --> <springProfile name="prod"> <root level="INFO"> <appender-ref ref="FILE" /> <appender-ref ref="SENTRY" /> </root> </springProfile>
4.4 Log monitoring and alarm
Integrated Sentry implementation error monitoring:
<!-- Sentry Appender --> <appender name="SENTRY" class=""> <filter class=""> <level>ERROR</level> </filter> </appender>
5. Frequently Asked Questions and Solutions
5.1 Log conflict issues
Problem phenomenon: SLF4j report an errorSLF4J: Class path contains multiple SLF4J bindings
Solution:usemvn dependency:tree
Check dependencies and exclude unnecessary log implementations
<dependency> <groupId></groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId></groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency>
5.2 Log files are not generated
Check steps:
- Confirm the configuration file location is correct (under the resources directory)
- Check whether the file path has write permissions
- Check whether there is any exception log output
- Confirm that Appender is cited
<appender-ref ref="FILE" />
5.3 The log level does not take effect
Possible Causes:
- Configuration overwritten (check multiple configuration files)
- Package path configuration error
- Configuration not reloaded after modification (settings
scan="true"
)
6. Practical case: E-commerce system log design
6.1 Log classification design
Log Type | level | Output target | content |
---|---|---|---|
Access log | INFO | Log all HTTP requests | |
Business Log | INFO | Core business operations | |
Error log | ERROR | System exceptions and errors | |
SQL Logs | DEBUG | SQL statements and parameters | |
Performance Log | INFO | Interface time-consuming statistics |
6.2 Complete configuration example
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- Public properties --> <property name="LOG_HOME" value="/var/logs/ecommerce" /> <property name="APP_NAME" value="ecommerce" /> <!-- publicPattern --> <property name="COMMON_PATTERN" value="%d{yyyy-MM-dd HH:mm:} [%X{requestId}] [%thread] %-5level %logger{36} - %msg%n" /> <!-- Console output --> <appender name="CONSOLE" class=""> <encoder> <pattern>${COMMON_PATTERN}</pattern> </encoder> </appender> <!-- Access log --> <appender name="ACCESS" class=""> <file>${LOG_HOME}/</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:} [%X{requestId}] %msg%n</pattern> </encoder> <rollingPolicy class=""> <fileNamePattern>${LOG_HOME}/access.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> </appender> <!-- Error log --> <appender name="ERROR" class=""> <file>${LOG_HOME}/</file> <encoder> <pattern>${COMMON_PATTERN}</pattern> </encoder> <rollingPolicy class=""> <fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.%</fileNamePattern> <maxFileSize>100MB</maxFileSize> <maxHistory>60</maxHistory> </rollingPolicy> <filter class=""> <level>ERROR</level> </filter> </appender> <!-- asynchronousAppender --> <appender name="ASYNC_ERROR" class=""> <queueSize>1024</queueSize> <appender-ref ref="ERROR" /> </appender> <!-- Log level configuration --> <root level="INFO"> <appender-ref ref="CONSOLE" /> </root> <!-- Access logLogger --> <logger name="ACCESS_LOG" level="INFO" additivity="false"> <appender-ref ref="ACCESS" /> </logger> <!-- Error logLogger --> <logger name="ERROR_LOG" level="ERROR" additivity="false"> <appender-ref ref="ASYNC_ERROR" /> </logger> <!-- MyBatis SQLlog --> <logger name="" level="DEBUG" additivity="false"> <appender-ref ref="SQL" /> </logger> </configuration>
6.3 AOP implementation access log
@Aspect @Component public class AccessLogAspect { private static final Logger accessLog = ("ACCESS_LOG"); @Around("execution(* ..*.*(..))") public Object logAccess(ProceedingJoinPoint joinPoint) throws Throwable { HttpServletRequest request = ((ServletRequestAttributes) ()).getRequest(); // Record request information String requestId = ().toString(); ("requestId", requestId); long start = (); try { Object result = (); long cost = () - start; ("method={} uri={} status=success cost={}ms ip={} params={}", (), (), cost, (), ()); return result; } catch (Exception e) { long cost = () - start; ("method={} uri={} status=error cost={}ms error={}", (), (), cost, ()); throw e; } finally { (); } } }
7. Summary
7.1 Summary of key points
- Unified use of SLF4j API: Keep code decoupling from specific implementations
- Reasonable configuration of log levels: production environment is usually INFO, development environment DEBUG
- Log file segmentation strategy: split by time and size
- Enhanced logs with MDC: Add request tracking information
- Performance optimization: asynchronous log, parameterized log, isXXXEnabled judgment
- Multi-environment support: Use Profile to achieve differentiated configuration
This is the article about Spring Boot Integration SLF4j from basic to advanced practice (latest recommendation). For more related Spring Boot Integration SLF4j content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!