欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中日志輸出規(guī)范的五種策略

 更新時間:2025年06月08日 09:53:55   作者:風象南  
在企業(yè)級應用開發(fā)中,合理規(guī)范的日志記錄是系統(tǒng)穩(wěn)定運行、問題排查和性能優(yōu)化的關鍵保障,SpringBoot作為流行的Java開發(fā)框架,提供了強大而靈活的日志支持,但如何建立統(tǒng)一、高效的日志輸出規(guī)范卻是許多團隊面臨的挑戰(zhàn),本文將介紹SpringBoot中5種日志輸出規(guī)范策略

一、統(tǒng)一日志格式配置策略

1.1 基本原理

統(tǒng)一的日志格式是團隊協(xié)作的基礎,可以提高日志的可讀性和可分析性。

SpringBoot允許開發(fā)者自定義日志輸出格式,包括時間戳、日志級別、線程信息、類名和消息內容等。

1.2 實現方式

1.2.1 配置文件方式

application.propertiesapplication.yml中定義日志格式:

# application.properties
# 控制臺日志格式
logging.pattern.console=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}

# 文件日志格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}

YAML格式配置:

logging:
  pattern:
    console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"
    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"

1.2.2 自定義Logback配置

對于更復雜的配置,可以使用logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="CONSOLE_LOG_PATTERN" 
        value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
    <property name="FILE_LOG_PATTERN" 
        value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
    
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>logs/archived/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

1.2.3 JSON格式日志配置

對于需要集中式日志分析的系統(tǒng),配置JSON格式日志更有利于日志處理:

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>7.2</version>
</dependency>
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logs/application.json</file>
    <encoder class="net.logstash.logback.encoder.LogstashEncoder">
        <includeMdcKeyName>requestId</includeMdcKeyName>
        <includeMdcKeyName>userId</includeMdcKeyName>
        <customFields>{"application":"my-service","environment":"${ENVIRONMENT:-development}"}</customFields>
    </encoder>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <fileNamePattern>logs/archived/application.%d{yyyy-MM-dd}.%i.json</fileNamePattern>
        <maxFileSize>10MB</maxFileSize>
        <maxHistory>30</maxHistory>
        <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>
</appender>

1.3 最佳實踐

  • 環(huán)境區(qū)分:為不同環(huán)境配置不同的日志格式(開發(fā)環(huán)境可讀性高,生產環(huán)境機器可解析)
<springProfile name="dev">
    <!-- 開發(fā)環(huán)境配置 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{15}) - %msg%n</pattern>
        </encoder>
    </appender>
</springProfile>
<springProfile name="prod">
    <!-- 生產環(huán)境配置 -->
    <appender name="JSON_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>
</springProfile>
  • 添加關鍵信息:確保日志中包含足夠的上下文信息
%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] [%X{userId}] %-5level [%thread] %logger{36} - %msg%n
  • 注意敏感信息:避免記錄密碼、令牌等敏感信息,必要時進行脫敏處理

二、分級日志策略

2.1 基本原理

合理使用日志級別可以幫助區(qū)分不同重要程度的信息,便于問題定位和系統(tǒng)監(jiān)控。

SpringBoot支持標準的日志級別:TRACE、DEBUG、INFO、WARN、ERROR。

2.2 實現方式

2.2.1 配置不同包的日志級別

# 全局日志級別
logging.level.root=INFO

# 特定包的日志級別
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
logging.level.com.mycompany.app=DEBUG

2.2.2 基于環(huán)境的日志級別配置

# application.yml
spring:
  profiles:
    active: dev

---
spring:
  config:
    activate:
      on-profile: dev
logging:
  level:
    root: INFO
    com.mycompany.app: DEBUG
    org.springframework: INFO

---
spring:
  config:
    activate:
      on-profile: prod
logging:
  level:
    root: WARN
    com.mycompany.app: INFO
    org.springframework: WARN

2.2.3 編程式日志級別管理

@RestController
@RequestMapping("/api/logs")
public class LoggingController {
    
    @Autowired
    private LoggingSystem loggingSystem;
    
    @PutMapping("/level/{package}/{level}")
    public void changeLogLevel(
            @PathVariable("package") String packageName,
            @PathVariable("level") String level) {
        LogLevel logLevel = LogLevel.valueOf(level.toUpperCase());
        loggingSystem.setLogLevel(packageName, logLevel);
    }
}

2.3 日志級別使用規(guī)范

