前面我们介绍plumlog的时候,可以看到在接口里面设置了webmvc,如果是定时器的话,则还要在单独的地方设置loggerhelper,那有没有更简单的方法呢?还有 feign,所以这里我们弄一篇稍微全一点的集成方案,方便大家直接开箱即用即可。
本文内容概览
本文将为java技术人员提供完整的Plumelog集成指南,涵盖从模式选型到具体实施的详细步骤。我们将重点介绍:
Plumelog的集成指南
plumelog 的使用指南
通过本指南,各个微服务模块的负责人可以快速掌握Plumelog集成技能,为团队构建统一的日志观测平台,大幅提升线上问题排查效率。
集成指南
1、添加 maven 依赖
这里需要在 maven 里面添加 plumelog 的依赖,对应的依赖如下:
<dependency> <groupId>com.plumelog</groupId> <artifactId>plumelog-logback</artifactId> <version>3.5.3</version> </dependency>
2、在 src/main/resources 目录下创建一个名称为 logback-spring.xml,然后把下面的内容拷贝进去
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- 添加追踪码模式 -->
<property name="TRACE_PATTERN" value="[%X{traceId}] "/>
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} ${TRACE_PATTERN}%clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- 环境配置 -->
<springProperty scope="context" name="plumelog.appName" source="plumelog.appName"/>
<springProperty scope="context" name="plumelog.redisHost" source="plumelog.redisHost"/>
<springProperty scope="context" name="plumelog.redisPort" source="plumelog.redisPort"/>
<springProperty scope="context" name="plumelog.redisAuth" source="plumelog.redisAuth"/>
<springProperty scope="context" name="plumelog.redisDb" source="plumelog.redisDb"/>
<springProperty scope="context" name="plumelog.env" source="spring.profiles.active"/>
<!-- 自动traceId生成TurboFilter -->
<turboFilter class="com.million.mes.basic.logic.utils.TraceIdTurboFilter" />
<!-- 开发环境配置 -->
<springProfile name="dev">
<!--输出到控制台,开发环境使用 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 输出到文件,开发环境使用 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/log-dev.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>logs/log--dev.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
<TotalSizeCap>1GB</TotalSizeCap>
</rollingPolicy>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- Plumelog日志输出,开发环境可选 -->
<appender name="plumelog" class="com.plumelog.logback.appender.RedisAppender">
<appName>${plumelog.appName}</appName>
<redisHost>${plumelog.redisHost}</redisHost>
<redisAuth>${plumelog.redisAuth}</redisAuth>
<redisDb>${plumelog.redisDb}</redisDb>
<!-- 启用追踪码 -->
<expand>traceId</expand>
</appender>
<!-- 配置日志输出级别 -->
<root level="INFO"> <!-- 改为 DEBUG -->
<appender-ref ref="CONSOLE"/>
<appender-ref ref="file"/>
<appender-ref ref="plumelog"/>
</root>
</springProfile>
<!--测试环境配置 -->
<springProfile name="test">
<!--输出到控制台,测试环境使用 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 输出到文件,测试环境使用 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/log-test.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>logs/log-test.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
<TotalSizeCap>1GB</TotalSizeCap>
</rollingPolicy>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- Plumelog日志输出,测试环境 -->
<appender name="plumelog" class="com.plumelog.logback.appender.RedisAppender">
<appName>${plumelog.appName}</appName>
<redisHost>${plumelog.redisHost}</redisHost>
<redisAuth>${plumelog.redisAuth}</redisAuth>
<redisDb>${plumelog.redisDb}</redisDb>
<env>${plumelog.env}</env>
<!-- 启用追踪码 -->
<expand>traceId</expand>
</appender>
<!-- 配置日志输出级别 -->
<root level="DEBUG"> <!-- 改为 DEBUG -->
<appender-ref ref="CONSOLE"/>
<appender-ref ref="file"/>
<appender-ref ref="plumelog"/>
</root>
</springProfile>
<!--生产环境配置 -->
<springProfile name="prod">
<!-- 输出到文件,生产环境不输出到控制台 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/log-prod.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>logs/log-prod.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>90</MaxHistory>
<TotalSizeCap>10GB</TotalSizeCap>
</rollingPolicy>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- Plumelog日志输出,生产环境必须 -->
<appender name="plumelog" class="com.plumelog.logback.appender.RedisAppender">
<appName>${plumelog.appName}</appName>
<redisHost>${plumelog.redisHost}</redisHost>
<redisPort>${plumelog.redisPort}</redisPort>
<redisAuth>${plumelog.redisAuth}</redisAuth>
<redisDb>${plumelog.redisDb}</redisDb>
<env>${plumelog.env}</env>
<!-- 启用追踪码 -->
<expand>traceId</expand>
</appender>
<!-- 配置日志输出级别,生产环境通常只记录INFO及以上级别 -->
<root level="DEBUG"> <!-- 改为 DEBUG -->
<appender-ref ref="file"/>
<appender-ref ref="plumelog"/>
</root>
</springProfile>
<!-- 默认配置,如果没有指定profile -->
<springProfile name="!dev && !test && !prod">
<!--输出到控制台,默认使用 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 输出到文件,默认使用 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/log-default.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>logs/log-default.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- Plumelog日志输出 -->
<appender name="plumelog" class="com.plumelog.logback.appender.RedisAppender">
<appName>${plumelog.appName}</appName>
<redisHost>${plumelog.redisHost}</redisHost>
<redisPort>${plumelog.redisPort}</redisPort>
<redisAuth>${plumelog.redisAuth}</redisAuth>
<redisDb>${plumelog.redisDb}</redisDb>
<env>${plumelog.env}</env>
<!-- 启用追踪码 -->
<expand>traceId</expand>
</appender>
<!-- 配置日志输出级别 -->
<root level="DEBUG"> <!-- 改为 DEBUG -->
<appender-ref ref="CONSOLE"/>
<appender-ref ref="file"/>
<appender-ref ref="plumelog"/>
</root>
</springProfile>
</configuration>3、创建 application-dev.yml文件
在各个微服务模块中,有的项目在 src/main/resources 目录下有 application-dev.xml文件,有的只有 application.xml文件但是没有 application-dev.xml文件,这里如果有 application-dev.xml文件就忽略掉这一步,如果没有则创建一个 application-dev.yml文件,然后把当前 module 中 application.yml文件的内容拷贝到application-dev.yml,然后修改 application.yml文件,指向使用 dev 文件,下面给出两个示例文件的内容。
application.yml文件示例内容:
server: port: 8080 spring: profiles: active: dev
application-dev.yml文件示例内容:
spring: application: name: logic-engine-server logging: config: classpath:logback-spring.xml level: com.baomidou.dynamic: debug feign: httpclient: enabled: true max-connections: 200 # 最大连接数 max-connections-per-route: 50 # 每个路由的最大连接数 follow-redirects: true # 是否跟随重定向 connection-timeout: 10000 # 连接超时时间(毫秒) connection-request-timeout: 10000 # 连接请求超时时间(毫秒) socket-timeout: 30000 # Socket超时时间(毫秒) client: config: default: # 默认配置 connectTimeout: 10000 # 连接超时时间(毫秒) readTimeout: 30000 # 读取超时时间(毫秒) loggerLevel: BASIC # 日志级别:NONE/BASIC/HEADERS/FULL platform-server: # 针对特定服务的配置 connectTimeout: 15000 readTimeout: 45000 loggerLevel: BASIC etl-server: connectTimeout: 15000 readTimeout: 60000 loggerLevel: BASIC compression: request: enabled: true mime-types: text/xml,application/xml,application/json min-request-size: 2048 response: enabled: true circuitbreaker: enabled: true # 启用断路器 retryer: enabled: true # 启用重试 max-attempts: 3 # 最大重试次数 period: 1000 # 初始延迟时间(毫秒) max-period: 2000 # 最大延迟时间(毫秒) multiplier: 1.5 # 延迟倍数 plumelog: appName: ${spring.application.name} redisHost: ${plumelog_redis_host} redisAuth: ${plumelog_redis_auth} redisDb: ${plumelog_redis_db}
4、修改 application-dev.yml文件
这里主要是添加 logging 的配置,让他指向使用的新的配置文件,同时添加 plumelog 的配置信息,示例
logging:
config: classpath:logback-spring.xml
plumelog:
appName: ${spring.application.name}
redisHost: 192.168.2.5:30787
redisAuth: 123456
redisDb: 0这里的配置主要分为两部分,第一部分的 logging 是让他指向新创建的 logback-spring.xml配置文件
5、把下面的类拷贝到对应的 modules 中
这里我们提供一个 traceid 的工具类,具体如下:
package com.million.mes.basic.logic.utils; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.turbo.TurboFilter; import ch.qos.logback.core.spi.FilterReply; import com.plumelog.core.TraceId; import org.slf4j.MDC; import org.slf4j.Marker; import java.util.UUID; /** * 自动traceId生成的TurboFilter * 当日志输出时如果没有traceId,则自动生成一个 */ public class TraceIdTurboFilter extends TurboFilter { @Override public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) { // 检查当前线程的MDC中是否有traceId String traceId = MDC.get("traceId"); if (traceId == null || traceId.trim().isEmpty()) { // 如果没有traceId,则生成一个新的 traceId = generateTraceId(); MDC.put("traceId", traceId); TraceId.logTraceID.set(traceId); } // 继续处理日志事件 return FilterReply.NEUTRAL; } private String generateTraceId() { return UUID.randomUUID().toString().replace("-", "").substring(0, 16); } }
一般 在对应的 module 项目的 utils目录中创建这个工具类,示例图如下:
6、添加 filter
既然我们这边是微服务,所以这里会涉及到使用 feign 进行调用,feign 调用其实核心就是 http 请求,所以既然我们是全链路日志的模式,我们当前服务调用的话就需要把这个 traceid 给传递给其他服务,让其他服务不生成自己的 traceid,而是从 http 头里面获取我们传递过去的 traceid,所以这里我们在项目的 config 目录下创建一个名称为:TraceIdFilter的类,具体的内容是:
package com.million.mes.basic.dbdesign.config; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.slf4j.MDC; import org.springframework.stereotype.Component; /** * 处理传入请求的traceId过滤器 * 如果请求头中包含traceId,则将其设置到MDC中,避免TraceIdTurboFilter生成新的traceId */ @Component public class TraceIdFilter implements Filter { private static final String TRACE_ID_HEADER = "traceId"; private static final String TRACE_ID_MDC_KEY = "traceId"; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; // 从请求头获取traceId String traceId = httpRequest.getHeader(TRACE_ID_HEADER); if (traceId != null && !traceId.trim().isEmpty()) { // 如果请求头中包含traceId,则将其放入MDC中 MDC.put(TRACE_ID_MDC_KEY, traceId); } try { // 继续执行过滤器链 chain.doFilter(request, response); } finally { // 请求结束后清理MDC,避免内存泄漏 MDC.remove(TRACE_ID_MDC_KEY); } } }
然后我们需要把这个类注册到当前的 springboot 启动中,可以创建一个名称为:FilterConfig的类,然后把下面的代码粘贴进去:
package com.million.mes.basic.dbdesign.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 过滤器配置类
*/
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<TraceIdFilter> traceIdFilterRegistration() {
FilterRegistrationBean<TraceIdFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new TraceIdFilter());
registration.addUrlPatterns("/*"); // 应用到所有路径
registration.setName("traceIdFilter");
registration.setOrder(1); // 设置较高优先级,确保在其他过滤器(包括TraceIdTurboFilter)之前执行
return registration;
}
}备注:
1、这里的filterconfig 可能在原来的 module 里面已经有了,如果有则不需要创建,直接添加这里的 traceidfilter 的注册即可。
7、添加 feign 拦截器
这里我们创建一个名称为FeignInterceptor的类,进行拦截,如果对应的代码示例如下:
package com.million.mes.basic.logic.config;
import cn.dev33.satoken.same.SaSameUtil;
import cn.dev33.satoken.stp.StpUtil;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* feign拦截器, 在feign请求发出之前,加入一些操作
*/
@Component
public class FeignInterceptor implements RequestInterceptor {
private final Logger log = LoggerFactory.getLogger(this.getClass());
// 为 Feign 的 RCP调用 添加请求头Id-Token
@Override
public void apply(RequestTemplate requestTemplate) {
// 获取当前线程MDC中的traceId
String currentTraceId = MDC.get("traceId");
if (StringUtils.isNotBlank(currentTraceId)) {
requestTemplate.header("traceId", currentTraceId);
}
}
@Bean
public ApplicationRunner forceParentSpanId() {
return args -> {
// 空实现,只是为了触发Sleuth的MDC设置
};
}
}这里主要的作用就是使用 feign 的时候,先查看本地是否有 traceid,如果有的话,把他放到 http 头里面传递下去。示例图如下:
备注:
1、这里我们主要是使用 feign 传递对应的 traceid,方便下一个节点使用到。
8、修改 logback-spring.xml
在我们前面修改的 logback-spring.xml文件中可以看到有配置
<!-- 自动traceId生成TurboFilter --> <turboFilter class="com.million.mes.basic.logic.utils.TraceIdTurboFilter" />
这里我们需要把配置里面的:
<turboFilter class="com.million.mes.basic.logic.utils.TraceIdTurboFilter" />
这里的 class 修改为当前 module 相关的完整包路径(这里很重要,每个 module 对应的路径都是不一样的)。
9、启动项目测试
接下来就是启动项目准备进行测试了,我们把当前 modules 给启动起来,然后查看下控制台的日志,注意发现下是否有 redis 写入失败的日志打出来
如果出现这个 redis 写入失败,则检查下自己的redis 配置有没有问题,如果有问题则修改,然后重新启动项目查看启动日志。
正常情况如果配置全部正确的话,则不会有这里 redis 写入失败的打印,也不会有其他的日志打印出来。
10、使用日志
前面如果没有问题的话,咱们就可以登录 plumelog 的 dashboar 查看日志了,对应的信息是:
开发环境的 plumelog dashboard 信息是:
地址:http://192.168.2.5:31030/#/login 账号:admin 密码:123456
咱们登录上去可以直接看到对应打印的日志信息:
plumelog测试效果
1、比如我们现在用 logic 项目进行测试,这里使用 feign 调用了 databasedesign-server,(这里测试的链路 id 是:35db330526bb41d6)我们看下测试效果
可以看到一个链路 id,横跨了多个服务,这就是全链路日志的使用。
plumelog使用指南
1、查看某个服务的所有日志的话,直接根据应用名称进行筛选即可:
2、如果想看对应同一链路相关的日志的话,找到对劲的追踪码,复制出来
当如追踪码里面进行搜索:











还没有评论,来说两句吧...