Spring Cloud Alibaba 微服务整合自定义日志注解完整教程

Spring Cloud 2025.0.0 整合自定义日志注解完整教程

本教程基于 Spring Cloud 2025.0.0 新特性,包含虚拟线程、响应式编程、AOT 原生编译支持

一、技术栈和架构

1.1 技术选型

  • Spring Cloud 2025.0.0 (代号: 2025.0.0)
  • Spring Boot 4.0
  • Java 21+ (支持虚拟线程)
  • 响应式编程 (WebFlux + R2DBC)
  • AOT 原生编译 (GraalVM 23.0+)
  • 分布式追踪 (Micrometer + Brave)
  • 日志收集 (Logback + ELK)

1.2 架构图

复制代码
┌─────────────────────────────────────────────────────────┐
│                   自定义日志注解系统                      │
├─────────────────────────────────────────────────────────┤
│  Log注解 → 切面处理 → 日志上下文 → 异步存储 → 分布式追踪    │
│      ↑          ↑         ↑          ↑           ↑      │
│   业务方法   虚拟线程    MDC/Reactor  Elasticsearch  Sleuth│
└─────────────────────────────────────────────────────────┘

二、项目初始化

2.1 父工程 pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-parent</artifactId>
        <version>2025.0.0</version>
        <relativePath/>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>spring-cloud-logging</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    
    <modules>
        <module>logging-annotation</module>
        <module>logging-starter</module>
        <module>user-service</module>
        <module>order-service</module>
        <module>gateway-service</module>
    </modules>
    
    <properties>
        <java.version>21</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        
        <!-- Spring Cloud 版本 -->
        <spring-cloud.version>2025.0.0</spring-cloud.version>
        <spring-cloud-alibaba.version>2025.0.0.0</spring-cloud-alibaba.version>
        
        <!-- 工具版本 -->
        <lombok.version>1.18.30</lombok.version>
        <mapstruct.version>1.5.5.Final</mapstruct.version>
        <guava.version>33.0.0-jre</guava.version>
        
        <!-- 日志版本 -->
        <logstash-logback.version>8.0</logstash-logback.version>
        <micrometer-tracing.version>1.2.0</micrometer-tracing.version>
        
        <!-- GraalVM -->
        <graalvm.version>23.0.0</graalvm.version>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <!-- Spring Cloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            
            <!-- Spring Cloud Alibaba -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.11.0</version>
                    <configuration>
                        <source>21</source>
                        <target>21</target>
                        <annotationProcessorPaths>
                            <path>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                                <version>${lombok.version}</version>
                            </path>
                            <path>
                                <groupId>org.mapstruct</groupId>
                                <artifactId>mapstruct-processor</artifactId>
                                <version>${mapstruct.version}</version>
                            </path>
                        </annotationProcessorPaths>
                    </configuration>
                </plugin>
                
                <!-- Spring Boot AOT Plugin -->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <image>
                            <builder>paketobuildpacks/builder-jammy-tiny:latest</builder>
                            <env>
                                <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                            </env>
                        </image>
                    </configuration>
                </plugin>
                
                <!-- GraalVM Native Image Plugin -->
                <plugin>
                    <groupId>org.graalvm.buildtools</groupId>
                    <artifactId>native-maven-plugin</artifactId>
                    <version>${graalvm.version}</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
    
    <profiles>
        <profile>
            <id>native</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.graalvm.buildtools</groupId>
                        <artifactId>native-maven-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>build-native</id>
                                <goals>
                                    <goal>compile-no-fork</goal>
                                </goals>
                                <phase>package</phase>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

三、日志注解模块 (logging-annotation)

3.1 pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <parent>
        <groupId>com.example</groupId>
        <artifactId>spring-cloud-logging</artifactId>
        <version>1.0.0</version>
    </parent>
    
    <modelVersion>4.0.0</modelVersion>
    <artifactId>logging-annotation</artifactId>
    
    <dependencies>
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <!-- AOP -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        
        <!-- 响应式 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        
        <!-- 分布式追踪 -->
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing</artifactId>
        </dependency>
        
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

3.2 基础注解定义

3.2.1 核心日志注解
java 复制代码
package com.example.logging.annotation;

import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * 自定义日志注解
 * Spring Cloud 2025.0.0 新特性支持
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Loggable {
    
    /**
     * 模块名称
     */
    String module() default "";
    
    /**
     * 操作类型
     */
    LogType type() default LogType.OTHER;
    
    /**
     * 操作描述
     */
    @AliasFor("value")
    String description() default "";
    
    @AliasFor("description")
    String value() default "";
    
    /**
     * 是否记录方法参数
     */
    boolean logParams() default true;
    
    /**
     * 是否记录返回值
     */
    boolean logResult() default true;
    
    /**
     * 是否记录执行时间
     */
    boolean logTime() default true;
    
    /**
     * 慢查询阈值(毫秒)
     */
    long slowThreshold() default 1000;
    
    /**
     * 是否启用异步记录
     */
    boolean async() default true;
    
    /**
     * 异步记录策略
     */
    AsyncStrategy asyncStrategy() default AsyncStrategy.VIRTUAL_THREAD;
    
    /**
     * 是否启用虚拟线程
     */
    boolean virtualThread() default true;
    
    /**
     * 日志级别
     */
    LogLevel level() default LogLevel.INFO;
    
    /**
     * 是否推送到日志中心
     */
    boolean pushToCenter() default true;
    
    /**
     * 业务标识表达式(SpEL)
     */
    String bizNo() default "";
    
    /**
     * 是否记录堆栈信息
     */
    boolean stackTrace() default false;
    
    /**
     * 日志分组
     */
    String group() default "default";
    
    /**
     * 操作类型枚举
     */
    enum LogType {
        SELECT,     // 查询
        INSERT,     // 新增
        UPDATE,     // 更新
        DELETE,     // 删除
        IMPORT,     // 导入
        EXPORT,     // 导出
        LOGIN,      // 登录
        LOGOUT,     // 登出
        UPLOAD,     // 上传
        DOWNLOAD,   // 下载
        EXECUTE,    // 执行
        CALL,       // 调用
        OTHER       // 其他
    }
    
    /**
     * 异步策略枚举
     */
    enum AsyncStrategy {
        VIRTUAL_THREAD,    // 虚拟线程
        THREAD_POOL,       // 线程池
        REACTIVE,          // 响应式
        IMMEDIATE          // 立即执行
    }
    
    /**
     * 日志级别枚举
     */
    enum LogLevel {
        TRACE,
        DEBUG,
        INFO,
        WARN,
        ERROR
    }
}
3.2.2 响应式日志注解
java 复制代码
package com.example.logging.annotation;

import org.springframework.core.annotation.AliasFor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.lang.annotation.*;
import java.util.concurrent.CompletableFuture;

/**
 * 响应式日志注解
 * 支持 Reactive Streams
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Loggable
public @interface ReactiveLog {
    
    /**
     * 是否跟踪响应式流
     */
    boolean traceStream() default false;
    
    /**
     * 最大跟踪元素数量
     */
    int maxTraceElements() default 10;
    
    /**
     * 响应式超时时间(毫秒)
     */
    long timeout() default 30000;
    
    /**
     * 是否记录背压
     */
    boolean logBackpressure() default false;
    
    /**
     * 支持的类型
     */
    Class<?>[] supportTypes() default {
        Mono.class,
        Flux.class,
        CompletableFuture.class
    };
    
    /**
     * 响应式操作类型
     */
    ReactiveOperation operation() default ReactiveOperation.UNKNOWN;
    
    enum ReactiveOperation {
        MONO_CREATE,
        MONO_TRANSFORM,
        MONO_DELAY,
        FLUX_STREAM,
        FLUX_WINDOW,
        FLUX_BUFFER,
        FUTURE_ASYNC,
        FUTURE_COMPLETABLE,
        UNKNOWN
    }
}
3.2.3 分布式追踪注解
java 复制代码
package com.example.logging.annotation;

import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;

/**
 * 分布式追踪注解
 * 集成 Micrometer Tracing
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Loggable
public @interface TraceLog {
    
    /**
     * Span名称
     */
    String spanName() default "";
    
    /**
     * 是否创建新Span
     */
    boolean newSpan() default true;
    
    /**
     * Span类型
     */
    SpanKind kind() default SpanKind.INTERNAL;
    
    /**
     * 是否记录异常栈
     */
    boolean logStackTrace() default true;
    
    /**
     * 标签(key=value格式)
     */
    String[] tags() default {};
    
    /**
     * 事件
     */
    String[] events() default {};
    
    /**
     * 是否远程调用
     */
    boolean remote() default false;
    
    /**
     * 远程服务名称
     */
    String remoteService() default "";
    
    /**
     * Span类型枚举
     */
    enum SpanKind {
        CLIENT,     // 客户端
        SERVER,     // 服务端
        PRODUCER,   // 生产者
        CONSUMER,   // 消费者
        INTERNAL    // 内部调用
    }
}
3.2.4 性能监控注解
java 复制代码
package com.example.logging.annotation;

import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * 性能监控注解
 * 集成 Micrometer Metrics
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Loggable
public @interface MetricLog {
    
    /**
     * 指标名称
     */
    String name() default "";
    
    /**
     * 指标描述
     */
    String description() default "";
    
    /**
     * 指标类型
     */
    MetricType type() default MetricType.TIMER;
    
    /**
     * 是否记录分位数
     */
    boolean percentiles() default true;
    
    /**
     * 分位数值
     */
    double[] percentileValues() default {0.5, 0.95, 0.99};
    
    /**
     * 是否记录直方图
     */
    boolean histogram() default false;
    
    /**
     * SLA配置(毫秒)
     */
    long[] slas() default {10, 50, 100, 500, 1000};
    
    /**
     * 指标类型枚举
     */
    enum MetricType {
        COUNTER,    // 计数器
        TIMER,      // 计时器
        GAUGE,      // 仪表
        LONG_TASK_TIMER, // 长任务计时器
        DISTRIBUTION_SUMMARY // 分布摘要
    }
}

3.3 日志上下文

3.3.1 日志上下文实体
java 复制代码
package com.example.logging.context;

import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.util.context.Context;
import reactor.util.context.ContextView;

import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 日志上下文
 * 支持虚拟线程和响应式编程
 */
@Data
@Accessors(chain = true)
public class LogContext implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    // 基本信息
    private String logId;
    private String traceId;
    private String spanId;
    private String parentSpanId;
    
    // 方法信息
    private String className;
    private String methodName;
    private String signature;
    
    // 业务信息
    private String module;
    private String operation;
    private String description;
    private String bizNo;
    
    // 参数和结果
    private Object[] args;
    private Object result;
    private Throwable throwable;
    
    // 时间信息
    private LocalDateTime startTime;
    private LocalDateTime endTime;
    private Duration duration;
    
    // 线程信息
    private ThreadInfo threadInfo;
    
    // 请求信息
    private RequestInfo requestInfo;
    
    // 扩展属性
    private Map<String, Object> attributes = new ConcurrentHashMap<>();
    
    // 响应式上下文
    private ReactiveContext reactiveContext;
    
    // 追踪信息
    private TraceInfo traceInfo;
    
    /**
     * 创建日志上下文
     */
    public static LogContext create() {
        LogContext context = new LogContext();
        context.setLogId(generateLogId());
        context.setStartTime(LocalDateTime.now());
        context.setThreadInfo(ThreadInfo.capture());
        context.setTraceInfo(TraceInfo.capture());
        return context;
    }
    
    /**
     * 从ServerWebExchange创建
     */
    public static LogContext fromExchange(ServerWebExchange exchange) {
        LogContext context = create();
        ServerHttpRequest request = exchange.getRequest();
        
        RequestInfo requestInfo = new RequestInfo();
        requestInfo.setRequestId(request.getId());
        requestInfo.setMethod(request.getMethod().name());
        requestInfo.setUri(request.getURI().toString());
        requestInfo.setHeaders(new ConcurrentHashMap<>(request.getHeaders().toSingleValueMap()));
        requestInfo.setQueryParams(new ConcurrentHashMap<>(request.getQueryParams().toSingleValueMap()));
        requestInfo.setRemoteAddress(request.getRemoteAddress() != null ? 
            request.getRemoteAddress().getAddress().getHostAddress() : "");
        requestInfo.setUserAgent(request.getHeaders().getFirst("User-Agent"));
        
        context.setRequestInfo(requestInfo);
        
        // 设置追踪信息
        String traceId = request.getHeaders().getFirst("X-B3-TraceId");
        String spanId = request.getHeaders().getFirst("X-B3-SpanId");
        if (traceId != null) {
            context.setTraceId(traceId);
        }
        if (spanId != null) {
            context.setSpanId(spanId);
        }
        
        return context;
    }
    
    /**
     * 计算持续时间
     */
    public LogContext calculateDuration() {
        if (startTime != null) {
            this.endTime = LocalDateTime.now();
            this.duration = Duration.between(startTime, endTime);
        }
        return this;
    }
    
    /**
     * 设置异常
     */
    public LogContext withException(Throwable throwable) {
        this.throwable = throwable;
        return this;
    }
    
    /**
     * 设置结果
     */
    public LogContext withResult(Object result) {
        this.result = result;
        return this;
    }
    
    /**
     * 设置响应式上下文
     */
    public LogContext withReactiveContext(ContextView contextView) {
        this.reactiveContext = ReactiveContext.from(contextView);
        return this;
    }
    
    /**
     * 添加属性
     */
    public LogContext addAttribute(String key, Object value) {
        this.attributes.put(key, value);
        return this;
    }
    
    /**
     * 生成日志ID
     */
    private static String generateLogId() {
        return java.util.UUID.randomUUID().toString().replace("-", "");
    }
    
    /**
     * 线程信息
     */
    @Data
    @Accessors(chain = true)
    public static class ThreadInfo implements Serializable {
        private long threadId;
        private String threadName;
        private boolean virtual;
        private Thread.State state;
        private int priority;
        private long threadGroupId;
        private String threadGroupName;
        
        public static ThreadInfo capture() {
            Thread thread = Thread.currentThread();
            ThreadInfo info = new ThreadInfo();
            info.setThreadId(thread.threadId());
            info.setThreadName(thread.getName());
            info.setVirtual(thread.isVirtual());
            info.setState(thread.getState());
            info.setPriority(thread.getPriority());
            
            ThreadGroup group = thread.getThreadGroup();
            if (group != null) {
                info.setThreadGroupId(group.getId());
                info.setThreadGroupName(group.getName());
            }
            
            return info;
        }
    }
    
    /**
     * 请求信息
     */
    @Data
    @Accessors(chain = true)
    public static class RequestInfo implements Serializable {
        private String requestId;
        private String method;
        private String uri;
        private Map<String, String> headers;
        private Map<String, String> queryParams;
        private String remoteAddress;
        private String userAgent;
        private Map<String, String> pathVariables;
    }
    
    /**
     * 响应式上下文
     */
    @Data
    @Accessors(chain = true)
    public static class ReactiveContext implements Serializable {
        private ContextView contextView;
        private boolean onVirtualThread;
        private String scheduler;
        private long subscriptionTime;
        private long requestTime;
        
        public static ReactiveContext from(ContextView contextView) {
            ReactiveContext context = new ReactiveContext();
            context.setContextView(contextView);
            context.setOnVirtualThread(Thread.currentThread().isVirtual());
            context.setSubscriptionTime(System.currentTimeMillis());
            return context;
        }
    }
    
    /**
     * 追踪信息
     */
    @Data
    @Accessors(chain = true)
    public static class TraceInfo implements Serializable {
        private String traceId;
        private String spanId;
        private String parentSpanId;
        private boolean sampled;
        private String baggage;
        
        public static TraceInfo capture() {
            // 这里可以从MDC或ThreadLocal获取追踪信息
            TraceInfo info = new TraceInfo();
            // 实际实现中会从Tracing API获取
            return info;
        }
    }
}

