appender log4j 扩展_Log4j2 自定义appender

本文介绍了Log4j 2的优势和性能,并展示了如何自定义一个KafkaAppender,用于将日志事件发送到Kafka集群。Log4j 2的异步Logger提供高性能,而自定义Appender则满足了特定业务场景的需求。
摘要由CSDN通过智能技术生成

Log4j 2介绍:

Log4j 2是Java的流行日志记录程序包,几乎每个大型应用程序都包含其自己的日志记录或跟踪API,将日志语句插入代码是调试它的低技术方法。这也可能是唯一的方法,因为调试器并不总是可用或不适用。对于多线程应用程序和整个分布式应用程序通常是这种情况。经验表明,日志记录是开发周期的重要组成部分。它提供有关应用程序运行的精确上下文。一旦插入到代码中,就无需人工干预即可生成日志输出。此外,日志输出可以保存在永久性介质中,以便以后进行研究。除了在开发周期中使用它外,足够丰富的日志记录包也可以视为审核工具。

Log4j 2优势:

Apache Log4j 2是Log4j的升级版,对Log4j的前身Log4j 1.x进行了重大改进.Log4j API是一个日志外观,可以与Log4j实现一起使用,但是也可以在其他日志实现(例如Logback)之前使用。与SLF4J相比,Log4j API具有多个优点:Log4j API支持记录消息而不只是字符串,可以参考FormattedMessage自定义消息格式。

Log4j API支持lambda表达式。

与SLF4J相比,Log4j API提供了更多的日志记录方法。

除了SLF4J支持的“参数化日志记录”格式外,Log4j API还支持使用java.text.MessageFormat语法以及printf样式消息的事件。

Log4j API提供了LogManager.shutdown()方法。基础的日志记录实现必须实现Terminable接口,该方法才能生效。

完全支持其他结构,例如标记,日志级别和ThreadContext(aka MDC)。

Log4j 2 API将提供最佳性能,而Log4j 2提供对Log4j 1.2,SLF4J,Commons Logging和java.util.logging(JUL)API的支持。

性能:

Log4j 2包含基于LMAX Disruptor库的下一代异步记录器。Disrupter是一个开源的并发框架,能够在无锁的情况下实现线程安全高效的并发操作,关于Disrupter框架的原理与使用,会在之后的高并发框架专栏详细剖析。在多线程方案中,与Log4j 1.x和Logback相比,异步Logger的吞吐量高18倍,延迟降低了几个数量级。否则,Log4j 2明显优于Log4j 1.x,Logback和java.util.logging,尤其是在多线程应用程序中。

官方性能测试图如下,此图为记录峰值吞吐量

与其他日志框架性能压测对比:

自定义appender:

Appender负责将LogEvents传递到其目的地。每个Appender必须实现Appender 接口。大多数Appender都会扩展 AbstractAppender ,从而增加生命周期和可过滤支持。生命周期允许组件在配置完成后完成初始化,并在关机期间执行清理。可过滤允许组件具有附加的过滤器,这些过滤器将在事件处理期间进行评估。由于场景需要将消息同步到ELK集群,进行分析,问题排查等操作,官方提供的appender不能满足业务场景,因此需要自定义.一. maven依赖:

org.apache.logging.log4j

log4j-api

2.14.0

org.apache.logging.log4j

log4j-core

2.14.0

org.apache.logging.log4j

log4j-slf4j-impl

2.14.0

二. KafkaAppender:

@Plugin(name="Kafka", //命名根据项目需要可自定义

category="Core",

elementType="appender",

printObject=true)

public final class KafkaAppender

extends AbstractAppender

...

//创建appender

public static KafkaAppender createAppender(final Layout extends Serializable> layout, final Filter filter,

final String name, final boolean ignoreExceptions, final String topic, final Property[] properties,

final Configuration configuration,

final String key) {

if (layout == null) {

AbstractLifeCycle.LOGGER.error("No layout provided for KafkaAppender");

return null;

}

final KafkaManager kafkaManager = KafkaManager.getManager(configuration.getLoggerContext(), name, topic, true,

properties, key);

return new KafkaAppender(name, layout, filter, ignoreExceptions, kafkaManager, null, null);

}

//实现父类append方法,真正将日志发送出去

public void append(final LogEvent event) {

if (event.getLoggerName() != null && event.getLoggerName().startsWith("org.apache.kafka")) {

LOGGER.warn("Recursive logging from [{}] for appender [{}].", event.getLoggerName(), getName());

} else {

try {

tryAppend(event);

} catch (final Exception e) {

if (this.retryCount != null) {

int currentRetryAttempt = 0;

while (currentRetryAttempt < this.retryCount) {

currentRetryAttempt++;

try {

tryAppend(event);

break;

} catch (Exception e1) {

}

}

}

error("Unable to write to Kafka in appender [" + getName() + "]", event, e);

}

}

}

private void tryAppend(final LogEvent event) throws ExecutionException, InterruptedException, TimeoutException {

final Layout extends Serializable> layout = getLayout();

byte[] data;

if (layout instanceof SerializedLayout) {

final byte[] header = layout.getHeader();

final byte[] body = layout.toByteArray(event);

data = new byte[header.length + body.length];

System.arraycopy(header, 0, data, 0, header.length);

System.arraycopy(body, 0, data, header.length, body.length);

} else {

data = layout.toByteArray(event);

}

manager.send(data);

}

//注意:log4j2 中kafkaManager初始化kafka的属性配置时序列化方式为org.apache.kafka.common.serialization.ByteArraySerializer

三. 关于配置文件.properties , .xml文件二选一即可,或者根据业务场景自行配置..xml部分配置如下:

...

localhost:9092

四. 异步日志处理

为了减小对业务系统的影响,建议采用异步方式处理日志.Log4j-2.9和更高版本要求在类路径上使用disruptor-3.3.4.jar或更高版本。在Log4j-2.9之前,需要使用disruptor-3.0.0.jar或更高版本

同步异步混合配置如下:

immediateFlush="false" append="false">

%d %p %class{1.} [%t] %location %m %ex%n

//includeLocation 会打印文件行数,影响性能,不推荐

关注我的公众号 : 宇哥996(id: java_zyh) Java全栈技术,大厂面试题不定期分享

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值