springboot+grpc全链路日志追踪

1.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <contextName>logback</contextName>
    <!-- 定义日志文件 名称 -->
    <springProperty scope="context" name="APP_NAME" source="spring.application.name"/>

    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="/data/logs/${APP_NAME}" />

    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <pattern> %d{yyyy-MM-dd HH:mm:ss} %green([%thread]) %highlight(%-5level) %boldMagenta(%logger) [trackId:%X{TRACK_ID}] - %cyan(%msg%n)</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 按照每天生成日志文件 -->
    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/logback-${APP_NAME}.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>180</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern> %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} [trackId:%X{TRACK_ID}]  - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>150MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!--日志级别-->
    <root level="INFO">
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

2.trackId放置拦截器,trackId可以由前端传过来这样出问题可以f12拿trackId

@Component
@Slf4j
public class TrackIdInterceptor implements HandlerInterceptor {
  private static final String TRACK_ID = "TRACK_ID";

  @Override
  public boolean preHandle(
      HttpServletRequest request, HttpServletResponse response, Object handler) {
    try {
      // 添加MDC日志(前端传)
      //    String trackId = request.getHeader("TRACK_ID");
      // 后端为每个请求生成
      String trackId = UUID.randomUUID().toString();
      MDC.put(TRACK_ID, trackId);
      return true;
    } catch (Exception e) {
      // 永远放行,不能阻碍请求
      return true;
    }
  }

  @Override
  public void afterCompletion(
      HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    // 移除MDC日志
    log.info("移除MDC中的trackId: {}", MDC.get("TRACK_ID"));
    MDC.remove(TRACK_ID);
  }
}

注册拦截器:interceptorRegistry.addInterceptor(xxx)

3.grpc客户端拦截器:

@GrpcGlobalClientInterceptor
@Slf4j
public class GrpcClientInterceptor implements ClientInterceptor {
  public GrpcClientInterceptor() {}

  @Override
  public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
      MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {

    return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
        next.newCall(method, callOptions)) {
      @Override
      public void start(Listener<RespT> responseListener, Metadata headers) {
        // 添加traceId
        String trackId = MDC.get("TRACK_ID");
        if (StringUtils.isNotBlank(trackId)) {
          headers.put(Metadata.Key.of("TRACK_ID", Metadata.ASCII_STRING_MARSHALLER), trackId);
        }
        super.start(
            new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(
                responseListener) {
              @Override
              public void onHeaders(Metadata headers) {
                super.onHeaders(headers);
              }
            },
            headers);
      }
    };
  }
}

4.grpc服务端拦截器

@GrpcGlobalServerInterceptor
@Slf4j
public class GrpcServiceInterceptor implements ServerInterceptor {
  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {

    // 将trackID放到MDC中
    String trackId =
        headers.get(
            Metadata.Key.of(Constants.CommonConstants.TRACK_ID, Metadata.ASCII_STRING_MARSHALLER));
    MDC.put("TRACK_ID", trackId);
    log.info("客户端请求trackId:{}", trackId);
    ServerCall.Listener<ReqT> listener =
        Contexts.interceptCall(Context.current(), call, headers, next);
    return new ServerCallListenerWithCleanup<>(listener);
  }

  private static class ServerCallListenerWithCleanup<ReqT>
      extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
    ServerCallListenerWithCleanup(ServerCall.Listener<ReqT> delegate) {
      super(delegate);
    }

    @Override
    public void onComplete() {
      try {
        // 请求结束后移除trackID
        log.info("请求结束移除trackId:{}", MDC.get("TRACK_ID"));
        MDC.remove("TRACK_ID");
      } finally {
        super.onComplete();
      }
    }
  }
}

5.据说还有子线程trackId为空的,我还没遇到,遇到了再补上。