四、日志切面实现

4.1 基础切面处理器

java 复制代码
package com.example.logging.aspect;

import com.example.logging.annotation.Loggable;
import com.example.logging.context.LogContext;
import com.example.logging.event.LogEvent;
import com.example.logging.service.LogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 日志切面处理器
 * Spring Cloud 2025.0.0 新特性支持
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class LogAspectHandler {
    
    private final ApplicationEventPublisher eventPublisher;
    private final LogService logService;
    private final LogExpressionEvaluator expressionEvaluator;
    
    // 虚拟线程执行器
    private static final java.util.concurrent.ExecutorService VIRTUAL_EXECUTOR = 
        Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("log-virtual-", 0)
                .factory()
        );
    
    /**
     * 切入点:所有@Loggable注解的方法
     */
    @Pointcut("@annotation(com.example.logging.annotation.Loggable)")
    public void loggablePointcut() {}
    
    /**
     * 环绕通知
     */
    @Around("loggablePointcut()")
    public Object handleLog(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        // 获取注解配置
        Loggable loggable = AnnotationUtils.findAnnotation(method, Loggable.class);
        if (loggable == null) {
            return joinPoint.proceed();
        }
        
        // 创建日志上下文
        LogContext logContext = createLogContext(joinPoint, loggable);
        
        // 记录开始
        logStart(logContext, loggable);
        
        Instant startTime = Instant.now();
        Object result = null;
        Throwable throwable = null;
        
        try {
            // 执行目标方法
            result = joinPoint.proceed();
            
            // 根据返回类型处理
            if (result instanceof Mono) {
                return handleMonoResult((Mono<?>) result, logContext, loggable, startTime);
            } else if (result instanceof Flux) {
                return handleFluxResult((Flux<?>) result, logContext, loggable, startTime);
            } else if (result instanceof CompletableFuture) {
                return handleFutureResult((CompletableFuture<?>) result, logContext, loggable, startTime);
            }
            
            return result;
        } catch (Throwable t) {
            throwable = t;
            throw t;
        } finally {
            // 处理同步结果
            handleSyncResult(result, throwable, logContext, loggable, startTime);
        }
    }
    
    /**
     * 创建日志上下文
     */
    private LogContext createLogContext(ProceedingJoinPoint joinPoint, Loggable loggable) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        LogContext context = LogContext.create();
        context.setClassName(joinPoint.getTarget().getClass().getName());
        context.setMethodName(method.getName());
        context.setSignature(signature.toString());
        context.setModule(loggable.module());
        context.setOperation(loggable.value());
        context.setDescription(loggable.description());
        
        // 解析业务编号
        if (!loggable.bizNo().isEmpty()) {
            String bizNo = expressionEvaluator.evaluateBizNo(joinPoint, loggable.bizNo());
            context.setBizNo(bizNo);
        }
        
        // 记录参数
        if (loggable.logParams()) {
            context.setArgs(joinPoint.getArgs());
        }
        
        return context;
    }
    
    /**
     * 处理Mono结果
     */
    private Mono<?> handleMonoResult(Mono<?> mono, LogContext logContext, 
                                   Loggable loggable, Instant startTime) {
        
        AtomicReference<Instant> subscribeTime = new AtomicReference<>(Instant.now());
        
        return mono
            .contextWrite(ctx -> {
                // 在Reactor Context中存储日志信息
                return ctx.put("log.context", logContext)
                         .put("log.startTime", startTime)
                         .put("log.subscribeTime", subscribeTime.get());
            })
            .doOnSubscribe(subscription -> {
                subscribeTime.set(Instant.now());
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncStart(logContext)
                    );
                } else {
                    logService.logSyncStart(logContext);
                }
            })
            .doOnSuccess(result -> {
                Duration duration = Duration.between(startTime, Instant.now());
                logContext.withResult(result)
                         .calculateDuration();
                
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncSuccess(logContext, duration)
                    );
                } else {
                    logService.logSyncSuccess(logContext, duration);
                }
                
                // 检查慢查询
                if (duration.toMillis() > loggable.slowThreshold()) {
                    logService.logSlowQuery(logContext, duration, loggable.slowThreshold());
                }
                
                // 发布事件
                if (loggable.pushToCenter()) {
                    eventPublisher.publishEvent(new LogEvent(logContext, loggable));
                }
            })
            .doOnError(throwable -> {
                Duration duration = Duration.between(startTime, Instant.now());
                logContext.withException(throwable)
                         .calculateDuration();
                
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncError(logContext, duration, throwable)
                    );
                } else {
                    logService.logSyncError(logContext, duration, throwable);
                }
                
                // 发布事件
                if (loggable.pushToCenter()) {
                    eventPublisher.publishEvent(new LogEvent(logContext, loggable));
                }
            })
            .doOnCancel(() -> {
                Duration duration = Duration.between(startTime, Instant.now());
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncCancel(logContext, duration)
                    );
                }
            });
    }
    
    /**
     * 处理Flux结果
     */
    private Flux<?> handleFluxResult(Flux<?> flux, LogContext logContext, 
                                   Loggable loggable, Instant startTime) {
        
        AtomicReference<Instant> subscribeTime = new AtomicReference<>(Instant.now());
        AtomicReference<Integer> elementCount = new AtomicReference<>(0);
        
        return flux
            .contextWrite(ctx -> {
                return ctx.put("log.context", logContext)
                         .put("log.startTime", startTime);
            })
            .doOnSubscribe(subscription -> {
                subscribeTime.set(Instant.now());
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncStart(logContext)
                    );
                }
            })
            .doOnNext(element -> {
                int count = elementCount.updateAndGet(c -> c + 1);
                if (loggable.async() && count <= 10) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncElement(logContext, element, count)
                    );
                }
            })
            .doOnComplete(() -> {
                Duration duration = Duration.between(startTime, Instant.now());
                logContext.calculateDuration();
                
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncComplete(logContext, duration, elementCount.get())
                    );
                }
                
                // 发布事件
                if (loggable.pushToCenter()) {
                    eventPublisher.publishEvent(new LogEvent(logContext, loggable));
                }
            })
            .doOnError(throwable -> {
                Duration duration = Duration.between(startTime, Instant.now());
                logContext.withException(throwable)
                         .calculateDuration();
                
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncError(logContext, duration, throwable)
                    );
                } else {
                    logService.logSyncError(logContext, duration, throwable);
                }
                
                // 发布事件
                if (loggable.pushToCenter()) {
                    eventPublisher.publishEvent(new LogEvent(logContext, loggable));
                }
            });
    }
    
    /**
     * 处理Future结果
     */
    private CompletableFuture<?> handleFutureResult(CompletableFuture<?> future, 
                                                  LogContext logContext, 
                                                  Loggable loggable, 
                                                  Instant startTime) {
        
        if (loggable.async()) {
            VIRTUAL_EXECUTOR.submit(() -> 
                logService.logAsyncStart(logContext)
            );
        } else {
            logService.logSyncStart(logContext);
        }
        
        return future.whenComplete((result, throwable) -> {
            Duration duration = Duration.between(startTime, Instant.now());
            
            if (throwable != null) {
                logContext.withException(throwable)
                         .calculateDuration();
                
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncError(logContext, duration, throwable)
                    );
                } else {
                    logService.logSyncError(logContext, duration, throwable);
                }
            } else {
                logContext.withResult(result)
                         .calculateDuration();
                
                if (loggable.async()) {
                    VIRTUAL_EXECUTOR.submit(() -> 
                        logService.logAsyncSuccess(logContext, duration)
                    );
                } else {
                    logService.logSyncSuccess(logContext, duration);
                }
                
                // 检查慢查询
                if (duration.toMillis() > loggable.slowThreshold()) {
                    logService.logSlowQuery(logContext, duration, loggable.slowThreshold());
                }
            }
            
            // 发布事件
            if (loggable.pushToCenter()) {
                eventPublisher.publishEvent(new LogEvent(logContext, loggable));
            }
        });
    }
    
    /**
     * 处理同步结果
     */
    private void handleSyncResult(Object result, Throwable throwable, 
                                LogContext logContext, Loggable loggable, 
                                Instant startTime) {
        
        Duration duration = Duration.between(startTime, Instant.now());
        logContext.calculateDuration();
        
        if (throwable != null) {
            logContext.withException(throwable);
            if (loggable.async()) {
                VIRTUAL_EXECUTOR.submit(() -> 
                    logService.logAsyncError(logContext, duration, throwable)
                );
            } else {
                logService.logSyncError(logContext, duration, throwable);
            }
        } else {
            logContext.withResult(result);
            if (loggable.async()) {
                VIRTUAL_EXECUTOR.submit(() -> 
                    logService.logAsyncSuccess(logContext, duration)
                );
            } else {
                logService.logSyncSuccess(logContext, duration);
            }
            
            // 检查慢查询
            if (duration.toMillis() > loggable.slowThreshold()) {
                logService.logSlowQuery(logContext, duration, loggable.slowThreshold());
            }
        }
        
        // 发布事件
        if (loggable.pushToCenter()) {
            eventPublisher.publishEvent(new LogEvent(logContext, loggable));
        }
    }
    
    /**
     * 记录开始日志
     */
    private void logStart(LogContext context, Loggable loggable) {
        switch (loggable.level()) {
            case TRACE:
                log.trace("【开始】{} - {}#{} [线程:{}]", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName(),
                    Thread.currentThread().getName()
                );
                break;
            case DEBUG:
                log.debug("【开始】{} - {}#{}", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName()
                );
                break;
            case INFO:
                log.info("【开始】{} - {}#{}", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName()
                );
                break;
            case WARN:
            case ERROR:
                // 不记录开始日志
                break;
        }
    }
}

4.2 响应式切面处理器

java 复制代码
package com.example.logging.aspect;