建立清晰的日志級別使用規(guī)范對團隊協(xié)作至關重要:

  • ERROR:系統(tǒng)錯誤、應用崩潰、服務不可用等嚴重問題
try {
    // 業(yè)務操作
} catch (Exception e) {
    log.error("Failed to process payment for order: {}", orderId, e);
    throw new PaymentProcessingException("Payment processing failed", e);
}
  • WARN:不影響當前功能但需要注意的問題
if (retryCount > maxRetries / 2) {
    log.warn("High number of retries detected for operation: {}, current retry: {}/{}", 
        operationType, retryCount, maxRetries);
}

  • INFO:重要業(yè)務流程、系統(tǒng)狀態(tài)變更等信息
log.info("Order {} has been successfully processed with {} items", 
    order.getId(), order.getItems().size());
  • DEBUG:調試信息,詳細的處理流程
log.debug("Processing product with ID: {}, name: {}, category: {}", 
    product.getId(), product.getName(), product.getCategory());
  • TRACE:最詳細的追蹤信息,一般用于框架內部
log.trace("Method execution path: class={}, method={}, params={}", 
    className, methodName, Arrays.toString(args));

2.4 最佳實踐

  • 默認使用INFO級別:生產環(huán)境默認使用INFO級別,開發(fā)環(huán)境可使用DEBUG
  • 合理劃分包結構:按功能或模塊劃分包,便于精細控制日志級別
  • 避免日志爆炸:謹慎使用DEBUG和TRACE級別,避免產生大量無用日志
  • 條件日志:使用條件判斷減少不必要的字符串拼接開銷
// 推薦方式
if (log.isDebugEnabled()) {
    log.debug("Complex calculation result: {}", calculateComplexResult());
}

// 避免這樣使用
log.debug("Complex calculation result: " + calculateComplexResult());

三、日志切面實現策略

3.1 基本原理

使用AOP(面向切面編程)可以集中處理日志記錄,避免在每個方法中手動編寫重復的日志代碼。尤其適合API調用日志、方法執(zhí)行時間統(tǒng)計等場景。

3.2 實現方式

3.2.1 基礎日志切面

@Aspect
@Component
@Slf4j
public class LoggingAspect {
    
    @Pointcut("execution(* com.mycompany.app.service.*.*(..))")
    public void serviceLayer() {}
    
    @Around("serviceLayer()")
    public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        
        log.info("Executing: {}.{}", className, methodName);
        
        long startTime = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long executionTime = System.currentTimeMillis() - startTime;
            log.info("Executed: {}.{} in {} ms", className, methodName, executionTime);
            return result;
        } catch (Exception e) {
            log.error("Exception in {}.{}: {}", className, methodName, e.getMessage(), e);
            throw e;
        }
    }
}

3.2.2 API請求響應日志切面

@Aspect
@Component
@Slf4j
public class ApiLoggingAspect {
    
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) || " +
              "@annotation(org.springframework.web.bind.annotation.GetMapping) || " +
              "@annotation(org.springframework.web.bind.annotation.PostMapping) || " +
              "@annotation(org.springframework.web.bind.annotation.PutMapping) || " +
              "@annotation(org.springframework.web.bind.annotation.DeleteMapping)")
    public void apiMethods() {}
    
    @Around("apiMethods()")
    public Object logApiCall(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .currentRequestAttributes()).getRequest();
        
        String requestURI = request.getRequestURI();
        String httpMethod = request.getMethod();
        String clientIP = request.getRemoteAddr();
        
        log.info("API Request - Method: {} URI: {} Client: {}", httpMethod, requestURI, clientIP);
        
        long startTime = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long duration = System.currentTimeMillis() - startTime;
            
            log.info("API Response - Method: {} URI: {} Duration: {} ms Status: SUCCESS", 
                     httpMethod, requestURI, duration);
            return result;
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            log.error("API Response - Method: {} URI: {} Duration: {} ms Status: ERROR Message: {}", 
                     httpMethod, requestURI, duration, e.getMessage(), e);
            throw e;
        }
    }
}

3.2.3 自定義注解實現有選擇的日志記錄

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface LogExecutionTime {
    String description() default "";
}
@Aspect
@Component
@Slf4j
public class CustomLogAspect {
    
    @Around("@annotation(logExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
        String description = logExecutionTime.description();
        String methodName = joinPoint.getSignature().getName();
        
        log.info("Starting {} - {}", methodName, description);
        long startTime = System.currentTimeMillis();
        
        try {
            Object result = joinPoint.proceed();
            long executionTime = System.currentTimeMillis() - startTime;
            log.info("Completed {} - {} in {} ms", methodName, description, executionTime);
            return result;
        } catch (Exception e) {
            long executionTime = System.currentTimeMillis() - startTime;
            log.error("Failed {} - {} after {} ms: {}", methodName, description, 
                     executionTime, e.getMessage(), e);
            throw e;
        }
    }
}

