自定义ApiBoot Logging链路以及单元ID

简介: `ApiBoot Logging`会为每一个请求都对应创建链路编号(`TraceID`)以及单元编号(`SpanID`),用于归类每一次请求日志,通过一个链路下日志单元的`Parent SpanID`可以进行上下级关系的梳理。

ApiBoot Logging会为每一个请求都对应创建链路编号(TraceID)以及单元编号(SpanID),用于归类每一次请求日志,通过一个链路下日志单元的Parent SpanID可以进行上下级关系的梳理。

了解链路编号的传递方式

apiboot-custom-logging-traceid-1.png

在每一次请求中链路编号(traceId)、单元编号(spanId)都是通过HttpHeader的方式进行传递,日志的起始位置会主动生成traceIdspanId,而起始位置的Parent SpanId则是不存在的,值为null

这样每次通过restTemplateOpenfeign的形式访问其他服务的接口时,就会携带起始位置生成的traceIdspanId到下一个服务单元

默认编号

ApiBoot Logging内部提供了默认的编号格式,默认为通用格式,没有区分性,无法从编号上进行区分日志的具体归类。

默认的链路编号

ApiBoot Logging内部通过集成minbox-logging日志组件来完成日志的采集等基本功能,每一次生成采集的日志时都会通过LoggingTraceGenerator接口进行生成链路编号(TraceID),该接口源码如下所示:

/**
 * ApiBoot Logging Tracer
 * Create new traceId
 *
 * @author:恒宇少年 - 于起宇
 * <p>
 * DateTime:2019-07-10 17:01
 * Blog:http://blog.minbox.org
 * WebSite:http://www.jianshu.com/u/092df3f77bca
 * Gitee:https://gitee.com/hengboy
 * GitHub:https://github.com/hengboy
 */
public interface LoggingTraceGenerator {
    /**
     * create new traceId
     *
     * @return traceId
     * @throws MinBoxLoggingException exception
     */
    String createTraceId() throws MinBoxLoggingException;

}

ApiBoot Logging默认的链路编号(TraceID)采用的是UUID随机字符串的方式生成的,内部实现是通过LoggingTraceGenerator接口的默认实现类LoggingDefaultTraceGenerator进行生成,生成类源码如下所示:

/**
 * ApiBoot Logging Tracer Default Support Instance
 *
 * @author:恒宇少年 - 于起宇
 * <p>
 * DateTime:2019-07-10 17:28
 * Blog:http://blog.minbox.org
 * WebSite:http://www.jianshu.com/u/092df3f77bca
 * Gitee:https://gitee.com/hengboy
 * GitHub:https://github.com/hengboy
 */
public class LoggingDefaultTraceGenerator implements LoggingTraceGenerator {
    /**
     * Use UUID as the default traceId
     *
     * @return traceId
     * @throws MinBoxLoggingException Exception
     */
    @Override
    public String createTraceId() throws MinBoxLoggingException {
        return UUID.randomUUID().toString();
    }
}

默认的单元编号

单元编号是一条链路下经过的每一个业务单元的唯一标识,在SpringCloud微服务的场景下每发起一个请求内部通过Openfeign可能会经过多个服务,这样每经过的一个服务称之为单元,而当前这条链路下的单元唯一标识字符串就称为单元编号

minbox-logging提供了生成单元编号的接口LoggingSpanGenerator,源码如下所示:

/**
 * ApiBoot Logging Span
 * Create new spanId
 *
 * @author:恒宇少年 - 于起宇
 * <p>
 * DateTime:2019-07-10 17:02
 * Blog:http://blog.minbox.org
 * WebSite:http://www.jianshu.com/u/092df3f77bca
 * Gitee:https://gitee.com/hengboy
 * GitHub:https://github.com/hengboy
 */
public interface LoggingSpanGenerator {
    /**
     * create new spanId
     *
     * @return span id
     * @throws MinBoxLoggingException exception
     */
    String createSpanId() throws MinBoxLoggingException;
}

spanId默认采用的跟traceId生成方式一致,都是UUID随机字符串,minbox-logging提供了LoggingSpanGenerator接口默认的实现LoggingDefaultSpanGenerator,源码如下所示:

