概述
是什么
log4j: log for java
一个开源的、轻量级的、用于日志管理的组件
Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。日志信息的优先级从高到低有ERROR、WARN、 INFO、DEBUG,分别用来指定这条日志信息的重要程度;日志信息的输出目的地指定了日志将打印到控制台还是文件中;而输出格式则控制了日志信息的显示内容。
log4j和self4j、logback的联系与区别
self4j(Simple logging Facade for Java)意思为简单日志门面,它是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的接口方法进行调用即可,由于它只是一个接口,并不是一个具体的可以直接单独使用的日志框架,所以最终日志的格式、记录级别、输出方式等都要通过接口绑定的具体的日志系统来实现,这些具体的日志系统就有log4j,logback,java.util.logging等,它们才实现了具体的日志系统的功能。
举个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
假设日志系统A的info日志输出方法如下
A.message();
日志系统B的info日志输出方法如下
B.show();
log4j的info日志输出方法如下:
logger.getInfo() //演示用 实际不是这个方法
slf4j的实现就是:
slf4j slf4j = new slf4j (A);
log.info();
这样我们用的就是日志系统A的方法,
现在假设我们的系统所在环境仅仅有log4j的日志输出环境,那么原来系统仅仅需要配置新的日志源即可
slf4j slf4j = new slf4j (log4j);
而不需要更改其他代码
|
Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch。Logback相比log4j有诸多优势,足以取代log4j。logback和log4j比较,前者是后者改良,logback配置详解
能干嘛
- 日志监控打印,在项目试运行期需要记录用户所有的操作
- 添加新的内容,比如时间和线程
- 程序调试期间,记录运行的步骤和运行行
- 成功上线稳定运行后,不再需要打印了
- 多个日志的输出源,比如到数据库、eclipse控制台,或者日志文件到linux服务器下
去哪下
apache log工具
maven依赖
1
2
3
4
5
6
|
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
|
怎么用
log4j.properties介绍
-
四个关键
-
目的地:appender
所有的输出源至少有两个:控制台/磁盘,这是工程经验
-
布局:layout
-
控制单元:logger
-
级别 leveal
-
#
表示注释
-
逐行解释
一句话总结就是配置 以什么什么样的格式,按照什么样的日志优先级,将日志输出到什么地方。
配置Demo
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
|
# appender名称=类型 eh 公司名,appender名称 eh.file
log4j.appender.eh.File=org.apache.log4j.DailyRollingFileAppender
# 文件名,也是当日文件名
log4j.appender.eh.File.file=/tmp/com.eh/java8.log
# 往日文件名后缀
log4j.appender.eh.File.DatePattern=.yyyy-MM-dd
# 输出样式布局,PatternLayout->用户自定义
log4j.appender.eh.File.layout=org.apache.log4j.PatternLayout
# 具体转换样式
# %d 日期
# %5p 5位对齐,eg INFO 4位,不够5位在前面补空格, p 表示优先级 priority
# %C 包名+类名
# %M 方法
# %m message
# %n 回车
log4j.appender.eh.File.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p (%C:%M) - %m%n
# 控制台
log4j.appender.eh.Console=org.apache.log4j.ConsoleAppender
log4j.appender.eh.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.eh.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p (%C:%M) - %m%n
# 默认控制单元,如果没有配置logger的话就使用这个
# 级别,appender...
log4j.rootLogger=warn,eh.File,eh.Console
|
日志级别和获得
Level
Log4j有多种级别:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL。
Log4j建议只用四个级别分别是ERROR、WARN、INFO、DEBUG。
他们四个的级别优先级:debug<info<warn<error,假如你选择的级别是info,那就是往后靠,打印出大于等于info级别的全部标注日志
优先级与输出关系:打印自身往后靠
使用Demo
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.eh.eden.log4jtest;
import org.apache.log4j.Logger;
public class Log4jTest {
private static final Logger logger = Logger.getLogger(Log4jTest.class);
public static void main(String[] args) {
logger.debug("debug log4j");
logger.info("info log4j");
logger.warn("warn log4j");
logger.error("error log4j");
}
}
|
输出源Appender
常见Appnder,前3个常用
- org.apache.log4j.ConsoleAppender(控制台)
- org.apache.log4j.FileAppender(就一个文件)
- org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
- org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
- org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
- org.apache.log4j.jdbc.JDBCAppender(把日志用JDBC记录到数据库中)
布局LayOut
布局就是指输出信息的格式。在Log4j中称作Layout
常见Layout
- org.apache.log4j.HTMLLayout(以HTML表格形式布局),
- org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
- org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
- org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
常用PatternLayout介绍
配合自定义布局(org.apache.log4j.PatternLayout)使用
常用的patternLayout介绍
-
%m
输出代码中指定的消息
-
%p
输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%5p
表示 5位对齐,eg INFO 4位,不够5位在前面补空格
-
%r
输出自应用启动到输出该log信息耗费的毫秒数
-
%c
输出所属的类目,通常就是所在类的全名
-
%t
输出产生该日志事件的线程名
-
%n
输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
-
%d
输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy-MM-dd HH:mm:ss,SSS}
,输出类似:2015-12-20 18:35:51,768
logger控制单元
多个控制单元并存时遵循的规则
- 级别取精确,取类的路径越全的那个控制单元的级别
- 输出为各自,几个控制单元按照确定好的级别各自输出
举个例子
1
2
3
4
5
|
# 默认控制单元,如果没有配置logger的话就使用这个
# 级别,appender...
log4j.rootLogger=info,eh.File,eh.Console
# 按照包名控制
log4j.logger.com.eh.eden.log4jtest=error,eh.Console
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.eh.eden.log4jtest;
import org.apache.log4j.Logger;
public class Log4jTest {
private static final Logger logger = Logger.getLogger(Log4jTest.class);
public static void main(String[] args) {
logger.debug("debug log4j");
logger.info("info log4j");
logger.warn("warn log4j");
logger.error("error log4j");
}
}
|
按照上述规则,级别取ERROR,两个控制单元各自输出,所以控制台会有两条error日志,文件里面有一条error日志。
Case
实际使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class Log4jTest {
private static final Logger logger = Logger.getLogger(Log4jTest.class);
public static void main(String[] args) {
int arg = 0;
logger.info("arg=" + arg);
Integer result = null;
try {
result = 10 / arg;
} catch (Exception e) {
logger.error("m不能为0", e);
} finally {
logger.info("result=" + result);
}
}
}
// 输出
2020-10-03 14:06:55,765 INFO (com.eh.eden.log4jtest.Log4jTest:main) - arg=0
2020-10-03 14:06:55,780 ERROR (com.eh.eden.log4jtest.Log4jTest:main) - m不能为0
java.lang.ArithmeticException: / by zero
at com.eh.eden.log4jtest.Log4jTest.main(Log4jTest.java:20)
2020-10-03 14:06:55,801 INFO (com.eh.eden.log4jtest.Log4jTest:main) - result=null
|
log4j.properties总结
Appender、Layout、Logger三者之间的关系
- 每个appender后面必然需要跟随layout,指定自己的风格样式
- 每个Logger都可以指定一个级别,同时引用一个或多个Appender
log4j.xml
log4j中log4j.properties和log4j.xml的加载顺序
log4j启动时,默认会寻找source folder下的log4j.xml配置文件,若没有,会寻找log4j.properties文件。
配置介绍
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
|
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM
"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration>
<appender name="eh.console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %5p (%C:%M) - %m%n"/>
</layout>
<!--
log4j中常用的Filter分为四种:DenyAllFilter、LevelMatchFilter、LevelRangeFilter、StringMatchFilter
这里需要注意的是,一旦匹配了某个filter,就无法再匹配后续的filter了
LevelRangeFilter:控制输出源输出哪个级别的日志
AcceptOnMatch:用来控制匹配到的appender是否打印日志
不打印指定level的日志:
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelToMatch" value="ERROR" />
<param name="AcceptOnMatch" value="false" />
</filter>
-->
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="levelMin" value="info"/>
<param name="levelMax" value="info"/>
<param name="AcceptOnMatch" value="true"/>
</filter>
</appender>
<appender name="eh.file" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="/tmp/com.eh/java8xml.log"/>
<param name="Append" value="true"/>
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %5p (%C{1}:%M) - %m%n"/>
</layout>
</appender>
<!--
additivity=false,停止日志传播机制,只要日志传到当前logger,日志就不会再往后传播
-->
<logger name="com.eh.eden" additivity="false">
<level value="info"/>
<appender-ref ref="eh.console"/>
<appender-ref ref="eh.file"/>
</logger>
<root>
<level value="error"/>
<appender-ref ref="eh.file"/>
<appender-ref ref="eh.console"/>
</root>
</log4j:configuration>
|