zoukankan      html  css  js  c++  java
  • log4j2 项目日志组件

    在项目运行过程中,常常需要进行功能调试以及用户行为的跟踪和记录,部分人习惯使用System.out,但这并不建议,它仅仅是使用方便但不便于维护也无扩展性。相比log4j的话,log4j可以控制日志信息的输送目的地、输出格式以及级别等等,使我们能够更加细致地控制日志的生成过程。

    Log4j2是对Log4j1的升级,在性能和功能上有显著的改进,包括多线程中吞吐量的增强、占位符的支持、配置文件自动重新加载等

    一、入门介绍

    1、下载jar包

    pox.xml

    <dependencies>
      <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.10.0</version>
      </dependency>
      <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.10.0</version>
      </dependency>
    </dependencies>

    2、配置文件

    Log4j包含四个配置工厂实现:JSON、YAML、properties、XML,本文介绍常用的方式XML。

    Log4j具有在初始化期间自动配置自身的能力。当Log4j启动时,它将定位类路径下所有符合名称的文件,优先级顺序:log4j2-test.properties > log4j2-test.xml > log4j2.properties > log4j2.xml

    3、一个简单的实例

    xml配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN">
      <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
          <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
      </Appenders>
      <Loggers>
        <Root level="info">
          <AppenderRef ref="Console"/>
        </Root>
      </Loggers>
    </Configuration>

    java代码:

    private static final Logger logger = LogManager.getLogger(MyApp.class);
    
        @Test
        public void testLog4j(){
            logger.info("hello world!");
        }
    
    }

    控制台信息

    22:17:47.146 [main] INFO  MyApp - hello world!

    二、模块介绍

    <Configuration>

    属性 描述
    monitorInterval 如果文件被修改了,指定时间后会重新加载配置。单位秒,最小值是5
    packages 以逗号隔开的包名列表,用于搜索插件,比如自定义filter、appender等。插件仅会加载一次,所以要想修改后生效必须重启项目
    status 内部日志级别,设置值为debug可以在控制台上清晰地看到整个日志事件流程,所使用的Logger是org.apache.logging.log4j.core.LOGGER
    strict  允许使用严格的XML格式。不支持JSON配置
    verbose   在加载插件时启用诊断信息

    <Appenders>

    Log4j允许将日志请求打印到多个目的地。在log4j语言中,输出目的地称为Appender。目前,appender存在于控制台、文件、远程套接字服务器、Apache Flume、JMS、远程UNIX Syslog守护进程和各种数据库api中。以下介绍几种比较常用的appender,如需了解更多可以到官网上进行查阅。

    1、ConsoleAppender

    输出到控制台,<Console>

    参数名称

    类型

    描述

    filter

    Filter

     过滤器

    layout

    Layout

     日志输出格式

    follow

    boolean

    direct

    boolean

    name

    String

    Appender的名称

    ignoreExceptions

    boolean

    默认true,忽略写入异常

    target

    String

    SYSTEM_OUT或SYSTEM_ERR,默认是SYSTEM_OUT

    2、FileAppender

    输出到文件,<File>

    参数

    类型

    描述

    append

    boolean

    默认是true,新记录将追加到文件尾部

    bufferedIO

    boolean

    默认是true,使用缓冲区可以显著地提高性能

    bufferSize

    int

    当bufferedIO是true时,这个属性缓冲区大小,默认是8192字节。

    createOnDemand

    boolean

    appender按需创建文件。只有当一个日志事件通过所有过滤器并被路由到这个appender时,appender才会创建这个文件。默认值为假

    filter

    Filter

    一个过滤器来确定事件是否应该由这个Appender处理。使用复合过滤器可以使用多个筛选器

    fileName

    String

    要写入的文件的名称。如果文件或它的任何父目录不存在,它们将被创建

    immediateFlush

    boolean

    默认true,每次写入后都将有一个刷新。这将保证缓冲区的数据被写入磁盘,但可能会影响性能。

    layout

    Layout

    日志格式

    locking

    boolean

    文件锁,默认false

    name

    String

    Appender的名称

    ignoreExceptions

    boolean

    默认true,忽略写入异常

    filePermissions

    String

    定义文件权限

    例: rw------- or rw-rw-rw- etc...

    fileOwner

    String

    定义文件所有者

    fileGroup

    String

    定义文件组

    3、JDBCAppender

    JDBCAppender使用标准JDBC将日志事件写入到关系数据库表中。它可以配置为使用JNDI数据源或自定义工厂方法获得JDBC连接。无论采用哪种方法,都必须由连接池来支持。否则,日志记录性能将受到极大的影响。如果已配置的JDBC驱动程序支持批处理语句,并且将缓冲区大小配置为一个正数,那么日志事件将被批处理。

    (1)<JDBC>

    参数

    类型

    描述

    name

    String

    必须,appender的名称

    ignoreExceptions

    boolean

    默认true,忽略日志事件异常

    filter

    Filter

    过滤器

    bufferSize

    int

    如果一个大于0的整数,这将导致appender缓冲日志事件,并在缓冲区达到该大小时刷新写入数据

    connectionSource

    ConnectionSource

    必须,可被检索到的数据库连接

    tableName

    String

    必须,插入日志事件的数据表名

    columnConfigs

    ColumnConfig[]

    必须,需要插入到数据库的字段,由多个<Column>元素组成

    columnMappings

    ColumnMapping[]

    必须,字段映射配置

    (2)使用<DataSource>来获得JDBC的连接,这里仅列出jndi:

    参数类型描述
    jndiName String 必需的,如已配置的jndi为jdbc/LoggingDatabase,那此处的值为java:comp/env/jdbc/LoggingDatabase。数据源必须由连接池来支持;否则,日志记录将非常缓慢。

    (3)使用<Column>来指定要写入表中的哪些列,以及如何对它们进行写入。它没有SQL注入漏洞。

    参数类型描述
    name String

    必须,表字段名称

    pattern String

    使用PatternLayout模式插入值,注:同一个Column元素中,patter、literal、isEventTimestamp3个属性只能存在一个

    literal String

    该值将直接包含在SQL语句中执行,比如:rand()函数将生成随机数,类似myibats中的${}

    isEventTimestamp boolean

    是否时间格式java.sql.Types.TIMESTAMP

    isUnicode boolean

    除非指定pattern,否则该属性将被忽略。如果是true,该值将插入Unicode。否则,该值将被插入非Unicode。

    isClob boolean

    除非指定pattern,否则该属性将被忽略。如果是true,该值将插入CLOB,否则将插入varchar、nvarchar

    实例:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="error">
      <Appenders>
        <JDBC name="databaseAppender" tableName="dbo.application_log">
          <DataSource jndiName="java:/comp/env/jdbc/LoggingDataSource" />
          <Column name="eventDate" isEventTimestamp="true" />
          <Column name="level" pattern="%level" />
          <Column name="logger" pattern="%logger" />
          <Column name="message" pattern="%message" />
          <Column name="exception" pattern="%ex{full}" />
        </JDBC>
      </Appenders>
      <Loggers>
        <Root level="warn">
          <AppenderRef ref="databaseAppender"/>
        </Root>
      </Loggers>
    </Configuration>

     

    <PatternLayout>

    (1)日期,%d / %date

    Pattern

    示例

    %d{DEFAULT}

    2012-11-02 14:34:02,781

    %d{ISO8601}

    2012-11-02T14:34:02,781

    %d{ISO8601_BASIC}

    20121102T143402,781

    %d{ABSOLUTE}

    14:34:02,781

    %d{DATE}

    02 Nov 2012 14:34:02,781

    %d{COMPACT}

    20121102143402781

    %d{HH:mm:ss,SSS}

    14:34:02,781

    %d{dd MMM yyyy HH:mm:ss,SSS}

    02 Nov 2012 14:34:02,781

    %d{HH:mm:ss}{GMT+0}

    18:34:02

    %d{UNIX}

    1351866842

    %d{UNIX_MILLIS}

    1351866842781

    当然你也可以自定义格式,比如 %d{yyyy-MM-dd HH:mm:ss}

    (2)记录器,%c / %logger

    Conversion Pattern

    Logger Name

    结果

    %c{1}

    org.apache.commons.Foo

    Foo

    %c{2}

    org.apache.commons.Foo

    commons.Foo

    %c{10}

    org.apache.commons.Foo

    org.apache.commons.Foo

    %c{-1}

    org.apache.commons.Foo

    apache.commons.Foo

    %c{-2}

    org.apache.commons.Foo

    commons.Foo

    %c{-10}

    org.apache.commons.Foo

    org.apache.commons.Foo

    %c{1.}

    org.apache.commons.Foo

    o.a.c.Foo

    %c{1.1.~.~}

    org.apache.commons.test.Foo

    o.a.~.~.Foo

    %c{.}

    org.apache.commons.test.Foo

    ....Foo

    {?} - ?是正整数时表示从右边开始取n个部分,负整数表示从左边开始移除n个部分,那为什么%c{-10}是完整的名称我也不清楚,欢迎留言

    (3)日志信息,%m / %msg / %message

    (4)日志级别,%level

    (5)换行符,%n

    <Filter>

    log4j2自带多种filter供直接使用,也可以由我们自己来定义filter:

    MyFilter.java

    import org.apache.logging.log4j.Level;
    import org.apache.logging.log4j.Marker;
    import org.apache.logging.log4j.ThreadContext;
    import org.apache.logging.log4j.core.LogEvent;
    import org.apache.logging.log4j.core.Logger;
    import org.apache.logging.log4j.core.config.plugins.Plugin;
    import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
    import org.apache.logging.log4j.core.filter.AbstractFilter;
    import org.apache.logging.log4j.message.Message;
    
    @Plugin(name = "MyFilter", category = "Core", elementType = "filter", printObject = true)
    public final class MyFilter extends AbstractFilter {
    
        private final Level level;
    
        private MyFilter(Level level, Result onMatch, Result onMismatch) {
            super(onMatch, onMismatch);
            this.level = level;
        }
    
        public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
            return filter(level);
        }
    
        public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
            return filter(level);
        }
    
        public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
            return filter(level);
        }
    
        @Override
        public Result filter(LogEvent event) {
            return filter(event.getLevel());
        }
    
        private Result filter(Level level) {
    
            /*
            * 业务逻辑
            * */
            
            return level.isMoreSpecificThan(this.level) ? onMatch : onMismatch;
        }
    
        @Override
        public String toString() {
            return level.toString();
        }
    
        @PluginFactory
        public static MyFilter createFilter(@PluginAttribute(value = "level", defaultString = "ERROR") Level level,
                                                   @PluginAttribute(value = "onMatch", defaultString = "NEUTRAL") Result onMatch,
                                                   @PluginAttribute(value = "onMismatch", defaultString = "DENY") Result onMismatch) {
            return new MyFilter(level, onMatch, onMismatch);
        }
    }

    log4j2.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="warn" monitorInterval="5"  packages="your packages" verbose="false" strict="true">
      <Appenders>
    
        <Console name="Console" target="SYSTEM_OUT" ignoreExceptions="true">
          <PatternLayout pattern="%d{yyyy-MM-dd  HH:mm:ss} %level %logger{10} - %msg%n"/>
          <MyFilter level="info" onMatch="ACCEPT"/>
        </Console>
    
      </Appenders>
      <Loggers>
        <Root level="info">
          <AppenderRef ref="Console"/>
        </Root>
      </Loggers>
    </Configuration>

    补充:

    在实际应用中,有时需要对用户的访问信息进行记录,比如请求参数、用户id等等。在log4j1中我们会使用MDC和NDC来存储应用程序的上下文信息,而log4j2使用ThreadContext来实现MDC和NDC两者的功能。 

    (1)NDC采用类似栈的机制来存储上下文信息,线程独立。

    在PatternLayout中使用 %x 来输出,注意x是小写。

    实例:

    Test.java

    ThreadContext.push("hello world!");

    log4j2.xml

    <Column name="tip" pattern="%x" />

    (2)MDC采用类似map的机制来存储信息,线程独立。

    在PatternLayout中使用 %X{userId} 来输出,注意X是大写。

    实例:

    Test.java

    ThreadContext.put("userId","1");

    log4j2.xml

    <Column name="userId" pattern="%X{userId}" />

    注意使用完后调用clearAll()清除上下文映射和堆栈。

    api:http://logging.apache.org/log4j/2.x/javadoc.html

    官网地址:https://logging.apache.org/log4j/2.x/index.html

    转载请注明出处:http://www.cnblogs.com/cjh-notes/p/8017855.html

  • 相关阅读:
    转:npm安装教程
    转:数据库收缩
    转:日志插件 log4net 的使用
    转:更改SQLServer实例默认字符集
    转:IIS 应用程序池 内存 自动回收
    IDisposable
    Sql Server 判断字符串是否可以转数字
    常用算法之快速排序
    Java调用JavaScript
    使用python生成iOS各规格icon
  • 原文地址:https://www.cnblogs.com/cjh-notes/p/8017855.html
Copyright © 2011-2022 走看看