/**
 * ApiBoot Logging Default Span
 * Use By Create New SpanId
 *
 * @author:恒宇少年 - 于起宇
 * <p>
 * DateTime:2019-07-15 17:24
 * Blog:http://blog.minbox.org
 * WebSite:http://www.jianshu.com/u/092df3f77bca
 * Gitee:https://gitee.com/hengboy
 * GitHub:https://github.com/hengboy
 */
public class LoggingDefaultSpanGenerator implements LoggingSpanGenerator {
    /**
     * Create New SpanId
     *
     * @return SpanId
     * @throws MinBoxLoggingException Exception
     */
    @Override
    public String createSpanId() throws MinBoxLoggingException {
        return UUID.randomUUID().toString();
    }
}

自定义编号

我们可以根据自己的业务进行自定义traceIdspanId,可以加入一些自己业务的元素,只需要提供minbox-logging提供的生成traceId的接口LoggingTraceGenerator、生成spanId的接口LoggingSpanGenerator对应的实现类,并将实现类交给LoggingFaceBean管理即可。

自定义链路编号

/**
 * 自定义traceId生成策略
 *
 * @author 恒宇少年
 */
public class CustomTraceIdGenerator implements LoggingTraceGenerator {
    /**
     * 链路编号前缀
     */
    private static final String TRACE_ID_PREFIX = "local";
    
    @Override
    public String createTraceId() throws MinBoxLoggingException {
        return TRACE_ID_PREFIX + UUID.randomUUID().toString().hashCode();
    }
}

我们创建名为CustomTraceIdGenerator的类并实现LoggingTraceGenerator接口,实现createTraceId()方法的返回值根据local-作为前缀,拼接UUID随机字符串的hashCode值作为后缀。

自定义单元编号

/**
 * 自定义单元编号生成策略
 *
 * @author 恒宇少年
 */
public class CustomSpanIdGenerator implements LoggingSpanGenerator {
    /**
     * 单元编号前缀
     */
    private static final String SPAN_ID_PREFIX = "group";

    @Override
    public String createSpanId() throws MinBoxLoggingException {
        return SPAN_ID_PREFIX + UUID.randomUUID().toString().hashCode();
    }
}

我们创建名为CustomSpanIdGenerator的类并实现LoggingSpanGenerator接口,在createSpanId()方法的返回值根据group-作为前缀,使用UUID随机字符串的hashCode值作为后缀。

在上面我们已经创建了自定义traceId以及spanId的实现类,我们需要将实现类的实例交给LoggingFactoryBean管理,这样我们才可以实现自定义编号。

LoggingFactoryBeanCustomizer

ApiBoot Logging提供了一个自定义设置LoggingFactoryBean的接口LoggingFactoryBeanCustomizer,通过该接口可以修改LoggingFactoryBean内允许修改的任意值。

我们创建名为CustomCreateTraceAndSpanId类并实现LoggingFactoryBeanCustomizer接口,源码如下所示:

/**
 * 自定义创建链路以及单元编号
 *
 * @author 恒宇少年
 * @see LoggingFactoryBeanCustomizer
 * @see LoggingFactoryBean
 * @see org.minbox.framework.logging.client.tracer.LoggingTraceGenerator
 * @see org.minbox.framework.logging.client.span.LoggingSpanGenerator
 */
@Component
public class CustomCreateTraceAndSpanId implements LoggingFactoryBeanCustomizer {
    /**
     * {@link CustomTraceIdGenerator} 自定义链路编号生成策略
     * {@link CustomSpanIdGenerator} 自定义单元编号生成策略
     *
     * @param factoryBean {@link LoggingFactoryBean}
     */
    @Override
    public void customize(LoggingFactoryBean factoryBean) {
        CustomTraceIdGenerator traceIdGenerator = new CustomTraceIdGenerator();
        factoryBean.setTraceGenerator(traceIdGenerator);

        CustomSpanIdGenerator spanIdGenerator = new CustomSpanIdGenerator();
        factoryBean.setSpanGenerator(spanIdGenerator);
    }
}

customize这种设计方式是在SpringBoot中比较常见的,ApiBoot也沿用了这种设计方式,customize()方法提供了LoggingFactoryBean对象实例作为参数,我们可以直接通过setXxx方法进行修改内定义的默认配置。

