【Log】(一)Java 中的日志框架 JUL、Log4j
【Log】(二)Java 中的日志框架 JCL、SLF
【Log】(三)Java 中的日志框架 Logback、log4j2
现有的日志框架:
logback
比 log4j
功能更加强大,性能更加好;log4j2
与 logback
功能相似,但前者的性能更好
JUL:全称 Java Util Logging
,它是 Java 原生的日志框架,使用时不需要引入第三方类库,相对其它日志框架使用方便、学习简单,能够在小型应用中灵活使用。
架构:
Logger
对象,调用其 API 来发布日志信息。Logger
对象通常是应用程序访问日志系统的入口程序;Handlers
。每个 Logger
都会关联一组 Handlers
。 Logger
会将日志交给关联的 Handlers
处理,由 Handlers
负责将日志做记录。 Handlers
在此是抽象的。其具体的实现决定了日志记录的位置可以是控制台、文件等;Formatters
。它负责对日志事件中的数据进行转换和格式化。Layouts
决定了数据在一条日志记录中的最终形式;Level
和 Loggers
、Appenders
做关联,以便于我们过滤消息;【总结】:用户使用 Logger
来进行日志记录,Logger
持有多个 Handlers
,日志的输出操作是由 Handler
完成。在 Handler
输出日志前,会经过 Filters
的过滤,判断哪些日志级别放行,哪些日志级别拦截。Handler
会将日志内容输出到指定位置(控制台/文件)。Handler
在输出日志时会使用 Layout
,将输出内容进行排版。
新建一个 SpringBoot 工程,引入一个 junit
依赖,POM 文件:
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
入门案例:
public class JulTest {
public static final String CALSS_NAME = "com.zzc.sbexp.log.jul.JulTest";
@Test
public void testQuick() {
Logger logger = Logger.getLogger(CALSS_NAME);
// 输出日志 日志级别:info
logger.info("hello jul");
// 通过方法输出
logger.log(Level.INFO, "hello jul");
// 通过占位符输出变量值
String name = "zzc";
Integer age = 24;
logger.log(Level.INFO, "用户信息:{0}, {1}", new Object[]{name, age});
}
}
日志级别从高至低:off
、server
、warning
、info
、config
、fine
、finer
、finest
、all
如果是:off
,那么就是关闭了日志级别输出;
如果是:all
,那么就是开启了日志级别输出。
Jul
默认级别是 info
,只要日志级别高于 info
,都会输出。
自定义日志级别:
步骤:
Handler
。我这里是输出到控制台和磁盘,所以是 ConsoleHandler
、FileHandler
;Formatter
;Handler
与Formatter
进行关联;Handler
添加到 Logger
中。@Test
public void testLogConfig() throws IOException {
Logger logger = Logger.getLogger(CALSS_NAME);
// 关闭系统默认配置
logger.setUseParentHandlers(false);
// 创建控制台输出Handler
ConsoleHandler consoleHandler = new ConsoleHandler();
SimpleFormatter simpleFormatter = new SimpleFormatter();
// 关联
consoleHandler.setFormatter(simpleFormatter);
// 创建文件输出Handler
FileHandler fileHandler = new FileHandler("logs.log");
fileHandler.setFormatter(simpleFormatter);
logger.addHandler(consoleHandler);
logger.addHandler(fileHandler);
// 配置日志级别
logger.setLevel(Level.ALL);
consoleHandler.setLevel(Level.ALL);
fileHandler.setLevel(Level.WARNING);
logger.severe("server");
logger.warning("warning");
logger.info("info");
}
【注意】:logs.log 的父级路径必须得存在,否则,会报错。
自定义配置文件修改 RootLogger 的默认配置:
在 resource 路径下添加一个配置文件 logging.properties
,其内容为:
#RootLogger默认的处理器,可以配置多个,所有非手动解除父日志的子日志都将使用这些处理器
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler
#RootLogger的日志级别(默认INFO),所有的Handler都受限于此日志级别,Handler的日志级别可以比RootLogger的日志级别
.level = INFO
java.util.logging.FileHandler.pattern = E:/logs/java%u.log
#单个日志文件大小,单位是bit,1024bit即为1kb
java.util.logging.FileHandler.limit = 1024 * 1024 * 10
#日志文件数量
java.util.logging.FileHandler.count = 1
#是否以追加方式添加日志内容
java.util.logging.FileHandler.append = true
java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.encoding = UTF-8
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
代码:
@Test
public void testLogProperties() throws IOException {
// 通过类加载加载配置文件
InputStream in = JulTest.class.getClassLoader().getResourceAsStream("logging.properties");
// 创建LogManger加载配置文件
LogManager logManager = LogManager.getLogManager();
logManager.readConfiguration(in);
Logger logger = Logger.getLogger(CALSS_NAME);
logger.severe("server");
logger.warning("warning");
logger.info("info");
logger.finest("finest");
}
自定义配置文件添加自定义的 Logger:
在 resource 路径下添加一个配置文件 logging.properties
,其内容为:
...
my.logger.handlers = java.util.logging.ConsoleHandler
my.logger.level = INFO
my.logger.useParentHandlers = false
代码:
@Test
public void testMyLogProperties() throws IOException {
// 通过类加载加载配置文件
InputStream in = JulTest.class.getClassLoader().getResourceAsStream("logging.properties");
// 创建LogManger加载配置文件
LogManager logManager = LogManager.getLogManager();
logManager.readConfiguration(in);
Logger logger = Logger.getLogger("my.logger");
logger.severe("server");
logger.warning("warning");
logger.info("info");
logger.finest("finest");
}
Log4j
是 Apache
下的一款开源的日志框架,通过在项目中使用 log4j
,我们可以控制日志信息输出的位置(控制台、文件、数据库);也可以控制每一条日志的输出格式,通过定义日志的输出级别,可以更灵活的控制日志的输出过程,方便项目的调试。
Log4j 组件
Log4j
主要由 Loggers
(日志记录器)、Appenders
(输出端)、Layout
(日志格式化器)组成。
1. Loggers
Loggers
:日志记录器,负责处理日志记录。实例的命名就是类的全限定名。Logger 的名字大小写敏感。其命名有继承机制。如:org.apache.commons
的 logger 会继承 org.apache
的 logger。
Log4j
中,有一个特殊的 logger,叫 root
,它是所有的 logger 的根。root logger 可以通过 Logger.getRootLogger()
方法获取。
2. Appenders
Appenders
用来指定日志输出到哪个地方,可以同时指定日志的输出目的地。常用的目的地有以下几种:
3. Layouts
Layouts
用于控制日志输出内容的格式,让我们可以使用各种需要的格式输出日志。常用的 Layouts
:
新建一个 SpringBoot 工程,引入 log4j
依赖:
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
入门案例:
public class Log4jTest {
@Test
public void testQuick() {
Logger logger = Logger.getLogger(Log4jTest.class);
logger.info("info");
}
}
执行后,查看控制台:
由此可知,需要进行系统配置。一般用配置文件进行配置,这里暂时先用代码进行配置。
@Test
public void testQuick() {
BasicConfigurator.configure();
Logger logger = Logger.getLogger(Log4jTest.class);
logger.info("info");
}
这样,日志信息就能正常输出。
日志级别:
Log4j
默认级别是 debug
,只要日志级别高于 debug
,都会输出。
在 resources
下新建一个配置文件 log4j.properties
:
# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=info,使用的 appender 是 console
log4j.rootLogger = info,console
# 指定控制台日志输出的 appender
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout = org.apache.log4j.SimpleLayout
在代码中使用:
@Test
public void testProperties() {
Logger logger = Logger.getLogger(Log4jTest.class);
logger.fatal("fatal");
logger.error("error");
logger.warn("warn");
logger.info("info");
logger.debug("debug");
logger.trace("trace");
}
1. 自定义配置 Appender 的格式
在 log4j.properties
配置文件中,我们定义了日志输出级别与输出端,在输出端中分别配置日志的输出格式:
# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=info,使用的 appender 是 console
log4j.rootLogger = info,console
# 指定控制台日志输出的 appender
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
#指定消息格式的内容
log4j.appender.console.layout.conversionPattern = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss} %m%n
log4j
采用类似 C 语言的 printf()
函数的打印格式格式化日志信息,具体的占位符及其含义如下:
%m=输出代码中指定的信息
%p=输出优先级
%n=换行符
%r=输出自应用启动到输出该 log 信息耗费的毫秒数
%c=输出打印语句所属的类的全限定名
%t=输出产生该日志的线程全名
%d=输出服务器当前时间。默认为 ISO8601。可指定格式:%d{yyyy年MM月dd日 HH:mm:ss}
%l=输出日志发生位置。包括:类名、线程名及在代码中的行数
%F=输出日志消息产生时所在的文件名称
%L=输出代码中的行号
%%=输出一个 % 字符
可以在 % 与字符之间加上修饰符来控制最小宽度,最大宽度和文本的对其方式。如:
%5c=输出类的全限定名,最小宽度是5,类名小于5,默认情况下右对齐
%-5c=输出类的全限定名,最小宽度是5,类名小于5,“-” 指定左对齐,会有空格
%.5c=输出类的全限定名,最大宽度是5,类名大于5,就会将左边多出的字符截掉;小于5,不会有空格
%20.30c%=类名小于20,补空格、右对齐;大于30,就会将左边多出的字符截掉
2. 自定义配置文件的 FileAppender
log4j.properties
:将日志信息输出到文件 FileAppender
# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=info,使用的 appender 是 console
log4j.rootLogger = info,console,rollFile
# 指定控制台日志输出的 appender
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.console.layout.conversionPattern = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss} %m%n
# 指定控制台日志输出的 appender
log4j.appender.file = org.apache.log4j.FileAppender
# 指定消息格式 layout
log4j.appender.file.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.file.layout.conversionPattern = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss} %m%n
# 指定日志文件的保存路径
log4j.appender.file.file = E:/temp/logs.log
# 指定日志文件的字符集
log4j.appender.file.encoding = UTF-8
log4j.properties
:按照文件大小进行拆分
# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=info,使用的 appender 是 console
log4j.rootLogger = info,console,rollFile
# 指定控制台日志输出的 appender
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.console.layout.conversionPattern = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss} %m%n
# 按照文件大小进行拆分的 appender 对象
log4j.appender.rollFile = org.apache.log4j.RollingFileAppender
# 指定消息格式 layout
log4j.appender.rollFile.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.rollFile.layout.conversionPattern = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss} %m%n
# 指定日志文件的保存路径
log4j.appender.rollFile.file = E:/temp/logs.log
# 指定日志文件的字符集
log4j.appender.rollFile.encoding = UTF-8
# 指定日志文件内容的大小
log4j.appender.rollFile.maxFileSize = 1MB
# 指定日志文件的数量
log4j.appender.rollFile.maxBackupIndex = 10
@Test
public void testPropertiesBySize() {
Logger logger = Logger.getLogger(Log4jTest.class);
for (int i = 0; i < 10000; i++) {
logger.fatal("fatal");
logger.error("error");
logger.warn("warn");
logger.info("info");
logger.debug("debug");
logger.trace("trace");
}
}
log4j.properties
:按照时间大小进行拆分
# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=info,使用的 appender 是 console
log4j.rootLogger = info,dailyFile
# 按照时间大小进行拆分的 appender 对象
log4j.appender.dailyFile = org.apache.log4j.DailyRollingFileAppender
# 指定消息格式 layout
log4j.appender.dailyFile.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.dailyFile.layout.conversionPattern = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss} %m%n
# 指定日志文件的保存路径
log4j.appender.dailyFile.file = E:/temp/logs.log
# 指定日志文件的字符集
log4j.appender.dailyFile.encoding = UTF-8
# 指定日志文件拆分的规则
log4j.appender.dailyFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss
3. 自定义 Logger
log4j.properties
:
# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=info,使用的 appender 是 console
log4j.rootLogger = trace,console
# 自定义 logger,也会继承RootLogger,所以也会输出到控制台
log4j.logger.com.zzc.sbexp.log.log4j = info,file
# apache 的logger,只有error级别及以上才会输出到控制台,并不会输出到文件
log4j.logger.org.apache = error
...
@Test
public void testMyLogger() {
Logger logger = Logger.getLogger(Log4jTest.class);
logger.fatal("fatal");
logger.error("error");
logger.warn("warn");
logger.info("info");
logger.debug("debug");
logger.trace("trace");
// apache 的 logger
Logger logger1 = Logger.getLogger(Logger.class);
logger1.fatal("fatal1");
logger1.error("error1");
logger1.warn("warn1");
logger1.info("info1");
logger1.debug("debug1");
logger1.trace("trace1");
}