Log4j 2使用教程二 【详解】

配置

Log4j 2的配置可以通过4种方式中的1种完成:

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

我主要是讲解配置文件的方式 
编程的方式可以参考: Extending Log4j 2和Programmatic Log4j Configuration.

自动配置

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.yamllog4j2-test.yml。 
4、如果没有找到这样的文件,JSON ConfigurationFactory将在类路径中查找log4j2-test.jsonlog4j2-test.jsn。 
5、如果没有找到这样的文件,XML ConfigurationFactory将在类路径中查找log4j2-test.xml。 
6、如果找不到测试文件,则properties ConfigurationFactory将在类路径中查找log4j2.properties。 
7、如果无法找到属性文件,则YAML ConfigurationFactory将在类路径上查找log4j2.yamllog4j2.yml。 
8、如果无法找到YAML文件,则JSON ConfigurationFactory将在类路径上查找log4j2.jsonlog4j2.jsn。 
9、如果无法找到JSON文件,则XML ConfigurationFactory将尝试在类路径上找到log4j2.xml。 
10、如果没有找到配置文件,将使用DefaultConfiguration。这将导致日志输出转到控制台。

日志级别

log4j规定了默认的几个级别:trace<debug<info<warn<error<fatal等。这里要说明一下:

①级别之间是包含的关系,意思是如果你设置日志级别是trace,则大于等于这个级别的日志都会输出。 
②基本上默认的级别没多大区别,就是一个默认的设定。你可以通过它的API自己定义级别。你也可以随意调用这些方法,不过你要在配置文件里面好好处理了,否则就起不到日志的作用了,而且也不易读,相当于一个规范,你要完全定义一套也可以,不用没多大必要。 
③这不同的级别的含义大家都很容易理解,这里就简单介绍一下:

level                   描述
trace是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出。
debug调试么,我一般就只用这个作为最低级别,trace压根不用。是在没办法就用eclipse或者idea的debug功能就好了么。
info输出一下你感兴趣的或者重要的信息,这个用的最多了。
warn有些信息不是错误信息,但是也要给程序员的一些提示,类似于eclipse中代码的验证不是有error 和warn(不算错误但是也请注意,比如以下depressed的方法)。
error错误信息。用的也比较多。
fatal级别比较高了。重大错误,这种级别你可以直接停止程序了,是不应该出现的错误么!不用那么紧张,其实就是一个程度的问题。

日志使用

紧接上篇博文

例子1:

<?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输出trace信息,其他的都是error级别--><!--additivity开启的话,由于这个logger也是满足root的,所以会被打印两遍。--><logger name="cn.lsw.base.log4j2.Hello" level="trace" additivity="false"><appender-ref ref="Console"/></logger><root level="error"><appender-ref ref="Console"/></root></loggers>
</configuration>

先简单介绍一下下面这个配置文件。 
1)根节点configuration,然后有两个子节点:appenders和loggers(都是复数,意思就是可以定义很多个appender和logger了)(如果想详细的看一下这个xml的结构,可以去jar包下面去找xsd文件和dtd文件)

2)appenders:这个下面定义的是各个appender,就是输出了,有好多类别,这里也不多说(容易造成理解和解释上的压力,一开始也未必能听懂,等于白讲),先看这个例子,只有一个Console,这些节点可不是随便命名的,Console就是输出控制台的意思。然后就针对这个输出设置一些属性,这里设置了PatternLayout就是输出格式了,基本上是前面时间,线程,级别,logger名称,log信息等,差不多,可以自己去查他们的语法规则。

3)loggers下面会定义许多个logger,这些logger通过name进行区分,来对不同的logger配置不同的输出,方法是通过引用上面定义的logger,注意,appender-ref引用的值是上面每个appender的name,而不是节点名称。

这个例子为了说明什么呢?我们要说说这个logger的name(名称)了(前面有提到)。

name机制

可以参考: http://logging.apache.org/log4j/2.x/manual/architecture.html

我们看到配置文件中的那个name是非常重要的。这个name要用好的,就不能随便乱起。 
(随便用的话,那就随便取名字)。这个机制很简单,就类似于java package一样。 
上篇中创建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,而且你也没有在配置文件中进行任何配置,它们也能够都输出,因为他们都继承了rootlog配置。

这种继承的说法官网的解释叫做logger 层次结构(Hierarchy) 
官网的例子:

例如:Logger配置中name为com.foo是name为com.foo.Bar的父类。类似的有,java是java.util的父类,是java.util.Vector的祖先。

