log4j2的学习

背景:

业务上面的代码,肯定都是需要打印日志的,不论是之后定位问题还是其他什么的。
最基础的诉求就是能够将不同级别的日志打印到不同的文件中,能够按天来区分。这些log4j2都有,并且支持异步处理。虽然我没有用过logback和log4j,但是通过博客中得出的结论就是log4j2有他们都有的优点,也有他们没有的优点。
本文并没有仔细钻研log4j2的底层,暂时只是出于用日志的地步。其实有日志也可以玩出很多玩意,比如小米的lcs,就可以通过log4j2来讲一些数据异步上传到服务器中,来完成一些数据打点。

日志配置

先来一个简单的日志配置
依赖:

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>

        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.4.2</version>
        </dependency>
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="error">
    <!--先定义所有的appender -->
    <appenders>
        <!--这个输出控制台的配置 -->
<!--        onMatch="ACCEPT" 表示匹配该级别及以上-->
<!--        onMatch="DENY" 表示不匹配该级别及以上-->
<!--        onMatch="NEUTRAL" 表示该级别及以上的,由下一个filter处理,如果当前是最后一个,则表示匹配该级别及以上-->
<!--        onMismatch="ACCEPT" 表示匹配该级别以下-->
<!--        onMismatch="NEUTRAL" 表示该级别及以下的,由下一个filter处理,如果当前是最后一个,则不匹配该级别以下的-->
<!--        onMismatch="DENY" 表示不匹配该级别以下的-->

        <Console name="Console" target="SYSTEM_OUT">
            <!--             控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <!--             这个都知道是输出日志的格式 -->
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </Console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用 -->
        <!--append为TRUE表示消息增加到指定文件中,false表示消息覆盖指定的文件内容,默认值是true -->
        <File name="log" fileName="D:/logs/log4j2.log" append="true">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </File>

        <!--添加过滤器ThresholdFilter,可以有选择的输出某个级别以上的类别  onMatch="ACCEPT" onMismatch="DENY"意思是匹配就接受,否则直接拒绝  -->
        <File name="ERROR" fileName="D:/logs/error.log">
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </File>

        <!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
        <RollingFile name="RollingFile" fileName="D:/logs/web.log"
                     filePattern="logs/$${date:yyyy-MM}/web-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
            <SizeBasedTriggeringPolicy size="2MB"/>
        </RollingFile>
    </appenders>


    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
    <loggers>
        <AsyncRoot level="info" includeLocation="true">
            <appender-ref ref="RollingFile"/>
            <appender-ref ref="Console"/>
            <appender-ref ref="log"/>
            <appender-ref ref="ERROR" />
        </AsyncRoot>
    </loggers>
</configuration>

测试程序

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
    private static  Logger logger= LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    @org.junit.Test
    public void Test(){
        System.out.println(1);
        logger.info("info");
        logger.error("error");
    }
}

=========================================================
上面中重要的配置标签有3个,一个是全局的Configuration, 然后是appender, 然后是logger.
下面这段话是copy过来的。


image.png

Logger是最常使用的类,用于打印日记的接口,通过LogManager类指定名字获得。LogManager定位LoggerContext并从它那获得Logger。如果Logger被创建,Logger会被关联一个LoggerConfig,该LoggerConfig可能与Logger同名,或同父package名或为root LoggerConfig(涉及Level Inheritance)(这边可以结合测试程序来看)。

使用Logger可以打印不同级别的日志,这些日志会被包装为LogEvent。LogEvent会被派送到LoggerConfig上。LoggerConfig在xml配置文件中由Logger元素配置的(我们日志中的应该就是rootlog),LoggerConfig含有日志级别(Log Level)信息,对应0到多个Appender。LoggerConfig根据自己的日志级别配置与LogEvent的级别,决定是否允许进一步的处理。如果NO则丢弃,如果Yes则传给Appender。

