最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

1.1 基本原理

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

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

1.2 實(shí)現(xiàn)方式

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配置

對于更復(fù)雜的配置,可以使用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 最佳實(shí)踐

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

二、分級日志策略

2.1 基本原理

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

SpringBoot支持標(biāo)準(zhǔn)的日志級別:TRACE、DEBUG、INFO、WARN、ERROR。

2.2 實(shí)現(xiàn)方式

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ī)范對團(tuán)隊協(xié)作至關(guān)重要:

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

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

2.4 最佳實(shí)踐

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

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

三、日志切面實(shí)現(xiàn)策略

3.1 基本原理

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

3.2 實(shí)現(xiàn)方式

3.2.1 基礎(chǔ)日志切面

@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請求響應(yīng)日志切面

@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 自定義注解實(shí)現(xiàn)有選擇的日志記錄

@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 最佳實(shí)踐

  • 合理定義切點(diǎn):避免過于寬泛的切點(diǎn)定義,防止產(chǎn)生過多日志
  • 注意性能影響:記錄詳細(xì)參數(shù)和結(jié)果可能帶來性能開銷,需權(quán)衡取舍
  • 異常處理:確保日志切面本身不會拋出異常,影響主業(yè)務(wù)流程
  • 避免敏感信息:敏感數(shù)據(jù)進(jìn)行脫敏處理后再記錄
// 敏感信息脫敏示例
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 實(shí)現(xiàn)方式

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());
            
            // 設(shè)置響應(yīng)頭,便于客戶端跟蹤
            response.setHeader("X-Request-ID", requestId);
            
            filterChain.doFilter(request, response);
        } finally {
            // 清理MDC上下文,防止內(nèi)存泄漏
            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集成,實(shí)現(xiàn)全鏈路追蹤:

<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 {
            // 設(shè)置新的MDC上下文
            MDC.put("jobId", jobId);
            if (context != null) {
                context.forEach(MDC::put);
            }
            
            log.info("Starting background job processing");
            
            // 執(zhí)行業(yè)務(wù)邏輯
            // ...
            
            log.info("Completed background job processing");
            return CompletableFuture.completedFuture(null);
        } finally {
            // 恢復(fù)原有MDC上下文或清除
            if (previousContext != null) {
                MDC.setContextMap(previousContext);
            } else {
                MDC.clear();
            }
        }
    }
}

4.3 最佳實(shí)踐

  • 唯一請求標(biāo)識:為每個請求生成唯一ID,便于追蹤完整請求鏈路
  • 傳遞MDC上下文:在異步處理和線程池中正確傳遞MDC上下文
  • 合理選擇MDC信息:記錄有價值的上下文信息,但避免過多信息造成日志膨脹
  • 與分布式追蹤結(jié)合:與Sleuth、Zipkin等工具結(jié)合,提供完整的分布式追蹤能力
// 自定義線程池配置,傳遞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 實(shí)現(xiàn)方式

5.2.1 Logback異步配置

<configuration>
    <!-- 定義日志內(nèi)容和格式 -->
    <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進(jìn)行更高級的性能優(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 自定義異步日志記錄器

對于特殊需求,可以實(shí)現(xiàn)自定義的異步日志記錄器:

@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;
        });
        
        // 確保應(yīng)用關(guān)閉時處理完所有日志
        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 最佳實(shí)踐

  • 隊列大小設(shè)置:根據(jù)系統(tǒng)吞吐量和內(nèi)存情況設(shè)置合理的隊列大小
  • 丟棄策略配置:在高負(fù)載情況下,可以考慮丟棄低優(yōu)先級的日志
<AsyncAppender name="ASYNC" queueSize="512" discardingThreshold="20">
    <!-- 當(dāng)隊列剩余容量低于20%時,會丟棄TRACE, DEBUG和INFO級別的日志 -->
</AsyncAppender>
  • 異步日志的注意事項
    • 異步日志可能導(dǎo)致異常堆棧信息不完整
    • 系統(tǒng)崩潰時可能丟失最后一批日志
    • 需要權(quán)衡性能和日志完整性
  • 合理使用同步與異步
    • 關(guān)鍵操作日志(如金融交易)使用同步記錄確保可靠性
    • 高頻但不關(guān)鍵的日志(如訪問日志)使用異步記錄提高性能
// 同步記錄關(guān)鍵業(yè)務(wù)日志
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);

另外,性能要求較高的應(yīng)用推薦使用log4j2的異步模式,性能遠(yuǎn)高于logback。

六、總結(jié)

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

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

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

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

相關(guān)文章

  • springboot實(shí)現(xiàn)maven多模塊和打包部署

    springboot實(shí)現(xiàn)maven多模塊和打包部署

    本文主要介紹了springboot實(shí)現(xiàn)maven多模塊和打包部署,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • java中request常用方法小結(jié)

    java中request常用方法小結(jié)

    這篇文章主要介紹了java中request常用方法小結(jié),需要的朋友可以參考下
    2014-10-10
  • Java實(shí)現(xiàn)根據(jù)地址智能識別省市區(qū)縣

    Java實(shí)現(xiàn)根據(jù)地址智能識別省市區(qū)縣

    這篇文章主要為大家詳細(xì)介紹了如何編寫一個Java工具類,可以根據(jù)身份證地址或用戶輸入的地址,智能識別并提取出詳細(xì)的省市區(qū)縣信息,感興趣的小伙伴可以了解下
    2025-03-03
  • SpringBoot中使用異步調(diào)度程序的高級方法

    SpringBoot中使用異步調(diào)度程序的高級方法

    本文主要介紹了SpringBoot中使用異步調(diào)度程序的高級方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • Spring?Boot整合ELK實(shí)現(xiàn)日志采集與監(jiān)控

    Spring?Boot整合ELK實(shí)現(xiàn)日志采集與監(jiān)控

    這篇文章主要介紹了Spring?Boot整合ELK實(shí)現(xiàn)日志采集與監(jiān)控,需要的朋友可以參考下
    2022-06-06
  • 最新評論

    西贡区| 鸡东县| 桐乡市| 梅州市| 陇川县| 左权县| 正阳县| 团风县| 定日县| 南宁市| 长乐市| 孟津县| 凌海市| 达拉特旗| 长治市| 泸西县| 牡丹江市| 沾化县| 盈江县| 九寨沟县| 延长县| 容城县| 长汀县| 岱山县| 富阳市| 甘南县| 双鸭山市| 来宾市| 禹城市| 县级市| 富裕县| 垫江县| 荆州市| 金华市| 威信县| 贡嘎县| 太白县| 孝义市| 斗六市| 图们市| 丰镇市|