import com.example.logging.annotation.ReactiveLog;
import com.example.logging.context.LogContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 响应式日志切面
 * Spring Cloud 2025.0.0 响应式增强
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class ReactiveLogAspect {
    
    /**
     * 处理响应式日志
     */
    @Around("@annotation(com.example.logging.annotation.ReactiveLog)")
    public Object handleReactiveLog(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        ReactiveLog reactiveLog = AnnotationUtils.findAnnotation(method, ReactiveLog.class);
        if (reactiveLog == null) {
            return joinPoint.proceed();
        }
        
        // 创建日志上下文
        LogContext logContext = LogContext.create();
        logContext.setClassName(joinPoint.getTarget().getClass().getName());
        logContext.setMethodName(method.getName());
        
        Object result = joinPoint.proceed();
        
        if (result instanceof Mono) {
            return wrapMono((Mono<?>) result, logContext, reactiveLog);
        } else if (result instanceof Flux) {
            return wrapFlux((Flux<?>) result, logContext, reactiveLog);
        }
        
        return result;
    }
    
    /**
     * 包装Mono
     */
    private Mono<?> wrapMono(Mono<?> mono, LogContext context, ReactiveLog reactiveLog) {
        AtomicLong subscribeTime = new AtomicLong();
        AtomicLong requestTime = new AtomicLong();
        
        return mono
            .doOnSubscribe(subscription -> {
                subscribeTime.set(System.currentTimeMillis());
                logReactiveStart(context, "MONO", reactiveLog);
            })
            .doOnRequest(n -> {
                requestTime.set(System.currentTimeMillis());
                if (reactiveLog.logBackpressure()) {
                    log.debug("【MONO】请求元素: {}", n);
                }
            })
            .doOnNext(value -> {
                long processTime = System.currentTimeMillis() - requestTime.get();
                if (reactiveLog.traceStream()) {
                    log.debug("【MONO】处理元素: {}, 耗时: {}ms", 
                        value, processTime
                    );
                }
            })
            .doOnSuccess(value -> {
                long totalTime = System.currentTimeMillis() - subscribeTime.get();
                logReactiveSuccess(context, "MONO", value, totalTime, reactiveLog);
            })
            .doOnError(throwable -> {
                long totalTime = System.currentTimeMillis() - subscribeTime.get();
                logReactiveError(context, "MONO", throwable, totalTime, reactiveLog);
            })
            .timeout(Duration.ofMillis(reactiveLog.timeout()))
            .onErrorResume(throwable -> {
                log.error("【MONO】响应式超时: {}ms", reactiveLog.timeout(), throwable);
                return Mono.error(throwable);
            })
            .doFinally(signalType -> {
                if (reactiveLog.traceStream()) {
                    log.debug("【MONO】最终信号: {}", signalType);
                }
            });
    }
    
    /**
     * 包装Flux
     */
    private Flux<?> wrapFlux(Flux<?> flux, LogContext context, ReactiveLog reactiveLog) {
        AtomicLong subscribeTime = new AtomicLong();
        AtomicInteger elementCount = new AtomicInteger(0);
        AtomicLong totalElements = new AtomicLong(0);
        
        return flux
            .doOnSubscribe(subscription -> {
                subscribeTime.set(System.currentTimeMillis());
                logReactiveStart(context, "FLUX", reactiveLog);
            })
            .doOnRequest(n -> {
                if (reactiveLog.logBackpressure()) {
                    log.debug("【FLUX】请求元素: {}", n);
                }
            })
            .doOnNext(element -> {
                int count = elementCount.incrementAndGet();
                totalElements.incrementAndGet();
                
                if (reactiveLog.traceStream() && count <= reactiveLog.maxTraceElements()) {
                    log.debug("【FLUX】元素[{}]: {}", count, element);
                }
            })
            .doOnComplete(() -> {
                long totalTime = System.currentTimeMillis() - subscribeTime.get();
                logReactiveComplete(context, "FLUX", elementCount.get(), totalTime, reactiveLog);
            })
            .doOnError(throwable -> {
                long totalTime = System.currentTimeMillis() - subscribeTime.get();
                logReactiveError(context, "FLUX", throwable, totalTime, reactiveLog);
            })
            .timeout(Duration.ofMillis(reactiveLog.timeout()))
            .onErrorResume(throwable -> {
                log.error("【FLUX】响应式超时: {}ms", reactiveLog.timeout(), throwable);
                return Flux.error(throwable);
            })
            .doFinally(signalType -> {
                if (reactiveLog.traceStream()) {
                    log.debug("【FLUX】最终信号: {}, 总元素: {}", 
                        signalType, totalElements.get()
                    );
                }
            });
    }
    
    private void logReactiveStart(LogContext context, String type, ReactiveLog reactiveLog) {
        log.info("【响应式{}】开始 - {}#{} [线程:{}]", 
            type,
            context.getClassName(),
            context.getMethodName(),
            Thread.currentThread().getName()
        );
    }
    
    private void logReactiveSuccess(LogContext context, String type, 
                                  Object value, long totalTime, ReactiveLog reactiveLog) {
        log.info("【响应式{}】成功 - {}#{}, 结果: {}, 耗时: {}ms", 
            type,
            context.getClassName(),
            context.getMethodName(),
            value != null ? value.toString() : "null",
            totalTime
        );
    }
    
    private void logReactiveComplete(LogContext context, String type, 
                                   int elementCount, long totalTime, ReactiveLog reactiveLog) {
        log.info("【响应式{}】完成 - {}#{}, 元素数: {}, 耗时: {}ms", 
            type,
            context.getClassName(),
            context.getMethodName(),
            elementCount,
            totalTime
        );
    }
    
    private void logReactiveError(LogContext context, String type, 
                                Throwable throwable, long totalTime, ReactiveLog reactiveLog) {
        log.error("【响应式{}】失败 - {}#{}, 耗时: {}ms, 错误: {}", 
            type,
            context.getClassName(),
            context.getMethodName(),
            totalTime,
            throwable.getMessage(),
            throwable
        );
    }
}

五、日志服务实现

5.1 日志服务接口

java 复制代码
package com.example.logging.service;

import com.example.logging.context.LogContext;
import reactor.core.publisher.Mono;

import java.time.Duration;

/**
 * 日志服务接口
 */
public interface LogService {
    
    // 同步日志
    void logSyncStart(LogContext context);
    void logSyncSuccess(LogContext context, Duration duration);
    void logSyncError(LogContext context, Duration duration, Throwable throwable);
    
    // 异步日志
    void logAsyncStart(LogContext context);
    void logAsyncSuccess(LogContext context, Duration duration);
    void logAsyncError(LogContext context, Duration duration, Throwable throwable);
    void logAsyncCancel(LogContext context, Duration duration);
    void logAsyncComplete(LogContext context, Duration duration, int elementCount);
    void logAsyncElement(LogContext context, Object element, int index);
    
    // 慢查询日志
    void logSlowQuery(LogContext context, Duration duration, long threshold);
    
    // 虚拟线程日志
    void logVirtualThreadMetrics();
    
    // 响应式日志
    Mono<Void> logReactiveStart(LogContext context);
    Mono<Void> logReactiveSuccess(LogContext context, Duration duration);
    Mono<Void> logReactiveError(LogContext context, Duration duration, Throwable throwable);
}

5.2 日志服务实现

java 复制代码
package com.example.logging.service.impl;

import com.example.logging.context.LogContext;
import com.example.logging.service.LogService;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 日志服务实现
 * 集成分布式追踪和性能指标
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DefaultLogServiceImpl implements LogService {
    
    private final MeterRegistry meterRegistry;
    private final ObjectProvider<Tracer> tracerProvider;
    
    // 虚拟线程执行器
    private final java.util.concurrent.ExecutorService virtualExecutor = 
        Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("log-virtual-", 0)
                .factory()
        );
    
    // 统计信息
    private final AtomicLong totalLogs = new AtomicLong(0);
    private final AtomicLong errorLogs = new AtomicLong(0);
    private final AtomicLong slowLogs = new AtomicLong(0);
    private final AtomicInteger virtualThreadCount = new AtomicInteger(0);
    
    // 计时器缓存
    private final Map<String, Timer> timerCache = new ConcurrentHashMap<>();
    
    @Override
    public void logSyncStart(LogContext context) {
        totalLogs.incrementAndGet();
        log.debug("【同步开始】{} - {}#{} [追踪ID:{}]", 
            context.getOperation(),
            context.getClassName(),
            context.getMethodName(),
            getTraceId()
        );
        
        // 记录指标
        meterRegistry.counter("log.sync.start", 
            "module", context.getModule(),
            "operation", context.getOperation()
        ).increment();
    }
    
    @Override
    public void logSyncSuccess(LogContext context, Duration duration) {
        log.info("【同步成功】{} - {}#{}, 耗时: {}ms [追踪ID:{}]", 
            context.getOperation(),
            context.getClassName(),
            context.getMethodName(),
            duration.toMillis(),
            getTraceId()
        );
        
        // 记录计时指标
        Timer timer = getOrCreateTimer(context.getModule(), context.getOperation());
        timer.record(duration);
        
        // 记录成功率
        meterRegistry.counter("log.sync.success", 
            "module", context.getModule()
        ).increment();
    }
    
    @Override
    public void logSyncError(LogContext context, Duration duration, Throwable throwable) {
        errorLogs.incrementAndGet();
        
        log.error("【同步失败】{} - {}#{}, 耗时: {}ms, 错误: {} [追踪ID:{}]", 
            context.getOperation(),
            context.getClassName(),
            context.getMethodName(),
            duration.toMillis(),
            throwable.getMessage(),
            getTraceId(),
            throwable
        );
        
        // 记录错误指标
        meterRegistry.counter("log.sync.error", 
            "module", context.getModule(),
            "exception", throwable.getClass().getSimpleName()
        ).increment();
    }
    
    @Override
    public void logAsyncStart(LogContext context) {
        virtualExecutor.submit(() -> {
            try {
                totalLogs.incrementAndGet();
                virtualThreadCount.incrementAndGet();
                
                log.debug("【异步开始】{} - {}#{} [虚拟线程:{}, 追踪ID:{}]", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName(),
                    Thread.currentThread().threadId(),
                    getTraceId()
                );
                
                // 记录虚拟线程指标
                meterRegistry.gauge("log.virtual.thread.count", virtualThreadCount);
                meterRegistry.counter("log.async.start", 
                    "module", context.getModule()
                ).increment();
                
            } catch (Exception e) {
                log.error("异步开始日志记录失败", e);
            }
        });
    }
    
    @Override
    public void logAsyncSuccess(LogContext context, Duration duration) {
        virtualExecutor.submit(() -> {
            try {
                log.info("【异步成功】{} - {}#{}, 耗时: {}ms [虚拟线程:{}, 追踪ID:{}]", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName(),
                    duration.toMillis(),
                    Thread.currentThread().threadId(),
                    getTraceId()
                );
                
                // 记录计时指标
                Timer timer = getOrCreateTimer(context.getModule(), context.getOperation());
                timer.record(duration);
                
                // 记录成功率
                meterRegistry.counter("log.async.success", 
                    "module", context.getModule()
                ).increment();
                
            } catch (Exception e) {
                log.error("异步成功日志记录失败", e);
            } finally {
                virtualThreadCount.decrementAndGet();
            }
        });
    }
    
    @Override
    public void logAsyncError(LogContext context, Duration duration, Throwable throwable) {
        virtualExecutor.submit(() -> {
            try {
                errorLogs.incrementAndGet();
                
                log.error("【异步失败】{} - {}#{}, 耗时: {}ms, 错误: {} [虚拟线程:{}, 追踪ID:{}]", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName(),
                    duration.toMillis(),
                    throwable.getMessage(),
                    Thread.currentThread().threadId(),
                    getTraceId(),
                    throwable
                );
                
                // 记录错误指标
                meterRegistry.counter("log.async.error", 
                    "module", context.getModule(),
                    "exception", throwable.getClass().getSimpleName()
                ).increment();
                
            } catch (Exception e) {
                log.error("异步错误日志记录失败", e);
            } finally {
                virtualThreadCount.decrementAndGet();
            }
        });
    }
    
    @Override
    public void logAsyncCancel(LogContext context, Duration duration) {
        virtualExecutor.submit(() -> {
            try {
                log.warn("【异步取消】{} - {}#{}, 耗时: {}ms [虚拟线程:{}]", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName(),
                    duration.toMillis(),
                    Thread.currentThread().threadId()
                );
                
                meterRegistry.counter("log.async.cancel", 
                    "module", context.getModule()
                ).increment();
                
            } catch (Exception e) {
                log.error("异步取消日志记录失败", e);
            } finally {
                virtualThreadCount.decrementAndGet();
            }
        });
    }
    
    @Override
    public void logAsyncComplete(LogContext context, Duration duration, int elementCount) {
        virtualExecutor.submit(() -> {
            try {
                log.info("【异步完成】{} - {}#{}, 元素数: {}, 耗时: {}ms [虚拟线程:{}]", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName(),
                    elementCount,
                    duration.toMillis(),
                    Thread.currentThread().threadId()
                );
                
                meterRegistry.counter("log.async.complete", 
                    "module", context.getModule(),
                    "elementCount", String.valueOf(elementCount)
                ).increment();
                
            } catch (Exception e) {
                log.error("异步完成日志记录失败", e);
            } finally {
                virtualThreadCount.decrementAndGet();
            }
        });
    }
    
    @Override
    public void logAsyncElement(LogContext context, Object element, int index) {
        virtualExecutor.submit(() -> {
            try {
                if (index <= 10) { // 只记录前10个元素
                    log.debug("【异步元素】{} - {}#{}, 元素[{}]: {} [虚拟线程:{}]", 
                        context.getOperation(),
                        context.getClassName(),
                        context.getMethodName(),
                        index,
                        element != null ? element.toString() : "null",
                        Thread.currentThread().threadId()
                    );
                }
                
            } catch (Exception e) {
                // 忽略元素记录错误
            }
        });
    }
    
    @Override
    public void logSlowQuery(LogContext context, Duration duration, long threshold) {
        slowLogs.incrementAndGet();
        
        virtualExecutor.submit(() -> {
            try {
                log.warn("【慢查询】{} - {}#{}, 耗时: {}ms, 阈值: {}ms [追踪ID:{}]", 
                    context.getOperation(),
                    context.getClassName(),
                    context.getMethodName(),
                    duration.toMillis(),
                    threshold,
                    getTraceId()
                );
                
                // 记录慢查询指标
                meterRegistry.counter("log.slow.query", 
                    "module", context.getModule(),
                    "duration", String.valueOf(duration.toMillis()),
                    "threshold", String.valueOf(threshold)
                ).increment();
                
            } catch (Exception e) {
                log.error("慢查询日志记录失败", e);
            }
        });
    }
    
    @Override
    public void logVirtualThreadMetrics() {
        virtualExecutor.submit(() -> {
            try {
                int count = virtualThreadCount.get();
                int activeThreads = Thread.activeCount();
                
                log.debug("【虚拟线程统计】活跃虚拟线程: {}, 总线程: {}, 总日志: {}, 错误日志: {}, 慢查询: {}", 
                    count,
                    activeThreads,
                    totalLogs.get(),
                    errorLogs.get(),
                    slowLogs.get()
                );
                
                // 记录到指标
                meterRegistry.gauge("log.metrics.total", totalLogs);
                meterRegistry.gauge("log.metrics.errors", errorLogs);
                meterRegistry.gauge("log.metrics.slow", slowLogs);
                
            } catch (Exception e) {
                log.error("虚拟线程指标记录失败", e);
            }
        });
    }
    
    @Override
    public Mono<Void> logReactiveStart(LogContext context) {
        return Mono.fromRunnable(() -> {
            log.debug("【响应式开始】{} - {}#{}", 
                context.getOperation(),
                context.getClassName(),
                context.getMethodName()
            );
        }).subscribeOn(Schedulers.boundedElastic()).then();
    }
    
    @Override
    public Mono<Void> logReactiveSuccess(LogContext context, Duration duration) {
        return Mono.fromRunnable(() -> {
            log.info("【响应式成功】{} - {}#{}, 耗时: {}ms", 
                context.getOperation(),
                context.getClassName(),
                context.getMethodName(),
                duration.toMillis()
            );
        }).subscribeOn(Schedulers.boundedElastic()).then();
    }
    
    @Override
    public Mono<Void> logReactiveError(LogContext context, Duration duration, Throwable throwable) {
        return Mono.fromRunnable(() -> {
            log.error("【响应式失败】{} - {}#{}, 耗时: {}ms, 错误: {}", 
                context.getOperation(),
                context.getClassName(),
                context.getMethodName(),
                duration.toMillis(),
                throwable.getMessage(),
                throwable
            );
        }).subscribeOn(Schedulers.boundedElastic()).then();
    }
    
    /**
     * 获取或创建计时器
     */
    private Timer getOrCreateTimer(String module, String operation) {
        String key = module + "." + operation;
        return timerCache.computeIfAbsent(key, k ->
            Timer.builder("log.execution.time")
                .description("Method execution time")
                .tag("module", module)
                .tag("operation", operation)
                .publishPercentiles(0.5, 0.95, 0.99)
                .publishPercentileHistogram()
                .register(meterRegistry)
        );
    }
    
    /**
     * 获取追踪ID
     */
    private String getTraceId() {
        try {
            Tracer tracer = tracerProvider.getIfAvailable();
            if (tracer != null && tracer.currentSpan() != null) {
                return tracer.currentSpan().context().traceId();
            }
        } catch (Exception e) {
            // 忽略异常
        }
        return "N/A";
    }
    
    /**
     * 关闭资源
     */
    public void shutdown() {
        virtualExecutor.shutdown();
        try {
            if (!virtualExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                virtualExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            virtualExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
        
        log.info("日志服务关闭完成");
    }
}

六、日志自动配置

6.1 自动配置类

java 复制代码
package com.example.logging.autoconfigure;

import com.example.logging.aspect.LogAspectHandler;
import com.example.logging.aspect.ReactiveLogAspect;
import com.example.logging.service.LogService;
import com.example.logging.service.impl.DefaultLogServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.concurrent.Executors;

/**
 * 日志自动配置
 */
@Slf4j
@Configuration
@EnableAspectJAutoProxy
@EnableAsync
@EnableScheduling
@EnableConfigurationProperties(LogProperties.class)
@ConditionalOnProperty(prefix = "spring.logging", name = "enabled", havingValue = "true", matchIfMissing = true)
public class LogAutoConfiguration {
    
    /**
     * 日志切面处理器
     */
    @Bean
    @ConditionalOnMissingBean
    public LogAspectHandler logAspectHandler() {
        return new LogAspectHandler();
    }
    
    /**
     * 响应式日志切面
     */
    @Bean
    @ConditionalOnMissingBean
    public ReactiveLogAspect reactiveLogAspect() {
        return new ReactiveLogAspect();
    }
    
    /**
     * 日志服务
     */
    @Bean
    @ConditionalOnMissingBean
    public LogService logService() {
        return new DefaultLogServiceImpl();
    }
    
    /**
     * 虚拟线程执行器
     */
    @Bean(destroyMethod = "shutdown")
    public java.util.concurrent.ExecutorService virtualThreadExecutor() {
        return Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("global-virtual-", 0)
                .factory()
        );
    }
    
    /**
     * 日志指标调度器
     */
    @Bean
    public LogMetricsScheduler logMetricsScheduler(LogService logService) {
        return new LogMetricsScheduler(logService);
    }
}