使用示例:

@Service
public class OrderService {
    
    @LogExecutionTime(description = "Process order payment")
    public PaymentResult processPayment(Order order) {
        // 處理支付邏輯
    }
}

3.3 最佳實踐

  • 合理定義切點:避免過于寬泛的切點定義,防止產生過多日志
  • 注意性能影響:記錄詳細參數和結果可能帶來性能開銷,需權衡取舍
  • 異常處理:確保日志切面本身不會拋出異常,影響主業(yè)務流程
  • 避免敏感信息:敏感數據進行脫敏處理后再記錄
// 敏感信息脫敏示例
private String maskCardNumber(String cardNumber) {
    if (cardNumber == null || cardNumber.length() < 8) {
        return "***";
    }
    return "******" + cardNumber.substring(cardNumber.length() - 4);
}

四、MDC上下文跟蹤策略

4.1 基本原理

MDC (Mapped Diagnostic Context) 是一種用于存儲請求級別上下文信息的工具,它可以在日志框架中保存和傳遞這些信息,特別適合分布式系統(tǒng)中的請求跟蹤。

4.2 實現方式

4.2.1 配置MDC過濾器

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MdcLoggingFilter extends OncePerRequestFilter {
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 
                                   FilterChain filterChain) throws ServletException, IOException {
        try {
            // 生成唯一請求ID
            String requestId = UUID.randomUUID().toString().replace("-", "");
            MDC.put("requestId", requestId);
            
            // 添加用戶信息(如果有)
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.isAuthenticated()) {
                MDC.put("userId", authentication.getName());
            }
            
            // 添加請求信息
            MDC.put("clientIP", request.getRemoteAddr());
            MDC.put("userAgent", request.getHeader("User-Agent"));
            MDC.put("httpMethod", request.getMethod());
            MDC.put("requestURI", request.getRequestURI());
            
            // 設置響應頭,便于客戶端跟蹤
            response.setHeader("X-Request-ID", requestId);
            
            filterChain.doFilter(request, response);
        } finally {
            // 清理MDC上下文,防止內存泄漏
            MDC.clear();
        }
    }
}

4.2.2 日志格式中包含MDC信息

<property name="CONSOLE_LOG_PATTERN" 
    value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] [%X{userId}] %-5level [%thread] %logger{36} - %msg%n"/>

4.2.3 分布式追蹤集成

與Spring Cloud Sleuth和Zipkin集成,實現全鏈路追蹤:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
spring.application.name=my-service
spring.sleuth.sampler.probability=1.0
spring.zipkin.base-url=http://localhost:9411

4.2.4 手動管理MDC上下文

@Service
public class BackgroundJobService {
    
    private static final Logger log = LoggerFactory.getLogger(BackgroundJobService.class);
    
    @Async
    public CompletableFuture<Void> processJob(String jobId, Map<String, String> context) {
        // 保存原有MDC上下文
        Map<String, String> previousContext = MDC.getCopyOfContextMap();
        
        try {
            // 設置新的MDC上下文
            MDC.put("jobId", jobId);
            if (context != null) {
                context.forEach(MDC::put);
            }
            
            log.info("Starting background job processing");
            
            // 執(zhí)行業(yè)務邏輯
            // ...
            
            log.info("Completed background job processing");
            return CompletableFuture.completedFuture(null);
        } finally {
            // 恢復原有MDC上下文或清除
            if (previousContext != null) {
                MDC.setContextMap(previousContext);
            } else {
                MDC.clear();
            }
        }
    }
}

4.3 最佳實踐

  • 唯一請求標識:為每個請求生成唯一ID,便于追蹤完整請求鏈路
  • 傳遞MDC上下文:在異步處理和線程池中正確傳遞MDC上下文
  • 合理選擇MDC信息:記錄有價值的上下文信息,但避免過多信息造成日志膨脹
  • 與分布式追蹤結合:與Sleuth、Zipkin等工具結合,提供完整的分布式追蹤能力
// 自定義線程池配置,傳遞MDC上下文
@Configuration
public class AsyncConfig implements AsyncConfigurer {
    
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("MyAsync-");
        
