Java log4j2日志配置

项目中日志的xml文件结构很复杂,这里逐步解析记录下,还有相应的参考教程。

<?xml version='1.0' encoding="UTF-8" ?>
<Configuration>
    <Properties>
	<!-- 定义日志文件的存储地址 -->
	
        <Property name="log-dir">/export/Logs/jx-search-web</Property>
        
        	<!--
		%p:输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
		%r:输出自应用启动到输出该日志讯息所耗费的毫秒数
		%t:输出产生该日志事件的线程名
		%f:输出日志讯息所属的类别的类别名
		%c:输出日志讯息所属的类的全名
		%d:输出日志时间点的日期或时间,指定格式的方式: %d{yyyy-MM-dd HH:mm:ss}
		%l:输出日志事件的发生位置,即输出日志讯息的语句在他所在类别的第几行。
		%m:输出代码中指定的讯息,如log(message)中的message
		%n:输出一个换行符号
	-->
	<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
	
        <Property name="output-pattern">%d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{100} %msg%n</Property>
    </Properties>
    
    <Appenders>
		<!-- 当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类 -->
        <RollingFile name="JX-SEREACH-DEBUG"
                     fileName="${log-dir}/debug.log"
                     immediateFlush="false" append="true" bufferedIO="true"
                     filePattern="${log-dir}/debug-%d{yyyy-MM-dd}-%i.log">
            <!-- LevelFilter: 级别过滤器,根据日志级别进行过滤 -->
            <!-- 用于配置符合过滤条件的操作 ACCEPT:日志会被立即处理,不再经过剩余过滤器 -->
            <!-- 这里设置一个INFO,高于INFO及以上的不管,低于则流转到下一个 -->
            <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
            <!-- 这里设置一个DEBUG,直接打印 -->
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${output-pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="500MB"/>
            </Policies>
        </RollingFile>
        <RollingFile name="JX-SEREACH-INFO"
                     fileName="${log-dir}/info.log"
                     filePattern="${log-dir}/info-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${output-pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="500MB"/>
            </Policies>
        </RollingFile>
        <RollingFile name="JX-SEREACH-WARN"
                     fileName="${log-dir}/warn.log"
                     immediateFlush="false" append="true" bufferedIO="true"
                     filePattern="${log-dir}/warn-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
            <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${output-pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="500MB"/>
            </Policies>
        </RollingFile>
        <RollingFile name="JX-SEREACH-ERROR"
                     fileName="${log-dir}/error.log"
                     immediateFlush="false" append="true" bufferedIO="true"
                     filePattern="${log-dir}/error-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="ERROR" onMatch="ACCEPT"/>
            <PatternLayout pattern="${output-pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="500MB"/>
            </Policies>
        </RollingFile>

        <RollingFile name="JX-SEREACH-MANAGER"
                     fileName="${log-dir}/manager.log"
                     immediateFlush="false" append="true" bufferedIO="true"
                     filePattern="${log-dir}/manager-%d{yyyy-MM-dd}-%i.log">
            <PatternLayout pattern="${output-pattern}"/>
            <TimeBasedTriggeringPolicy/>
        </RollingFile>
        <RollingFile name="JX-SEREACH-ACCESS"
                     fileName="${log-dir}/access.log"
                     immediateFlush="false" append="true" bufferedIO="true"
                     filePattern="${log-dir}/access-%d{yyyy-MM-dd}-%i.log">
            <PatternLayout pattern="${output-pattern}"/>
            <TimeBasedTriggeringPolicy/>
        </RollingFile>
    </Appenders>
    <Loggers>
        <AsyncRoot level="WARN">
            <AppenderRef ref="JX-SEREACH-DEBUG"/>
            <AppenderRef ref="JX-SEREACH-INFO"/>
            <AppenderRef ref="JX-SEREACH-WARN"/>
            <AppenderRef ref="JX-SEREACH-ERROR"/>
        </AsyncRoot>
        <AsyncLogger name="com.jx.search.logging.manager" level="WARN" additivity="false">
            <AppenderRef ref="JX-SEREACH-MANAGER"/>
        </AsyncLogger>
        <AsyncLogger name="com.jx.search.logging.access" level="INFO" additivity="false">
            <AppenderRef ref="JX-SEREACH-ACCESS"/>
        </AsyncLogger>
    </Loggers>
</Configuration>

项目中想在日志中加几个功能:
1、支持配置动态调整某个Logger的日志级别
2、支持配置白名单,以无视日志级别的方式全量打印该用户的请求所经过的所有日志
3、支持收集log.info()、log.error等函数打印的、格式化好的message,应用侧可以自行拓展。如搜索中收集了之后输出给前端,在测试阶段大大提升debug效率
4、解决了当程序打印日志的速度 > Log4j2将日志写入到文件的速度时,打满队列导致的阻塞问题(多余日志使用丢弃策略)

log4j2中,当使用异步Logger时日志event会写入到Disruptor环形队列中并立刻返回,再由一个线程异步执行appender的打印,默认情况下当Disruptor队列打满时,会阻塞打印日志的线程的入队操作。
使用log4j2.component.properties配置将队列打满的策略设置为丢弃。
以SDK方式提供代码需要以编程的方式来实现这个配置,目前还在探索;

前三个都能通过log4j2的FIlter机制实现。

一些关于log4j2的介绍:

主要组件之间的关系

使用 Log4j 2 API 的应用程序将从 LogManager 请求具有特定名称的 Logger。 LogManager 将找到适当的 LoggerContext,然后从中获取 Logger。如果必须创建 Logger,它将与 LoggerConfig 关联,该 LoggerConfig 包含 a)与 Logger 相同的名称,b)父程序包的名称或 c)根 LoggerConfig。 LoggerConfig 对象是根据配置中的 Logger 声明创建的。 LoggerConfig 与实际提供 LogEvent 的 Appender 关联。

