《Log4j 2.x的简单使用》

下载与安装log4j

  从版本2.9.1开始,Log4j支持Java 9,但仍可在Java 7或8中运行。在此版本中,log4j-api打包为多版本jar,并支持使用StackWalker和Process API。 从版本2.4开始,Log4J需要Java 7。 Log4j 2.3及更早版本需要Java 6。Log4j 2 Log4j 1.x已被广泛采用并用于许多应用中。
  在apache网站:https://logging.apache.org/log4j/2.x/download.html ,下载apache-log4j-2.11.2-bin.zip 。
在这里插入图片描述
  下载解压出来后,会发现许多不同的jar包,不同的jar包是log4j用于不同场景的模块jar包,有些jar包并不能单独使用,需要导入其他依赖,有具体使用到某一项时,https://logging.apache.org/log4j/2.x/runtime-dependencies.html查看。
在这里插入图片描述
  简单入门使用的话,只需要找出log4j-api-2.11.2.jar、log4j-core-2.11.2.jar两个jar包,添加到工程的类加载路径中。现有的各种log4j教程很多,但是自己实际使用时还是需要和博客中版本比较,由于开源的技术不断更新,个人建议直接官网看看新手guide。将两个jar包添加至构建路径中。
在这里插入图片描述

简单入门案例

  假设我们要使用log4j2,我们一般是先声明成一个静态成员变量:

private static Logger logger = LogManager.getLogger(Hello.class.getName());

  在工程 的类路径下新建配置文件: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="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

声明好logger后,我们就可以开始使用它了:

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

public class Hello {
    private static Logger logger = LogManager.getLogger(Hello.class.getName());
    public void getHello() {
        logger.entry();
        logger.trace("我是trace");
        logger.info("我是info信息");
        logger.error("我是error");
        logger.fatal("我是fatal");
        logger.trace("退出程序.");
        logger.exit();
    }
    public static void main(String[] args) {
        new Hello().getHello();
    }
}

          在这里插入图片描述
从结果上看出,只有>=error级别的日志打印出来了。 这是因为Log4j有一个默认的配置,它的日志级别是ERROR,输出只有控制台。 如果我已经定义好了日志,我把配置文件中的日志级别 < Root level=“error”>改成了TRACE,输出会变成下面这样:
          在这里插入图片描述

Log4j的配置文件有多种形式

  Log4j能够在初始化期间自动配置自身。当Log4j启动时,将找到所有ConfigurationFactory插件,并按照从最高到最低的加权顺序进行排列。 交付时,Log4j包含四个ConfigurationFactory实现:一个用于JSON,一个用于YAML,一个用于properties,一个用于XML。
  1、Log4j将检查log4j.configurationFile系统属性,如果设置,将尝试使用与文件扩展名匹配的ConfigurationFactory加载配置。
  2、如果没有设置系统属性,则properties ConfigurationFactory将在类路径中查找log4j2-test.properties。
  3、如果没有找到这样的文件,YAML ConfigurationFactory将在类路径中查找log4j2-test.yaml或log4j2-test.yml。
  4、如果没有找到这样的文件,JSON ConfigurationFactory将在类路径中查找log4j2-test.json或log4j2-test.jsn。
  5、如果没有找到这样的文件,XML ConfigurationFactory将在类路径中查找log4j2-test.xml。
  6、如果找不到测试文件,则properties ConfigurationFactory将在类路径中查找log4j2.properties。
  7、如果无法找到属性文件,则YAML ConfigurationFactory将在类路径上查找log4j2.yaml或log4j2.yml。
  8、如果无法找到YAML文件,则JSON ConfigurationFactory将在类路径上查找log4j2.json或log4j2.jsn。
  9、如果无法找到JSON文件,则XML ConfigurationFactory将尝试在类路径上找到log4j2.xml。
  10、如果没有找到配置文件,将使用DefaultConfiguration。这将导致日志输出转到控制台。

日志是输出级别可以配置

  log4j规定了默认的几个级别:trace<debug<info<warn<error<fatal等。这里要说明一下:级别之间是包含的关系,意思是如果你设置日志级别是trace,则大于等于这个级别的日志都会输出。

level 描述
trace 是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出。
debug 调试
info 输出一下你感兴趣的或者重要的信息,这个用的最多了
warn 有些信息不是错误信息,但是也要给程序员的一些提示,类似于eclipse中代码的验证不是有error 和warn
error 错误信息。用的也比较多
fatal 级别比较高了。重大错误,这种级别你可以直接停止程序了

配置文件介绍