6.2 配置属性

java 复制代码
package com.example.logging.autoconfigure;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * 日志配置属性
 */
@Data
@ConfigurationProperties(prefix = "spring.logging")
public class LogProperties {
    
    /**
     * 是否启用日志功能
     */
    private boolean enabled = true;
    
    /**
     * 是否启用异步日志
     */
    private boolean asyncEnabled = true;
    
    /**
     * 是否启用虚拟线程
     */
    private boolean virtualThreadEnabled = true;
    
    /**
     * 是否启用响应式日志
     */
    private boolean reactiveEnabled = true;
    
    /**
     * 默认日志级别
     */
    private String defaultLevel = "INFO";
    
    /**
     * 慢查询阈值(毫秒)
     */
    private long slowThreshold = 1000;
    
    /**
     * 是否记录方法参数
     */
    private boolean logParams = true;
    
    /**
     * 是否记录返回值
     */
    private boolean logResult = true;
    
    /**
     * 是否记录执行时间
     */
    private boolean logTime = true;
    
    /**
     * 是否推送到日志中心
     */
    private boolean pushToCenter = true;
    
    /**
     * 日志中心地址
     */
    private String centerUrl = "http://localhost:8080";
    
    /**
     * 连接超时时间
     */
    private Duration connectTimeout = Duration.ofSeconds(5);
    
    /**
     * 读取超时时间
     */
    private Duration readTimeout = Duration.ofSeconds(10);
    
    /**
     * 重试次数
     */
    private int retryTimes = 3;
    
    /**
     * 批量发送大小
     */
    private int batchSize = 100;
    
    /**
     * 批量发送间隔
     */
    private Duration batchInterval = Duration.ofSeconds(5);
    
    /**
     * 模块配置
     */
    private Map<String, ModuleConfig> modules = new HashMap<>();
    
    @Data
    public static class ModuleConfig {
        private boolean enabled = true;
        private String level = "INFO";
        private boolean async = true;
        private boolean virtualThread = true;
        private boolean logParams = true;
        private boolean logResult = true;
        private long slowThreshold = 1000;
    }
}

七、日志 Starter 模块

7.1 pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <parent>
        <groupId>com.example</groupId>
        <artifactId>spring-cloud-logging</artifactId>
        <version>1.0.0</version>
    </parent>
    
    <modelVersion>4.0.0</modelVersion>
    <artifactId>logging-starter</artifactId>
    
    <dependencies>
        <!-- 内部模块依赖 -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>logging-annotation</artifactId>
            <version>${project.version}</version>
        </dependency>
        
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <!-- AOP -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        
        <!-- 配置处理器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- Micrometer 追踪 -->
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing</artifactId>
        </dependency>
        
        <!-- Micrometer 指标 -->
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-core</artifactId>
        </dependency>
        
        <!-- Reactor -->
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
        </dependency>
    </dependencies>
</project>

7.2 spring.factories

properties 复制代码
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.logging.autoconfigure.LogAutoConfiguration

# Spring Boot Configuration Processor
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.logging.autoconfigure.LogPropertiesConfiguration

八、使用示例

8.1 用户服务示例

java 复制代码
package com.example.user.service;

import com.example.logging.annotation.Loggable;
import com.example.logging.annotation.ReactiveLog;
import com.example.logging.annotation.TraceLog;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;

/**
 * 用户服务示例
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserService {
    
    /**
     * 同步方法日志
     */
    @Loggable(
        module = "用户管理",
        value = "创建用户",
        type = Loggable.LogType.INSERT,
        bizNo = "#user.username"
    )
    @Transactional
    public User createUser(User user) {
        // 业务逻辑
        return userRepository.save(user);
    }
    
    /**
     * 异步方法日志
     */
    @Loggable(
        module = "用户管理",
        value = "批量导入用户",
        async = true,
        virtualThread = true,
        slowThreshold = 5000
    )
    public CompletableFuture<List<User>> batchImport(List<User> users) {
        return CompletableFuture.supplyAsync(() -> {
            // 批量处理逻辑
            return userRepository.saveAll(users);
        }, Executors.newVirtualThreadPerTaskExecutor());
    }
    
    /**
     * 响应式方法日志
     */
    @ReactiveLog(
        traceStream = true,
        maxTraceElements = 20,
        timeout = 30000
    )
    @Loggable(
        module = "用户管理",
        value = "查询用户列表",
        async = true
    )
    public Flux<User> listUsers(int page, int size) {
        return userRepository.findAll()
            .skip(page * size)
            .take(size)
            .doOnNext(user -> 
                log.debug("处理用户: {}", user.getUsername())
            );
    }
    
    /**
     * 分布式追踪日志
     */
    @TraceLog(
        spanName = "user.update",
        tags = {"userId=#userId", "operation=update"},
        remote = false
    )
    @Loggable(
        module = "用户管理",
        value = "更新用户信息",
        level = Loggable.LogLevel.INFO
    )
    public Mono<User> updateUser(Long userId, UserDTO dto) {
        return userRepository.findById(userId)
            .flatMap(user -> {
                user.setEmail(dto.getEmail());
                user.setPhone(dto.getPhone());
                return userRepository.save(user);
            });
    }
    
    /**
     * 错误处理示例
     */
    @Loggable(
        module = "用户管理",
        value = "删除用户",
        level = Loggable.LogLevel.ERROR,
        stackTrace = true
    )
    public void deleteUser(Long userId) {
        try {
            userRepository.deleteById(userId);
        } catch (Exception e) {
            log.error("删除用户失败: {}", userId, e);
            throw new BusinessException("删除用户失败");
        }
    }
    
    /**
     * 虚拟线程示例
     */
    @Loggable(
        module = "用户管理",
        value = "并发处理用户",
        async = true,
        virtualThread = true,
        asyncStrategy = Loggable.AsyncStrategy.VIRTUAL_THREAD
    )
    public void processUsersConcurrently(List<Long> userIds) {
        try (var scope = new java.util.concurrent.StructuredTaskScope.ShutdownOnFailure()) {
            for (Long userId : userIds) {
                scope.fork(() -> processUser(userId));
            }
            scope.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("处理中断", e);
        }
    }
    
    private User processUser(Long userId) {
        // 处理单个用户
        return userRepository.findById(userId)
            .map(user -> {
                // 业务处理
                return user;
            })
            .orElseThrow(() -> new RuntimeException("用户不存在"));
    }
}

九、配置示例

9.1 application.yml

yaml 复制代码
spring:
  application:
    name: user-service
  
  # 日志配置
  logging:
    enabled: true
    async-enabled: true
    virtual-thread-enabled: true
    reactive-enabled: true
    default-level: INFO
    slow-threshold: 1000
    log-params: true
    log-result: true
    push-to-center: true
    center-url: http://log-center:8080
    
    # 模块配置
    modules:
      user-service:
        enabled: true
        level: INFO
        async: true
        virtual-thread: true
        slow-threshold: 500
      order-service:
        enabled: true
        level: DEBUG
        async: false
  
  # 虚拟线程配置
  threads:
    virtual:
      enabled: true
      name-prefix: "app-virtual-"
  
  # 响应式配置
  webflux:
    base-path: /api
  
  # 分布式追踪
  sleuth:
    enabled: true
    sampler:
      probability: 1.0
    propagation:
      type: B3
    baggage:
      enabled: true
  
  # Micrometer
  micrometer:
    tracing:
      enabled: true
    metrics:
      export:
        prometheus:
          enabled: true

# 日志级别配置
logging:
  level:
    com.example: INFO
    com.example.logging: DEBUG
    org.springframework.web: INFO
    reactor.netty: INFO
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
  
  # Logback配置
  logback:
    rollingpolicy:
      max-file-size: 10MB
      max-history: 30
      total-size-cap: 1GB
    
  # Logstash
  logstash:
    enabled: true
    destination: logstash:5044

# 管理端点
management:
  endpoints:
    web:
      exposure:
        include: "health,info,metrics,prometheus,loggers"
  endpoint:
    health:
      show-details: always
    loggers:
      enabled: true
  metrics:
    tags:
      application: ${spring.application.name}
  tracing:
    sampling:
      probability: 0.1

十、网关集成

十一、Spring Cloud Gateway 集成

11.1 网关全局过滤器

java 复制代码
package com.example.gateway.filter;