LoggerConfig中的日记级别只是一个种定义好了的过滤器(Filter),还可以在Logger元素中为LoggerConfig配置过滤器,进行更细致的控制。
Appender负责将LogEvent派送到目的地,可以有很多目的地,如console,文件、远程服务器或数据库等等。一个loggerConfig可以对应很多Appender,loggerConfig含有父(或祖先)loggerConfig的引用。因此loggerConfig不仅将LogEvent发送给自己的所有Appender,还发给它的父(或祖先)LoggerConfig的appender,然后递归向上,这种行为被称为Additivity。
appender只关心如何将LogEvent送到目的地,而Layout负责格式化LogEvent。log4j中含有不同种Layout,用于不同的用途,如JSON,XML,HTML等等。
每个Logger都有自己的名字,通常使用Logger所处类的全限定名作为Logger的名字。
在log4j中必定存在root LoggerConfig,即使没有手动配置,也会使用默认的,保证Logger能够关联到LoggerConfig。
==================================================
(这边有一个疑惑,logger的日志级别设置和appender中的ThresholdFilter日志级别设置)
问题解答:经过我本地的测试,其实这边消息会经过多种过滤。首先在logger中会根据日志级别将消息传到所有满足的logger上(当有多个logger的时候),然后logger会传送给appender, appender如果设置了ThresholdFilter, 就会筛选出符合对应日志级别的信息,床送到目的地中

学习的有些片面,刚会使用的地步,但是在调用异步的时候,程序开始报错了,明天需要好好探究一下原因。 原因居然是因为少加了一个依赖=-=,也是醉了,算了,明天再写吧

        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.4.2</version>
        </dependency>

3个标签:

Configuration

Configuration元素一些重要的属性如下:
status:log4j框架内部要输出到console的LogEvent的级别。可选值:trace", “debug”, “info”, “warn”, “error” and “fatal”。貌似默认warn。
dest:输出到console具体的流。可选值:“err”,“out”,文件或url。默认out。
monitorInterval:多少秒扫描一下配置文件

Appenders

<appenders>主要有3种类型的子标签,console(控制台), File 普通文件, RollingFile 一种可以自动调节的文件
Console节点用来定义输出到控制台的Appender.
File节点用来定义输出到指定位置的文件的Appender.
RollingFile节点用来定义超过指定大小自动删除旧的创建新的的Appender.
其中滚动策略可以做成时间和大小双重滚动,配置如下:

<!--此处举例为每小时滚动一个文件且每500M滚动一个文件,控制每小时最多保留20个文件,总的文件保留3天-->
  <!--具体需要根据应用的日志量和希望保留日志大小以及磁盘空间进行评估-->
  <RollingRandomAccessFile name="APPINFO_APPENDER" fileName="${baseLogDir}/appinfo.log"
      filePattern="${baseLogDir}/appinfo.log.%d{yyyyMMddHH}.%i.gz">
      <PatternLayout>
          <Pattern>${pattern}</Pattern>
      </PatternLayout>
      <Policies>
          <SizeBasedTriggeringPolicy size="500MB" />
          <TimeBasedTriggeringPolicy interval="1" modulate="true" />
      </Policies>
      <Filters>
          <!-- 当前appender只打印info日志,warn及以上日志忽略,由后面的错误日志记录 -->
          <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL" />
          <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
      </Filters>
      <!-- max=20表示一小时内最多保留20个日志文件 -->
      <DefaultRolloverStrategy max="20">
          <!-- 对于指定的路径下的指定后缀的文件,只保留3天的日志文件,那么最多会有3天*24小时*20个日志文件 -->
          <!-- 注意应用需要根据业务需求和磁盘大小评估需要保留的日志个数,对于500M的日志文件来说,要根据应用日志的情况,观察单个日志压缩后文件大小,并计算总大小需要的空间 -->
          <Delete basePath="${baseLogDir}" maxDepth="1">
              <IfFileName glob="*.gz" />
              <IfLastModified age="3d" />
          </Delete>
      </DefaultRolloverStrategy>
  </RollingRandomAccessFile>

具体标签,看配置文件应该是可以看懂的,之后的例子都可以这样子设置

Logger

Loggers标签中常见同步的有两种:Root和Logger,异步有AsyncRoot ,和 AsyncLogger。
log4j2支持同步,异步,混合模式。
Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出
Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
自定义的Logger(子Loggger)继承自rootLogger,如果存在继承,那么他们也会继承他们的父类中的appender,这个就是上面所说的这种行为被称为Additivity。

总结:

对目前来说,会用就行,不要搞出都不知道日志打印到了哪边,日志怎么不输出的玩笑出来。

参考博客:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352