log4j2的异步使用及添加自定义参数方式是什么

蜗牛 互联网技术资讯 2021-12-22 273 0

今天就跟大家聊聊有关log4j2的异步使用及添加自定义参数方式是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

    log4j2异步使用及添加自定义参数

    关于log4j2的性能和原理就不赘述了,这篇主要讲使用,配置文件解读,和添加自定义参数,偏应用的一篇文章。

    相比与其他的日志系统,log4j2丢数据这种情况少;disruptor技术,在多线程环境下,性能高于logback等10倍以上;利用jdk1.5并发的特性,减少了死锁的发生;

    目前看来,log4j2的性能最突出。

    添加依赖(这里省略了版本号)

    <dependency> 
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions><!-- 去掉springboot默认配置 -->
    <exclusion> 
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
    </exclusion> 
    </exclusions> 
    </dependency> 
    <dependency> <!-- 引入log4j2依赖 -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>

    然后再各个项目中添加文件log4j2.xml,在要使用的类上添加@slf4j 注解(lombok的),即可使用log对象。

    log4j 2.0与以往的1.x有一个明显的不同,其配置文件只能采用.xml, .json或者 .jsn。在默认情况下,系统选择configuration文件的优先级如下:(classpath为src文件夹)

    • classpath下名为 log4j-test.json 或者log4j-test.jsn文件

    • classpath下名为 log4j2-test.xml

    • classpath下名为 log4j.json 或者log4j.jsn文件

    • classpath下名为 log4j2.xml

    level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.

    下面写一个生产可用的log4j2.xml的模板

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
    <!-- monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
    <configuration status="WARN">
    <Properties>
    <!--常用变量配置 供下文中使用-->
    <property name="APP_NAME">项目名称</property>
    <property name="LOGGER_LEVEL">INFO</property>
    <!--日志路径 对应服务器路径-->
    <property name="LOGGER_PATH">/data/logs</property> 
    <Property name="LOG_HOME">${LOGGER_PATH}/${APP_NAME}</Property>
    <!--文件大小-->
    <Property name="FILE_SIZE">10M</Property>
    <!--日志格式-->
    <Property name="log_pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{36} - %msg%n</Property>
    <!--日志文件命名格式-->
    <Property name="rolling_file_name">-%d{yyyy-MM-dd}.%i.zip</Property>
    <!--日志留存最大文件数-->
    <Property name="rollover_strategy_max">30</Property>
    <Property name="LOG_HOME_PROJECT">${LOG_HOME}/${APP_NAME}-project</Property>
    <Property name="LOG_HOME_PROJECT_ERROR">${LOG_HOME}/${APP_NAME}-project-error</Property>
    <Property name="LOG_HOME_SQL">${LOG_HOME}/${APP_NAME}-sql</Property>
    </Properties>
    <appenders>
    <!--控制台打印 及格式-->
    <Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="${log_pattern}" />
    </Console>
    <!--定义rolling() 供下文使用-->
    <RollingRandomAccessFile name="projectRolling"
    fileName="${LOG_HOME_PROJECT}.log"
    filePattern="${LOG_HOME_PROJECT}${rolling_file_name}"
    immediateFlush="false" append="true">
    <PatternLayout>
    <Pattern>${log_pattern}</Pattern>
    <Charset>UTF-8</Charset>
    </PatternLayout>
    <Policies>
    <!--滚动规则 时间或者文件大小 滚动后将按照filePattern命名-->
    <!--interval属性用来指定多久滚动一次,默认是1 hour-->
    <TimeBasedTriggeringPolicy interval="24"/>
    <SizeBasedTriggeringPolicy size="${FILE_SIZE}"/>
    </Policies>
    <DefaultRolloverStrategy max="${rollover_strategy_max}" />
    </RollingRandomAccessFile>
    <RollingRandomAccessFile name="projectErrorRolling"
    fileName="${LOG_HOME_PROJECT_ERROR}.log"
    filePattern="${LOG_HOME_PROJECT_ERROR}${rolling_file_name}"
    immediateFlush="false" append="true">
    <Filters>
    <!-- 只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)可以使用多个ThresholdFilter 达到精准过滤某个级别的日志-->
    <ThresholdFilter level="${LOGGER_LEVEL}" onMatch="ACCEPT" onMismatch="DENY" />
    </Filters>
    <PatternLayout>
    <Pattern>${log_pattern}</Pattern>
    <Charset>UTF-8</Charset>
    </PatternLayout>
    <Policies>
    <SizeBasedTriggeringPolicy size="${FILE_SIZE}"/>
    </Policies>
    <DefaultRolloverStrategy max="${rollover_strategy_max}" />
    </RollingRandomAccessFile>
    </RollingRandomAccessFile>
    <RollingRandomAccessFile name="sqlRolling"
    fileName="${LOG_HOME_SQL}.log"
    filePattern="${LOG_HOME_SQL}${rolling_file_name}"
    immediateFlush="false" append="true">
    <PatternLayout>
    <Pattern>${log_pattern}</Pattern>
    <Charset>UTF-8</Charset>
    </PatternLayout>
    <Policies>
    <SizeBasedTriggeringPolicy size="${FILE_SIZE}"/>
    </Policies>
    <DefaultRolloverStrategy max="${rollover_strategy_max}" />
    </RollingRandomAccessFile>
    </appenders>
    <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
    <loggers>
    <!--异步日志 区别于普通使用的logger root 搭配-->
    <!--name 为包名 对应配置日志输出等级level -->
    <!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
    <!--将org.springframework包下的日志打印到Console控制台,projectRolling文件,projectErrorRolling(error级别单独一个文件)-->
    <AsyncLogger name="org.springframework" level="${LOGGER_LEVEL}" additivity="false">
    <appender-ref ref="Console"/>
    <appender-ref ref="projectRolling"/>
    <appender-ref ref="projectErrorRolling"/>
    </AsyncLogger>
    <AsyncLogger name="com.alibaba.dubbo" level="${LOGGER_LEVEL}" additivity="false">
    <appender-ref ref="Console"/>
    <appender-ref ref="projectRolling"/>
    <appender-ref ref="projectErrorRolling"/>
    </AsyncLogger>
    <AsyncLogger name="druid.sql" level="${LOGGER_LEVEL}" additivity="false">
    <appender-ref ref="Console"/>
    <appender-ref ref="sqlRolling"/>
    </AsyncLogger>
    <AsyncLogger name="org.mybatis" level="${LOGGER_LEVEL}" additivity="false">
    <appender-ref ref="Console"/>
    <appender-ref ref="sqlRolling"/>
    </AsyncLogger>
    <AsyncLogger name="com.项目包名" level="${LOGGER_LEVEL}" additivity="false">
    <appender-ref ref="Console"/>
    <appender-ref ref="projectRolling"/>
    <appender-ref ref="projectErrorRolling"/>
    </AsyncLogger>
    <AsyncRoot level="${LOGGER_LEVEL}">
    <appender-ref ref="Console"/>
    <appender-ref ref="projectRolling" />
    <appender-ref ref="projectErrorRolling" />
    </AsyncRoot>
    </loggers>
    </configuration>

    如上配置会产生3个日志文件

    • 项目名称-project.log

    • 项目名称-project-error.log

    • 项目名称-sql.log

    补充知识

    onMatch和onMismatch都有三个属性值,分别为Accept、DENY和NEUTRAL

    分别介绍这两个配置项的三个属性值:

    • onMatch=“ACCEPT” 表示匹配该级别及以上

    • onMatch=“DENY” 表示不匹配该级别及以上

    • onMatch=“NEUTRAL” 表示该级别及以上的,由下一个filter处理,如果当前是最后一个,则表示匹配该级别及以上

    • onMismatch=“ACCEPT” 表示匹配该级别以下

    • onMismatch=“NEUTRAL” 表示该级别及以下的,由下一个filter处理,如果当前是最后一个,则不匹配该级别以下的

    • onMismatch=“DENY” 表示不匹配该级别以下的

    自定义日志格式
    • %d{HH:mm:ss.SSS} 表示输出到毫秒的时间

    • %logger{36} 简单理解为类名

    • %thread 输出当前线程名称

    • %-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0

    • %logger 输出logger名称,因为Root Logger没有名称,所以没有输出

    • %msg 日志文本

    • %n 换行

    • %X{xxx} xxx为自定义参数

    如何在日志中添加自己想传的参数?

    定义拦截器(web服务拦controller,dubbo服务拦api),每次请求过来,拦住,然后将自定义参数传入。至于自定义参数怎么存,就是另一个问题了。

    eg: traceId 跟踪号 对应log4j2.xml中的 %X{traceId}

    下面是关键代码:

    public class ContextFilter implements Filter {
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            String traceId = UUID.randomUUID().toString().replaceAll("-", "");
    // org.slf4j.MDC 
            MDC.put(CommonConsts.TRACE_ID_LOG, traceId);// 用来给日志文件使用
    // org.apache.logging.log4j.ThreadContext
        ThreadContext.put(CommonConsts.TRACE_ID_LOG, traceId); //经测试,这两行都可行。
        filterChain.doFilter(servletRequest, servletResponse);
    }

    最后的日志打印效果如下:

    2019-05-29 12:04:30.122 [http-nio-8080-exec-2] [2333333] INFO com.core.web.filter.ContextFilter - 接口调用时间:245毫秒

    log4j 输入自定义参数

    使用log4j、log4j2输入日志时,有时想追加打印自定义参数(比如客户端环境:手机型号、浏览器数据,request数据、用户数据等),以便于快速定位问题所在。

    亦或在多线程环境中,快速定位哪些日志是由同一用户输出,便于其他工具进行日志分析。

    log4j提供了ThreadContext 线程上下文类,用于存储自定义数据,以便在输入日志时,包含指定数据。

    测试代码如下

    package com.howtodoinjava.log4j2.examples;
    import java.util.UUID;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.apache.logging.log4j.ThreadContext;
     
    public class Log4j2HelloWorldExample {
        private static final Logger LOGGER = LogManager.getLogger(Log4j2HelloWorldExample.class.getName());
        public static void main(String[] args) {
            //Add context information
            ThreadContext.put("id", UUID.randomUUID().toString());
            ThreadContext.put("ipAddress", "192.168.21.9");
     
            LOGGER.debug("Debug Message Logged !!");
            LOGGER.info("Info Message Logged !!");
            LOGGER.debug("Another Debug Message !!");
     
            //Clear the map
            ThreadContext.clearMap();
    		
            LOGGER.debug("Thread Context Cleaned up !!");
            LOGGER.debug("Log message with no context information !!");
        }
    }

    而后在 log4j.xml 中指定上述参数,

    log4j2的异步使用及添加自定义参数方式是什么  log4j2 第1张

    单独使用%X以包含地图的全部内容。

    使用%X{key}包括指定的键。

    使用%x包括堆栈的全部内容。

    在实际应用时,一般是在过滤器、拦截器进行上述操作,方法之前,将数据绑定到线程中,方法完成后,清理线程数据。

    看完上述内容,你们对log4j2的异步使用及添加自定义参数方式是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注蜗牛博客行业资讯频道,感谢大家的支持。

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    评论

    有免费节点资源,我们会通知你!加入纸飞机订阅群

    ×
    天气预报查看日历分享网页手机扫码留言评论Telegram