import com.example.logging.annotation.Loggable;
import com.example.logging.context.LogContext;
import io.micrometer.tracing.Span;
import io.micrometer.tracing.Tracer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.*;

/**
 * Spring Cloud Gateway 全局日志过滤器
 * 支持响应式日志记录和虚拟线程
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class GatewayGlobalLogFilter implements GlobalFilter, Ordered {
    
    private final Tracer tracer;
    
    // 请求计数器
    private final AtomicLong requestCounter = new AtomicLong(0);
    
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 1;
    }
    
    @Loggable(
        module = "网关",
        value = "网关请求处理",
        async = true,
        virtualThread = true,
        level = Loggable.LogLevel.INFO,
        pushToCenter = true
    )
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        long requestId = requestCounter.incrementAndGet();
        Instant startTime = Instant.now();
        ServerHttpRequest request = exchange.getRequest();
        
        // 创建日志上下文
        LogContext logContext = createLogContext(exchange, requestId);
        
        // 获取路由信息
        Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
        if (route != null) {
            logContext.addAttribute("route.id", route.getId());
            logContext.addAttribute("route.uri", route.getUri().toString());
        }
        
        // 创建Span
        Span gatewaySpan = createGatewaySpan(request, logContext);
        
        // 包装请求和响应
        ServerHttpRequest decoratedRequest = decorateRequest(request, logContext);
        ServerHttpResponse decoratedResponse = decorateResponse(exchange.getResponse(), logContext);
        
        ServerWebExchange decoratedExchange = exchange.mutate()
            .request(decoratedRequest)
            .response(decoratedResponse)
            .build();
        
        // 记录请求开始
        logRequestStart(logContext, request);
        
        return chain.filter(decoratedExchange)
            .contextWrite(ctx -> {
                // 在上下文中存储日志信息
                return ctx.put("gateway.logContext", logContext)
                         .put("gateway.startTime", startTime)
                         .put("gateway.requestId", requestId)
                         .put("gateway.span", gatewaySpan);
            })
            .doOnSuccess(v -> {
                // 记录请求成功
                long duration = Duration.between(startTime, Instant.now()).toMillis();
                logRequestSuccess(logContext, duration, gatewaySpan);
            })
            .doOnError(throwable -> {
                // 记录请求失败
                long duration = Duration.between(startTime, Instant.now()).toMillis();
                logRequestError(logContext, throwable, duration, gatewaySpan);
            })
            .doFinally(signalType -> {
                // 结束Span
                if (gatewaySpan != null) {
                    gatewaySpan.tag("signal.type", signalType.name());
                    gatewaySpan.end();
                }
                
                // 清理资源
                DataBufferUtils.release(logContext.getAttributes().remove("request.body"));
                DataBufferUtils.release(logContext.getAttributes().remove("response.body"));
                
                log.debug("【网关】请求处理完成: {},信号: {}", requestId, signalType);
            });
    }
    
    /**
     * 创建日志上下文
     */
    private LogContext createLogContext(ServerWebExchange exchange, long requestId) {
        ServerHttpRequest request = exchange.getRequest();
        LogContext context = LogContext.create();
        
        // 请求信息
        LogContext.RequestInfo requestInfo = new LogContext.RequestInfo();
        requestInfo.setRequestId(String.valueOf(requestId));
        requestInfo.setMethod(request.getMethod().name());
        requestInfo.setUri(request.getURI().toString());
        
        // 请求头
        Map<String, String> headers = request.getHeaders().toSingleValueMap();
        requestInfo.setHeaders(headers);
        
        // 查询参数
        Map<String, String> queryParams = request.getQueryParams().toSingleValueMap();
        requestInfo.setQueryParams(queryParams);
        
        // 远程地址
        InetSocketAddress remoteAddress = request.getRemoteAddress();
        if (remoteAddress != null) {
            requestInfo.setRemoteAddress(remoteAddress.getAddress().getHostAddress());
        }
        
        // User Agent
        requestInfo.setUserAgent(request.getHeaders().getFirst("User-Agent"));
        
        context.setRequestInfo(requestInfo);
        
        // 追踪信息
        String traceId = request.getHeaders().getFirst("X-B3-TraceId");
        String spanId = request.getHeaders().getFirst("X-B3-SpanId");
        if (traceId != null) {
            context.setTraceId(traceId);
        }
        if (spanId != null) {
            context.setSpanId(spanId);
        }
        
        return context;
    }
    
    /**
     * 创建网关Span
     */
    private Span createGatewaySpan(ServerHttpRequest request, LogContext logContext) {
        if (tracer == null) {
            return null;
        }
        
        String spanName = "gateway:" + request.getMethod().name() + ":" + 
                         request.getURI().getPath();
        
        Span span = tracer.nextSpan()
            .name(spanName)
            .kind(Span.Kind.SERVER)
            .tag("http.method", request.getMethod().name())
            .tag("http.path", request.getURI().getPath())
            .tag("gateway.request.id", String.valueOf(logContext.getRequestInfo().getRequestId()))
            .tag("thread.virtual", String.valueOf(Thread.currentThread().isVirtual()))
            .start();
        
        // 设置追踪ID到上下文
        logContext.setTraceId(span.context().traceId());
        logContext.setSpanId(span.context().spanId());
        
        return span;
    }
    
    /**
     * 包装请求(记录请求体)
     */
    private ServerHttpRequest decorateRequest(ServerHttpRequest request, LogContext logContext) {
        // 如果不是JSON请求,直接返回原请求
        MediaType contentType = request.getHeaders().getContentType();
        if (contentType == null || !contentType.includes(MediaType.APPLICATION_JSON)) {
            return request;
        }
        
        return new ServerHttpRequestDecorator(request) {
            private final AtomicReference<byte[]> cachedBody = new AtomicReference<>();
            
            @Override
            public Flux<DataBuffer> getBody() {
                return super.getBody()
                    .doOnNext(dataBuffer -> {
                        // 缓存请求体用于日志记录
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        DataBufferUtils.release(dataBuffer);
                        
                        // 限制大小,避免大请求体导致内存问题
                        if (bytes.length <= 1024 * 10) { // 10KB以内
                            cachedBody.set(bytes);
                            logContext.addAttribute("request.body", new String(bytes, StandardCharsets.UTF_8));
                        }
                        
                        // 重新创建DataBuffer
                        DataBufferFactory factory = request.bufferFactory();
                        DataBuffer newBuffer = factory.wrap(bytes);
                        cachedBody.set(bytes);
                    })
                    .thenMany(Flux.defer(() -> {
                        byte[] body = cachedBody.get();
                        if (body != null) {
                            return Flux.just(request.bufferFactory().wrap(body));
                        }
                        return Flux.empty();
                    }));
            }
        };
    }
    
    /**
     * 包装响应(记录响应体)
     */
    private ServerHttpResponse decorateResponse(ServerHttpResponse response, LogContext logContext) {
        return new ServerHttpResponseDecorator(response) {
            private final AtomicReference<byte[]> cachedBody = new AtomicReference<>();
            
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                return super.writeWith(Flux.from(body)
                    .doOnNext(dataBuffer -> {
                        // 缓存响应体用于日志记录
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        DataBufferUtils.release(dataBuffer);
                        
                        // 限制大小,避免大响应体导致内存问题
                        if (bytes.length <= 1024 * 10) { // 10KB以内
                            cachedBody.set(bytes);
                            logContext.addAttribute("response.body", new String(bytes, StandardCharsets.UTF_8));
                            logContext.addAttribute("response.status", String.valueOf(getStatusCode().value()));
                        }
                        
                        // 重新创建DataBuffer
                        DataBufferFactory factory = response.bufferFactory();
                        DataBuffer newBuffer = factory.wrap(bytes);
                        cachedBody.set(bytes);
                    })
                    .thenMany(Flux.defer(() -> {
                        byte[] bodyBytes = cachedBody.get();
                        if (bodyBytes != null) {
                            return Flux.just(response.bufferFactory().wrap(bodyBytes));
                        }
                        return Flux.empty();
                    })));
            }
            
            @Override
            public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
            }
        };
    }
    
    /**
     * 记录请求开始
     */
    private void logRequestStart(LogContext context, ServerHttpRequest request) {
        log.info("【网关请求开始】ID: {}, 方法: {}, 路径: {}, 来源IP: {}, 虚拟线程: {}", 
            context.getRequestInfo().getRequestId(),
            request.getMethod().name(),
            request.getURI().getPath(),
            context.getRequestInfo().getRemoteAddress(),
            Thread.currentThread().isVirtual()
        );
    }
    
    /**
     * 记录请求成功
     */
    private void logRequestSuccess(LogContext context, long duration, Span span) {
        String traceId = span != null ? span.context().traceId() : "N/A";
        
        log.info("【网关请求成功】ID: {}, 耗时: {}ms, 追踪ID: {}, 线程: {}", 
            context.getRequestInfo().getRequestId(),
            duration,
            traceId,
            Thread.currentThread().getName()
        );
        
        // 记录到指标
        io.micrometer.core.instrument.Metrics.counter("gateway.requests.success",
            "method", context.getRequestInfo().getMethod(),
            "path", context.getRequestInfo().getUri()
        ).increment();
        
        io.micrometer.core.instrument.Timer.builder("gateway.request.duration")
            .tag("status", "success")
            .register(io.micrometer.core.instrument.Metrics.globalRegistry)
            .record(Duration.ofMillis(duration));
    }
    
    /**
     * 记录请求失败
     */
    private void logRequestError(LogContext context, Throwable throwable, 
                               long duration, Span span) {
        String traceId = span != null ? span.context().traceId() : "N/A";
        
        log.error("【网关请求失败】ID: {}, 耗时: {}ms, 追踪ID: {}, 错误: {}", 
            context.getRequestInfo().getRequestId(),
            duration,
            traceId,
            throwable.getMessage(),
            throwable
        );
        
        // 记录到指标
        io.micrometer.core.instrument.Metrics.counter("gateway.requests.error",
            "method", context.getRequestInfo().getMethod(),
            "path", context.getRequestInfo().getUri(),
            "exception", throwable.getClass().getSimpleName()
        ).increment();
    }
}

11.2 网关虚拟线程配置

java 复制代码
package com.example.gateway.config;

import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
import org.springframework.cloud.gateway.config.HttpClientCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.resources.LoopResources;

import java.time.Duration;
import java.util.concurrent.Executors;

/**
 * 网关虚拟线程配置
 */
@Configuration
public class GatewayVirtualThreadConfig {
    
    /**
     * 配置Netty使用虚拟线程
     */
    @Bean
    public ReactiveWebServerFactory reactiveWebServerFactory(ServerProperties serverProperties) {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        
        factory.addServerCustomizers(httpServer -> {
            // 使用虚拟线程的事件循环组
            httpServer.runOn(LoopResources.create("gateway-virtual", 
                1,  // 线程数
                true,  // 守护线程
                true   // 选择最佳事件循环
            ));
            
            return httpServer;
        });
        
        return factory;
    }
    
    /**
     * 配置HTTP客户端使用虚拟线程
     */
    @Bean
    public HttpClientCustomizer httpClientVirtualThreadCustomizer() {
        return factory -> {
            ConnectionProvider provider = ConnectionProvider.builder("gateway-virtual-connection")
                .maxConnections(500)
                .pendingAcquireTimeout(Duration.ofSeconds(60))
                .evictInBackground(Duration.ofSeconds(120))
                .build();
            
            HttpClient httpClient = HttpClient.create(provider)
                .runOn(LoopResources.create("client-virtual", 
                    2, 
                    true, 
                    true
                ))
                .responseTimeout(Duration.ofSeconds(30))
                .compress(true);
            
            return httpClient;
        };
    }
    
    /**
     * Reactor资源工厂
     */
    @Bean
    public ReactorResourceFactory reactorResourceFactory() {
        ReactorResourceFactory factory = new ReactorResourceFactory();
        factory.setUseGlobalResources(false);
        factory.setLoopResourcesSupplier(() -> 
            LoopResources.create("gateway-global-virtual", 
                Runtime.getRuntime().availableProcessors() * 2,
                true,
                true
            )
        );
        return factory;
    }
    
    /**
     * 虚拟线程执行器
     */
    @Bean
    public java.util.concurrent.ExecutorService gatewayVirtualExecutor() {
        return Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("gateway-vt-", 0)
                .factory()
        );
    }
}

十二、服务间调用日志

12.1 OpenFeign 日志拦截器

java 复制代码
package com.example.feign.interceptor;

import com.example.logging.annotation.Loggable;
import com.example.logging.context.LogContext;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.micrometer.tracing.Span;
import io.micrometer.tracing.Tracer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