        // 包裝原始Executor,傳遞MDC上下文
        executor.setTaskDecorator(runnable -> {
            Map<String, String> contextMap = MDC.getCopyOfContextMap();
            return () -> {
                try {
                    if (contextMap != null) {
                        MDC.setContextMap(contextMap);
                    }
                    runnable.run();
                } finally {
                    MDC.clear();
                }
            };
        });
        
        executor.initialize();
        return executor;
    }
}

五、異步日志策略

5.1 基本原理

在高性能系統(tǒng)中,同步記錄日志可能成為性能瓶頸,特別是在I/O性能受限的環(huán)境下。

異步日志通過將日志操作從主線程中分離,可以顯著提升系統(tǒng)性能。

5.2 實現方式

5.2.1 Logback異步配置

<configuration>
    <!-- 定義日志內容和格式 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 配置詳情... -->
    </appender>
    
    <!-- 異步appender -->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE" />
        <queueSize>512</queueSize>
        <discardingThreshold>0</discardingThreshold>
        <includeCallerData>false</includeCallerData>
        <neverBlock>false</neverBlock>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="ASYNC" />
    </root>
</configuration>

5.2.2 Log4j2異步配置

添加依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.4.4</version>
</dependency>

配置Log4j2:

<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        
        <RollingFile name="RollingFile" fileName="logs/app.log"
                    filePattern="logs/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
        
        <!-- 異步Appender -->
        <Async name="AsyncFile">
            <AppenderRef ref="RollingFile"/>
            <BufferSize>1024</BufferSize>
        </Async>
    </Appenders>
    
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="AsyncFile"/>
        </Root>
    </Loggers>
</Configuration>

5.2.3 性能優(yōu)化配置

針對Log4j2進行更高級的性能優(yōu)化:

<Configuration status="WARN" packages="com.mycompany.logging">
    <Properties>
        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
    </Properties>
    
    <Appenders>
        <!-- 使用MappedFile提高I/O性能 -->
        <RollingRandomAccessFile name="RollingFile" 
                               fileName="logs/app.log"
                               filePattern="logs/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="25 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="20"/>
        </RollingRandomAccessFile>
        
        <!-- 使用更高性能的Async配置 -->
        <Async name="AsyncFile" bufferSize="2048">
            <AppenderRef ref="RollingFile"/>
            <DisruptorBlockingQueue />
        </Async>
    </Appenders>
    
    <Loggers>
        <!-- 降低某些高頻日志的級別 -->
        <Logger name="org.hibernate.SQL" level="debug" additivity="false">
            <AppenderRef ref="AsyncFile" level="debug"/>
        </Logger>
        
        <Root level="info">
            <AppenderRef ref="AsyncFile"/>
        </Root>
    </Loggers>
</Configuration>

5.2.4 自定義異步日志記錄器

對于特殊需求,可以實現自定義的異步日志記錄器:

@Component
public class AsyncLogger {
    
    private static final Logger log = LoggerFactory.getLogger(AsyncLogger.class);
    
    private final ExecutorService logExecutor;
    
    public AsyncLogger() {
        this.logExecutor = Executors.newSingleThreadExecutor(r -> {
            Thread thread = new Thread(r, "async-logger");
            thread.setDaemon(true);
            return thread;
        });
        
        // 確保應用關閉時處理完所有日志
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            logExecutor.shutdown();
            try {
                if (!logExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                    log.warn("AsyncLogger executor did not terminate in the expected time.");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }));
    }
    
    public void info(String format, Object... arguments) {
        logExecutor.submit(() -> log.info(format, arguments));
    }
    
    public void warn(String format, Object... arguments) {
        logExecutor.submit(() -> log.warn(format, arguments));
    }
    
    public void error(String format, Object... arguments) {
        Throwable throwable = extractThrowable(arguments);
        if (throwable != null) {
            logExecutor.submit(() -> log.error(format, arguments));
        } else {
            logExecutor.submit(() -> log.error(format, arguments));
        }
    }
    
    private Throwable extractThrowable(Object[] arguments) {
        if (arguments != null && arguments.length > 0) {
            Object lastArg = arguments[arguments.length - 1];
            if (lastArg instanceof Throwable) {
                return (Throwable) lastArg;
            }
        }
        return null;
    }
}

5.3 最佳實踐

  • 隊列大小設置:根據系統(tǒng)吞吐量和內存情況設置合理的隊列大小
  • 丟棄策略配置:在高負載情況下,可以考慮丟棄低優(yōu)先級的日志
