一、总览
设计一个日志组件来监控业务中的流程节点;我们需要分三步;
- 获取数据
- 整理数据
- 上传数据
二、获取数据
- 日常项目中使用的日志组件有:logback
-
log4j:
-
- 优点:成熟稳定,灵活性高,性能良好,社区支持强大。
- 缺点:异步日志处理较慢,日志轮转处理不够完善。
-
SLF4J:
-
- 优点:提供抽象层,易于集成,可插拔性。
- 缺点:性能开销,配置稍显复杂。
-
logback:
-
- 优点:性能优异,功能丰富,集成log4j优点,社区支持良好。
- 缺点:配置复杂,学习曲线较陡。
怎么能获取到logback中的日志数据呢:
主要基于logback的扩展接口实现了自定义logback appender。
一个自定义Appender的基本步骤:
- 创建自定义Appender类: 创建一个类,继承自
ch.qos.logback.core.Appender
接口,并实现append
方法。 - 配置自定义Appender: 在Logback的配置文件中,引用你的自定义Appender,并指定其处理日志的方式。
- 使用自定义Appender: 在你的应用程序中,使用
Logger
对象将日志事件添加到你的自定义Appender。
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.spi.AppenderAttachableImpl;
import ch.qos.logback.core.spi.FilterReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class CustomAppender extends AppenderAttachableImpl<Object> {private static final Logger logger = LoggerFactory.getLogger(CustomAppender.class);@Overrideprotected void append(Object eventObject) {// 这里是你自定义的日志处理逻辑logger.info("Custom Appender Event: {}", eventObject);}// 你可以添加初始化方法,或者实现其他Appender的方法
}
在Logback的配置文件中引用你的自定义Appender:
<configuration><appender name="customAppender" class="com.yourpackage.CustomAppender"><!-- 这里可以添加额外的配置,例如过滤器或者布局 --></appender><root level="info"><appender-ref ref="customAppender" /></root></configuration>
三、整理数据
这部分我们的目标就是整理数据---->我们需要的数据;有哪些?
- 服务名
- 项目组(指定范围的日志)—不上传数据
- 类名
- 方法名
- 日志信息
public class LogMessage {private String systemName;private String className;private String methodName;private List<String> logList;.......
}
接下来我们就需要获取数据;数据来源就是上述我们开发的自定义的Appender;
// 获取日志
if (eventObject instanceof ILoggingEvent) {ILoggingEvent event = (ILoggingEvent) eventObject;String methodName = "unknown";String className = "unknown";StackTraceElement[] callerDataArray = event.getCallerData();if (null != callerDataArray && callerDataArray.length > 0) {StackTraceElement callerData = callerDataArray[0];methodName = callerData.getMethodName();className = callerData.getClassName();}if (!className.startsWith(groupId)){return;}// 构建日志LogMessage logMessage = new LogMessage(systemName, className, methodName, Arrays.asList(event.getFormattedMessage().split(" ")));
}
这样我们就获得了需要的数据;
四、上传数据
上述操作将log中的message保存到了实体中;接下来我们就上传数据(发布数据);这里我们采用的是redis;使用成本比较低;后续可以通过接口实现策略模式来扩充多种上传方式:rockermq、kafka等等;
public interface IPush {/**用于初始化redis链接*/void open(String host, int port);void send(LogMessage logMessage);}
在具体实现中实例化redis后进行监听对应的主题:xbhog-monitor-sdk-topic
public synchronized void open(String host, int port) {/**确保项目中只实例化一次redis*/if (null != redissonClient && !redissonClient.isShutdown()) return;Config config = new Config();config.setCodec(JsonJacksonCodec.INSTANCE);config.useSingleServer().setAddress("redis://" + host + ":" + port).setConnectionPoolSize(64).setConnectionMinimumIdleSize(10).setIdleConnectionTimeout(1000).setConnectTimeout(1000).setRetryAttempts(3).setRetryInterval(1000).setPingConnectionInterval(0).setKeepAlive(true);this.redissonClient = Redisson.create(config);//redis的发布订阅RTopic topic = this.redissonClient.getTopic("xbhog-monitor-sdk-topic");topic.addListener(LogMessage.class, new Listener());
}
最后就可以在Appender进行数据的上传了;
......
push.send(logMessage);
redis的监听部分如下:
import org.redisson.api.listener.MessageListener;
class Listener implements MessageListener<LogMessage> {@Overridepublic void onMessage(CharSequence charSequence, LogMessage logMessage) {logger.info("接收消息:{}", JSON.toJSONString(logMessage));}
}
最后效果
五、总结
- 通过自定义logback Appender来设计日志组件,以监控业务流程节点的三个步骤:获取、整理和上传日志数据。
- 整理数据阶段,从日志中提取服务名、类名、方法名等信息,构建LogMessage对象。
- 上传数据阶段,使用Redis发布订阅模式实现日志消息的发送和监听。