一、总览
设计一个日志组件来监控业务中的流程节点;我们需要分三步;
- 获取数据
- 整理数据
- 上传数据
二、获取数据
- 日常项目中使用的日志组件有: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);
@Override
protected 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> {
@Override
public void onMessage(CharSequence charSequence, LogMessage logMessage) {
logger.info("接收消息:{}", JSON.toJSONString(logMessage));
}
}
最后效果
五、总结
- 通过自定义logback Appender来设计日志组件,以监控业务流程节点的三个步骤:获取、整理和上传日志数据。
- 整理数据阶段,从日志中提取服务名、类名、方法名等信息,构建LogMessage对象。
- 上传数据阶段,使用Redis发布订阅模式实现日志消息的发送和监听。