<AsyncAppender name="ASYNC" queueSize="512" discardingThreshold="20">
    <!-- 當隊列剩余容量低于20%時,會丟棄TRACE, DEBUG和INFO級別的日志 -->
</AsyncAppender>
  • 異步日志的注意事項
    • 異步日志可能導致異常堆棧信息不完整
    • 系統(tǒng)崩潰時可能丟失最后一批日志
    • 需要權衡性能和日志完整性
  • 合理使用同步與異步
    • 關鍵操作日志(如金融交易)使用同步記錄確??煽啃?/li>
    • 高頻但不關鍵的日志(如訪問日志)使用異步記錄提高性能
// 同步記錄關鍵業(yè)務日志
log.info("Transaction completed: id={}, amount={}, status={}", 
         transaction.getId(), transaction.getAmount(), transaction.getStatus());

// 異步記錄高頻統(tǒng)計日志
asyncLogger.info("API usage stats: endpoint={}, count={}, avgResponseTime={}ms", 
                endpoint, requestCount, avgResponseTime);

另外,性能要求較高的應用推薦使用log4j2的異步模式,性能遠高于logback。

六、總結

這些策略不是相互排斥的,而是可以結合使用,共同構建完整的日志體系。

在實際應用中,應根據項目規(guī)模、團隊情況和業(yè)務需求,選擇合適的日志規(guī)范策略組合。

好的日志實踐不僅能幫助開發(fā)者更快地定位和解決問題,還能為系統(tǒng)性能優(yōu)化和安全審計提供重要依據。

以上就是SpringBoot中日志輸出規(guī)范的五種策略的詳細內容,更多關于SpringBoot日志輸出規(guī)范的資料請關注腳本之家其它相關文章!

相關文章

  • java并發(fā)分段鎖實踐代碼

    java并發(fā)分段鎖實踐代碼

    這篇文章主要介紹了java并發(fā)分段鎖實踐代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-07-07
  • java中的動態(tài)代理(jdk和Cglib)實現詳解

    java中的動態(tài)代理(jdk和Cglib)實現詳解

    這篇文章主要介紹了java中的動態(tài)代理(jdk和Cglib)的相關資料,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2025-04-04
  • java封裝及四種權限修飾符詳解

    java封裝及四種權限修飾符詳解

    這篇文章主要介紹了java封裝及四種權限修飾符詳解,對屬性進行封裝,使用戶不能直接輸入數據,我們需要避免用戶再使用"對象.屬性"的方式對屬性進行賦值
    2022-08-08
  • java類中元素初始化順序詳解

    java類中元素初始化順序詳解

    對于靜態(tài)變量、靜態(tài)初始化塊、變量、初始化塊、構造器,它們的初始化順序依次是(靜態(tài)變量、靜態(tài)初始化塊)>(變量、初始化塊)>構造器
    2013-08-08
  • Spring中的@RestController注解詳細解析

    Spring中的@RestController注解詳細解析

    這篇文章主要介紹了Spring中的@RestController注解詳細解析,@RestController 是 Spring Framework 中的一個注解,用于標識一個類為 RESTful Web 服務的控制器(Controller),處理 HTTP 請求并返回相應的數據,
    2024-01-01
  • 如何解決UnsupportedOperationException異常問題

    如何解決UnsupportedOperationException異常問題

    這篇文章主要介紹了如何解決UnsupportedOperationException異常問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Spring Cloud Feign組成配置過程解析

    Spring Cloud Feign組成配置過程解析

    這篇文章主要介紹了Spring Cloud Feign組成配置過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • SpringBoot 集成 Jasypt 對數據庫加密以及踩坑的記錄分享

    SpringBoot 集成 Jasypt 對數據庫加密以及踩坑的記錄分享

    這篇文章主要介紹了SpringBoot 集成 Jasypt 對數據庫加密以及踩坑,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Java之SpringBoot自定義配置與整合Druid

    Java之SpringBoot自定義配置與整合Druid

    這篇文章主要介紹的是java之SpringBoot自定義配置與整合Druid的相關資料,關于SpringBoot配置文件可以是properties或者是yaml格式的文件,但是在SpringBoot加載application配置文件時是存在一個優(yōu)先級,下面小編就和大家一起進入文章學習這項知識
    2021-09-09
  • java多線程解決生產者消費者問題

    java多線程解決生產者消費者問題

    這篇文章主要介紹了java多線程解決生產者消費者問題的方法,實例分析了java采用多線程的方法解決生產者消費者問題的相關技巧,需要的朋友可以參考下
    2015-05-05

最新評論