### 回答1: Spring Boot 是一个用于构建基于Java的微服务的开发框架。它提供了一种快速开发、简化配置的方式,使得开发者能够更容易地构建和部署应用程序。 Spring Boot MVC 是 Spring Boot 中用于构建Web应用程序的一部分。它基于 Spring MVC 框架,提供了简化的配置和开发方式,使得开发者能够更高效地构建和维护Web应用。 gRPC是一种高性能、开源的远程过程调用(RPC)框架,由Google开发并开源。它使用Protocol Buffers作为接口定义语言(IDL),可以跨语言地进行通信。与传统的HTTP+JSON通信相比,gRPC提供了更快、更轻量级、更高效的跨网络通信方式。 Spring Boot可以集成gRPC,实现基于gRPC的远程过程调用。集成gRPC的步骤如下: 1. 在Spring Boot项目中添加gRPC的依赖,例如在pom.xml中添加相关依赖。 2. 使用Protocol Buffers编写接口定义文件(.proto文件),定义服务和消息格式。 3. 使用gRPC编译器生成相应的Java代码。 4. 编写服务的实现类,实现生成的接口。 5. 在Spring Boot中配置gRPC服务端和客户端的相关信息。 6. 启动Spring Boot应用程序。 通过上述步骤,就可以在Spring Boot中实现基于gRPC的远程过程调用。通过gRPC,服务端和客户端可以直接调用对方提供的方法,以实现跨网络的通信。gRPC使用Protocol Buffers进行序列化和反序列化,提供了高效的通信方式。同时,通过Spring Boot的集成,开发者可以更方便地进行开发和部署。总之,Spring Boot MVC gRPC实现可以为开发者提供快速、高效地构建基于gRPC的微服务应用的能力。 ### 回答2: Spring Boot是一个用于构建独立的、生产级别的Spring应用程序的框架。它简化了Spring应用程序的配置和部署过程,并提供了大量的开箱即用的功能。而MVC(Model-View-Controller)是一种常用的软件设计模式,用于将应用程序的业务逻辑、数据和呈现逻辑分离。 gRPC是一种高性能、开源的远程过程调用(RPC)框架,它使用Protocol Buffers作为接口定义语言。gRPC支持多种语言,包括Java和Spring Boot。使用gRPC,可以定义消息类型和服务接口,并生成用于客户端和服务器之间通信的代码。 在Spring Boot中使用gRPC实现通常需要以下步骤: 1.定义gRPC服务接口:使用Protocol Buffers定义服务接口和消息类型,并生成相应的代码。 2.实现gRPC服务接口:在Spring Boot应用程序中实现gRPC服务接口中定义的方法。 3.配置gRPC服务器:在Spring Boot应用程序中配置gRPC服务器,指定端口和服务实现类。 4.编写客户端代码:编写客户端代码以使用gRPC调用服务器端提供的服务。 使用gRPC的好处包括高性能、跨语言支持、自动化的代码生成等。在Spring Boot中使用gRPC可以方便地将gRPC集成到现有的Spring应用程序中,并利用Spring Boot提供的便利功能,如自动配置和部署。 总结:Spring Boot MVC和gRPC是两种不同的技术,分别用于构建Web应用程序和实现远程过程调用。在Spring Boot应用程序中使用gRPC实现时,需要通过定义gRPC服务接口、实现服务接口方法、配置和启动gRPC服务器等步骤来集成gRPC。这样可以在Spring Boot应用程序中使用gRPC高性能的远程过程调用功能。 ### 回答3: Spring Boot是一个基于Spring框架的快速开发框架,它简化了Spring的配置和部署过程。而MVC是Spring框架中的一种设计模式,通过它可以将应用程序的不同部分进行解耦,使得每个部分可以独立开发、测试和部署。 gRPC是一个高性能、开源的远程过程调用(RPC)框架,它使用Google Protocol Buffers作为接口定义语言,并支持多种编程语言。通过gRPC,我们可以轻松地定义RPC服务,然后使用自动生成的客户端和服务端代码进行通信。 在Spring Boot中集成MVC和gRPC可以实现两者的优势互补。我们可以使用Spring MVC来处理HTTP请求,同时使用gRPC来处理RPC请求。这样一来,我们就可以使用Spring Boot的自动配置和注解来简化开发,同时利用gRPC的高效性能和跨语言能力。 首先,我们需要在Spring Boot项目中引入gRPC的依赖。然后,我们可以定义gRPC的服务接口和实现类,就像定义普通的Java接口和实现类一样。接着,我们可以使用gRPC的注解来定义服务的类型、方法、输入参数和返回值。同时,我们也可以在服务实现类中编写具体的逻辑代码。 在Spring MVC中,我们可以使用@RestController注解来定义HTTP接口,通过调用gRPC服务来处理请求。这样,我们就可以将HTTP请求转发到gRPC服务,从而实现在一个应用中同时支持HTTP和RPC两种协议。 总之,通过Spring Boot集成MVC和gRPC,我们可以在一个应用中同时支持HTTP和RPC协议,并可以充分利用两者的优势。这样,我们就可以更加方便地开发和部署分布式系统,提高系统的性能和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值