背??景随着微服务的盛行,很多公司根据业务边界将系统拆分成很多微服务。在排查和查看日志的时候,由于业务环节贯穿了很多微服务节点,很难定位到一个请求日志,上下游业务的日志会变得有些困难。这时候可能有朋友会想到使用SkyWalking、Pinpoint等分布式跟踪系统来解决问题,而这些系统通常是非侵入性的,同时也提供了相对友好的管理界面来查询linkspan。但是搭建一个分布式跟踪系统还是需要一定的成本的,所以本文不是介绍这些分布式跟踪系统,而是一个简单易用,几乎零侵入的适合中小型的日志跟踪框架TLog-规模的公司。TLog简介TLog提供了解决日志跟踪问题的最简单方法。TLog会自动标记你的日志,并帮助你自动生成贯穿微服务整个链路的traceId。查看日志时,可以根据traceId快速定位到请求处理的链接。TLog不收集日志,只是对你原来打印的日志进行增强,将请求链接信息traceId绑定到你打印的日志上。当微服务节点非常多时,官方推荐使用TLog+日志采集方案来解决。当然,分布式跟踪系统实际上是链接跟踪的最终解决方案。如果项目中已经安装了分布式跟踪系统,则TLog不适用。下图是ELK配合TLog快速定位请求处理链接的例子。TLog接入1,接入步骤1.1,引入依赖com.yomahubtlog-all-spring-boot-starter1.5.0>/dependency>1.2,替换logback配置项至此,其实已经配置完成。1.3.测试这里通过slf4j的LoggerFactory获取Logger对象,因为logback是适配slf4j的,最后会通过logback输出日志。从这里可以看出,11794076298070144就是本次输出日志时产生的一个request的traceId。在查看日志的时候,可以通过这个traceId来查找整个请求的链接日志。2、TLog的访问方式TLog一共提供了三种访问方式:Javaagent访问方式、字节码注入方式、日志框架适配器方式。上述案例中的访问方法实际上是一个日志框架适配器方法,适用于Logback框架。匹配。TLog除了适配Logback框架外,还适配了Log4j框架和Log4j2框架,项目可以选择使用。Javaagent接入方式和字节码注入方式相比日志框架适配器方式对代码的侵入性更小,但是这两种方式只支持SpringBoot项目,并且与日志框架适配器方式相比,不支持MDC和异步日志功能,所以如果想充分体验TLog的功能,建议选择日志框架适配器方式。日志框架适配器方式其实访问起来很快,其实就是修改配置文件的事情。项目环境的兼容性和比较特性支持TLog的基本原理1.日志标签在介绍TLog的时候提到过TLog会自动给你的日志打标签。这个标签就是日志标签。一个日志标签最多可以包含以下信息:preApp:接口调用者的服务名preHost:接口调用者HostpreIp:接口调用者ipcurrIp:当前服务iptraceId:链接id,如果调用者传值,则重新生成spanId:链接spanId默认为根据下面的labelPattern进行数据拼接生成日志标签,所以默认只显示spanId和traceId。这就是为什么在上面的例子中输出格式为<0><11794076298070144>的原因。前面的0其实就是spanId。如果想改变日志标签输出其他信息或者输出顺序,只需要在SpringBoot配置文件中配置日志标签生成样式即可。tlog.pattern=$preApp][$preIp2,TLogContextTLogContext是TLog的核心组件。该组件内部使用TransmittableThreadLocal传递traceId、preApp等信息。当有请求到来时,它会解析出traceId、preApp等信息,然后设置在TransmittableThreadLocal中,然后整个调用环节就可以从TLogContext中获取traceId等信息。3、TLogRPCHandler组件用于处理调用者传入的traceId、preApp等信息,设置在TLogContext和MDC中,并根据logtags的格式生成logtags。第三方框架的适配在实际项目中,请求处理过程中可能会出现以下几种情况。异步线程处理对MQ调用的跨服务调用。对于这些情况,应该在异步线程、跨服务、MQ等中传递traceId,以便更好的排查请求的处理环节。TLog针对以上可能出现的情况做了很多适配,以保证traceId在异步线程、微服务、MQ等中都能正确传输。1.异步线程1.1通用异步线程所谓通用异步线程是指创建一个异步线程直接通过newThread的方法,然后执行它。这样TLog自然就支持携带traceId了,如图。从执行结果可以看出,这个异步方法确实成功传递了traceId。1.2线程池对于线程池,默认是支持traceId的传递的,但是由于线程池中的线程是可以复用的,为了保证线程之间的数据互不干扰,有必要使用TLogInheritableTask来打包提交的任务。ThreadPoolExecutorpool=newThreadPoolExecutor(1,2,1,TimeUnit.SECONDS,newLinkedBlockingQueue<>(10));pool.execute(newTLogInheritableTask(){@OverridepublicvoidrunTask(){"(logger.infoexecution);}});上面代码的写法会有点耦合,每提交一个任务,一个TLogInheritableTask需要创建,比较繁琐,可以简化如下。TLogThreadPoolExecutor写一个TLogThreadPoolExecutor继承ThreadPoolExecutor,重写exe??cute方法(提交最终会调用execute方法执行),然后将提交的任务统一打包到TLogInheritableTask中,这样就可以在需要使用线程池的地方直接创建TLogThreadPoolExecutor,提交任务时不需要创建TLogInheritableTask。ThreadPoolExecutorpool=newTLogThreadPoolExecutor(1,2,1,TimeUnit.SECONDS,newLinkedBlockingQueue<>(10));pool.execute(()->logger.info("异步执行"));2.对于RPC框架的支持除了支持异步线程外,TLog还支持Dubbo、Dubbox、OpenFeign这三种常见的RPC框架。在SpringBoot项目中,不需要配置,只需要引入依赖就可以在服务之间传递traceId。2.1对于Dubbo和Dubbox的支持Dubbo和Dubbox的支持是基于Dubbo的Filter扩展点。TLog通过SPI机制扩展了Filter,在消费者发送请求前从TLogContext中获取traceId,然后在请求数据中设置traceId和其他调用者数据。服务提供者在处理请求时,也会通过Filter从请求中获取traceId等信息,然后设置到TLogContext中,从而实现traceId在dubbo消费者和提供者之间的传递。2.2对OpenFeign的支持对OpenFeign的支持实际上是通过Feign提供的扩展点RequestInterceptor来实现的。在发送请求之前,先从TLogContext中获取traceId,将traceId等信息添加到请求头中,然后就可以通过Http请求传递traceId等信息了。信息传递。当被调用方收到请求后,会被TLogWebInterceptor拦截器拦截,从请求头中获取这些参数,并设置到TLogContext中。3.支持常用的Http框架除了一些RPC框架,TLog还适配了一些Http框架,比如HttpClientOkhttphutool-httpRestTemplateforest。使用这些Http框架也可以实现traceId的传递。其实这些框架的适配和Feign类似。它们大同小异,都是基于这些HTTP框架提供的扩展点进行适配的。traceId等信息放在请求头中,这里不举例。具体使用方法可以到官网查看。4、对SpringCloudGateway的支持同样,TLog也适配了SpringCloudGateway。原理是一样的,就是适配Gateway的GlobalFilter,从请求头中获取traceId等信息。TLog除了适配Gateway网关外,还适配了Soul网关。5、对MQ的支持MQ的支持类似于异步线程。您需要将发送的消息打包到TLogMqWrapBean对象中。发送TLogMqWrapBean时,直接将TLogMqWrapBean对象发送过去。tLogMqWrap);TLogMqWrapBean会携带traceId等信息,消费者接收TLogMqWrapBean,然后通过TLogMqConsumerProcessor处理业务消息。TLogMqConsumerProcessor.process(tLogMqWrapBean,newTLogMqRunner(){@OverridepublicvoidmqConsume(BizBeano){//业务操作}});这样traceId就通过MQ传递了。在实际使用中,可以根据不同的MQ类型,将消息包装成TLogMqWrapBean对象的过程和处理消息的过程统一封装起来,降低发送消息和处理消息到TLog的耦合度。6、任务框架支持TLog主要支持四种任务框架JDKTimerQuartz框架spring-scheduledXXL-JOB框架其中spring-scheduled和XXL-JOB在SpringBoot环境下不需要任务配置,只需要引入依赖即可。Timer在使用的时候需要把任务包装成TLogTimerTask,而Quartz需要把QuartzJobBean换成TLogQuartzJobBean。总结其实从上面的各种适配可以看出本质是一样的,就是根据具体框架的扩展点,在发送请求前从TLogContext中获取traceId,以及调用者的信息如traceId携带在request中,然后被叫方解析请求,取出traceId和caller信息,设置到被叫方服务中的TLogContext中。所以如果遇到官方没有适配的框架或者组件,可以参考上面的适配流程进行适配。最后,总的来说,TLog是一个非常优秀的日志跟踪框架,非常适合中小型公司使用。这里总结一下TLog的特点。通过标记日志完成轻量级微服务日志追踪,提供三种访问方式:javaagent完全无侵入访问,bytecode一行代码访问,基于配置文件访问有利于业务代码无侵入设计,方便使用,10分钟内即可连接。支持log4j、log4j2、logback三种常见的日志框架,并提供自动检测和完全适配。支持dubbo、dubbox、feign三种RPC框架。支持SpringCloudGateway和SoulGateway,支持HttpClient、Okhttp等HTTP调用框架。标签传输支持多种任务框架。JDK的TimerTask、Quartz、XXL-JOB、spring-scheduled支持配置日志标签自定义模板,提供多种系统级嵌入标签。选择支持异步线程的跟踪,包括线程池、多级异步线程等场景几乎没有性能损失,快速稳定,经过压测,损失0.01%。由于本文篇幅有限,无法对TLog进行全面的讲解。如果想深入了解这个框架,可以自行阅读官网或源码。官网:tlog.yomahub.comGitHub地址:github.com/dromara/TLo...