上面的那个配置文件里面还定义了一个logger,他的名称是cn.lsw.base.log4j2.Hello,这个名称其实就是通过前面的Hello.class.getName()或者Hello.class得到的。上面那个配置文件,我们为了给它做单独配置。意思是:只有cn.lsw.base.log4j2.Hello这个logger输出trace信息。也就是它的日志级别为trace,其他的logger则继承root的日志配置,日志级别为error,只能打印出error及以上级别的日志。

那么有人会问,你单独配置的那个logger不也是继承了root的配置么,那这样的话,岂不是会打印两遍日志? 这个问题确实是存在的。当然如果你设置了additivity=false,就不会输出两遍。

我们再写一个测试类: 
(我们先对上面的配置文件做下修改,一个是logger的name改为:test.Hello,第二把additivity=false去掉或改为true)

package test;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;public class Logger2Test {private static Logger logger = LogManager.getLogger(Logger2Test.class.getName());public static void main(String[] args){logger.trace("start programe");Hello hello = new Hello();hello.getHello();logger.trace("end programe");}
}

结果就是:

2017-05-17 11:51:40.783 [main] TRACE test.Hello - Enter
2017-05-17 11:51:40.783 [main] TRACE test.Hello - Enter
2017-05-17 11:51:40.787 [main] TRACE test.Hello - 我是trace
2017-05-17 11:51:40.787 [main] TRACE test.Hello - 我是trace
2017-05-17 11:51:40.787 [main] INFO  test.Hello - 我是info信息
2017-05-17 11:51:40.787 [main] INFO  test.Hello - 我是info信息
2017-05-17 11:51:40.787 [main] ERROR test.Hello - 我是error
2017-05-17 11:51:40.787 [main] ERROR test.Hello - 我是error
2017-05-17 11:51:40.787 [main] FATAL test.Hello - 我是fatal
2017-05-17 11:51:40.787 [main] FATAL test.Hello - 我是fatal
2017-05-17 11:51:40.787 [main] TRACE test.Hello - 退出程序.
2017-05-17 11:51:40.787 [main] TRACE test.Hello - 退出程序.
2017-05-17 11:51:40.787 [main] TRACE test.Hello - Exit
2017-05-17 11:51:40.787 [main] TRACE test.Hello - Exit

我们可以看出主程序Logger2Test并没有trace日志输出,因为它继承了root的日志配置(error级别及以上)。而Hello输出了trace及以上级别的日志,但是呢,每个都输出了两遍。为什么会这样呢?前面也说过默认所有的logger都继承root的配置的。此时的Hello既有自己单独的配置,也有从root那里继承下来的配置,所以会打印两次。这样的特性,在其name的层次结构中也是同样适用的,比如:

我创建三个logger名称为testtest.Hellotest.Hello.Hello2

<?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="test.Hello" level="info" additivity="true"><appender-ref ref="Console"/></logger><logger name="test.Hello" level="info" additivity="true"><appender-ref ref="Console"/></logger><logger name="test.foo.Hello2" level="info" additivity="true"><appender-ref ref="Console"/></logger><root level="error"><appender-ref ref="Console" /></root></loggers>
</configuration>

打印结果:

2017-05-17 14:18:09.388 [main] INFO  test.Hello - 我是info信息
2017-05-17 14:18:09.388 [main] INFO  test.Hello - 我是info信息
2017-05-17 14:18:09.388 [main] INFO  test.Hello - 我是info信息
2017-05-17 14:18:09.392 [main] ERROR test.Hello - 我是error
2017-05-17 14:18:09.392 [main] ERROR test.Hello - 我是error
2017-05-17 14:18:09.392 [main] ERROR test.Hello - 我是error
2017-05-17 14:18:09.392 [main] FATAL test.Hello - 我是fatal
2017-05-17 14:18:09.392 [main] FATAL test.Hello - 我是fatal
2017-05-17 14:18:09.392 [main] FATAL test.Hello - 我是fatal
2017-05-17 14:18:09.393 [main] INFO  test.foo.Hello2 - 我是info信息
2017-05-17 14:18:09.393 [main] INFO  test.foo.Hello2 - 我是info信息
2017-05-17 14:18:09.393 [main] INFO  test.foo.Hello2 - 我是info信息
2017-05-17 14:18:09.393 [main] ERROR test.foo.Hello2 - 我是error
2017-05-17 14:18:09.393 [main] ERROR test.foo.Hello2 - 我是error
2017-05-17 14:18:09.393 [main] ERROR test.foo.Hello2 - 我是error
2017-05-17 14:18:09.393 [main] FATAL test.foo.Hello2 - 我是fatal
2017-05-17 14:18:09.393 [main] FATAL test.foo.Hello2 - 我是fatal
2017-05-17 14:18:09.393 [main] FATAL test.foo.Hello2 - 我是fatal