Logger 层级继承

在 Log4j 1.x 中,通过 Logger 之间的关系维护 Logger 层次结构。在 Log4j 2 中,此关系不再存在。而是在 LoggerConfig 对象之间的关系中维护层次结构。

Logger 和 LoggerConfigs 是命名实体。Logger 名称区分大小写,并且遵循分层命名规则:
如果 LoggerConfig 的名称后跟一个点,则该 LoggerConfig 被称为另一个 LoggerConfig 的祖先。如果 LoggerConfig 与子 LoggerConfig 之间没有祖先,则称该 LoggerConfig 为子 LoggerConfig 的父级。

例如,名为“ com.foo”的 LoggerConfig 是名为“ com.foo.Bar”的 LoggerConfig 的父级。同样,“ java”是“ java.util”的父代,也是“ java.util.Vector”的祖先。大多数开发人员都应该熟悉这种命名方案。
根 LoggerConfig 位于 LoggerConfig 层次结构的顶部。它的特殊之处在于它始终存在,并且是每个层次结构的一部分。直接链接到根 LoggerConfig 的 Logger 可以通过以下方式获得:

Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
Logger logger = LogManager.getRootLogger();

LogEvent

在调用Logger对象的info、error、trace等函数时,就会产生LogEvent。LogEvent跟LoggerConfig一样,也是由Level的。LogEvent的Level主要是用在Event传递时,判断在哪里停下。

FIlter机制

除了上一节所述的自动日志级别过滤之外,Log4j 还提供了Filter,可以在将控制权传递给任何 LoggerConfig 之前,将控制权传递给 LoggerConfig 之后但在调用任何 Appender 之前,在控制完成之后应用Filter。传递给 LoggerConfig,但在调用特定的 Appender 之前以及在每个 Appender 上传递。以与防火墙过滤器非常相似的方式,每个过滤器可以返回以下三个结果之一:“接受”,“拒绝”或“中性”。接受的响应表示不应调用其他任何筛选器,并且事件应 continue 进行。拒绝的响应意味着应立即忽略该事件,并将控制权返回给调用方。中性的响应表示该事件应传递给其他过滤器。如果没有其他过滤器,则事件将被处理。

Filter允许对日志事件进行评估,以确定是否或如何发布它们。一个过滤器将使用其一种过滤方法被调用并返回一个结果,该结果是一个枚举,具有以下三个值之一:ACCEPT,DENY 或 NEUTRAL。

可以在以下四个位置之一中配置Filter:

上下文范围的Filter直接在Configuration中配置。
这些过滤器拒绝的事件将不会传递给 Logger 以进行进一步处理。事件被上下文范围的过滤器接受后,将不再由其他任何上下文范围的过滤器进行评估,也不会使用 Logger 的级别来过滤事件。但是,该事件将由 Logger 和 Appender 筛选器评估。

Logger Filter在指定的 Logger 上配置。
这些是在上下文范围过滤器和 Logger 的日志级别之后评估的。无论可加性设置如何,这些过滤器拒绝的事件都将被丢弃,并且该事件将不会传递给父 Logger。

Appender 筛选器用于确定特定的 Appender 是否应处理事件的格式和发布。

Appender 参考过滤器用于确定 Logger 是否应将事件路由到 Appender。
在这里插入图片描述

filter本身已经自带了许多功能的过滤器,比如日志包含某一字符的过滤器、日志级别的过滤器等等。

我们也可以自己写相关功能的过滤器。完成项目中日志的诉求,也是用了这部分特性。
通过写个类继承AbstractFilter,实现自定义过滤器。

在这里插入图片描述

技术方案

日志级别动态调整

简述:ducc配置root和对应log4j2配置文件的logger的日志级别,使用定时线程来查询ducc key(目前30秒,后续可以改为走配置),如果发现配置有更新则刷新为ducc的日志级别(使用log4j2暴露的调整日志级别方法org.apache.logging.log4j.core.config.Configurator#setLevel)

加白用户无视日志级别打印日志

简述:

1.log.isInfoEnable等判断时,会看当前config中有没filter,如果有filter并且filter返回的结果非neutral的话,会根据这个结果来判断是否为true,代码 =>

org.apache.logging.log4j.core.Logger.PrivateConfig#filter(org.apache.logging.log4j.Level, org.apache.logging.log4j.Marker, java.lang.String)

2.因此我们可以通过开发Log4j2 Filter插件,并返回一个Result来决定log.isInfoEnable是否为true

采集日志并输出到响应

PS:

1.继承一个filter时需要实现很多方法,filter配置在config中的不同位置、log的不同方法会调用到filter中的不同方法

2.一条log日志的打印会成为一个logEvent,经过不同的filter最终决定在哪里停下,如果不停下则最终会打印成为一条日志,因此我们的思路很简单,通过我们自己写的filter来收集到log的日志

3.一个logevent会多次进入同一个filter方法,如果不对event进行标记则会被重复采集,因此需要对原生LogEvent进行扩展一下。

4.扩展了之后还需要保证创建log event时创建的是我们的log event,因此需要还需要一个LogEventFactory,并配置到log4j的配置文件中

logger.info 执行流程:
在这里插入图片描述
logger.isInfoEnabled执行流程:
在这里插入图片描述

参考教程:
lookback
log4j2使用filter过滤日志

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值