/**
 * OpenFeign 日志拦截器
 * 自动传播追踪信息和记录调用日志
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FeignLoggingInterceptor implements RequestInterceptor {
    
    private final Tracer tracer;
    
    // Feign调用计数器
    private final AtomicLong feignCallCounter = new AtomicLong(0);
    
    // 虚拟线程执行器
    private final java.util.concurrent.ExecutorService virtualExecutor = 
        Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("feign-log-", 0)
                .factory()
        );
    
    @Loggable(
        module = "服务调用",
        value = "Feign远程调用",
        async = true,
        virtualThread = true,
        level = Loggable.LogLevel.INFO
    )
    @Override
    public void apply(RequestTemplate template) {
        long callId = feignCallCounter.incrementAndGet();
        Instant startTime = Instant.now();
        
        // 创建日志上下文
        LogContext logContext = LogContext.create();
        logContext.setOperation("Feign远程调用");
        logContext.setClassName(template.feignTarget().type().getName());
        logContext.setMethodName(template.methodMetadata().configKey());
        logContext.addAttribute("feign.call.id", String.valueOf(callId));
        logContext.addAttribute("service.url", template.feignTarget().url());
        logContext.addAttribute("request.url", template.url());
        logContext.addAttribute("request.headers", template.headers());
        
        // 记录开始日志
        logFeignCallStart(logContext, template);
        
        // 注入追踪头
        injectTraceHeaders(template);
        
        // 注入自定义头
        template.header("X-Feign-Call-Id", String.valueOf(callId));
        template.header("X-Feign-Start-Time", String.valueOf(startTime.toEpochMilli()));
        template.header("X-Is-Virtual-Thread", 
            String.valueOf(Thread.currentThread().isVirtual()));
        
        // 记录请求体(如果有)
        if (template.body() != null) {
            String body = new String(template.body());
            if (body.length() <= 1024) { // 只记录1KB以内的请求体
                logContext.addAttribute("request.body", body);
            }
        }
        
        // 异步记录调用信息
        virtualExecutor.submit(() -> {
            try {
                // 记录到指标
                io.micrometer.core.instrument.Metrics.counter("feign.calls.initiated",
                    "service", extractServiceName(template),
                    "method", template.method()
                ).increment();
                
                // 创建Feign调用的Span
                createFeignSpan(template, logContext);
                
            } catch (Exception e) {
                log.error("Feign日志记录失败", e);
            }
        });
        
        // 存储日志上下文,供响应拦截器使用
        template.header("X-Log-Context", serializeLogContext(logContext));
    }
    
    /**
     * 注入追踪头
     */
    private void injectTraceHeaders(RequestTemplate template) {
        if (tracer == null) {
            return;
        }
        
        Span currentSpan = tracer.currentSpan();
        if (currentSpan != null) {
            // 传播追踪上下文
            tracer.inject(currentSpan.context(), template, (carrier, key, value) -> {
                if (carrier instanceof RequestTemplate) {
                    ((RequestTemplate) carrier).header(key, value);
                }
            });
            
            // 记录追踪信息到日志上下文
            template.header("X-Parent-Trace-Id", currentSpan.context().traceId());
            template.header("X-Parent-Span-Id", currentSpan.context().spanId());
        }
    }
    
    /**
     * 创建Feign调用Span
     */
    private void createFeignSpan(RequestTemplate template, LogContext logContext) {
        if (tracer == null) {
            return;
        }
        
        String spanName = "feign:" + extractServiceName(template) + ":" + 
                         template.methodMetadata().method().getName();
        
        Span span = tracer.nextSpan()
            .name(spanName)
            .kind(Span.Kind.CLIENT)
            .tag("rpc.system", "feign")
            .tag("rpc.service", extractServiceName(template))
            .tag("rpc.method", template.methodMetadata().method().getName())
            .tag("http.method", template.method())
            .tag("http.url", template.url())
            .tag("feign.call.id", String.valueOf(logContext.getAttributes().get("feign.call.id")))
            .start();
        
        // 设置追踪ID到日志上下文
        logContext.setTraceId(span.context().traceId());
        logContext.setSpanId(span.context().spanId());
        
        // 在Span上下文中执行
        try (Tracer.SpanInScope scope = tracer.withSpan(span)) {
            log.debug("【Feign调用Span创建】名称: {}, 追踪ID: {}", 
                spanName, span.context().traceId()
            );
        }
    }
    
    /**
     * 提取服务名称
     */
    private String extractServiceName(RequestTemplate template) {
        Class<?> targetType = template.feignTarget().type();
        FeignClient feignClient = targetType.getAnnotation(FeignClient.class);
        if (feignClient != null) {
            return feignClient.name();
        }
        return targetType.getSimpleName();
    }
    
    /**
     * 记录Feign调用开始
     */
    private void logFeignCallStart(LogContext context, RequestTemplate template) {
        log.info("【Feign调用开始】服务: {}, 方法: {}, URL: {}, 虚拟线程: {}", 
            extractServiceName(template),
            template.methodMetadata().method().getName(),
            template.url(),
            Thread.currentThread().isVirtual()
        );
    }
    
    /**
     * 序列化日志上下文
     */
    private String serializeLogContext(LogContext context) {
        try {
            // 简单序列化,实际可以使用JSON
            return String.format("%s|%s|%s", 
                context.getLogId(),
                context.getTraceId(),
                context.getSpanId()
            );
        } catch (Exception e) {
            return "";
        }
    }
}

12.2 Feign 响应拦截器

java 复制代码
package com.example.feign.interceptor;

import com.example.logging.context.LogContext;
import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Executors;

/**
 * Feign 响应拦截器
 * 记录响应日志和处理错误
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FeignResponseInterceptor implements ErrorDecoder {
    
    // 虚拟线程执行器
    private final java.util.concurrent.ExecutorService virtualExecutor = 
        Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("feign-resp-", 0)
                .factory()
        );
    
    @Override
    public Exception decode(String methodKey, Response response) {
        // 解析日志上下文
        String logContextHeader = response.request().headers().get("X-Log-Context");
        if (logContextHeader != null && !logContextHeader.isEmpty()) {
            LogContext logContext = deserializeLogContext(logContextHeader);
            String startTimeHeader = response.request().headers().get("X-Feign-Start-Time");
            
            if (startTimeHeader != null) {
                try {
                    long startTime = Long.parseLong(startTimeHeader);
                    long duration = System.currentTimeMillis() - startTime;
                    
                    // 异步记录错误响应
                    virtualExecutor.submit(() -> {
                        logFeignError(logContext, methodKey, response, duration);
                    });
                } catch (NumberFormatException e) {
                    log.warn("解析Feign开始时间失败", e);
                }
            }
        }
        
        // 使用默认错误解码器
        return new ErrorDecoder.Default().decode(methodKey, response);
    }
    
    /**
     * 记录Feign调用成功
     */
    public void logFeignSuccess(Response response, Duration duration) {
        virtualExecutor.submit(() -> {
            try {
                String logContextHeader = response.request().headers().get("X-Log-Context");
                if (logContextHeader != null && !logContextHeader.isEmpty()) {
                    LogContext logContext = deserializeLogContext(logContextHeader);
                    
                    log.info("【Feign调用成功】服务: {}, 方法: {}, 耗时: {}ms, 状态码: {}", 
                        extractServiceNameFromRequest(response.request()),
                        extractMethodNameFromRequest(response.request()),
                        duration.toMillis(),
                        response.status()
                    );
                    
                    // 记录到指标
                    io.micrometer.core.instrument.Metrics.counter("feign.calls.success",
                        "service", extractServiceNameFromRequest(response.request()),
                        "status", String.valueOf(response.status())
                    ).increment();
                    
                    io.micrometer.core.instrument.Timer.builder("feign.call.duration")
                        .tag("status", "success")
                        .register(io.micrometer.core.instrument.Metrics.globalRegistry)
                        .record(duration);
                }
            } catch (Exception e) {
                log.error("Feign成功日志记录失败", e);
            }
        });
    }
    
    /**
     * 记录Feign调用错误
     */
    private void logFeignError(LogContext context, String methodKey, 
                             Response response, long duration) {
        log.error("【Feign调用失败】服务: {}, 方法: {}, 耗时: {}ms, 状态码: {}, 错误: {}", 
            extractServiceName(context),
            methodKey,
            duration,
            response.status(),
            response.reason()
        );
        
        // 记录到指标
        io.micrometer.core.instrument.Metrics.counter("feign.calls.error",
            "service", extractServiceName(context),
            "status", String.valueOf(response.status())
        ).increment();
        
        io.micrometer.core.instrument.Timer.builder("feign.call.duration")
            .tag("status", "error")
            .register(io.micrometer.core.instrument.Metrics.globalRegistry)
            .record(Duration.ofMillis(duration));
    }
    
    /**
     * 反序列化日志上下文
     */
    private LogContext deserializeLogContext(String header) {
        try {
            String[] parts = header.split("\\|");
            if (parts.length >= 3) {
                LogContext context = new LogContext();
                context.setLogId(parts[0]);
                context.setTraceId(parts[1]);
                context.setSpanId(parts[2]);
                return context;
            }
        } catch (Exception e) {
            log.warn("反序列化日志上下文失败", e);
        }
        return LogContext.create();
    }
    
    /**
     * 从请求中提取服务名称
     */
    private String extractServiceNameFromRequest(feign.Request request) {
        // 从URL或header中提取服务名称
        String url = request.url();
        // 简化的提取逻辑
        if (url.contains("/api/")) {
            String[] parts = url.split("/");
            for (int i = 0; i < parts.length; i++) {
                if ("api".equals(parts[i]) && i + 1 < parts.length) {
                    return parts[i + 1];
                }
            }
        }
        return "unknown";
    }
    
    /**
     * 从请求中提取方法名称
     */
    private String extractMethodNameFromRequest(feign.Request request) {
        String url = request.url();
        String[] parts = url.split("/");
        return parts.length > 0 ? parts[parts.length - 1] : "unknown";
    }
    
    /**
     * 从上下文中提取服务名称
     */
    private String extractServiceName(LogContext context) {
        Object serviceName = context.getAttributes().get("service.url");
        return serviceName != null ? serviceName.toString() : "unknown";
    }
}

十三、服务网格集成

13.1 Istio 边车日志集成

java 复制代码
package com.example.mesh.integration;

import com.example.logging.annotation.Loggable;
import com.example.logging.context.LogContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;

/**
 * 服务网格集成配置
 * 支持Istio边车日志和追踪
 */
@Slf4j
@Configuration
@RequiredArgsConstructor
public class ServiceMeshIntegrationConfig {
    
    /**
     * RestTemplate 拦截器(支持Istio)
     */
    @Bean
    @LoadBalanced
    public RestTemplate meshAwareRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setInterceptors(Collections.singletonList(
            new MeshRestTemplateInterceptor()
        ));
        return restTemplate;
    }
    
    /**
     * WebClient 过滤器(支持Istio)
     */
    @Bean
    @LoadBalanced
    public WebClient meshAwareWebClient() {
        return WebClient.builder()
            .filter(meshExchangeFilterFunction())
            .build();
    }
    
    /**
     * Mesh感知的ExchangeFilterFunction
     */
    @Bean
    public ExchangeFilterFunction meshExchangeFilterFunction() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            // 在请求前添加Mesh相关header
            ClientRequest newRequest = ClientRequest.from(clientRequest)
                .header("X-Request-Id", generateRequestId())
                .header("X-Mesh-Service", getCurrentServiceName())
                .header("X-Envoy-Timeout", "30s")
                .build();
            
            return Mono.just(newRequest);
        });
    }
    
    /**
     * RestTemplate拦截器实现
     */
    @Loggable(
        module = "服务网格",
        value = "Mesh服务调用",
        async = true,
        virtualThread = true
    )
    private static class MeshRestTemplateInterceptor implements ClientHttpRequestInterceptor {
        
        private final java.util.concurrent.ExecutorService virtualExecutor = 
            Executors.newThreadPerTaskExecutor(
                Thread.ofVirtual()
                    .name("mesh-rest-", 0)
                    .factory()
            );
        
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, 
                                          ClientHttpRequestExecution execution) throws IOException {
            
            long startTime = System.currentTimeMillis();
            String requestId = generateRequestId();
            
            // 添加Mesh header
            request.getHeaders().add("X-Request-Id", requestId);
            request.getHeaders().add("X-Mesh-Service", getCurrentServiceName());
            request.getHeaders().add("X-Caller-Service", System.getProperty("spring.application.name", "unknown"));
            
            // 记录调用开始
            logMeshCallStart(request, requestId);
            
            try {
                ClientHttpResponse response = execution.execute(request, body);
                long duration = System.currentTimeMillis() - startTime;
                
                // 异步记录调用成功
                virtualExecutor.submit(() -> {
                    logMeshCallSuccess(request, response, requestId, duration);
                });
                
                return response;
                
            } catch (IOException e) {
                long duration = System.currentTimeMillis() - startTime;
                
                // 异步记录调用失败
                virtualExecutor.submit(() -> {
                    logMeshCallError(request, e, requestId, duration);
                });
                
                throw e;
            }
        }
        
        private void logMeshCallStart(HttpRequest request, String requestId) {
            log.info("【Mesh调用开始】ID: {}, 服务: {}, 路径: {}, 虚拟线程: {}", 
                requestId,
                extractServiceName(request.getURI().toString()),
                request.getURI().getPath(),
                Thread.currentThread().isVirtual()
            );
        }
        
        private void logMeshCallSuccess(HttpRequest request, ClientHttpResponse response, 
                                      String requestId, long duration) {
            try {
                log.info("【Mesh调用成功】ID: {}, 服务: {}, 耗时: {}ms, 状态码: {}", 
                    requestId,
                    extractServiceName(request.getURI().toString()),
                    duration,
                    response.getStatusCode().value()
                );
                
                // 记录到指标
                io.micrometer.core.instrument.Metrics.counter("mesh.calls.success",
                    "service", extractServiceName(request.getURI().toString()),
                    "status", String.valueOf(response.getStatusCode().value())
                ).increment();
                
            } catch (IOException e) {
                log.error("记录Mesh调用成功日志失败", e);
            }
        }
        
        private void logMeshCallError(HttpRequest request, IOException exception, 
                                    String requestId, long duration) {
            log.error("【Mesh调用失败】ID: {}, 服务: {}, 耗时: {}ms, 错误: {}", 
                requestId,
                extractServiceName(request.getURI().toString()),
                duration,
                exception.getMessage(),
                exception
            );
            
            // 记录到指标
            io.micrometer.core.instrument.Metrics.counter("mesh.calls.error",
                "service", extractServiceName(request.getURI().toString()),
                "exception", exception.getClass().getSimpleName()
            ).increment();
        }
    }
    
    /**
     * 生成请求ID
     */
    private static String generateRequestId() {
        return java.util.UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }
    
    /**
     * 获取当前服务名称
     */
    private static String getCurrentServiceName() {
        return System.getProperty("spring.application.name", "unknown-service");
    }
    
    /**
     * 从URL中提取服务名称
     */
    private static String extractServiceName(String url) {
        // 简化的服务名称提取逻辑
        // 实际中可能根据服务发现机制来提取
        if (url.contains("://")) {
            url = url.substring(url.indexOf("://") + 3);
        }
        if (url.contains("/")) {
            url = url.substring(0, url.indexOf("/"));
        }
        if (url.contains(":")) {
            url = url.substring(0, url.indexOf(":"));
        }
        return url;
    }
}