可以看出打印三篇。

在实际使用过程中,我们其实就是需要一个就行了,这时你可以设置:additivity=false。 
它会把父类全部屏蔽掉。官方说法就是把追加性关闭。


现在我们看一个稍微复杂的例子:

<?xml version="1.0" encoding="UTF-8"?><configuration status="error"><!--先定义所有的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><!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用--><File name="log" fileName="log/test.log" append="false"><PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/></File><!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--><RollingFile name="RollingFile" fileName="logs/app.log"filePattern="log/$${date:yyyy-MM}/app-%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="50MB"/></RollingFile></appenders><!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--><loggers><!--建立一个默认的root的logger--><root level="trace"><appender-ref ref="RollingFile"/><appender-ref ref="Console"/></root></loggers>
</configuration>

转载于:https://www.cnblogs.com/Remenber-Ray/p/8858033.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353890.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

firstJava

import java.util.Date;/*** Created by Administrator on 2018/3/30.*/ public class Test {public static void main(String[] args) {System.out.println("强调自主练习");new Date();} } 转载于:https://www.cnblogs.com/fengdaren/p/8675148.html

将Java EE Monolith雕刻成微服务

在介绍了为什么微服务应该由事件驱动的简介博客之后&#xff0c;我想采取一些其他步骤&#xff0c;并在有关博客的同时准备我即将进行的一系列演讲&#xff08;请参阅jBCNconf和Red Hat Summit&#xff0c;旧金山 &#xff09;。 在Twitter christianposta上关注我&#xff0c;…

【终结版】C#常用函数和方法集汇总

C#里面的常用的函数和方法非常重要&#xff0c;然而做题的时候会经常忘记这些封装好的方法&#xff0c;所以我总结一下 C#常用函数和方法集。 【1】C#操作字符串的常用使用方法 在 C# 中&#xff0c;您可以使用字符数组来表示字符串&#xff0c;但是&#xff0c;更常见的做法是…

hadoop hdfs (java api)

简单介绍使用java控制hdfs文件系统 一、注意namenode端访问权限&#xff0c;修改hdfs-site.xml文件或修改文件目录权限 本次采用修改hdfs-site.xml用于测试&#xff0c;在configuration节点中添加如下内容 <property><name>dfs.permissions.enabled</name>&l…

glassfish_重写到边缘–充分利用它! 在GlassFish上!

glassfish现代应用程序开发的一个重要主题是重写。 自从Java Server Faces引入和Java EE 6中新的轻量级编程模型以来&#xff0c;您一直在努力使用漂亮&#xff0c;简单&#xff0c;可添加书签的URL。 PrettyFaces已有一段时间了&#xff0c;即使我可以说服它在3.3.3版本中被称…

BZOJ 4557 JLOI2016 侦查守卫 树形dp

题目链接&#xff1a;https://www.lydsy.com/JudgeOnline/problem.php?id4557 题意概述&#xff1a; 给出一棵树&#xff0c;每个点付出代价w[i]可以控制距离和它不超过d的点&#xff0c;现在给出一些点&#xff0c;问控制这些点的最小代价是多少。 分析: 观察一下数据范围发现…

Java6上开发WebService

Java6上开发WebService 2010-01-23 16:19:00 标签&#xff1a;Java6 WebService 休闲 职场 版权声明&#xff1a;原创作品&#xff0c;如需转载&#xff0c;请与作者联系。否则将追究法律责任。 近日朋友问起Java开发WebService的问题&#xff0c;于是为其写了一份简单说明&…

在spring中该如何使用DTO,以及DTO和Entity的关系

1. DTO是用于将后台的数据结构&#xff08;javaBean&#xff09;转换为对用户友好的表现方式的数据结构&#xff0c;同时也能防止后台数据直接传送到前台而存在的潜在危险。 2. 可以时候要哪个springbot框架提供的转换器接口&#xff1a; org.springframework.core.convert.con…

带有Kafka和ZeroMQ的分布式类星体演员

