log4j2_log4j2日志输出 - CSDN
精华内容
参与话题
  • Log4j2-Log4j 2介绍及使用

    万次阅读 2017-07-16 05:12:37
    Log4j 2 官网https://logging.apache.org/log4j/2.x/Log4j 2简介Log4j的1.x版本已经被广泛使用于很多应用程序中。然而,它这些年的发展已经放缓。它变得越来越难以维护,因为它需要严格遵循很老的Java版本,并在2015...

    Log4j 2 官网

    https://logging.apache.org/log4j/2.x/


    Log4j 2简介

    Log4j的1.x版本已经被广泛使用于很多应用程序中。然而,它这些年的发展已经放缓。它变得越来越难以维护,因为它需要严格遵循很老的Java版本,并在2015年8月寿终正寝。它的替代品,SLF4J和Logback对框架做了很多必要的改进。

    那么为什么还要费心去做Log4j 2呢?几个原因如下:

    • Log4j 2被设计为可以作为审计框架使用。Log4j 1.x和Logback都会在重新配置的时候失去事件,而Log4j2不会。在Logback中,Appender当中的异常对应用从来都是不可见的。但Log4j2的Appender可以设置为允许将异常渗透给应用程序。
    • Log4j 2包含基于LMAX Disruptor库的下一代异步日志器。在多线程情况下,异步日志器具有比Log4j 1.x和Logback高出10倍的吞吐性能以及更低的延迟。
    • Log4j 2在稳定记录状态下,对单机应用是无垃圾的,对Web应用是低垃圾的。这不仅降低了垃圾回收器的压力,还可以提供更好的响应性能。
    • Log4j 2使用插件系统使得它非常容易通过新的Appender、Filter、Layout、Lookup和Pattern Converter来扩展框架,且不需要对Log4j做任何修改。
    • 由于插件系统的配置更简单了,配置项不需要声明类名称。
    • 支持自定义日志级别。自定义日志级别可以在代码或配置中定义。
    • 支持Lambda表达式。运行在Java 8上的客户端代码可以使用Lambda表达式来实现仅在对应的日志级别启用时延迟构造日志消息。由于不需要明确地层层把关,这带来了更简洁的代码。
    • 支持Message对象。Message允许支持感兴趣或复杂的结构体在日志系统中传输,且可以被高效地操作。用户可以自由地创建他们自己的Message类型,并编写自定义的Layout、Filter和Lookup来操作它们。
    • Log4j 1.x支持Appender上的Filter。Logback引入了TurboFilter来在事件被Logger处理之前对它们进行过滤。Log4j 2支持的Filter可以设置为在被Logger接管之前即处理事件,如同它在Logger或Appender中被处理。
    • 很多Logback的Appender不接受一个Layout,且只能发送固定格式的数据。而大多数Log4j 2的Appender接受Layout,允许数据以任意一种所需的格式传输。
    • Log4j 1.x和Logback中的Layout返回一个String。这导致了在Logback Encoder中讨论的问题。Log4j 2用更简单的方法,Layout总是返回一个字节数组。优点是这意味着它们可以用于任何Appender,而不仅仅是写入到OutputStream中的那些。
    • Syslog Appender既支持TCP也支持UDP,同样支持BSD系统日志以及RFC 5424格式。
    • Log4j 2利用了Java 5的并发优势,并在尽可能最低的程度上进行锁定。Log4j 1.x中已知存在死锁问题。其中很多已经在Logback中修复,但很多Logback的class文件仍然需要在更高的编译级别中同步。
    • 这是一个被所有ASF项目集体支持使用的Apache软件基金会项目。如果你想要贡献或修改,只要参照贡献中的方法。

    架构

    这里写图片描述

    应用程序要使用Log4j 2的API,需要从LogManager中获取一个有明确名称的Logger。

    LogManager将会定位到一个合适的LoggerContext并且从中获取Logger。

    如果Logger必须被创建,那么它会和包含这些信息的LogConfig相关联:
    a)与Logger相同的名称;
    b)父包的名称;
    c)根LoggerConfig。LoggerConfig对象根据配置中的Logger声明而创建。

    LoggerConfig与实际处理LogEvent事件的Appender关联。


    日志级别

    这里写图片描述

    在表格中,垂直列为LogEvent的级别,水平列为从合适的LoggerConfig中分配到的级别。二者的交点处标识了LogEvent是否会被通过并传递给下一步处理,是(YES)或否(NO)。


    Filter

    Log4j提供Filter并可应用于:控制被传递到任何LoggerConfig之前、控制被传递到达一个LoggerConfig但在调用任何Appender之前、控制被传递到一个LoggerConfig单在调用一个指定的Appender和每一个Appender之前。

    与防火墙过滤的方式类似,每一个Filter都将返回三个结果之一:Accept(接受)、Deny(拒绝)或Neutral(中立)。

    • 响应Accept意味着其他的Filter都不应该再被调用,而事件应该被处理。
    • 响应Deny意味着事件应该被立即忽略,且将控制讲给调用处。
    • 响应Neutral代表事件应该被传递给其他的Filter。如果没有其他Filter,则事件将被处理。

    尽管一个事件可能被Filter接受,但事件仍然可能不被记录。这种情况会发生于事件被LoggerConfig之前的Filter接受,但被LoggerConfig的Filter拒绝或者被所有的Appender拒绝。


    Appender 将日志请求打印到多个目标

    http://logging.apache.org/log4j/2.x/manual/appenders.html

    Log4j允许将日志请求打印到多个目标。用Log4j的说法,一个输出的目标位置被称为Appender。目前,Appender存在几种:控制台、文件、远程Socket服务器、Apache Flume、JMS、远程UNIX系统日志后台以及好几种数据库API。

    一个Logger上可以装配多个Appender。


    Layout 自定义输出格式

    用户不仅希望自定义输出的目的位置,也希望自定义输出格式。

    这可以通过将一个Layout与Appender关联来实现。Layout负责根据用户的希望来格式化LogEvent,然而是Appender负责将格式化的内容输出到目的位置。

    PatternLayout,Log4j中的一部分,让用户根据C语言printf函数的方式来具体化输出格式。

    例如,使用转换模式“%r [%t] %-5p %c - %m%n”的PatternLayout将会输出类似于下面的内容:

    176 [main] INFO  org.foo.Bar - Located nearest gas station.

    第一个字段是程序启动以来锁经过的毫秒时间。
    第二个字段是发出日志请求的线程。
    第三个字段是日志声明的级别。
    第四个字段是与日志请求相关联的Logger名称。

    在“-”之后的文本是日志的消息内容。

    Log4j带有很多不同的Layout以支持诸如JSON、XML、HTML和Syslog


    转到Log4j 2 API

    大多数情况下,从Log4j 1.x API转换到Log4j 2相当简单。很多日志声明都不需要修改,但以下这些变更是必要的

    这里写图片描述

    控制台Appender的简单配置

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
      <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
          <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </Console>
      </Appenders>
      <Loggers>
        <Logger name="org.apache.log4j.xml" level="info"/>
        <Root level="debug">
          <AppenderRef ref="STDOUT"/>
        </Root>
      </Loggers>
    </Configuration>

    文件Appender的简单配置

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
      <Appenders>
        <File name="A1" fileName="A1.log" append="false">
          <PatternLayout pattern="%t %-5p %c{2} - %m%n"/>
        </File>
        <Console name="STDOUT" target="SYSTEM_OUT">
          <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </Console>
      </Appenders>
      <Loggers>
        <Logger name="org.apache.log4j.xml" level="debug">
          <AppenderRef ref="A1"/>
        </Logger>
        <Root level="debug">
          <AppenderRef ref="STDOUT"/>
        </Root>
      </Loggers>
    </Configuration>

    SocketAppender

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
      <Appenders>
        <Socket name="A1" host="localHost" port="5000">
          <SerializedLayout/>
        </Socket>
        <Console name="STDOUT" target="SYSTEM_OUT">
          <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </Console>
      </Appenders>
      <Loggers>
        <Logger name="org.apache.log4j.xml" level="debug">
          <AppenderRef ref="A1"/>
        </Logger>
        <Root level="debug">
          <AppenderRef ref="STDOUT"/>
        </Root>
      </Loggers>
    </Configuration>

    AsyncAppender

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="debug">
      <Appenders>
        <File name="TEMP" fileName="temp">
          <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </File>
        <Async name="ASYNC">
          <AppenderRef ref="TEMP"/>
        </Async>
      </Appenders>
      <Loggers>
        <Root level="debug">
          <AppenderRef ref="ASYNC"/>
        </Root>
      </Loggers>
    </Configuration>

    控制台和文件的AsyncAppender

    注意AsyncAppender应该在它引用Appender的后面被配置,这会让它正确地关闭。

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="debug">
      <Appenders>
        <Console name="CONSOLE" target="SYSTEM_OUT">
          <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </Console>
        <File name="TEMP" fileName="temp">
          <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </File>
        <Async name="ASYNC">
          <AppenderRef ref="TEMP"/>
          <AppenderRef ref="CONSOLE"/>
        </Async>
      </Appenders>
      <Loggers>
        <Root level="debug">
          <AppenderRef ref="ASYNC"/>
        </Root>
      </Loggers>
    </Configuration>

    配置Log4j 2

    Log4j 2的配置可以通过以下4种方式之一完成:

    1. 通过以XML、JSON、YAML或属性格式编写的配置文件。
    2. 以编程方式,通过创建ConfigurationFactory和配置实现。
    3. 通过调用配置接口中公开的API,以编程方式将组件添加到默认配置。
    4. 以编程方式,通过调用内部Logger类上的方法

    举例,具体请根据实际需要修改

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- log4j2使用说明:
    使用方式如下:
    private static final Logger logger = LogManager.getLogger(实际类名.class.getName());
    
    2、日志说明:
    (1)请根据实际情况配置各项参数
    (2)需要注意日志文件备份数和日志文件大小,注意预留目录空间
    (3)实际部署的时候backupFilePatch变量需要修改成linux目录
     -->
    <configuration status="debug">
        <Properties>
            <Property name="fileName">loginModule.log</Property>
            <Property name="backupFilePatch">D:/workspace/workspace-jee/HelloSpring/hello-spring4/log/</Property>
          </Properties>
        <!--先定义所有的appender-->
        <appenders>
            <!--这个输出控制台的配置-->
            <Console name="Console" target="SYSTEM_OUT">
                 <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
                <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY" />
                <!-- 输出日志的格式-->
                <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
            </Console>
    
            <!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
            <RollingFile name="RollingFile" fileName="${backupFilePatch}${fileName}"
                filePattern="${backupFilePatch}$${date:yyyy-MM}/app-%d{yyyyMMddHHmmssSSS}.log.gz">
                <PatternLayout
                    pattern="%d{yyyy.MM.dd 'at' HH:mm:ss.SSS z} %-5level %class{36} %L %M - %msg%xEx%n" />
    
                <!-- 日志文件大小 -->
                <SizeBasedTriggeringPolicy size="20MB" />
                <!-- 最多保留文件数 -->
                <DefaultRolloverStrategy max="20"/>
            </RollingFile>
        </appenders>
    
        <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
        <loggers>
            <!--建立一个默认的root的logger-->
            <Logger name="org.apache.log4j.xml" level="trace"
                additivity="true">
                <AppenderRef ref="RollingFile" />
            </Logger>
            <Root level="error">
                <AppenderRef ref="Console" />
            </Root>
        </loggers>
    </configuration>

    使用Log4j 2

    maven 的引用

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>${log4j2.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>${log4j2.version}</version>
    </dependency>
    <!-- web容器中需要添加log4j-web -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-web</artifactId>
        <version>${log4j2.version}</version>
    </dependency>
    
    
    <properties>
    
            <log4j2.version>2.8.2</log4j2.version>
    </properties>
    import com.foo.Bar;
    
    // 导入Log4j的类
    import org.apache.logging.log4j.Logger;
    import org.apache.logging.log4j.LogManager;
    
    public class MyApp {
    
        // 定义一个静态的日志器变量,引用名为MyApp的实例
        private static final Logger logger = LogManager.getLogger(MyApp.class);
    
        public static void main(final String... args) {
    
            // 设置一个简单的配置,日志显示在控制台中
    
            logger.trace("Entering application.");
            Bar bar = new Bar();
            if (!bar.doIt()) {
                logger.error("Didn't do it.");
            }
            logger.trace("Exiting application.");
        }
    }
    import org.apache.logging.log4j.Logger;
    import org.apache.logging.log4j.LogManager;
    
    public class Bar {
      static final Logger logger = LogManager.getLogger(Bar.class.getName());
    
      public boolean doIt() {
        logger.entry();
        logger.error("Did it again!");
        return logger.exit(false);
      }
    }

    如果Log4j找不到配置文件,它将提供默认配置。DefaultConfiguration类中提供的默认配置将设置:

    • 一个附加到根记录器的ConsoleAppender。
    • 一个设置为“%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} -
      %msg%n”的PatternLayout,被附加到ConsoleAppender上。

    注意,默认情况下Log4j将根日志记录器分配给Level.ERROR。

    MyApp的输出类似如下:

    17:13:01.540 [main] ERROR com.foo.Bar - Did it again!
    17:13:01.540 [main] ERROR MyApp - Didn't do it.

    如前所述,Log4j将首先尝试从配置文件配置自身。与默认配置相同的配置如下所示:

    <?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="error">
          <AppenderRef ref="Console"/>
        </Root>
      </Loggers>
    </Configuration>

    一旦上述文件作为log4j2.xml放入到类路径中,你将得到与上面列出的相同结果。将根级别更改为trace将得到类似于以下的结果:

    17:13:01.540 [main] TRACE MyApp - Entering application.
    17:13:01.540 [main] TRACE com.foo.Bar - entry
    17:13:01.540 [main] ERROR com.foo.Bar - Did it again!
    17:13:01.540 [main] TRACE com.foo.Bar - exit with (false)
    17:13:01.540 [main] ERROR MyApp - Didn't do it.
    17:13:01.540 [main] TRACE MyApp - Exiting application.

    请注意,使用默认配置时,将禁用状态日志的记录。


    展开全文
  • log4j2 实际使用详解

    万次阅读 多人点赞 2019-08-13 11:37:04
    日志框架简单比较(slf4j、log4j、logback、log4j2log4j2基础知识 log4j2实用配置 实战部分 slf4j + log4j2 实际使用 二、日志框架比较(slf4j、log4j、logback、log4j2 ) 日志接口(slf4j) slf4j是对所有日志...

    分享一个朋友的人工智能教程(请以“右键”->"在新标签页中打开连接”的方式访问)。比较通俗易懂,风趣幽默,感兴趣的朋友可以去看看。

    一、目录简介

    • 基础部分
      • 日志框架简单比较(slf4j、log4j、logback、log4j2 )
      • log4j2基础示例
      • log4j2配置文件
    • 实战部分
      • slf4j + log4j2 实际使用

    二、日志框架比较(slf4j、log4j、logback、log4j2 )

    • 日志接口(slf4j)
      slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体的日志框架实现配合使用(如log4j、logback)

    • 日志实现(log4j、logback、log4j2)

      • log4j是apache实现的一个开源日志组件
      • logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,是slf4j的原生实现
      • Log4j2是log4j 1.x和logback的改进版,据说采用了一些新技术(无锁异步、等等),使得日志的吞吐量、性能比log4j 1.x提高10倍,并解决了一些死锁的bug,而且配置更加简单灵活,官网地址: http://logging.apache.org/log4j/2.x/manual/configuration.html
    • 为什么需要日志接口,直接使用具体的实现不就行了吗?

      接口用于定制规范,可以有多个实现,使用时是面向接口的(导入的包都是slf4j的包而不是具体某个日志框架中的包),即直接和接口交互,不直接使用实现,所以可以任意的更换实现而不用更改代码中的日志相关代码。

      比如:slf4j定义了一套日志接口,项目中使用的日志框架是logback,开发中调用的所有接口都是slf4j的,不直接使用logback,调用是 自己的工程调用slf4j的接口,slf4j的接口去调用logback的实现,可以看到整个过程应用程序并没有直接使用logback,当项目需要更换更加优秀的日志框架时(如log4j2)只需要引入Log4j2的jar和Log4j2对应的配置文件即可,完全不用更改Java代码中的日志相关的代码logger.info(“xxx”),也不用修改日志相关的类的导入的包(import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;)

      使用日志接口便于更换为其他日志框架。

      log4j、logback、log4j2都是一种日志具体实现框架,所以既可以单独使用也可以结合slf4j一起搭配使用)


    三、log4j2基础示例

    1. 创建maven web 项目, 结构如下
      这里写图片描述

    2. 配置pom.xml,引入log4j2必要的依赖(log4j-api、log4j-core)

    <properties>
      	<junit.version>3.8.1</junit.version>
      	<log4j.version>2.5</log4j.version>
    </properties>
    
    <!-- 使用aliyun镜像 -->
    <repositories>
      <repository>
          <id>aliyun</id>
          <name>aliyun</name>
          <url>http://maven.aliyun.com/nexus/content/groups/public</url>
      </repository>
    </repositories>
    
    <dependencies>
    	<dependency>  
            <groupId>org.apache.logging.log4j</groupId>  
            <artifactId>log4j-api</artifactId>  
            <version>${log4j.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.apache.logging.log4j</groupId>  
            <artifactId>log4j-core</artifactId>  
            <version>${log4j.version}</version>  
        </dependency>  
    </dependencies>
    

    3、 使用Main方法简单测试
    这里写图片描述

    测试说明:

    1. 工程中只引入的jar并没有引入任何配置文件,在测试的时候可以看到有ERROR输出:“ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.”

    2. 输出logger时可以看到只有error和fatal级别的被输出来,是因为没有配置文件就使用默认的,默认级别是error,所以只有error和fatal输出来

    3. 引入的包是log4j本身的包(import org.apache.logging.log4j.LogManager)


    四:log2j 配置文件详解

    配置文件的格式和位置

    配置文件的格式:log2j配置文件可以是xml格式的,也可以是json格式的,
    配置文件的位置:log4j2默认会在classpath目录下寻找log4j2.xml、log4j.json、log4j.jsn等名称的文件,如果都没有找到,则会按默认配置输出,也就是输出到控制台,也可以对配置文件自定义位置(需要在web.xml中配置),一般放置在src/main/resources根目录下即可
    这里写图片描述

    纯Java方式:

    public static void main(String[] args) throws IOException {  
        File file = new File("D:/log4j2.xml");  
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));  
        final ConfigurationSource source = new ConfigurationSource(in);  
        Configurator.initialize(null, source);  
          
        Logger logger = LogManager.getLogger("myLogger");  
    } 
    

    Web工程方式:

    <context-param>  
        <param-name>log4jConfiguration</param-name>  
        <param-value>/WEB-INF/conf/log4j2.xml</param-value>  
    </context-param>  
      
    <listener>  
        <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>  
    </listener> 
    

    示例一:简单配置(使用根控制器输出到控制台上)

    log4j2.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>
    

    示例结果:

    这里写图片描述

    结果解释:
    日志管理器获取的是根日志器LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    对应的log4j2.xml中的Loggers节点下的Root,因为该根日志器的level=“info”,所以输出的info级别以上的日志


    示例二:File Logger

    <?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>
            
            <File name="FileAppender" fileName="D:/logs/app.log">  
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />  
            </File>  
            
            <!-- 发现Async 好像PatternLayout的输出格式配置的和输出的格式不一样,不用异步就完全一样  -->
            <Async name="AsyncAppender">
    	    <AppenderRef ref="FileAppender"/>
        	</Async>
        </Appenders>  
        
        <Loggers>  
        	<Logger name="AsyncFileLogger" level="trace" additivity="true">  
    	        <AppenderRef ref="AsyncAppender" />  
    		</Logger>
            <Root level="info">  
                <AppenderRef ref="Console" />  
            </Root>  
        </Loggers>  
    </Configuration>
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class Log4j2Test {
    
    	public static void main(String[] args) {
    		Logger logger = LogManager.getLogger("AsyncFileLogger"); // Logger的名称
    		
    		logger.trace("trace level");
    		logger.debug("debug level");
    		logger.info("info level");
    		logger.warn("warn level");
    		logger.error("error level");
    		logger.fatal("fatal level");
    	}
    }
    
    

    AsyncFileLogger的additivity的值如果为false的话,就不会在控制台上输出或者为该Logger再增加一个输出源Consloe

    <Logger name="AsyncFileLogger" level="trace" additivity="false">  
    	<AppenderRef ref="AsyncAppender" />  
    	<AppenderRef ref="Console" />  
    </Logger>
    

    示例三: RollingRandomAccessFile

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN"> 
    	<properties>
    		<property name="LOG_HOME">D:/logs</property>
    		<property name="FILE_NAME">mylog</property>
    	</properties>
    	
    	 
        <Appenders>  
            <Console name="Console" target="SYSTEM_OUT">  
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />  
            </Console>
            
            <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log">
            	<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            	<Policies>
            		<TimeBasedTriggeringPolicy interval="1"/>
            		<SizeBasedTriggeringPolicy size="10 MB"/>
            	</Policies>
            	<DefaultRolloverStrategy max="20"/>
            </RollingRandomAccessFile>
            
            <Async name="AsyncAppender">
            	<AppenderRef ref="RollingRandomAccessFile"/>
        	</Async>
        </Appenders>  
        
        <Loggers>  
        	<Logger name="RollingRandomAccessFileLogger" level="info" additivity="false">  
    	        <AppenderRef ref="AsyncAppender" />  
    	        <AppenderRef ref="Console" />  
    	    </Logger>
        </Loggers>  
    </Configuration>
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class Log4j2Test {
    
    	public static void main(String[] args) {
    		
    	    Logger logger = LogManager.getLogger("RollingRandomAccessFileLogger");  
    	    for(int i = 0; i < 50000; i++) {  
    	        logger.trace("trace level");  
    	        logger.debug("debug level");  
    	        logger.info("info level");  
    	        logger.warn("warn level");  
    	        logger.error("error level");  
    	        logger.fatal("fatal level");  
    	    }  
    	    
    	    try {  
    	        Thread.sleep(1000 * 61);  
    	    } catch (InterruptedException e) {}  
    	    
    	    logger.trace("trace level");  
    	    logger.debug("debug level");  
    	    logger.info("info level");  
    	    logger.warn("warn level");  
    	    logger.error("error level");  
    	    logger.fatal("fatal level"); 
    	}
    }
    
    

    这里写图片描述

    RollingRandomAccessFile 会根据命名规则当文件满足一定大小时就会另起一个新的文件


    五:log4j2配置文件详解

    log4j2.xml文件的配置大致如下:

    • Configuration
      • properties
      • Appenders
        • Console
          • PatternLayout
        • File
        • RollingRandomAccessFile
        • Async
      • Loggers
        • Logger
        • Root
          • AppenderRef

    • Configuration:为根节点,有status和monitorInterval等多个属性

      • status的值有 “trace”, “debug”, “info”, “warn”, “error” and “fatal”,用于控制log4j2日志框架本身的日志级别,如果将stratus设置为较低的级别就会看到很多关于log4j2本身的日志,如加载log4j2配置文件的路径等信息
      • monitorInterval,含义是每隔多少秒重新读取配置文件,可以不重启应用的情况下修改配置
    • Appenders:输出源,用于定义日志输出的地方
      log4j2支持的输出源有很多,有控制台Console、文件File、RollingRandomAccessFile、MongoDB、Flume 等

      • Console:控制台输出源是将日志打印到控制台上,开发的时候一般都会配置,以便调试

      • File:文件输出源,用于将日志写入到指定的文件,需要配置输入到哪个位置(例如:D:/logs/mylog.log)

      • RollingRandomAccessFile: 该输出源也是写入到文件,不同的是比File更加强大,可以指定当文件达到一定大小(如20MB)时,另起一个文件继续写入日志,另起一个文件就涉及到新文件的名字命名规则,因此需要配置文件命名规则
        这种方式更加实用,因为你不可能一直往一个文件中写,如果一直写,文件过大,打开就会卡死,也不便于查找日志。

        • fileName 指定当前日志文件的位置和文件名称
        • filePattern 指定当发生Rolling时,文件的转移和重命名规则
        • SizeBasedTriggeringPolicy 指定当文件体积大于size指定的值时,触发Rolling
        • DefaultRolloverStrategy 指定最多保存的文件个数
        • TimeBasedTriggeringPolicy 这个配置需要和filePattern结合使用,注意filePattern中配置的文件重命名规则是${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i,最小的时间粒度是mm,即分钟
        • TimeBasedTriggeringPolicy指定的size是1,结合起来就是每1分钟生成一个新文件。如果改成%d{yyyy-MM-dd HH},最小粒度为小时,则每一个小时生成一个文件
      • NoSql:MongoDb, 输出到MongDb数据库中

      • Flume:输出到Apache Flume(Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力。)

      • Async:异步,需要通过AppenderRef来指定要对哪种输出源进行异步(一般用于配置RollingRandomAccessFile)

      PatternLayout:控制台或文件输出源(Console、File、RollingRandomAccessFile)都必须包含一个PatternLayout节点,用于指定输出文件的格式(如 日志输出的时间 文件 方法 行数 等格式),例如 pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"

        %d{HH:mm:ss.SSS} 表示输出到毫秒的时间
        %t 输出当前线程名称
        %-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
        %logger 输出logger名称,因为Root Logger没有名称,所以没有输出
        %msg 日志文本
        %n 换行
      
        其他常用的占位符有:
        %F 输出所在的类文件名,如Log4j2Test.java
        %L 输出行号
        %M 输出所在方法名
        %l 输出语句所在的行数, 包括类名、方法名、文件名、行数
      
    • Loggers:日志器
      日志器分根日志器Root和自定义日志器,当根据日志名字获取不到指定的日志器时就使用Root作为默认的日志器,自定义时需要指定每个Logger的名称name(对于命名可以以包名作为日志的名字,不同的包配置不同的级别等),日志级别level,相加性additivity(是否继承下面配置的日志器), 对于一般的日志器(如Console、File、RollingRandomAccessFile)一般需要配置一个或多个输出源AppenderRef;

      每个logger可以指定一个level(TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF),不指定时level默认为ERROR

      additivity指定是否同时输出log到父类的appender,缺省为true。

    <Logger name="rollingRandomAccessFileLogger" level="trace" additivity="true">  
    	<AppenderRef ref="RollingRandomAccessFile" />  
    </Logger>
    
    • properties: 属性
      使用来定义常量,以便在其他配置的时候引用,该配置是可选的,例如定义日志的存放位置
      D:/logs

    【实战部分】

    1. 引入slf4j和log4j需要的依赖
    <properties>
      	<junit.version>3.8.1</junit.version>
      	<log4j.version>2.5</log4j.version>
      </properties>
      
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>${junit.version}</version>
          <scope>test</scope>
        </dependency>
        
        <!-- slf4j + log4j2 begin -->
        <dependency>
    	    <groupId>org.slf4j</groupId>
    	    <artifactId>slf4j-api</artifactId>
    	    <version>1.7.10</version>
    	</dependency>
    	
    	<dependency> <!-- 桥接:告诉Slf4j使用Log4j2 -->
    	    <groupId>org.apache.logging.log4j</groupId>
    	    <artifactId>log4j-slf4j-impl</artifactId>
    	    <version>2.2</version>
    	</dependency>
    	<dependency> <!-- 桥接:告诉commons logging使用Log4j2 -->
    	    <groupId>org.apache.logging.log4j</groupId>
    	    <artifactId>log4j-jcl</artifactId>
    	    <version>2.2</version>
    	</dependency>
        
        <dependency>  
            <groupId>org.apache.logging.log4j</groupId>  
            <artifactId>log4j-api</artifactId>  
            <version>${log4j.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.apache.logging.log4j</groupId>  
            <artifactId>log4j-core</artifactId>  
            <version>${log4j.version}</version>  
        </dependency>  
        <!-- log4j end-->
      </dependencies>
      
      <!-- 使用aliyun镜像 -->
      <repositories>
        <repository>
            <id>aliyun</id>
            <name>aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
        </repository>
      </repositories>
    

    2、配置log2.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN"> 
    	<properties>
    		<property name="LOG_HOME">D:/logs</property>
    		<property name="FILE_NAME">mylog</property>
    		<property name="log.sql.level">info</property>
    	</properties>
    	
    	 
        <Appenders>  
            <Console name="Console" target="SYSTEM_OUT">  
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n" />  
            </Console>
            
            <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log">
            	<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/>
            	<Policies>
            		<TimeBasedTriggeringPolicy interval="1"/>
            		<SizeBasedTriggeringPolicy size="10 MB"/>
            	</Policies>
            	<DefaultRolloverStrategy max="20"/>
            </RollingRandomAccessFile>
        </Appenders>  
        
        <Loggers>  
        	<Root level="info">  
        		<AppenderRef ref="Console" />  
    	        <AppenderRef ref="RollingRandomAccessFile" />  
    	    </Root>
    	    
    	    <Logger name="com.mengdee.dao" level="${log.sql.level}" additivity="false">
                 <AppenderRef ref="Console" />
            </Logger>
        </Loggers>  
    </Configuration>
    

    3、 Java

    package com.mengdee.manage;
    
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class Log4j2Test {
    
    	// Logger和LoggerFactory导入的是org.slf4j包
    	private final static Logger logger = LoggerFactory.getLogger(Log4j2Test.class);
    	public static void main(String[] args) {
    		long beginTime = System.currentTimeMillis();
    		
    		for(int i = 0; i < 100000; i++) {  
    			logger.trace("trace level");  
    		    logger.debug("debug level");  
    		    logger.info("info level");  
    		    logger.warn("warn level");  
    		    logger.error("error level");
    		}
    		
    		try {  
    	        Thread.sleep(1000 * 61);  
    	    } catch (InterruptedException e) {}  
    	      
    	    
    	    logger.info("请求处理结束,耗时:{}毫秒", (System.currentTimeMillis() - beginTime));    //第一种用法
    	    logger.info("请求处理结束,耗时:" + (System.currentTimeMillis() - beginTime)  + "毫秒");    //第二种用法
    
    	}
    }
    

    4、运行结果
    这里写图片描述

    这里写图片描述

    这里写图片描述

    持续完善中。。。

    分享一个朋友的人工智能教程(请以“右键”->"在新标签页中打开连接”的方式访问)。比较通俗易懂,风趣幽默,感兴趣的朋友可以去看看。

    我的微信公众号

    这里写图片描述

    展开全文
  • log4j2 日志配置实战

    千次阅读 2017-04-28 12:02:23
    替换log4j,log4j2log4j的2.x版本但是在log4j上做了比较大的改变,log4j2的性能比log4j好。该文不会具体讲解常用的基础配置,主要介绍日志发邮件、日志写mysql数据库、日志写Mongo功能。 2.实战 预设环境 ...
    
    

    1.目的

    替换log4j,log4j2是log4j的2.x版本但是在log4j上做了比较大的改变,log4j2的性能比log4j好。该文不会具体讲解常用的基础配置,主要介绍日志发邮件日志写mysql数据库日志写Mongo功能。

    2.实战

    预设环境

    • 默认项目为maven管理

    • 使用jdk1.8及以上

    • idea开发环境

    • mongo

    2.1 配置

    添加依赖

    log4j2 日志配置实战

    log4j2 日志配置实战

    对以上依赖包的说明:

    1. slf4j和log4j*包是日志门面接口和实际日志发送者

    2. log4j-slf4j-impl是用于log4j2桥接slf4j,便于使用slf4j声明,log4j2输出日志。

    3. log4j-nosql是为了使得log4j2支持非关系型数据库(如Mongo,CouchDb)。

    4. log4j-web是为了在代码中使用Spring管理log4j2,通过Spring进行初始化,并应用Druid的数据源。

    5. mysql-connector-java:java操作mysql数据库的驱动。

    6. mail:发送邮件时需要。

    7. spring-data-mongodb: 是Spring对Mongo的集成,方便以Spring的方式操作Mongo。

    8. mongo-java-driver:是mongo的java驱动,便于java对mongo的调用

    9. fastjson:是将java类格式化为json格式,用于发送日志时将日志转为json。

    这些只是当前讲解日志相关功能使用的包,而Spring的核心包以及其他如Mybatis等不在此文关心范围内。

    2.2 log4j2.xml配置

    log4j2.xml是作为log4j2使用时指定的文件名称之一,其他的还有(log4j.configurationFile,log4j2-test.properties,log4j2-test.yaml,log4j2-test.yml,log4j2-test.json,log4j2-test.jsn,log4j2-test.xml,log4j2.properties,log4j2.yaml,log4j2.yml,log4j2.json,log4j2.jsn,log4j2.xml,默认配置),log42会以名称出现的顺序查找上面的文件依次是否存在,而log4j2.xml是优先级最低的,log4j.configurationFile是指用户自定义指定的文件名,优先级最高。

    贴出所有的log4j2.xml代码,但不会全部介绍

    log4j2 日志配置实战

    log4j2 日志配置实战

    log4j2 日志配置实战

    具体配置的各个属性名称不做具体解释了,自解释了。

    2.3 log4j2配置写mysql数据库功能

    节选部分配置

    log4j2 日志配置实战

    • tableName是数据库中的表名;

    • ConnectionFactory需要自定义数据库连接工厂类,并提供获取DataSource或者Connection的静态方法。

    • Column的name属性是指定数据库表中的字段名,pattern是匹配日志的内容格式,会将对应的内容写入到指定的字段下。

    2.4 编写LoggerConnectionFactory类实现逻辑

    LoggerConnectionFactory

    类的代码如下:

    log4j2 日志配置实战

    这样的方式是可以获取到Mysql数据库的Connection并且也可以将日志写入到数据库中,但是很明显这样有两个很大的缺点:

    • 自己控制对数据库的链接,没有应用业界比较好的数据源库也没有使用线程池。

    • 没有应用到Spring的IOC和DI。

    2.5 Log4j2设置解惑

    有人会问:

    对于连接属性的配置直接调用Spring管理的数据源不行吗?答案是现在这样的配置不行,因为log4j2等日志是在Spring初始化前加载并初始化的,因此log4j2在当前配置下是拿不到Spring的bean信息的。

    那这个问题就无解了吗?当然不是,要不然干嘛要引入log4j-web包呢。引入该包就是为了在web应用中使用Log4j2的,具体可以参考【logging.apache.org/log4j/2.x/manual/webapp.html】

    要说明的是:Log4j2仅支持Servlet3.0及以上版本,Tomcat7.0及以上

    Log4j2会在WEB容器启动和销毁时自动启动和关闭。是通过Log4jServletContainerInitializer(继承自ServletContainerInitializer)达到自动启动的目的。在Tomcat7.0.43之前,基于性能原因,web容器会忽略名为log4j*.jar包,阻止其获取随web容器启动的特性。但在之后的版本中已经修复。

    如果禁止Log4j2的自动初始化,那么需要在web.xml中加入配置:

    log4j2 日志配置实战

    但是在Servlet2.5需要在其他应用代码执行前初始化Log4j。

    如果使用的是Servlet2.5,那么需要在web.xml文件中加入配置:

    log4j2 日志配置实战

    详情请看【logging.apache.org/log4j/2.x/manual/webapp.html】,接下来就说明下怎样通过在Log4j2中使用Spring管理的bean。

    2.6 重新配置Log4j2支持JDBC

    这次配置是基于Spring的,使用了Spring容器的功能,对配置文件中Log4j2的配置进行增加。

    代码如下:

    log4j2 日志配置实战

    log4j2 日志配置实战

    log4j2 日志配置实战

    以上代码中的注释已经比较详细了,概括来说就是在当前LoggerBean被IOC实例化之后获取到已经从配置文件中读取的Log4j2的配置,并在init()方法中用代码将JDBC部分的逻辑补充上,更新下Log4j2的上下文即可。一个类内就把Log4j2的JDBC功能实现了,不需要在任何地方做log4j2对JBDC支持的配置。

    2.7 Log4j2配置发邮件功能

    log4j2.xml中SMTP内的配置就是控制日志发送邮件的功能了,默认使用的Lauout是HtmlLayout,对应类org.apache.logging.log4j.core.layout.HtmlLayout,比较蛋疼的是该类是final型的,不能被继承也就是说不能通过继承该类实现自定义Html布局。唉没办法,使用自定义的Layout吧!自定义的layout需要继承org.apache.logging.log4j.core.layout.AbstractStringLayout,并且要在类上加上注解:

    log4j2 日志配置实战

    其中name处value是配置文件log4j2.xml中使用的标签,如HtmlLayout ,写者没有对其原理进行分析,直接强行复制其代码新建了个类,并修改了关键的位置@Plugin的name作为自己的布局模板。

    自定义的布局模板关键代码如下:

    log4j2 日志配置实战

    通过将上面解释的逻辑调整为自己想要的就实现了自定义布局。

    2.8 Log4j2支持Mongo写日志

    此处不涉及Mongo的安装和使用

    对于NoSql的配置就比较简单了,以Mongo为例:

    log4j2 日志配置实战

    相信Mongo配置的属性不用解释也能看明白了,就这点配置,只要能连上Mongo就可以将日志写入到Mongo中,当然前提是要在Logger或者Root标签中引用noSqlDbAppender。

    Mongo存储结构如下:

    log4j2 日志配置实战

    3 注意事项

    log4j2 中配置Async标签异步存储日志会使得写Mysql库和Mongo库时,调用Logger的ClassName和MethodName都为空,写者当前在项目中暂时没有使用异步写日志操作。

    展开全文
  • Log4j2 简明教程

    千次阅读 2019-03-19 18:07:23
    log4j2官方文档内容非常多,要一次性了解全部是不可能的。正确的步骤应当是先了解最常见的配置,当发现原有知识无法解决问题,再重新查看文档看有没有合适的配置。 下面将从文件结构入手,再到简单的实例,从实例...

    转载:http://blog.bensonlin.me/post/log4j2-tutorial

    一、概述

    log4j2官方文档内容非常多,要一次性了解全部是不可能的。正确的步骤应当是先了解最常见的配置,当发现原有知识无法解决问题,再重新查看文档看有没有合适的配置。
    下面将从文件结构入手,再到简单的实例,从实例入手分析常见的配置的用途,其中涉及其中包括Appenders, Filters, Layout, Lookups的知识,最后根据学习。

    可以搜索到的关于log4j2的教程非常少,这篇文章更多的是让大家对log4j2有个大体的了解,免得大家看到官方文档那么多就晕了!

    欢迎关注我的github: https://github.com/benson-lin

    如果觉得排版不好,可以访问:http://blog.bensonlin.me/post/log4j2-tutorial

    log4j2.xml文件结构

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    <?xml version="1.0" encoding="UTF-8"?>;

    <Configuration>

      <Properties>

        <Property name="name1">value</property>

        <Property name="name2" value="value2"/>

      </Properties>

      <Filter type="type" ... />

      <Appenders>

        <Appender type="type" name="name">

          <Filter type="type" ... />

        </Appender>

        ...

      </Appenders>

      <Loggers>

        <Logger name="name1">

          <Filter type="type" ... />

        </Logger>

        ...

        <Root level="level">

          <AppenderRef ref="name"/>

        </Root>

      </Loggers>

    </Configuration>

      

    下面是一个比较完整的例子:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    <?xml version="1.0" encoding="UTF-8"?>

    <!-- 设置log4j2的自身log级别为warn -->

    <!-- OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->

    <configuration status="WARN" monitorInterval="30">

        <appenders>

            <console name="Console" target="SYSTEM_OUT">

                <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>

            </console>

     

            <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"

                         filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">

                <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->        

                <Filters>

                    <ThresholdFilter level="INFO"/>

                    <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>

                </Filters>

                <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>

                <Policies>

                    <TimeBasedTriggeringPolicy/>

                    <SizeBasedTriggeringPolicy size="100 MB"/>

                </Policies>

            </RollingFile>

     

            <RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log"

                         filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">

                <Filters>

                    <ThresholdFilter level="WARN"/>

                    <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>

                </Filters>

                <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>

                <Policies>

                    <TimeBasedTriggeringPolicy/>

                    <SizeBasedTriggeringPolicy size="100 MB"/>

                </Policies>

            </RollingFile>

     

            <RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log"

                         filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">

                <ThresholdFilter level="ERROR"/>

                <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>

                <Policies>

                    <TimeBasedTriggeringPolicy/>

                    <SizeBasedTriggeringPolicy size="100 MB"/>

                </Policies>

            </RollingFile>

     

        </appenders>

     

        <loggers>

            <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->

            <logger name="org.springframework" level="INFO"></logger>

            <logger name="org.mybatis" level="INFO"></logger>

            <root level="all">

                <appender-ref ref="Console"/>

                <appender-ref ref="RollingFileInfo"/>

                <appender-ref ref="RollingFileWarn"/>

                <appender-ref ref="RollingFileError"/>

            </root>

        </loggers>

     

    </configuration>

      

    log4j2有默认的配置,如果要替换配置,只需要在classpath根目录下放置log4j2.xml。
    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

    如果本地要测试,可以把log4j2-test.xml放到classpath,而正式环境使用log4j2.xml,则在打包部署的时候不要打包log4j2-test.xml即可。

    下面是其缺省配置:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    <?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="error">

          <AppenderRef ref="Console"/>

        </Root>

      </Loggers>

    </Configuration>

      

    下面将对上面的配置文件进行一一讲解。

    二、示例Java代码

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    package com.foo;

    // Import log4j classes.

    import org.apache.logging.log4j.Logger;

    import org.apache.logging.log4j.LogManager;

     

    public class MyApp {

     

        // Define a static logger variable so that it references the

        // Logger instance named "MyApp".

        private static final Logger logger = LogManager.getLogger(MyApp.class);

     

        public static void main(final String... args) {

     

            // Set up a simple configuration that logs on the console.

     

            logger.trace("Entering application.");

            Bar bar = new Bar();

            if (!bar.doIt()) {

                logger.error("Didn't do it.");

            }

            logger.trace("Exiting application.");

        }

    }

     

    package com.foo;

     

     

    import org.apache.logging.log4j.LogManager;

    import org.apache.logging.log4j.Logger;

     

    public class Bar {

     

      static final Logger logger = LogManager.getLogger(Bar.class.getName());

     

      public boolean doIt() {

        logger.entry();

        logger.error("Did it again!");

        return logger.exit(false);

      }

    }

      

    如果使用如下配置,也就是缺省配置:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    <?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="error">

          <AppenderRef ref="Console"/>

        </Root>

      </Loggers>

    </Configuration>

      

    输出如下:只输出error以上的日志信息

    1

    2

    17:13:01.540 [main] ERROR com.foo.Bar - Did it again!

    17:13:01.540 [main] ERROR MyApp - Didn't do it.

    如果我们希望除了com.foo.Bar类下输出TRACE以上到控制台外,其他停止TRACE的输出到控制台,只输出ERROR以上的日志。可以如下配置:

    1

    2

    3

    4

    5

    6

    <Loggers>

      <Logger name="com.foo.Bar" level="TRACE"/>

      <Root level="ERROR">

        <AppenderRef ref="STDOUT">

      </Root>

    </Loggers>

    结果如下:

    1

    2

    3

    4

    14:14:17.176 [main] TRACE com.foo.Bar - Enter

    14:14:17.182 [main] ERROR com.foo.Bar - Did it again!

    14:14:17.182 [main] TRACE com.foo.Bar - Exit with(false)

    14:14:17.182 [main] ERROR com.foo.MyApp - Didn't do it.

    因为com.foo.Bar没有自己的Appender,所以会使用ROOT的Appender,如果自己也配置了在控制台打印,就要注意可加性:如下配置,会ERROR以上的会打印两次

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    <?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>

        <Logger name="com.foo.Bar" level="trace">

          <AppenderRef ref="Console"/>

        </Logger>

        <Root level="error">

          <AppenderRef ref="Console"/>

        </Root>

      </Loggers>

    </Configuration>

    结果如下

    1

    2

    3

    4

    5

    6

    7

    14:11:27.103 [main] TRACE com.foo.Bar - Enter

    14:11:27.103 [main] TRACE com.foo.Bar - Enter

    14:11:27.106 [main] ERROR com.foo.Bar - Did it again!

    14:11:27.106 [main] ERROR com.foo.Bar - Did it again!

    14:11:27.107 [main] TRACE com.foo.Bar - Exit with(false)

    14:11:27.107 [main] TRACE com.foo.Bar - Exit with(false)

    14:11:27.107 [main] ERROR com.foo.MyApp - Didn't do it.

    如果我们确实有这种需求(不想遵循父类的Appender),可以加上additivity="false"参数。如下配置,com.foo.Bar的trace以上日志将保存到文件中,并且不会打印到控制台。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    <Configuration status="WARN">

      <Appenders>

        <Console name="Console" target="SYSTEM_OUT">

          <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

        </Console>

        <RollingFile name="RollingFile" fileName="${sys:user.home}/logs/trace.log"

                         filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">

               ...

        </RollingFile>

      </Appenders>

      <Loggers>

        <Logger name="com.foo.Bar" level="trace" additivity="false">

          <AppenderRef ref="RollingFile"/>

        </Logger>

        <Root level="error">

          <AppenderRef ref="Console"/>

        </Root>

      </Loggers>

    </Configuration>

    log4j2支持自动重新配置,如果配置了monitorInterval,那么log4j2每隔一段时间就会检查一遍这个文件是否修改。最小是5s

    1

    2

    3

    4

    <?xml version="1.0" encoding="UTF-8"?>

    <Configuration monitorInterval="30">

    ...

    </Configuration>

     

    三、Appenders

    ConsoleAppender

    将使用 System.out 或 System.err输出到控制台。

    可以有如下参数

    • name:Appender的名字
    • target:SYSTEM_OUT 或 SYSTEM_ERR,默认是SYSTEM_OUT
    • layout:如何格式化,如果没有默认是%m%n

    典型的ConsoleAppender如下

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    <?xml version="1.0" encoding="UTF-8"?>

    <Configuration status="warn" name="MyApp" packages="">

      <Appenders>

        <Console name="STDOUT" target="SYSTEM_OUT">

          <PatternLayout pattern="%m%n"/>

        </Console>

      </Appenders>

      <Loggers>

        <Root level="error">

          <AppenderRef ref="STDOUT"/>

        </Root>

      </Loggers>

    </Configuration>

      

    RollingFileAppender

    顾名思义,日志文件回滚,也就是删除最旧的日志文件,默认是3个文件。可以通过DefaultRolloverStrategy设置max参数为多个

    例子如下:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    <Appenders>

        <RollingFile name="RollingFile" fileName="logs/app.log"

                     filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">

          <PatternLayout>

            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>

          </PatternLayout>

          <Policies>

            <TimeBasedTriggeringPolicy />

            <SizeBasedTriggeringPolicy size="250 MB"/>

          </Policies>

          <DefaultRolloverStrategy max="20"/>

        </RollingFile>

      </Appenders>

      

    现在说说TimeBasedTriggeringPolicy和SizeBasedTriggeringPolicy的作用。
    第一个是基于时间的rollover,第二个是基于大小的rollover。第二个很容易理解,如果大小大于某个阈值,上面是50MB的时候就会滚动。

    TimeBasedTriggeringPolicy中有其中一个参数是interval,表示多久滚动一次。默认是1 hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am

    四、Layouts

    这里只描述最常见的PatternLayout!更多看官方文档Layouts

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    <RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log"

                         filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">

                <ThresholdFilter level="ERROR"/>

        <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>

        <Policies>

            <TimeBasedTriggeringPolicy/>

            <SizeBasedTriggeringPolicy size="50 MB"/>

        </Policies>

         <DefaultRolloverStrategy max="20"/>

    </RollingFile>

      

    上面的%是什么含义,还有哪些呢?其实最主要的参数还是%d, %p, %l, %m, %n, %X。下面的图是摘取网上的。

    %X用来获取MDC记录,这些记录从哪来的?我们可以使用org.apache.logging.log4j.ThreadContext将需要记录的值put进去。(我发现slf的MDC.java的put方法对log4j2不可用,因为底层依赖的是log4j1)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    package com.bensonlin.service.web.interceptor;

     

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

     

    import org.apache.logging.log4j.ThreadContext;

    import org.springframework.web.servlet.HandlerInterceptor;

    import org.springframework.web.servlet.ModelAndView;

     

    public class MDCInterceptor implements HandlerInterceptor {

     

        public final static String USER_KEY            = "user_id";

        public final static String REQUEST_REQUEST_URI = "request_uri";

     

        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object arg2)

                                                                                                                             throws Exception {

            ThreadContext.put(REQUEST_REQUEST_URI, httpServletRequest.getRequestURI());

            return true;

        }

     

        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object arg2,

                               ModelAndView modelAndView) throws Exception {

        }

     

        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,

                                    Object arg2, Exception exception) throws Exception {

            ThreadContext.remove(USER_KEY);

            ThreadContext.remove(REQUEST_REQUEST_URI);

        }

     

        public static void setUserKeyForMDC(String userId) {

            ThreadContext.put(USER_KEY, userId);

        }

    }

      

    xml中使用%X{aaa}取出来:

    1

    2

    3

    <console name="Console" target="SYSTEM_OUT">

        <PatternLayout pattern="%X{user_id} %X{request_uri} [%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>

    </console>

      

    对应ThreadContext的文档在这里

    五、Filters

    Filters决定日志事件能否被输出。过滤条件有三个值:ACCEPT(接受), DENY(拒绝) or NEUTRAL(中立).

    ACCEP和DENY比较好理解就是接受和拒绝的意思,在使用单个过滤器的时候,一般就是使用这两个值。但是在组合过滤器中,如果用接受ACCEPT的话,日志信息就会直接写入日志文件,后续的过滤器不再进行过滤。所以,在组合过滤器中,接受使用NEUTRAL(中立),被第一个过滤器接受的日志信息,会继续用后面的过滤器进行过滤,只有符合所有过滤器条件的日志信息,才会被最终写入日志文件。

    ThresholdFilter

    有几个参数:

    • level:将被过滤的级别。
    • onMatch:默认值是NEUTRAL
    • onMismatch:默认是DENY

    如果LogEvent 中的 Log Level 大于 ThresholdFilter 中配置的 Log Level,那么返回 onMatch 的值, 否则返回 onMismatch 的值,例如 : 如果ThresholdFilter 配置的 Log Level 是 ERROR , LogEvent 的Log Level 是 DEBUG。 那么 onMismatch 的值将被返回, 因为 ERROR 小于DEBUG。如果是Accept,将自己被接受,而不经过下一个过滤器

    下面的例子可以这样理解:如果是INFO级别及其以上,将经过通过第一个过滤,进入第二个,否则是onMismatch:拒绝进入。对于第二个,如果是大于等于WARN(WARN/ERROR/ERROR),那么将返回onMatch,也就是拒绝,如果是其他情况(也就是INFO),将是中立情况,因为后面没有其他过滤器,则被接受。最后的结果就只剩下INFO级别的日志。也就符合了RollingFileInfo只记录Info级别的规则。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"

                 filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">

        <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->        

        <Filters>

            <ThresholdFilter level="INFO"/>

            <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>

        </Filters>

        <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>

        <Policies>

            <TimeBasedTriggeringPolicy interval="24" modulate="true"/>

            <SizeBasedTriggeringPolicy size="50 MB"/>

        </Policies>

        <DefaultRolloverStrategy max="20"/>

    </RollingFile>

      

    六、Lookups

    提供另外一种方式添加某些特殊的值到日志中。

    Date Lookup

    与其他lookup不同,它不是通过key去查找值,而是通过SimpleDateFormat验证格式是否有效,然后记录当前时间

    1

    2

    3

    4

    5

    6

    <RollingFile name="Rolling-${map:type}" fileName="${filename}" filePattern="target/rolling1/test1-$${date:MM-dd-yyyy}.%i.log.gz">

      <PatternLayout>

        <pattern>%d %p %c{1.} [%t] %m%n</pattern>

      </PatternLayout>

      <SizeBasedTriggeringPolicy size="500" />

    </RollingFile>

    Context Map Lookup: 如记录loginId

    1

    2

    3

    4

    5

    <File name="Application" fileName="application.log">

      <PatternLayout>

        <pattern>%d %p %c{1.} [%t] $${ctx:loginId} %m%n</pattern>

      </PatternLayout>

    </File>

    这个的结果和前面的MDC是一样的,即 %X{loginId}

    Environment Lookup:记录系统环境变量

    比如可以获取如/etc/profile中的变量值

    1

    2

    3

    4

    5

    <File name="Application" fileName="application.log">

      <PatternLayout>

        <pattern>%d %p %c{1.} [%t] $${env:USER} %m%n</pattern>

      </PatternLayout>

    </File>

      

    System Properties Lookup

    可以获取Java中的系统属性值。

    1

    2

    3

    <Appenders>

      <File name="ApplicationLog" fileName="${sys:logPath}/app.log"/>

    </Appenders>

    和系统属性值有什么区别呢?其实就是System.getProperties();和System.getenv();的区别。下面是一个小例子。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    package com.bensonlin.service.common;

     

    import java.util.Iterator;

    import java.util.Map;

    import java.util.Map.Entry;

    import java.util.Properties;

     

    public class Main {

     

        public static void main(String[] args) {

     

            Properties properties = System.getProperties();

            Iterator i = properties.entrySet().iterator();

            while (i.hasNext()) {

                Map.Entry entry = (Map.Entry) i.next();

                Object key = entry.getKey();

                Object value = entry.getValue();

                System.out.println(key + "=" + value);

            }

     

            System.out.println("===================");

            Map map = System.getenv();

            Iterator it = map.entrySet().iterator();

            while (it.hasNext()) {

                Entry entry = (Entry) it.next();

                System.out.print(entry.getKey() + "=");

                System.out.println(entry.getValue());

            }

        }

    }

    输出(摘取部分):

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    java.runtime.name=Java(TM) SE Runtime Environment

    sun.boot.library.path=C:\Program Files\Java\jdk1.8.0_25\jre\bin

    java.vm.version=25.25-b02

    java.vm.vendor=Oracle Corporation

    java.vendor.url=http://java.oracle.com/

    path.separator=;

    ...

    ===================

    JAVA_HOME=C:\Program Files\Java\jdk1.8.0_25

    TEMP=D:\Temp

    ProgramFiles=C:\Program Files

    ...

    可以看到其实Environment是获取环境变量,而System Properties获取的更多是与Java相关的值

     

    展开全文
  • log4j2 &slf4j 日志不打印的解决

    万次阅读 2018-07-25 17:34:24
    一血献给狗日的log4j2 几乎翻遍百度各个角落的有关log4j的文档,参看别人的经验写配置,根本没用,到最后error都没有就是不打印日志 硬着头皮读官网对于log4j2的说明,才明白log4j2log4j不是简单的升级关系……...
  • slf4j仅仅是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案,就比如JDBC一样,只是一种规则而已,所以单独的slf4j是不能工作的,必须搭配其他具体的日志实现方案,比如log4j或者log4j2,要在...
  • Log4j2的一个重要特性,日志异步输出。日志异步输出的好处在于,使用单独的进程来执行日志打印的功能,可以提高日志执行效率,减少日志功能对正常业务的影响。异步日志在程序的classpath需要加载disrupt...
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • 不打印日志,并且连简单的nullporint等异常都不输出!!! 也不报错。。。 狠蒙蔽 问题出在哪呢?...博主此次通过debug ,发现日志走的jar包,并不是导入的jar包,而是进入子模块中引用的腾讯...
  • Log4j2 日志级别

    万次阅读 2018-03-28 15:26:37
    Log4j2日志级别级别 在log4j2中, 共有8个级别,按照从低到高为:ALL &lt; TRACE &lt; DEBUG &lt; INFO &lt; WARN &lt; ERROR &lt; FATAL &lt; OFF。 All:最低等级的,用于打开所有...
  • Log4j2介绍及使用

    2019-04-07 13:14:36
    Log4j 2 官网 Log4j 2简介 架构 日志级别 Filter Appender 将日志请求打印到多个目标 Layout 自定义输出格式 转到Log4j 2 API 控制台Appender的简单配置 文件Appender的简单配置 SocketAppender...
  • log4j与log4j2性能对比及log4j升级至log4j2方案

    千次阅读 多人点赞 2019-06-18 10:41:51
    1.前言 之前某个服务在压测环境中出现了问题,分析之后得知是log4jLogger对象争用厉害,很多线程阻塞在此。...关于log4j与log4j2的性能对比文章有很多,本文不过多描述,给出几张结论图及原文链接,作为参考...
  • slf4j与log4j、log4j2

    万次阅读 多人点赞 2018-05-23 17:53:56
    最近公司项目系统需要将日志从log4j+slf4j升级为log4j2,然后彻彻底底的把它们研究了一遍,在网上查找相关资源,发现并没有一篇文章能够很完整的把它们之间的关联和区别写出来,所以我在这里做一个总结。log4j 如果...
  • Log4j2与Slf4j的最佳实践

    万次阅读 2019-06-15 09:49:23
    日志对于项目的重要性不言而喻,现在市面上的日志框架多种多样:Log4j、Log4j2、Slf4j、JDKLog、Logback等等,如果没有真正深入了解过,可能会被搞得眼花缭乱。本文将介绍目前Java项目中最常见的Log4j2 + Slf4j的...
  • Spring Boot系列教程六:日志输出配置log4j2

    万次阅读 热门讨论 2019-12-23 17:41:46
    spring boot支持的日志框架有,logback,Log4j2Log4j和Java Util Logging,默认使用的是logback日志框架,笔者一直在使用log4j2,并且看过某博主写的一篇这几个日志框架的性能比对,决定仍使用log4j2,本文章主要...
  • Log4j日志配置详解(Log4j2)

    千次阅读 2019-03-19 17:11:06
    首先来说一下日志升级,log4j配置的变化,配置文件从log4j.xml变成了log4j2.xml,配置文件的内容也有很大不同,log file现在可以同时支持时间和文件大小分割。而且log4j2支持log的动态变化加载,直接指定监控周期就...
  • Log4j,Log4j2,logback,slf4j日志学习

    万次阅读 2016-10-22 09:23:37
    Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、数据库等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志...
  • Log4j,Log4j2,logback,slf4j日志框架比较

    万次阅读 多人点赞 2019-09-07 16:37:54
    Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、数据库等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志...
  • 浅谈Log4j和Log4j2的区别

    万次阅读 多人点赞 2016-12-11 00:37:37
    相信很多程序猿朋友对log4j都很熟悉,log4j可以说是陪伴了绝大多数的朋友开启的编程。我不知道log4j之前是用什么,至少在我的生涯中,是log4j带我开启的日志时代。log4j是Apache的一个开源项目,我们不去考究它的...
  • log4j升级为log4j2(不需要改动代码)

    千次阅读 2017-11-15 17:22:52
    公司的项目决定升级log4j,因为log4j2有一个自动删除日志的功能,这样可以减轻运维的一些工作,而且在多线程环境下,log4j2的异步日志系统比log4j和logback提高了十倍的性能(吞吐量和延迟率),官方原文如下: ...
1 2 3 4 5 ... 20
收藏数 635,466
精华内容 254,186
关键字:

log4j2