十四、监控与告警

14.1 Actuator 端点扩展

java 复制代码
package com.example.logging.actuator;

import com.example.logging.context.LogContext;
import com.example.logging.service.LogService;
import io.micrometer.core.instrument.MeterRegistry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 自定义Actuator端点
 * 提供日志相关的监控和管理功能
 */
@Slf4j
@Component
@WebEndpoint(id = "logging")
@RequiredArgsConstructor
public class LoggingActuatorEndpoint {
    
    private final MeterRegistry meterRegistry;
    private final LogService logService;
    
    // 日志统计缓存
    private final Map<String, LogStatistics> statisticsCache = new ConcurrentHashMap<>();
    private final AtomicLong lastResetTime = new AtomicLong(System.currentTimeMillis());
    
    private static final DateTimeFormatter TIME_FORMATTER = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    /**
     * 获取日志统计信息
     */
    @ReadOperation
    public Map<String, Object> getLoggingStats() {
        Map<String, Object> stats = new LinkedHashMap<>();
        
        // 基本统计
        stats.put("timestamp", LocalDateTime.now().format(TIME_FORMATTER));
        stats.put("lastReset", formatTime(lastResetTime.get()));
        
        // 线程统计
        stats.put("threads", getThreadStats());
        
        // 日志量统计
        stats.put("volume", getLogVolumeStats());
        
        // 性能统计
        stats.put("performance", getPerformanceStats());
        
        // 虚拟线程统计
        stats.put("virtualThreads", getVirtualThreadStats());
        
        // 错误统计
        stats.put("errors", getErrorStats());
        
        return stats;
    }
    
    /**
     * 重置统计信息
     */
    @WriteOperation
    public Map<String, Object> resetStats() {
        statisticsCache.clear();
        lastResetTime.set(System.currentTimeMillis());
        
        Map<String, Object> result = new HashMap<>();
        result.put("message", "统计信息已重置");
        result.put("resetTime", formatTime(lastResetTime.get()));
        
        log.info("日志统计信息已重置");
        
        return result;
    }
    
    /**
     * 获取线程统计
     */
    private Map<String, Object> getThreadStats() {
        Map<String, Object> threadStats = new HashMap<>();
        
        ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
        while (rootGroup.getParent() != null) {
            rootGroup = rootGroup.getParent();
        }
        
        Thread[] threads = new Thread[rootGroup.activeCount()];
        rootGroup.enumerate(threads, true);
        
        long virtualThreadCount = Arrays.stream(threads)
            .filter(Thread::isVirtual)
            .count();
        
        long platformThreadCount = Arrays.stream(threads)
            .filter(t -> !t.isVirtual())
            .count();
        
        threadStats.put("total", threads.length);
        threadStats.put("virtual", virtualThreadCount);
        threadStats.put("platform", platformThreadCount);
        threadStats.put("daemon", Arrays.stream(threads)
            .filter(Thread::isDaemon)
            .count());
        
        return threadStats;
    }
    
    /**
     * 获取日志量统计
     */
    private Map<String, Object> getLogVolumeStats() {
        Map<String, Object> volumeStats = new HashMap<>();
        
        // 从MeterRegistry获取指标
        Collection<io.micrometer.core.instrument.Counter> counters = 
            meterRegistry.find("log.").counters();
        
        Map<String, Double> counterValues = new HashMap<>();
        counters.forEach(counter -> {
            String name = counter.getId().getName();
            double value = counter.count();
            counterValues.put(name, value);
        });
        
        volumeStats.put("counters", counterValues);
        volumeStats.put("totalLogs", counterValues.values().stream()
            .mapToDouble(Double::doubleValue)
            .sum());
        
        return volumeStats;
    }
    
    /**
     * 获取性能统计
     */
    private Map<String, Object> getPerformanceStats() {
        Map<String, Object> perfStats = new HashMap<>();
        
        // 收集计时器信息
        Collection<io.micrometer.core.instrument.Timer> timers = 
            meterRegistry.find("log.execution.time").timers();
        
        List<Map<String, Object>> timerInfos = new ArrayList<>();
        timers.forEach(timer -> {
            Map<String, Object> timerInfo = new HashMap<>();
            timerInfo.put("name", timer.getId().getName());
            timerInfo.put("count", timer.count());
            timerInfo.put("mean", timer.mean(io.micrometer.core.instrument.TimeUnit.MILLISECONDS));
            timerInfo.put("max", timer.max(io.micrometer.core.instrument.TimeUnit.MILLISECONDS));
            timerInfo.put("p95", timer.percentile(0.95, io.micrometer.core.instrument.TimeUnit.MILLISECONDS));
            timerInfos.add(timerInfo);
        });
        
        perfStats.put("timers", timerInfos);
        
        return perfStats;
    }
    
    /**
     * 获取虚拟线程统计
     */
    private Map<String, Object> getVirtualThreadStats() {
        Map<String, Object> vtStats = new HashMap<>();
        
        // 虚拟线程创建率
        io.micrometer.core.instrument.Counter vtCounter = 
            meterRegistry.find("log.virtual.thread.count").counter();
        
        if (vtCounter != null) {
            vtStats.put("created", vtCounter.count());
        }
        
        // 活跃虚拟线程数
        long activeVirtualThreads = Thread.getAllStackTraces().keySet().stream()
            .filter(Thread::isVirtual)
            .count();
        
        vtStats.put("active", activeVirtualThreads);
        vtStats.put("carrierThreads", getCarrierThreadCount());
        
        return vtStats;
    }
    
    /**
     * 获取载体线程数
     */
    private int getCarrierThreadCount() {
        // 估算载体线程数
        return Runtime.getRuntime().availableProcessors() * 2;
    }
    
    /**
     * 获取错误统计
     */
    private Map<String, Object> getErrorStats() {
        Map<String, Object> errorStats = new HashMap<>();
        
        // 错误计数器
        Collection<io.micrometer.core.instrument.Counter> errorCounters = 
            meterRegistry.find("log.*.error").counters();
        
        Map<String, Double> errors = new HashMap<>();
        errorCounters.forEach(counter -> {
            String name = counter.getId().getName();
            double value = counter.count();
            errors.put(name, value);
        });
        
        errorStats.put("counters", errors);
        errorStats.put("totalErrors", errors.values().stream()
            .mapToDouble(Double::doubleValue)
            .sum());
        
        return errorStats;
    }
    
    /**
     * 格式化时间戳
     */
    private String formatTime(long timestamp) {
        return LocalDateTime.ofInstant(
            java.time.Instant.ofEpochMilli(timestamp),
            java.time.ZoneId.systemDefault()
        ).format(TIME_FORMATTER);
    }
    
    /**
     * 日志统计数据结构
     */
    @Data
    private static class LogStatistics {
        private String module;
        private long totalRequests;
        private long successfulRequests;
        private long failedRequests;
        private long slowQueries;
        private double avgResponseTime;
        private double p95ResponseTime;
        private double p99ResponseTime;
        private LocalDateTime lastUpdated;
        
        public void incrementTotal() {
            totalRequests++;
            lastUpdated = LocalDateTime.now();
        }
        
        public void incrementSuccess() {
            successfulRequests++;
            lastUpdated = LocalDateTime.now();
        }
        
        public void incrementFailure() {
            failedRequests++;
            lastUpdated = LocalDateTime.now();
        }
        
        public void incrementSlowQuery() {
            slowQueries++;
            lastUpdated = LocalDateTime.now();
        }
    }
}

十五、测试与验证

15.1 集成测试配置

java 复制代码
package com.example.test;

import com.example.logging.annotation.Loggable;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

/**
 * 日志注解集成测试
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class LoggingIntegrationTest {
    
    @Autowired
    private TestService testService;
    
    @MockBean
    private LoggingMetricsCollector metricsCollector;
    
    @Test
    void testSyncMethodLogging() {
        // 执行测试方法
        String result = testService.syncMethod("test-input");
        
        // 验证结果
        assertThat(result).isEqualTo("SYNC-test-input");
        
        // 验证指标被记录
        verify(metricsCollector, times(1)).recordLogCount(
            eq("test-module"), eq("INFO"), eq(true)
        );
    }
    
    @Test
    void testAsyncMethodLogging() throws Exception {
        // 执行异步方法
        CompletableFuture<String> future = testService.asyncMethod("async-input");
        String result = future.get(5, TimeUnit.SECONDS);
        
        // 验证结果
        assertThat(result).isEqualTo("ASYNC-async-input");
        
        // 验证虚拟线程指标
        verify(metricsCollector, atLeastOnce()).recordVirtualThreadMetrics();
    }
    
    @Test
    void testReactiveMethodLogging() {
        // 执行响应式方法
        Mono<String> mono = testService.reactiveMethod("reactive-input");
        
        StepVerifier.create(mono)
            .expectNext("REACTIVE-reactive-input")
            .verifyComplete();
        
        // 验证响应式指标
        verify(metricsCollector, atLeastOnce()).recordReactiveMetrics(
            anyString(), anyInt(), any()
        );
    }
    
    @Test
    void testErrorLogging() {
        // 验证异常日志
        try {
            testService.errorMethod();
        } catch (RuntimeException e) {
            assertThat(e.getMessage()).isEqualTo("Test error");
        }
        
        // 验证错误指标
        verify(metricsCollector, times(1)).recordLogCount(
            eq("test-module"), eq("ERROR"), eq(false)
        );
    }
    
    @Test
    void testVirtualThreadMethod() throws Exception {
        // 执行虚拟线程方法
        CompletableFuture<String> future = testService.virtualThreadMethod("virtual-input");
        String result = future.get(5, TimeUnit.SECONDS);
        
        assertThat(result).isEqualTo("VIRTUAL-virtual-input");
        
        // 验证虚拟线程使用情况
        verify(metricsCollector, atLeastOnce()).recordVirtualThreadMetrics();
    }
    
    /**
     * 测试服务
     */
    @Component
    static class TestService {
        
        @Loggable(
            module = "test-module",
            value = "同步方法测试",
            level = Loggable.LogLevel.INFO
        )
        public String syncMethod(String input) {
            return "SYNC-" + input;
        }
        
        @Loggable(
            module = "test-module",
            value = "异步方法测试",
            async = true,
            virtualThread = true
        )
        public CompletableFuture<String> asyncMethod(String input) {
            return CompletableFuture.supplyAsync(() -> {
                try {
                    Thread.sleep(100); // 模拟耗时操作
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                return "ASYNC-" + input;
            });
        }
        
        @Loggable(
            module = "test-module",
            value = "响应式方法测试",
            async = true
        )
        public Mono<String> reactiveMethod(String input) {
            return Mono.fromCallable(() -> "REACTIVE-" + input)
                .delayElement(java.time.Duration.ofMillis(100));
        }
        
        @Loggable(
            module = "test-module",
            value = "错误方法测试",
            level = Loggable.LogLevel.ERROR
        )
        public void errorMethod() {
            throw new RuntimeException("Test error");
        }
        
        @Loggable(
            module = "test-module",
            value = "虚拟线程方法测试",
            async = true,
            virtualThread = true,
            asyncStrategy = Loggable.AsyncStrategy.VIRTUAL_THREAD
        )
        public CompletableFuture<String> virtualThreadMethod(String input) {
            return CompletableFuture.supplyAsync(() -> {
                // 在虚拟线程中执行
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                return "VIRTUAL-" + input;
            });
        }
    }
}

十六、部署配置

16.1 Dockerfile (原生镜像)

dockerfile 复制代码
# 第一阶段:构建原生镜像
FROM ghcr.io/graalvm/native-image:ol8-java21 AS builder

# 安装必要的构建工具
RUN microdnf install -y gcc gcc-c++ zlib-devel

# 设置工作目录
WORKDIR /app

# 复制构建文件
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src

# 下载依赖
RUN ./mvnw dependency:go-offline -B

# 构建原生镜像
RUN ./mvnw clean package -DskipTests -Pnative

# 第二阶段:运行镜像
FROM oraclelinux:9-slim