因此&#xff0c;您已经有了使用actor的精美设计&#xff0c;选择了JVM和Quasar在该主题上的强大而忠实的观点。 所有明智的决定&#xff0c;但是在集群上进行分配时您有什么选择呢&#xff1f; 星系 Galaxy是一个非常酷的选择&#xff1a;快速的内存中数据网格&#xff0c;针…

JAVA中断线程的方法

JAVA中断线程的方法 Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit 这些终止线程运行的方法已经被废弃&#xff0c;使用它们是极端不安全的&#xff01; 现在&#xff0c;如果你要安全有效地终止一个线程&#xff0c;应该采用以下这些方法&a…

最常见的Java异常及其对Java开发人员的评价

我知道我说在完成视频之前我不会张贴帖子&#xff0c;但这一直困扰着我。 至于视频的更新&#xff0c;我有些懒散&#xff0c;有些忙碌&#xff0c;但是我已经准备好记录第一集&#xff0c;这是我第一次有机会&#xff0c;而且我不需要太多的编辑。 无论如何&#xff0c;还是今…

日志系统设计

日志系统设计 2009-12-11 00:46:58| 分类&#xff1a; 技术 | 标签&#xff1a; |字号大中小 订阅 一、重要性日志系统在整个系统架构中的重要性可以称得上基础的基础&#xff0c;但是这一点&#xff0c;都容易被大多数人所忽视。因为日志在很多人看来只是printf。在系…

bzoj 1124 [POI2008]枪战Maf 贪心

[POI2008]枪战Maf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 741 Solved: 295[Submit][Status][Discuss]Description 有n个人&#xff0c;每个人手里有一把手枪。一开始所有人都选定一个人瞄准&#xff08;有可能瞄准自己&#xff09;。然后他们按某个顺序开枪&#x…

核心API最佳实践——JDK日志分级

核心API最佳实践——JDK日志分级 时间:2005-10-29 08:00 来源:网管之家bitsCN.com 字体:[大 中 小]日志&#xff08;Log&#xff09;是什么&#xff1f;字典对其的解释是"对某种机器工作情况或某项任务进展情况的记载"。对于应用系统来说&#xff0c;日志就应该记录应…

20165234 《Java程序设计》第五周学习总结

第五周学习总结 教材学习内容总结 第七章 内部类与异常类 内部类内部类&#xff1a;在一个类中定义另一个类。 外嵌类&#xff1a;包含内部类的类&#xff0c;称为内部类的外嵌类。 内部类的类体中不能声明类变量和类方法。外嵌类的类体中可以用内部类声明对象&#xff0c;作为…

Java日志操作总结

Java日志操作总结 (2008-04-21 17:39:06)标签&#xff1a; 杂谈 . 使用Jakarta Commons Logging(JCL) 1.1. 概述 Apache的开源日志组件Jakarta CommonsLogging(JCL)提供的是一个日志(Log)接口(Interface)&#xff0c;同时兼顾轻量级和不依赖于具体的日志实现工具。它提供给中…

4-2日装饰器,带参数的装饰器

1&#xff0c;函数的有用信息 from functools import wraps#引用模块 def wrapper(f): # f func1wraps(f)def inner(*args,**kwargs): #聚合#args &#xff08;1,2,3&#xff09;执行函数之前的相关操作ret f(*args,**kwargs) # 打散 1,2,3执行函数之后的相关操作return re…

Apache Storm:如何使用Flux配置KafkaBolt

微型框架中的助焊剂可以帮助我们定义和部署Storm拓扑。 Flux有各种包装器&#xff0c;可帮助您定义所需的流并初始化Bolts和Spouts&#xff08;使用带有或不带有参数的构造函数&#xff0c;并通过反射自动调用自定义配置方法&#xff09;。 您只需要使用Flux就是将其作为依赖…

java 获取当前函数名

import java.text.SimpleDateFormat; import java.util.Date; /** * Java实现类似C/C中的__FILE__、__FUNC__、__LINE__等,主要用于日志等功能中。 * * version 1.0 2011-07-13 * */ public abstract class CommonFunction { /** * 打印日志时获取当前的程序文件名、行号、方法…

美国华尔街拥抱区块链是最大的威胁

Overstock的首席执行官帕特里克伯恩宣布证券交易委员会已批准其计划在区块链上发行股票&#xff0c;该区块链是推动比特币数字货币的巨大在线分类账。 这是一个重要的时刻。至少在理论上&#xff0c;区块链可以更有效&#xff0c;准确和公开地跟踪股票&#xff0c;债券和其他金…