通过facetory.setTraceGenerator方法可以修改默认的traceId生成策略。

通过facetory.setSpanGenerator方法可以修改默认的spanId生成策略。

测试

启动项目后我们来查看控制台打印的日志内容,确认是否修改成功。

{
    "endTime":1571711067664,
    "httpStatus":200,
    "requestBody":"",
    "requestHeaders":{
        "accept":"*/*",
        "host":"localhost:8080",
        "user-agent":"curl/7.64.1"
    },
    "requestIp":"0:0:0:0:0:0:0:1",
    "requestMethod":"GET",
    "requestParam":"{}",
    "requestUri":"/index",
    "responseBody":"this is index.",
    "responseHeaders":{},
    "serviceId":"apiboot-custom-logging-traceid",
    "serviceIp":"127.0.0.1",
    "servicePort":"8080",
    "spanId":"group-1780993769",
    "startTime":1571711067643,
    "timeConsuming":21,
    "traceId":"local1111437283"
}

traceIdspanId已经修改成我们自定义的编号生成策略方式。

敲黑板划重点

本章节主要是讲到了如何自定义traceId以及spanId,我们可以通过LoggingFactoryBeanCustomizerLoggingFactoryBean对象进行深度的自定义配置,有关ApiBoot Logging使用的正确姿势还有很多,敬请期待。

请结合文中前文回顾部分进行编写测试。

代码示例

如果您喜欢本篇文章请为源码仓库点个Star,谢谢!!!
本篇文章示例源码可以通过以下途径获取,目录为apiboot-custom-logging-traceid

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1天前
|
前端开发
基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持多实例自定义条件的流程流转
基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持多实例自定义条件的流程流转
基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持多实例自定义条件的流程流转
|
8月前
|
存储 Java 中间件
SpringBoot+MDC链路追踪trace_id丢失
前言 trace_id是用来标识同一个请求的唯一标识,不管请求经过多少服务,都可以通过tracid排查对应模块的日志信息找到对应请求的一些细节,是排查问题的一个重要线索。
247 0
|
存储 JSON Prometheus
SpringBoot动态修改日志级别
SpringBoot动态修改日志级别
629 0
SpringBoot动态修改日志级别
|
11月前
|
存储 SQL Java
skywalking08 - 链路追踪tag查找配置(上)
skywalking08 - 链路追踪tag查找配置(上)
340 0
|
11月前
|
设计模式 关系型数据库 MySQL
skywalking08 - 链路追踪tag查找配置(下)
skywalking08 - 链路追踪tag查找配置(下)
186 0
|
12月前
|
JavaScript 小程序 Java
Spring Boot 实现日志链路追踪,无需引入组件,让日志定位更方便!
Spring Boot 实现日志链路追踪,无需引入组件,让日志定位更方便!
|
存储 缓存 druid
基于springboot+jpa 实现多租户动态切换多数据源 - 基于dynamic-datasource实现多租户动态切换数据源
基于springboot+jpa 实现多租户动态切换多数据源 - 基于dynamic-datasource实现多租户动态切换数据源
2819 0
基于springboot+jpa 实现多租户动态切换多数据源 - 基于dynamic-datasource实现多租户动态切换数据源
|
监控 Java 开发工具
使用ApiBoot Logging进行统一管理请求日志
`ApiBoot Logging`通过集成`minbox-logging`来进行管理每一次请求的日志信息,包含`头信息`、`参数`、`主体内容`、`路径`、发生的`服务器`相关信息等,根据接口的响应状态还可以记录响应的头信息、响应的内容以及发生异常时的`堆栈信息`。
|
Java Maven 容器
ApiBoot Logging使用RestTemplate透传链路信息
使用RestTempalte透传日志链路信息
|
负载均衡 Java Maven
ApiBoot Logging使用SpringCloud Openfeign透传链路信息
`ApiBoot Logging`可以无缝整合`SpringCloud`来采集请求日志,目前支持`RestTemplate`、`Openfeign`两种方式,我们本章来讲解下在使用`Openfeign`完成服务之间请求相互调用的一条链路请求日志是否可以都采集到。