介绍
log4j 用于日志记录 ,log4j 1.x 项目已终止,目前推荐使用 log4j 2 。log4j 有三个主要的组件: Loggers 、Appenders 、Layouts
组成
Loggers 层
logger记录器取代了 System.out.println 的 直接输出语句 , Log4j 1.2 中的 Logger 类 取代了 Category 类 。
Loggers 是命名的实体。Logger 的名称是 大小写敏感的,并且遵循如下分层的命名规则:
如果名称后面紧跟着一个点的 logger(记录器) 是 另一个 后代 logger 名称的前缀 , 那么这个 logger 被认为是 另一个 logger 的祖先;
如果在 logger 本身 和 其后代 logger 之间没有祖先,那么认为该 logger 是其子 logger 的 父记录器。
比如 "com.foo" 是 "com.foo.bar" 的 父记录器。"java" 是 "java.util" 的父记录器 , 是 "java.util.Vector" 的 祖先 。
★ 根记录器位于 logger 层次结构的顶层 ,具有两个特殊的特点 :
①总是存在的
② 不能根据名称获取; 可以调用类的静态方法 Logger.getRootLogger 方法获取
★ 其他的所有 logger 可以根据名称使用 Logger.getLogger(String name) 实例化和获取
Logger 继承了 Category 类 ,以下列出部分方法(Logger 中 主要是一些获取 logger 的方法 ,设置等级的方法主要在 Category 类中):
package org.apache.log4j;
public class Logger {
// Creation & retrieval methods:
public static Logger getRootLogger();
public static Logger getLogger(String name);
// printing methods:
public void trace(Object message);
public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
public void fatal(Object message);
// generic printing method:
public void log(Level l, Object message);
}
Logger 可以设置日志等级 ,有如下的等级:
trace
比 debug 颗粒度更加细化的信息通知事件
debug
info
warn
指定了潜在有害的情况。
error
指定了仍然允许应用继续运行的 错误事件。
fatal
指定了非常严重的错误事件,可能会导致应用程序终止。
等级继承: 如果一个 Logger 没有指定 等级 ,那么他将从最近的已经指定等级的祖先中继承。根 Logger 总是会被指定 level。
如下栗子: X 指定了等级 ; X.Y 未指定等级 ,所以 从 X 继承等级。
Logger name | Assigned level | Inherited level |
---|---|---|
root | Proot | Proot |
X | Px | Px |
X.Y | none | Px |
X.Y.Z | Pxyz | Pxyz |
level 选择规则:
等级 为 q 的 logger 发送 等级为 p 的日志请求 ,如果 p >= q , 那么 该等级请求 是 可执行的。
level 是已排序的 ,优先级顺序为:
Debug < Info < Warn < Error < Fatal
使用 类名 作为每个 Logger 的名称 来初始化 .
根logger 配置模式:
log4j.rootLogger = [ level ] , appenderName1, appenderName2, …
level : 设置 根 logger 的 输出等级 ,如 设置为 INFO 则 DEBUG 等级的信息不会输出 。
appenderName1,appenderName2,.. : 指定日志信息的输出位置,可以指定多个,用逗号隔开。名称自定义;
分别设置不同的 appender 属性 方法:
#输出到控制台
log4j.appender.appenderName1=org.apache.log4j.ConsoleAppender
#灵活指定布局模式
log4j.appender.appenderName1.layout=org.apache.log4j.PatternLayout
#指定布局模式
log4j.appender.error.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%p] %c{1}:%L - %m%n
特定 logger 的 配置模式:
java 代码使用类名作为 logger 的名称:
package com.ycit.controller;
import com.ycit.service.CRUDService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
/**
* Created by xlch on 2016/10/24.
*/
@Controller
public class HomeController {
private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(HomeController.class);
@Autowired
private CRUDService crudService;
@RequestMapping("/home")
public String home(){
crudService.update();
return "home";
}
}
则 controller 包下的 logger 名称为 log4j.logger.com.ycit.controller
log4j.logger.com.ycit.controller=debug,controller
log4j.additivity.com.ycit.controller=false
log4j.logger.org.springframework=ERROR
1. 配置 某个特定 logger 的日志输出级别 以及设置该 logger 的别名
2.设置 该 logger 不会在 父 logger 的 appender 里输出 ,默认为 true
3. 设置特定框架的日志输出级别 ,只输出 ERROR 以及以上级别的信息,也可以关闭 OFF
Appenders 层和 Layouts 层
在 log4j 中,一个输出目标被称为一个 appender 。
当前, appenders 可以是 控制台(console)、文件、 GUI组件、远程 socket 服务、JMS、NT event loggers、等等 ,可以同时指定多个 appender。
appender 也具有继承的特性 ,祖先的 appender 会被 子孙继承,但是如果 additivity flag 被设置为 false ,责不会继承祖先的 appender。根 logger 没有默认的 appender .
栗子:
Logger Name | Added Appenders | Additivity Flag | Output Targets | Comment |
---|---|---|---|---|
root | A1 | not applicable | A1 | The root logger is anonymous but can be accessed with the Logger.getRootLogger() method. There is no default appender attached to root. |
x | A-x1, A-x2 | true | A1, A-x1, A-x2 | Appenders of "x" and root. |
x.y | none | true | A1, A-x1, A-x2 | Appenders of "x" and root. |
x.y.z | A-xyz1 | true | A1, A-x1, A-x2, A-xyz1 | Appenders in "x.y.z", "x" and root. |
security | A-sec | false | A-sec | No appender accumulation since the additivity flag is set to false. |
security.access | none | true | A-sec | Only appenders of "security" because the additivity flag in "security" is set to false. |
通常 , 用户不仅仅需要自定义 输出目标,还需要自定义输出格式。可以给 appender 关联 一个 layout 来实现。
Layout 负责 根据使用者的需求来格式化日志请求 ,输出到 appender 上。
PatternLayout 类提供接口 完成格式化 输出。
例如上面的 rootLogger 后面设置了自定义的 appender 名称:
log4j.rootLogger = [ level ] , appenderName1, appenderName2, …
然后,会为自定义的appender 名称 分别分配log4j 中内置的不同的appender 以及 layout:
#输出到控制台
log4j.appender.appenderName1=org.apache.log4j.ConsoleAppender
#灵活指定布局模式
log4j.appender.appenderName1.layout=org.apache.log4j.PatternLayout
#指定布局模式
log4j.appender.error.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%p] %c{1}:%L - %m%n
常用 appender :
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
appender配置模式:
log4j.appender.appenderName = className
log4j.appender.appenderName.Option1 = value1
…
log4j.appender.appenderName.OptionN = valueN
org.apache.log4j.ConsoleAppender 的选项 option
Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Target=System.err:默认值是System.out。
org.apache.log4j.FileAppender option
Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Append=true:true表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true。
File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件中。
org.apache.log4j.DailyRollingFileAppender option
Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Append=false:true表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true。
File=D:/logs/logging.log4j:指定当前消息输出到logging.log4j文件中。
DatePattern='.'yyyy-MM:每月滚动一次日志文件,即每月产生一个新的日志文件。当前月的日志文件名为logging.log4j,前一个月的日志文件名为logging.log4j.yyyy-MM。
另外,也可以指定按周、天、时、分等来滚动日志文件,对应的格式如下:
1)'.'yyyy-MM:每月
2)'.'yyyy-ww:每周
3)'.'yyyy-MM-dd:每天
4)'.'yyyy-MM-dd-a:每天两次
5)'.'yyyy-MM-dd-HH:每小时
6)'.'yyyy-MM-dd-HH-mm:每分钟
org.apache.log4j.RollingFileAppender option
Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Append=false:true表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true。
File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件中。
MaxFileSize=100KB:后缀可以是KB, MB 或者GB。在日志文件到达该大小时,将会自动滚动,即将原来的内容移到logging.log4j.1文件中。
MaxBackupIndex=2:指定可以产生的滚动文件的最大数,例如,设为2则可以产生logging.log4j.1,logging.log4j.2两个滚动文件和一个logging.log4j文件
常用 layout:
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)
layout配置模式:
log4j.appender.appenderName.layout =className
log4j.appender.appenderName.layout.Option1 = value1
…
log4j.appender.appenderName.layout.OptionN = valueN
org.apache.log4j.HTMLLayout option
LocationInfo=true:输出java文件名称和行号,默认值是false。
Title=My Logging: 默认值是Log4J Log Messages。
org.apache.log4j.PatternLayout option
ConversionPattern=%m%n:设定以怎样的格式显示消息。
格式符号说明:
%p:输出日志信息的优先级,即DEBUG,INFO,WARN,ERROR,FATAL。
%d:输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,如:%d{yyyy/MM/dd HH:mm:ss,SSS}。
%r:输出自应用程序启动到输出该log信息耗费的毫秒数。
%t:输出产生该日志事件的线程名。
%l:输出日志事件的发生位置,相当于%c.%M(%F:%L)的组合,包括类全名、方法、文件名以及在代码中的行数。例如:test.TestLog4j.main(TestLog4j.java:10)。
%c:输出日志信息所属的类目,通常就是所在类的全名。
%M:输出产生日志信息的方法名。
%F:输出日志消息产生时所在的文件名称。
%L::输出代码中的行号。
%m::输出代码中指定的具体日志信息。
%n:输出一个回车换行符,Windows平台为"rn",Unix平台为"n"。
%x:输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%%:输出一个"%"字符。
另外,还可以在%与格式字符之间加上修饰符来控制其最小长度、最大长度、和文本的对齐方式。如:
1) c:指定输出category的名称,最小的长度是20,如果category的名称长度小于20的话,默认的情况下右对齐。
2)%-20c:"-"号表示左对齐。
3)%.30c:指定输出category的名称,最大的长度是30,如果category的名称长度大于30的话,就会将左边多出的字符截掉,但小于30的话也不会补空格。
配置
Log4j 的环境完全可以程序化的配置,但是使用配置文件会更加的灵活 。,Log4j 1.x 的配置文件可以通过 XML 或者 java properties(key=value) 的形式 配置。
Hello World
这里使用 slf4j + log4j ,首先 Maven 引入 slf4j-log4j12 的 jar 包。
程序如下:
package com.ycit;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by xlch on 2016/11/9.
*/
public class LogTest {
private static final Logger logger = LoggerFactory.getLogger(LogTest.class);
@Test
public void logTest() {
logger.info("logTest run ...");
}
}
编译运行,发现会有如下警告:
log4j:WARN No appenders could be found for logger (com.ycit.LogTest).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
log4j 没有 发现 log4j.xml 和 log4j.properties 文件,并且应用在运行时没有指定配置文件。
@Test
public void logTest() {
BasicConfigurator.configure();//增加一个使用PatternLayout 的ConsoleAppender
logger.info("logTest run ...");
}
增加如上一行代码即可,编译运行,控制台打印 info 信息。输出如下:
0 [main] INFO com.ycit.LogTest - logTest run ... //pattern 为 %-4r [%t] %-5p %c %x - %m%n
注意 : root logger 默认 指定等级为 Level.DEBUG. (Log4j 2 默认配置 输出指定等级为 Level.ERROR)
自定义配置文件
自定义 log4j 配置文件 log4j.properties ,放在 resources 目录下
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG,A1
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%p] %c{1}:%L - %m%n
在代码中加载配置文件:
package com.ycit;
import org.apache.log4j.PropertyConfigurator;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.Properties;
/**
* Created by xlch on 2016/11/9.
*/
public class LogTest {
private static final Logger logger = LoggerFactory.getLogger(LogTest.class);
@Test
public void logTest() throws Exception {
// BasicConfigurator.configure();//增加一个使用PatternLayout 的ConsoleAppender
Properties properties = new Properties();
InputStream in = ClassLoader.getSystemResourceAsStream("log4j.properties");
// InputStream in = LogTest.class.getClassLoader().getResourceAsStream("log4j.properties");
properties.load(in);
PropertyConfigurator.configure(properties);
logger.info("logTest run ...");
}
}
打印如下信息:
2016-11-09 16:15:07 [INFO] LogTest:26 - logTest run ...
更改配置文件,设置多个 appender(控制台打印 + 文件)
# Set root logger level to DEBUG and its appender to A1 and stdout.
log4j.rootLogger=DEBUG,A1,stdout
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n
# set stdout to file
log4j.appender.stdout=org.apache.log4j.RollingFileAppender
#设置文件保存路径
log4j.appender.stdout.file=D:\\test.log
#文件达到指定大小时,文件名变为文件名.n,重新在文件中存储
log4j.appender.stdout.MaxFileSize=2KB
# 指定最多可备份日志文件数量
log4j.appender.stdout.MaxBackupIndex=1
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n
默认的初始化过程
Log4j 类库 没有 设置 任何 的环境 ,尤其是 没有设置默认的 appender.
加载 log4j 的配置文件方法(properties 或者 .xml)
①
InputStream in = ClassLoader.getSystemResourceAsStream("log4j.properties");
或者
InputStream in = LogTest.class.getClassLoader().getResourceAsStream("log4j.properties");
② 使用 log4j 提供的 Loader 类
URL url = Loader.getResource("log4j.properties");
InputStream in = url.openStream();
然后
Properties properties = new Properties();
properties.load(in);
PropertyConfigurator.configure(properties);
WEB 项目中使用 log4j
使用 slf4j + log4j 实现
引入 中间件 jar 包 ,会自动引入其余的两个 jar 包
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
log4j.properties 配置文件
# Root logger option, debug 级别 ,三个 appender:file error stdout
log4j.rootLogger=debug, file, error, stdout,MAIL
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=D:\\pps.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
# error log
log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.File = d:\\pps-error.log
log4j.appender.error.Append = true
#设置输入信息级别,只有 ERROR 或者 ERROR 以上才会输入此 appender
log4j.appender.error.Threshold = ERROR
log4j.appender.error.layout = org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%p] %c{1}:%L - %m%n
## MAIL 还需要引入 mail 和 activation 的 jar 包
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=ERROR
log4j.appender.MAIL.BufferSize=1
log4j.appender.MAIL.SMTPHost=smtp.163.com
#邮件标题
log4j.appender.MAIL.Subject=ErrorMessage
#发件邮箱
log4j.appender.MAIL.From=xxx@163.com
#收件邮箱
log4j.appender.MAIL.To=xxx@163.com
#发件箱登陆用户名
log4j.appender.MAIL.SMTPUsername=xxx
#发件箱登陆密码
log4j.appender.MAIL.SMTPPassword=********
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[ErrorMessage] %d - %c -%-4r [%t] %-5p %c %x - %m%n
web.xml 加载 配置文件
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
使用:
使用
slf4j 的 api 进行日志记录 (简单示范)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger log = LoggerFactory.getLogger(LogTest.class);
log.trace("test trace");
log.debug("test debug");
更详细的,以及其他的功能 参看 : Log4J日志配置详解