# 安装必要的运行时库
RUN microdnf install -y \
    ca-certificates \
    tzdata \
    glibc-langpack-en \
    && microdnf clean all

# 设置时区
ENV TZ=Asia/Shanghai

# 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser

# 设置工作目录
WORKDIR /app

# 复制原生可执行文件
COPY --from=builder /app/target/*-runner /app/application
COPY --from=builder /app/src/main/resources /app/resources

# 设置权限
RUN chown -R appuser:appuser /app
USER appuser

# 暴露端口
EXPOSE 8080
EXPOSE 8081  # 监控端口

# 设置健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8080/actuator/health || exit 1

# 运行应用
ENTRYPOINT ["/app/application"]
CMD []

16.2 docker-compose.yml

yaml 复制代码
version: '3.8'

services:
  # 日志中心服务
  log-center:
    build: 
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
      - "8081:8081"
    environment:
      - SPRING_PROFILES_ACTIVE=production
      - JAVA_OPTS=-XX:+UseZGC -Xmx512m -Xms512m
      - LOGGING_CONFIG_ENABLED=true
      - LOGGING_VIRTUAL_THREAD_ENABLED=true
      - MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE=health,info,metrics,prometheus,logging
    networks:
      - logging-network
    depends_on:
      - elasticsearch
      - redis
    deploy:
      resources:
        limits:
          memory: 768M
        reservations:
          memory: 512M
      replicas: 3
      placement:
        constraints:
          - node.role==manager
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  # Elasticsearch
  elasticsearch:
    image: elasticsearch:8.12.0
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
    ports:
      - "9200:9200"
    volumes:
      - esdata:/usr/share/elasticsearch/data
    networks:
      - logging-network
    deploy:
      resources:
        limits:
          memory: 1G

  # Redis缓存
  redis:
    image: redis:7.2-alpine
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    volumes:
      - redisdata:/data
    networks:
      - logging-network

  # Prometheus监控
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    networks:
      - logging-network
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.retention.time=200h'
      - '--web.enable-lifecycle'

  # Grafana可视化
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    networks:
      - logging-network
    depends_on:
      - prometheus

networks:
  logging-network:
    driver: bridge

volumes:
  esdata:
    driver: local
  redisdata:
    driver: local
  prometheus-data:
    driver: local
  grafana-data:
    driver: local

十七、最佳实践总结

17.1 使用建议

java 复制代码
/**
 * 日志注解最佳实践示例
 */
@Slf4j
@Service
public class LoggingBestPracticeService {
    
    // 1. 明确的模块划分
    @Loggable(
        module = "用户管理",
        value = "创建用户账户",
        type = Loggable.LogType.INSERT,
        bizNo = "#userDto.username"
    )
    public User createUser(UserDTO userDto) {
        // 业务逻辑
    }
    
    // 2. 敏感信息脱敏
    @Loggable(
        module = "认证授权",
        value = "用户登录认证",
        logParams = false,  // 不记录密码参数
        logResult = false   // 不记录令牌结果
    )
    public AuthToken login(String username, String password) {
        // 认证逻辑
    }
    
    // 3. 大文件/大结果集处理
    @Loggable(
        module = "文件服务",
        value = "下载文件",
        logParams = true,
        logResult = false   // 不记录文件内容
    )
    public byte[] downloadFile(String fileId) {
        // 文件下载逻辑
    }
    
    // 4. 性能敏感操作使用异步
    @Loggable(
        module = "报表服务",
        value = "生成年度报表",
        async = true,
        virtualThread = true,
        slowThreshold = 30000  // 30秒超时标记为慢查询
    )
    public CompletableFuture<Report> generateAnnualReport(ReportRequest request) {
        // 报表生成逻辑
    }
    
    // 5. 分布式追踪集成
    @TraceLog(
        spanName = "payment.process",
        tags = {"orderId=#orderId", "amount=#amount"},
        remote = true,
        remoteService = "payment-service"
    )
    @Loggable(
        module = "支付服务",
        value = "处理支付订单"
    )
    public PaymentResult processPayment(String orderId, BigDecimal amount) {
        // 支付处理逻辑
    }
    
    // 6. 响应式方法
    @ReactiveLog(
        traceStream = true,
        maxTraceElements = 50,
        timeout = 15000
    )
    @Loggable(
        module = "消息服务",
        value = "流式处理消息"
    )
    public Flux<Message> processMessageStream(Flux<Message> messages) {
        return messages
            .doOnNext(msg -> log.debug("Processing message: {}", msg.getId()))
            .buffer(10)
            .flatMap(this::processBatch);
    }
    
    // 7. 错误处理和降级
    @Loggable(
        module = "外部服务",
        value = "调用第三方API",
        level = Loggable.LogLevel.WARN,
        stackTrace = true
    )
    public ExternalResponse callExternalApi(ExternalRequest request) {
        try {
            return externalClient.call(request);
        } catch (ExternalServiceException e) {
            log.error("外部服务调用失败", e);
            return fallbackResponse();
        }
    }
    
    // 8. 虚拟线程并发处理
    @Loggable(
        module = "数据处理",
        value = "批量数据处理",
        async = true,
        virtualThread = true,
        asyncStrategy = Loggable.AsyncStrategy.VIRTUAL_THREAD
    )
    public void batchProcess(List<DataItem> items) {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            List<Future<ProcessResult>> futures = items.stream()
                .map(item -> scope.fork(() -> processItem(item)))
                .toList();
            
            scope.join();
            scope.throwIfFailed();
            
            futures.forEach(future -> {
                try {
                    ProcessResult result = future.resultNow();
                    log.debug("Processed item: {}", result.getItemId());
                } catch (Exception e) {
                    log.warn("Item processing failed", e);
                }
            });
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("批量处理被中断", e);
        }
    }
    
    // 9. 审计日志
    @Loggable(
        module = "审计日志",
        value = "重要业务操作",
        level = Loggable.LogLevel.WARN,
        pushToCenter = true,
        group = "audit"
    )
    @Transactional
    public AuditRecord auditImportantOperation(AuditOperation operation) {
        // 审计记录逻辑
    }
}

17.2 性能优化配置

yaml 复制代码
# application-performance.yml
spring:
  logging:
    # 生产环境推荐配置
    enabled: true
    async-enabled: true
    virtual-thread-enabled: true
    reactive-enabled: true
    default-level: INFO
    slow-threshold: 1000
    log-params: true
    log-result: true
    push-to-center: true
    
    # 模块特定配置
    modules:
      gateway-service:
        enabled: true
        level: INFO
        async: true
        virtual-thread: true
        slow-threshold: 500
      user-service:
        enabled: true
        level: INFO
        async: true
        virtual-thread: true
        slow-threshold: 800
      order-service:
        enabled: true
        level: INFO
        async: false  # 订单服务追求强一致性,使用同步日志
        log-params: false  # 订单数据量大,不记录参数
      
  # 虚拟线程配置
  threads:
    virtual:
      enabled: true
      executor:
        core-pool-size: 10
        max-pool-size: 100
        queue-capacity: 1000
        keep-alive-seconds: 60
        thread-name-prefix: "app-vt-"
        
  # 响应式配置
  webflux:
    max-in-memory-size: 256KB  # 限制内存使用
    
  # 监控配置
  management:
    metrics:
      export:
        prometheus:
          step: 1m
      distribution:
        percentiles-histogram:
          http.server.requests: true
        sla:
          http.server.requests: 10ms, 50ms, 100ms, 500ms, 1s, 5s
          
  # Sleuth配置
  sleuth:
    enabled: true
    sampler:
      probability: 0.1  # 生产环境采样率
    propagation:
      type: B3,W3C
      
# 日志级别控制
logging:
  level:
    root: INFO
    com.example: DEBUG
    com.example.logging: INFO
    org.springframework.web: WARN
    reactor.netty: WARN
    io.netty: WARN
    
  # 异步日志配置
  async:
    enabled: true
    queue-size: 10000
    discarding-threshold: 0
    include-caller-data: false
    never-block: true

十八、故障排查指南

18.1 常见问题解决方案

java 复制代码
package com.example.logging.troubleshooting;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 日志系统故障排查工具
 */
@Slf4j
@Component
public class LoggingTroubleshooter {
    
    // 问题计数器
    private final Map<String, AtomicInteger> issueCounters = new ConcurrentHashMap<>();
    
    // 最后检测时间
    private volatile long lastCheckTime = System.currentTimeMillis();
    
    /**
     * 诊断日志系统健康状况
     */
    public HealthDiagnosis diagnoseHealth() {
        HealthDiagnosis diagnosis = new HealthDiagnosis();
        diagnosis.setTimestamp(System.currentTimeMillis());
        
        // 检查线程状态
        diagnoseThreadIssues(diagnosis);
        
        // 检查内存状态
        diagnoseMemoryIssues(diagnosis);
        
        // 检查死锁
        diagnoseDeadlocks(diagnosis);
        
        // 检查虚拟线程泄漏
        diagnoseVirtualThreadLeaks(diagnosis);
        
        // 检查日志积压
        diagnoseLogBacklog(diagnosis);
        
        // 生成诊断报告
        generateDiagnosticReport(diagnosis);
        
        return diagnosis;
    }
    
    /**
     * 诊断线程问题
     */
    private void diagnoseThreadIssues(HealthDiagnosis diagnosis) {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        
        // 活跃线程数
        int activeThreadCount = Thread.activeCount();
        diagnosis.setActiveThreads(activeThreadCount);
        
        // 虚拟线程比例
        long virtualThreadCount = getAllThreads().stream()
            .filter(Thread::isVirtual)
            .count();
        diagnosis.setVirtualThreadRatio((double) virtualThreadCount / activeThreadCount);
        
        // 线程峰值
        diagnosis.setPeakThreadCount(threadMXBean.getPeakThreadCount());
        
        // 检查线程泄漏
        if (activeThreadCount > 1000) {
            diagnosis.addIssue("THREAD_LEAK", 
                "活跃线程数过多: " + activeThreadCount);
            incrementIssueCounter("THREAD_LEAK");
        }
    }
    
    /**
     * 诊断内存问题
     */
    private void diagnoseMemoryIssues(HealthDiagnosis diagnosis) {
        Runtime runtime = Runtime.getRuntime();
        
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        long maxMemory = runtime.maxMemory();
        
        diagnosis.setTotalMemory(totalMemory);
        diagnosis.setUsedMemory(usedMemory);
        diagnosis.setFreeMemory(freeMemory);
        diagnosis.setMaxMemory(maxMemory);
        diagnosis.setMemoryUsage((double) usedMemory / totalMemory);
        
        // 检查内存使用率
        if (diagnosis.getMemoryUsage() > 0.8) { // 80%阈值
            diagnosis.addIssue("HIGH_MEMORY_USAGE", 
                "内存使用率过高: " + (diagnosis.getMemoryUsage() * 100) + "%");
            incrementIssueCounter("HIGH_MEMORY_USAGE");
        }
        
        // 检查内存泄漏迹象
        if (usedMemory > maxMemory * 0.9) { // 90%阈值
            diagnosis.addIssue("MEMORY_LEAK_SUSPECTED", 
                "疑似内存泄漏,使用内存接近最大值");
            incrementIssueCounter("MEMORY_LEAK_SUSPECTED");
        }
    }
    
    /**
     * 诊断死锁
     */
    private void diagnoseDeadlocks(HealthDiagnosis diagnosis) {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        
        long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
        if (deadlockedThreads != null && deadlockedThreads.length > 0) {
            diagnosis.addCriticalIssue("DEADLOCK_DETECTED", 
                "检测到死锁,涉及线程: " + deadlockedThreads.length);
            incrementIssueCounter("DEADLOCK_DETECTED");
        }
    }
    
    /**
     * 诊断虚拟线程泄漏
     */
    private void diagnoseVirtualThreadLeaks(HealthDiagnosis diagnosis) {
        long virtualThreadCount = getAllThreads().stream()
            .filter(Thread::isVirtual)
            .count();
        
        long platformThreadCount = getAllThreads().stream()
            .filter(t -> !t.isVirtual())
            .count();
        
        // 虚拟线程与平台线程比例异常
        if (platformThreadCount > 0 && 
            virtualThreadCount / platformThreadCount > 100) {
            diagnosis.addIssue("VIRTUAL_THREAD_LEAK", 
                "虚拟线程与平台线程比例异常: " + 
                virtualThreadCount + "/" + platformThreadCount);
            incrementIssueCounter("VIRTUAL_THREAD_LEAK");
        }
相关推荐
就叫飞六吧2 小时前
pdf转国产ofd格式代码案例-Java
java·python·pdf
Yng Forever2 小时前
腾讯云人脸识别SDK集成
java·后端·云计算·腾讯云
LiamTuc2 小时前
Java 接口定义变量
java·开发语言
拾忆,想起2 小时前
Dubbo服务注册与发现深度解析:微服务架构的“通讯录”与“导航系统”
微服务·云原生·性能优化·架构·dubbo·safari
赵得C3 小时前
软件设计师进阶知识点解析:分布式与数据应用考点精讲
java·开发语言·分布式·设计模式
雨中飘荡的记忆3 小时前
Docker与Java实战指南
java·docker·容器
是一个Bug3 小时前
声明式事务
java·开发语言·面试
妮妮喔妮3 小时前
Redis Cluster故障处理机制
java·数据库·redis
lang201509283 小时前
Sentinel预热限流:WarmUpController原理详解
java·spring·sentinel