官网地址 | 官方文档
1 2 3 4 5
| <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency>
|
日志级别
- fatal
- error
- warn
- info
- debug
- 一般用于细粒度级别上,对调试应用程序非常有帮助。默认级别
- trace
- 是程序追踪,可以用于输出程序运行中的变量,显示执行的流程。
推荐:实际开发中只会使用到最中间的四个步骤。
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void testQuick(){ Logger logger = Logger.getLogger(Log4jTest.class); BasicConfigurator.configure(); logger.fatal("fatal"); logger.error("error"); logger.warn("warn"); logger.info("info"); logger.debug("debug"); logger.trace("trace"); }
|
Log4j 组件
Log4J 主要由 Loggers (日志记录器)、Appenders(输出端)和 Layout(日志格式化器)组成。
其中 Loggers 控制日志的输出级别与日志是否输出;Appenders 指定日志的输出方式(输出到控制台、文件 等);Layout 控制日志信息的输出格式。
Loggers
日志记录器,负责收集处理日志记录,实例的命名就是类“XX”的full quailied name(类的全限定名), Logger的名字大小写敏感,其命名有继承机制:例如:name为org.apache.commons的logger会继承 name为org.apache的logger。
Log4J中有一个特殊的logger叫做“root”,他是所有logger的根,也就意味着其他所有的logger都会直接 或者间接地继承自root。root logger可以用Logger.getRootLogger()方法获取。
但是,自log4j 1.2版以来, Logger 类已经取代了 Category 类。对于熟悉早期版本的log4j的人来说, Logger 类可以被视为 Category 类的别名。
Appenders
Appender 用来指定日志输出到哪个地方,可以同时指定日志的输出目的地。Log4j 常用的输出目的地有以下几种:
- ConsoleAppender
- FileAppender
- DailyRollingFileAppender
- 将日志输出到一个日志文件,并且每天输出到一个新的文件
- RollingFileAppender
- 将日志信息输出到一个日志文件,并且指定文件的尺寸,当文件大 小达到指定尺寸时,会自动把文件改名,同时产生一个新的文件
- JDBCAppender
Layouts
布局器 Layouts用于控制日志输出内容的格式,让我们可以使用各种需要的格式输出日志。
Log4j常用 的Layouts:
- HTMLLayout
- SimpleLayout
- 简单的日志输出格式化,打印的日志格式为(info - message)
- PatternLayout
- 最强大的格式化期,可以根据自定义格式输出日志,如果没有指定转换格式, 就是用默认的转换格式
配置文件详情
配置文件的后缀名称全部来源于对应的set方法注入,例如conversionPattern 使用SetConversionPattern方法完成
1 2 3 4 5 6 7 8
| log4j.rootLogger = trace,console
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.conversionPattern = %r [%5t] %p %l - %m%n
|
配置文件源码
支持的配置文件
1 2 3 4 5 6 7 8 9 10 11
| public class LogManager { public static final String DEFAULT_CONFIGURATION_FILE = "log4j.properties"; static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml"; public static final String DEFAULT_CONFIGURATION_KEY = "log4j.configuration"; public static final String CONFIGURATOR_CLASS_KEY = "log4j.configuratorClass"; public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride"; }
|
org.apache.log4j.LogManager ->
org.apache.log4j.helpers.OptionConverter#selectAndConfigure ->
org.apache.log4j.PropertyConfigurator ->
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class PropertyConfigurator implements Configurator { protected Hashtable registry = new Hashtable(11); protected LoggerFactory loggerFactory = new DefaultCategoryFactory(); static final String CATEGORY_PREFIX = "log4j.category."; static final String LOGGER_PREFIX = "log4j.logger."; static final String FACTORY_PREFIX = "log4j.factory"; static final String ADDITIVITY_PREFIX = "log4j.additivity."; static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory"; static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger"; static final String APPENDER_PREFIX = "log4j.appender."; static final String RENDERER_PREFIX = "log4j.renderer."; static final String THRESHOLD_PREFIX = "log4j.threshold"; public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory"; private static final String INTERNAL_ROOT_NAME = "root"; }
|
rootLogger 解析原理
rootLogger 的配置源码 org.apache.log4j.PropertyConfigurator#parseCategory
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
| void parseCategory(Properties props, Logger logger, String optionKey, String loggerName, String value) { LogLog.debug("Parsing for [" + loggerName + "] with value=[" + value + "]."); StringTokenizer st = new StringTokenizer(value, ","); if (!value.startsWith(",") && !value.equals("")) { if (!st.hasMoreTokens()) { return; } String levelStr = st.nextToken(); LogLog.debug("Level token is [" + levelStr + "]."); if (!"inherited".equalsIgnoreCase(levelStr) && !"null".equalsIgnoreCase(levelStr)) { logger.setLevel(OptionConverter.toLevel(levelStr, Level.DEBUG)); } else if (loggerName.equals("root")) { LogLog.warn("The root logger cannot be set to null."); } else { logger.setLevel((Level)null); }
LogLog.debug("Category " + loggerName + " set to " + logger.getLevel()); }
logger.removeAllAppenders(); while(st.hasMoreTokens()) { String appenderName = st.nextToken().trim(); if (appenderName != null && !appenderName.equals(",")) { LogLog.debug("Parsing appender named \"" + appenderName + "\"."); Appender appender = this.parseAppender(props, appenderName); if (appender != null) { logger.addAppender(appender); } } } }
|
内部日志记录
1 2 3 4 5 6 7
| public class LogLog { public static void debug(String msg) { if (debugEnabled && !quietMode) { System.out.println("log4j: " + msg); } } }
|
可以使用 LogLog.setInternalDebugging(true) 打开开关,这是LogLog的内部静态方法。
Layouts 格式
在 log4j.properties 配置文件中,我们定义了日志输出级别与输出端,在输出端中分别配置日志的输出 格式。
log4j 采用类似 C 语言的 printf 函数的打印格式格式化日志信息,具体的占位符及其含义如下:
%m
%p
%n
- 换行符(Windows平台的换行符为 “\n”,Unix 平台为 “\n”)
%r
%c
%t
%d
- 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日HH:mm:ss}
%l
- 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10) 小写 【不推荐】会影响性能
%F
- 输出日志消息产生时所在的文件名称 【不推荐】会影响性能
%L
%%
- 输出一个 “%” 字符
可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式。如:
%5c
- 输出category名称,最小宽度是5,category<5,默认的情况下右对齐
%-5c
- 输出category名称,最小宽度是5,category<5,”-“号指定左对齐,会有空格
%.5c
- 输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格
%20.30c
- category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉
日志文件配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| log4j.rootLogger = trace,console
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.conversionPattern = %r [%5t] %p %l - %m%n
log4j.appender.file = org.apache.log4j.FileAppender log4j.appender.file.layout = org.apache.log4j.PatternLayout log4j.appender.file.layout.conversionPattern = %r [%5t] %p %l - %m%n
log4j.appender.file.file = ./log4j.log log4j.appender.file.encoding = UTF-8
|
RollingFileAppender
1 2 3 4 5 6 7 8 9
| log4j.rootLogger = trace,rollingFile
log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout log4j.appender.rollingFile.layout.conversionPattern = %r [%5t] %p %l - %m%n log4j.appender.rollingFile.file = ./log4j.log log4j.appender.rollingFile.encoding = UTF-8 log4j.appender.rollingFile.maxFileSize = 10KB log4j.appender.rollingFile.maxBackupIndex = 1
|
DailyRollingFileAppender
1 2 3 4 5 6 7 8 9 10
| log4j.rootLogger = trace,dailyRollingFile
log4j.appender.dailyRollingFile = org.apache.log4j.DailyRollingFileAppender log4j.appender.dailyRollingFile.layout = org.apache.log4j.PatternLayout log4j.appender.dailyRollingFile.layout.conversionPattern = %r [%5t] %p %l - %m%n log4j.appender.dailyRollingFile.file = ./log4j.log log4j.appender.dailyRollingFile.encoding = UTF-8
log4j.appender.dailyRollingFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss
|
JDBCAppender
1 2 3 4 5 6 7 8 9 10
| log4j.rootLogger = trace,sql
log4j.appender.sql = org.apache.log4j.jdbc.JDBCAppender log4j.appender.sql.layout = org.apache.log4j.PatternLayout log4j.appender.sql.Driver = com.mysql.jdbc.Driver log4j.appender.sql.URL = jdbc:mysql://localhost:3306/test log4j.appender.sql.User = root log4j.appender.sql.Password = root log4j.appender.sql.Sql = INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('itcast','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| CREATE TABLE `log` ( `log_id` int(11) NOT NULL AUTO_INCREMENT, `project_name` varchar(255) DEFAULT NULL COMMENT '目项名', `create_date` varchar(255) DEFAULT NULL COMMENT '创建时间', `level` varchar(255) DEFAULT NULL COMMENT '优先级', `category` varchar(255) DEFAULT NULL COMMENT '所在类的全名', `file_name` varchar(255) DEFAULT NULL COMMENT '输出日志消息产生时所在的文件名称 ', `thread_name` varchar(255) DEFAULT NULL COMMENT '日志事件的线程名', `line` varchar(255) DEFAULT NULL COMMENT '号行', `all_category` varchar(255) DEFAULT NULL COMMENT '日志事件的发生位置', `message` varchar(4000) DEFAULT NULL COMMENT '输出代码中指定的消息', PRIMARY KEY (`log_id`) );
|
自定义Logger
level会进行覆盖,appender会进行继承,也就是dailyRollingFile和console会同时起作用。
该包名下面的全部类都是使用这个这种类型
1 2 3 4
| log4j.rootLogger = trace,dailyRollingFile
log4j.logger.cn.quguai = info,console
|
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
| log4j.rootLogger = trace,dailyRollingFile
log4j.logger.cn.quguai = info,console
log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.conversionPattern = %r [%5t] %p %l - %m%n
log4j.appender.file = org.apache.log4j.FileAppender log4j.appender.file.layout = org.apache.log4j.PatternLayout log4j.appender.file.layout.conversionPattern = %r [%5t] %p %l - %m%n log4j.appender.file.file = ./log4j.log log4j.appender.file.encoding = UTF-8
log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout log4j.appender.rollingFile.layout.conversionPattern = %r [%5t] %p %l - %m%n log4j.appender.rollingFile.file = ./log4j.log log4j.appender.rollingFile.encoding = UTF-8 log4j.appender.rollingFile.maxFileSize = 1KB log4j.appender.rollingFile.maxBackupIndex = 5
log4j.appender.dailyRollingFile = org.apache.log4j.DailyRollingFileAppender log4j.appender.dailyRollingFile.layout = org.apache.log4j.PatternLayout log4j.appender.dailyRollingFile.layout.conversionPattern = %r [%5t] %p %l - %m%n log4j.appender.dailyRollingFile.file = ./log4j.log log4j.appender.dailyRollingFile.encoding = UTF-8 log4j.appender.dailyRollingFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss
log4j.appender.sql = org.apache.log4j.jdbc.JDBCAppender log4j.appender.sql.layout = org.apache.log4j.PatternLayout log4j.appender.sql.Driver = com.mysql.jdbc.Driver log4j.appender.sql.URL = jdbc:mysql://localhost:3306/test log4j.appender.sql.User = root log4j.appender.sql.Password = root log4j.appender.sql.Sql = INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('itcast','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
|