java+日志报警_基于log4j2简易实现日志告警

本文介绍了如何利用log4j2的Filter功能,在出现ERROR级别日志时,实现实时消息通知。通过自定义ErrorNotifyLog4j2Filter,捕获ERROR日志并发送通知,同时考虑到性能和重复告警问题,加入了频率限制策略,避免无限循环告警。此外,还讨论了配置和优化细节。
摘要由CSDN通过智能技术生成

需求

系统报ERROR错误时,能实时做到消息通知。

思路

当前项目比较小,不想过多的依赖额外的第三方组件。

项目在ERROR时,都会打印ERROR日志,所以可以在log4j接收到ERROR日志请求时,发送通知消息。

实践

Filter是log4j2的扩展点,从图中(图片来自如何编写Log4j2脱敏插件)流程可以看到,Filter分别可以在全局、Logger、Appender三个地方做过滤。

4ff7729781ac2aa424e84296edf06a95.png

三个地方对应的log4j.xml配置地方如下:

log4j提供了过滤器的基类AbstractFilter:全局过滤器入口方法是filter(Logger logger, Level level, Marker marker, String msg, Object... params),msg是填充参数之前的内容,params是参数列表,包含Throwable对象。

Logger和Appender入口方式是filter(final LogEvent event),通过event.getMessage().getFormattedMessage()取到填充参数之后的内容,通过event.getThrown()获取异常对象。

代码@Plugin(name = "ErrorNotifyFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)

public class ErrorNotifyLog4j2Filter extends AbstractFilter {

// 默认打印异常堆栈长度

public static final int DEFAULT_PRINT_EXCEPTIONSTACK_LENGTH = 3;

// 默认消息最长长度

// 2020-07-09 测试企业微信允许最大长度为4000

public static final int DEFAULT_MAX_MSG_LENGTH = 4000;

private String projectName;

private List rtxReceivers;

private boolean noPrintExceptionStack;

private int printExceptionStackLength;

private int maxMsgLength;

private Object lock = new Object();

private ErrorNotifyLog4j2Filter(String projectName, String rtxReceivers,

boolean noPrintExceptionStack, int printExceptionStackLength, int maxMsgLength) {

super();

this.projectName = projectName;

this.rtxReceivers = Lists.newArrayList(rtxReceivers.split(","));

this.noPrintExceptionStack = noPrintExceptionStack;

this.printExceptionStackLength = printExceptionStackLength <= 0 ? DEFAULT_PRINT_EXCEPTIONSTACK_LENGTH : printExceptionStackLength;

this.maxMsgLength = (maxMsgLength <= 0 || maxMsgLength > DEFAULT_MAX_MSG_LENGTH) ? DEFAULT_MAX_MSG_LENGTH : maxMsgLength;

}

@Override

public Result filter(LogEvent event) {

notify(event.getLevel(), event.getMessage().getFormattedMessage(), event.getThrown());

return super.filter(event);

}

@Override

public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {

notify(level, msg.getFormattedMessage(), t);

return super.filter(logger, level, marker, msg, t);

}

@Override

public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {

notify(level, msg == null ? "" : msg.toString(), t);

return super.filter(logger, level, marker, msg, t);

}

@Override

public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) {

notify(level, msg, getExceptionParam(params));

return super.filter(logger, level, marker, msg, params);

}

/**

* @param level

* @param msg

* @param t

* @author

* @date

*/

private void notify(Level level, String msg, Throwable t) {

try {

if (level == null || level.intLevel() != Level.ERROR.intLevel()) {

return;

}

if (StringUtils.isBlank(msg) && t == null) {

return;

}

Log4j2AsyncExecutor.executorService.submit(() -> {

try {

String notifyMsg = getNotifyMsg(msg, t); MessageUtil.postMessage(Lists.newArrayList(MessageTypeEnum.RTX),

rtxReceivers,

getNotifyTitle(),

notifyMsg);

} catch (Exception ignoreException) {

ignoreException.printStackTrace();

}

});

} catch (Throwable ignoreException) {

ignoreException.printStackTrace();

}

}

/**

* @param params

* @return java.lang.Throwable

* @author

* @date

*/

private Throwable getExceptionParam(Object... params) {

if (params == null || params.length == 0) {

return null;

}

for (Object param : params) {

if (param instanceof Throwable) {

return (Throwable) param;

}

}

return null;

}

/**

* 如果开启堆栈信息,能让告警更清晰,但同样的也就降低了性能

*

* @param msg

* @param t

* @return java.lang.String

* @author

* @date

*/

private String getNotifyMsg(String msg, Throwable t) {

String errorMsg = "信息:" + (msg == null ? "" : msg);

String exceptionMsg = "";<

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值