以下面这个配置文件为例,相比上面的例子,除了root,还定义了一个logger名字为TestLog4j.Hello

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
    <appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </appenders>
    <loggers>
        <!--
        	additivity开启的话,由于这个logger也是满足root的,所以会被打印两遍。
        -->
        <logger name="TestLog4j.Hello" level="FATAL" additivity="true">
            <appender-ref ref="Console"/>
        </logger>
        <root level="error">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

  根节点configuration,然后有两个子节点:appenders和loggers(都是复数,意思就是可以定义多个appender和logger了)

  1. appenders:这个下面定义的是各个appender,就是输出了,有好多类别,先看这个例子,只有一个Console,这些节点不是随便命名的,Console就是输出控制台的意思。然后就针对这个输出设置一些属性,这里设置了PatternLayout就是输出格式了,基本上是前面时间,线程,级别,logger名称,log信息等,可以自己去查他们的语法规则。
  2. loggers下面会定义许多个logger,这些logger通过name进行区分,来对不同的logger配置不同的输出,方法是通过引用上面定义的logger,注意,appender-ref引用的值是上面每个appender的name,而不是节点名称。

Logger4j的name机制:上面的Hello例子,上篇中创建logger对象的时候,名称是通过Hello.class或者Hello.class.getName()这样的方法。为什么要这样做呢?很重要的原因就是有所谓的继承问题。比如 如果你给com.Hello定义了一个logger,那么它也适用于com.Hello.base这个logger。名称的继承是通过(.)点号分隔的。然后你会发现上面的loggers里面有个子节点不是logger而是root,而且这个root没有name属性。 这个root相当于根节点。你所有的logger都适用于这个logger,所以,即使你在很多类里面通过类名.class.getName()或者类名.class得到很多的logger,而且你也没有在配置文件中进行任何配置,它们也能够都输出,因为他们都继承了root的log配置。
  上面例子中,我还定义了一个logger名字为TestLog4j.Hello,此Logger我将其输出级别改为FATAL,那么此时Hello测试程序不用动,还是通过 private static Logger logger = LogManager.getLogger(Hello.class.getName());获得logger,获得的logger是我定制的logger名字为TestLog4j.Hello。你会发现,输出:只出现FATAL的错误。
在这里插入图片描述
  但是为何会重复出现两条呢?由于默认所有的logger都继承root的配置的。此时的TestLog4j.Hello既有自己单独的配置,也有从root那里继承下来的配置,所以会打印两次,要想关闭只需要将additivity=“false”,这样相当于不需要打印root的配置。这样的特性,在其name的层次结构中也是同样适用的,此时我定义两个logger,名字为TestLog4j、TestLog4j.Hello,由于name名字类似包名一样的特性,TestLog4j.Hello相当于TestLog4j的子包,拥有TestLog4j父logger的特性,当程序private static Logger logger = LogManager.getLogger(Hello.class.getName());其实连上root的默认Logger,应该是有3个Logger都满足。所以最终会重复输出3条。
配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
    <appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </appenders>
    <loggers>
        <logger name="TestLog4j.Hello" level="FATAL" additivity="true">
            <appender-ref ref="Console"/>
        </logger>
        <logger name="TestLog4j" level="FATAL" additivity="true">
            <appender-ref ref="Console"/>
        </logger>
        <root level="error">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

输出结果:当然想让其中的某个不起作用,修改additivity即可。
        在这里插入图片描述

将日志输出保存在某一文件案例

  上面介绍过appenders指定输出的形式,RollingFileAppender是一个OutputStreamAppender,它(会把日志)写入到filename参数命名的文件中,并且会根据TriggeringPolicy和RolloverPolicy来rollover(rolls the file over)。RollingFileAppender会使用RollingFileManager(继承OutputStreamManager)来实际执行文件的I/O和执行rollover。尽管不能共享来做不同配置的RolloverFileAppenders,但是如果Manager可以访问的话,那么RolloverFileAppenders可以(进行共享)。
   例如:在一个servlet容器中的两个web应用程序,他们有自己的配置,如果他们Log4j是共用一个类加载器(ClassLoader)那么就可以安全的写入到一个文件中。
  RollingFileAppender 需要TriggeringPolicy和RolloverStrategy。triggering policy决定是否应该执行rollover的操作,而RolloverStrategy定义了应该如何完成rollover。如果RolloverStrategy没有配置的话,RollingFileAppender将使用DefaultRolloverStrategy。从log4j2.5版本开始,在DefaultRolloverStrategy中配置的自定义删除操作在rollover时将被执行。
从2.8版本开始,如果在DirectWriteRolloverStrategy中没有配置文件名,将使用DefaultRolloverStrategy进行替换RollingFileAppender不支持文件锁的。
  下面是使用RollingFileAppender的一个示例配置,会将日志输出写入logs/app.log中。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <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>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>

其中:Policies中有基于大小的触发策略SizeBasedTriggeringPolicy 也有基于时间的触发策略TimeBasedTriggeringPolicy ,上诉配置中是基于大小的触发策略,一旦日志文件达到SizeBasedTriggeringPolicy 的size 250M,将会导致当前日期与日志的开始日期不匹配时滚动日志的策略。
  


猜你喜欢

转载自blog.csdn.net/weixin_41262453/article/details/88759383