JUL
JUL是Java原生日志框架
java.util.logging
Logger快速入门
@Test
public void test() throws IOException {
//获取日志记录器对象
Logger logger = Logger.getLogger("LogsTest.test");
//关闭系统默认配置
logger.setUseParentHandlers(false);
//设置日志级别
logger.setLevel(Level.ALL);
//创建简单格式转换对象
SimpleFormatter simpleFormatter = new SimpleFormatter();
//创建 consoleHandler 控制台输出
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
consoleHandler.setFormatter(simpleFormatter);
logger.addHandler(consoleHandler);
//创建 FileHandler 文件输出
//需要有文件
FileHandler fileHandler = new FileHandler("jul.log");
fileHandler.setFormatter(simpleFormatter);
logger.addHandler(fileHandler);
//输出所有级别日志
logger.severe("severe");
logger.warning("warning");
logger.info("info");
logger.config("config");
logger.fine("fine");
}
Logger对象父子关系
@Test
public void test() throws IOException {
//根据包命名规范定义父记录器
//子记录器会继承父记录器的级别
Logger logger1 = Logger.getLogger("cn");
Logger logger2 = Logger.getLogger("cn.landsall");
//所有日志记录器的顶级父元素 LogManager$RootLogger
//java.util.logging.LogManager$RootLogger@61e4705b
System.out.println(logger1.getParent());
System.out.println(logger2.getParent() == logger1);
}
读取配置文件
@Test
public void test() throws IOException {
InputStream inputStream = LogsTest.class.getClassLoader().getResourceAsStream("logging,properties");
LogManager logManager = LogManager.getLogManager();
logManager.readConfiguration(inputStream);
Logger logger = logManager.getLogger("cn.landsall");
}
log4j
https://wiki.jikexueyuan.com/project/log4j/overview.html
maven
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
log4j入门
@Test
public void log4jTest(){
//初始化配置信息
BasicConfigurator.configure();
//创建日志记录器对象
Logger logger = Logger.getLogger(LogsTest.class);
//严重错误,一般会导致系统崩溃
logger.fatal("fatal");
//错误信息,不会影响系统运行
logger.error("error");
//警告信息
logger.warn("warn");
//运行信息
logger.info("info");
//调试信息
logger.debug("debug");
//追踪信息
logger.trace("trace");
}
log4j组件
Loggers(记录器)
Appenders(输出源)
Layouts(布局)
配置文件
log4j会读取Resource下的配置文件log4.xml 或 log4j.properties
Log4j内置日志
LogLog.setInternalDebugging(true);日志格式
SimpleLayout
HTMLLayout
html格式
Log4j.appender.FILE.layout=org.apache.Log4j.HTMLLayout
Log4j.appender.FILE.layout.Title=HTML Layout Example
Log4j.appender.FILE.layout.LocationInfo=true
方法 & 描述 |
---|
setContentType(String)设置 HTML 的内容类型,默认为 text/html。 |
setLocationInfo(String)设置日志事件的地域信息。 |
setTitle(String)设置 HTML 文件的标题,默认为 Log4j Log Messages。 |
PatternLayout
自定义格式
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定PatternLayout的消息格式
log4j.appender.console.layout.conversionPattern = [%-5p]%r %l %d{yyyy-MM-d HH:mm:ss.SSS} %m%n
模式转换字符
下面的表格解释了上面模式中用到的字符,以及所有定制模式时能用到的字符:
转换字符 | 含义 |
---|---|
%c | 使用它为输出的日志事件分类,比如对于分类 “a.b.c”,模式 %c{2} 会输出 “b.c” 。 |
%C | 使用它输出发起记录日志请求的类的全名。比如对于类 “org.apache.xyz.SomeClass”,模式 %C{1} 会输出 “SomeClass”。 |
%d | 使用它输出记录日志的日期,比如 %d{HH:mm:ss,SSS} 或 %d{dd MMM yyyy HH:mm:ss,SSS}。 |
%F | 在记录日志时,使用它输出文件名。 |
%l | 用它输出生成日志的调用者的地域信息。 |
%L | 使用它输出发起日志请求的行号。 |
%m | 使用它输出和日志事件关联的,由应用提供的信息。 |
%M | 使用它输出发起日志请求的方法名。 |
%n | 输出平台相关的换行符。 |
%p | 输出日志事件的优先级。 |
%r | 使用它输出从构建布局到生成日志事件所花费的时间,以毫秒为单位。 |
%t | 输出生成日志事件的线程名。 |
%x | 输出和生成日志事件线程相关的 NDC (嵌套诊断上下文)。 |
%X | 该字符后跟 MDC 键,比如 X{clientIP} 会输出保存在 MDC 中键 clientIP 对应的值。 |
%% | 百分号, %% 会输出一个 %。 |
格式修饰符
缺省情况下,信息保持原样输出。但是借助格式修饰符的帮助,就可调整最小列宽、最大列宽以及对齐。
下面的表格涵盖了各种修饰符:
格式修饰符 | 左对齐 | 最小宽度 | 最大宽度 | 注释 |
---|---|---|---|---|
%20c | 否 | 20 | 无 | 如果列名少于 20 个字符,左边使用空格补齐。 |
%-20c | 是 | 20 | 无 | 如果列名少于 20 个字符,右边使用空格补齐。 |
%.30c | 不适用 | 无 | 30 | 如果列名长于 30 个字符,从开头剪除。 |
%20.30c | 否 | 20 | 30 | 如果列名少于 20 个字符,左边使用空格补齐,如果列名长于 30 个字符,从开头剪除。 |
%-20.30c | 是 | 20 | 30 | 如果列名少于 20 个字符,右边使用空格补齐,如果列名长于 30 个字符,从开头剪除。 |
Appenders
ConsoleAppenders
输出到控制台
# 指定日志级别=trace,添加 appender 名为console
log4j.rootLogger = trace,console
# 指定 console 的类型
log4j.appender.console = org.apache.log4j.ConsoleAppender
#指定 console 的 Layout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定PatternLayout的消息格式
log4j.appender.console.layout.conversionPattern = [%-5p]%r %l %d{yyyy-MM-d HH:mm:ss.SSS} %m%n
FileAppenders
输出到文件
# 指定rootLogger的日志级别 trace,添加 appender 名为 file
log4j.rootLogger = trace,file
# 指定 file 的类型
log4j.appender.file = org.apache.log4j.FileAppender
# 指定 file 的layout
log4j.appender.file.layout = org.apache.log4j.PatternLayout
# 指定消息格式
log4j.appender.file.layout.conversionPattern = [%-5p]%r %l %d{yyyy-MM-d HH:mm:ss.SSS} %m%n
# 指定日志文件的保存路径
log4j.appender.file.file = log4j.log
# 指定日志文件字符集
log4j.appender.file.encoding = UTF-8
RollingFileAppender
输出到多个文件(以文件大小拆分)
# 指定日志级别 trace,指定 appender 为 rollingFile
log4j.rootLogger = trace,rollingFile
# 指定 appender 的类型
log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender
# 指定 rollingFile 的 layout
log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout
# 指定消息格式
log4j.appender.rollingFile.layout.conversionPattern = [%-5p]%r %l %d{yyyy-MM-d HH:mm:ss.SSS} %m%n
# 指定日志文件的保存路径
log4j.appender.rollingFile.file = log4j.log
# 指定日志文件字符集
log4j.appender.rollingFile.encoding = UTF-8
# 指定每个日志文件的最大容量 (KB,MB,GB)
log4j.appender.rollingFile.maxFileSize = 1MB
# 指定日志文件的数量 (超出数量会覆盖最早的)
log4j.appender.rollingFile.maxBackupIndex = 10
DailyRollingFileAppender
以日期分隔日志文件
# 指定日志级别 trace,指定 appender 为 dailyFile
log4j.rootLogger = trace,dailyFile
# 指定 appender 的类型
log4j.appender.dailyFile = org.apache.log4j.DailyRollingFileAppender
# 指定 rollingFile 的 layout
log4j.appender.dailyFile.layout = org.apache.log4j.PatternLayout
# 指定消息格式
log4j.appender.dailyFile.layout.conversionPattern = [%-5p]%r %l %d{yyyy-MM-d HH:mm:ss.SSS} %m%n
# 指定日志文件的保存路径
log4j.appender.dailyFile.file = log4j.log
# 指定日志文件字符集
log4j.appender.dailyFile.encoding = UTF-8
# 指定日期拆分规则 (只能用-分隔)
log4j.appender.dailyFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss
DatePattern | 描述 |
---|---|
‘.’ yyyy-MM | 在本月末,下月初回滚文件。 |
‘.’ yyyy-MM-dd | 在每天午夜回滚文件,这是缺省值。 |
‘.’ yyyy-MM-dd-a | 在每天中午和午夜回滚文件。 |
‘.’ yyyy-MM-dd-HH | 在每个整点回滚文件。 |
‘.’ yyyy-MM-dd-HH-mm | 每分钟回滚文件。 |
‘.’ yyyy-ww | 根据地域,在每周的第一天回滚。 |
JDBCAppenders
JDBCAppender 配置
属性 | 描述 |
---|---|
bufferSize | 设置缓冲区大小,缺省为 1。 |
driver | 以字符串形式设置驱动类,如果未设置,缺省为 sun.jdbc.odbc.JdbcOdbcDriver。 |
layout | 设置 layout,缺省为 org.apache.Log4j.PatternLayout。 |
password | 设置数据库密码。 |
sql | 设置每次日志事件触发时需要执行的 SQL 语句,该语句可以是 INSERT、UPDATE 或 DELETE。 |
URL | 设置 JDBC URL. |
user | 设置数据库用户名。 |
# 指定日志级别 trace,指定 appender 为 logDB
log4j.rootLogger = trace,logDB
# 指定 appender 的类型
log4j.appender.logDB = org.apache.log4j.jdbc.JDBCAppender
# 驱动
Log4j.appender.logDB.Driver = com.mysql.cj.jdbc.Driver
# url
Log4j.appender.logDB.URL = jdbc:mysql://ip/database?serverTimezone=Asia/Shanghai
# 用户名密码
Log4j.appender.logDB.User = admin
Log4j.appender.logDB.Password = XXXXXX
# 插入语句
Log4j.appender.logDB.Sql = INSERT INTO LOGS VALUES('%x','%d','%C','%p','%m')
# 指定 rollingFile 的 layout
log4j.appender.logDB.layout = org.apache.log4j.PatternLayout
日志门面
JCL
- Log的实现类
- JCL支持的日志实现
SLF4J
简介
SLF4J入门
maven
<!--slf4j 门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<!--slf4j 实现-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
public static final Logger LOGGER = LoggerFactory.getLogger(LogsTest.class);
@Test
public void log4jTest() {
//日志输出
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.trace("trace");
//使用占位符
String name = "admin";
LOGGER.info("用户:{}登入", name);
//将系统的异常信息输出
try {
int i = 10/0;
}catch (Exception e){
LOGGER.error("出现异常",e);
}
}
绑定日志实现
-
log4j
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!-- log4j适配器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
JUL
<!-- JUL适配器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.30</version>
</dependency>
桥接器
JCL
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.6</version>
</dependency>
日志实现
logback
https://www.cnblogs.com/cjsblog/p/9113131.html
组件
日志级别
从上往下递减
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--
属性 get ${name}
-->
<property name="pattern" value="[%-5level] %d{yyyy-mm-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"/>
<!--
日志输出格式:
%level 级别
%d{yyyy-MM-dHH:mm:SS.SSS} 日期
%c类的完整名称
%M为 method
%L为行号
%thread 线程名称
%m或者%msg为信息
%n换行
-->
<!-- 控制台 appender -->
<!-- name:console -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- 控制输出流对象狀认 System.out 改为 System,err -->
<target>System.err</target>
<!-- 日志消息格式配置 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!-- root Logger配置 -->
<root level="ALL">
<appender-ref ref="console"/>
</root>
</configuration>
appender
ConsoleAppender
控制台输出
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- 控制输出流对象狀认 System.out 改为 System,err -->
<target>System.err</target>
<!-- 日志消息格式配置 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
FileAppender
log
<!-- FileAppender -->
<!-- name:file -->
<appender name="file" class="ch.qos.logback.core.FileAppender">
<!-- 日志文件保存路径 -->
<file>logback.log</file>
<!-- 日志消息格式配置 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
html
<!-- FileAppender 输出html-->
<appender name="htmlFile" class="ch.qos.logback.core.FileAppender">
<!-- 日志文件保存路径 -->
<file>logback.html</file>
<!-- 日志消息格式配置 -->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%-5level%d{yyyy-mm-dd HH:mm:ss.SSS}%c%M%L%thread%m</pattern>
</layout>
</encoder>
</appender>
RollingFileAppender
实现日志拆分(时间和大小)和归档压缩
<!-- RollingFileAppender -->
<!-- 实现日志拆分(时间和大小)和归档压缩 -->
<appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>rolling_logback.log</file>
<!-- 日志消息格式配置 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
<!-- 指定拆分规则 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 按照时间和文件大小拆分的文件名 -->
<fileNamePattern>rolling_logback.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
<!-- 按照文件大小拆分 -->
<maxFileSize>1MB</maxFileSize>
</rollingPolicy>
</appender>
rolling_logback.log 为最新的log文件
其他文件为归档文件AsyncAppender
异步日志
在使用JDBC等耗时较大的情况下能够提高性能<!-- 异步日志 -->
<appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender">
<!-- 指定某个具体的 appender -->
<appender-ref ref="rollFile"/>
</appender>
filter
- Appender属性之一
日志级别过滤器
<appender>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 日志过滤规则 -->
<!-- 拦截指定级别 ERROR -->
<level>ERROR</level>
<!-- 大于等于指定级别 ACCEPT放行 -->
<omMatch>ACCEPT</omMatch>
<!-- 小于指定级别 DENY拦截 -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
自定义Logger
<!--
自定义 logger 对象
level 日志级别
name="包名" 指定该包下的日志输出appender
additivity="false" 该logger不会继承 rootLogger
-->
<logger name="cn.landsall" level="info" additivity="false">
<appender-ref ref="console"/>
</logger>
access
logback转换器
http://logback.qos.ch/translator/
将log4j.properties 转换为 logback.xml
log4j2
http://logging.apache.org/log4j/2.x/index.html
https://www.docs4dev.com/docs/zh/log4j2/2.x/all/index.html#
<!-- log4j2 门面 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.3</version>
</dependency>
<!-- log4j2 日志实现 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.3</version>
</dependency>
- 使用 slf4j 门面
```xml
org.slf4j slf4j-api 1.7.30
<a name="Z0XNU"></a>
### Appender
<a name="Tlbw0"></a>
#### Console
[https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-appenders.html#ConsoleAppender](https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-appenders.html#ConsoleAppender)
```xml
<!-- 控制台输出 Appender -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36:L} --- %m%n"/>
</Console>
File
<!-- 文件输出 -->
<File name="File" fileName="./logs/log4j2.log">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %c{36} %L %M - %m%n</Pattern>
</PatternLayout>
</File>
RollingFile
<RollingFile name="err" bufferedIO="true" fileName="${fileName}" filePattern="${filePatternSizeAndTime}">
<PatternLayout pattern="${logPattern}" />
<Policies>
<!-- 根据时间切割日志 -->
<!-- 当小时可被 6 整除时,它将每 6 小时滚动一次 -->
<TimeBasedTriggeringPolicy interval="6" modulate="true"/>
<!-- 根据文件大小自动切割日志 -->
<!-- 文件模式必须包含%i,否则目标文件将在每次翻转时均被覆盖 -->
<SizeBasedTriggeringPolicy size="100KB" />
</Policies>
<!-- 相同切割模式的日志最多保留10份 -->
<DefaultRolloverStrategy max="10" />
</RollingFile>
JDBC
- 不通过数据库连接池
性能最差
<!-- 写入数据库 -->
<JDBC name="databaseAppender" tableName="table">
<DriverManager connectionString="jdbc:mysql://ip:datebase/table?serverTimezone=Asia/Shanghai"
driverClassName="com.mysql.cj.jdbc.Driver"
username="username"
password="pasword" />
<Column name="level" pattern="%level" />
<Column name="logger" pattern="%logger" />
<Column name="message" pattern="%message" />
</JDBC>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">
<Properties>
<!-- 定义日志格式 -->
<Property name="logPattern">%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36:L} --- %m%n</Property>
<!-- 定义文件名变量 -->
<Property name="fileName">logs/app.log</Property>
<Property name="filePatternSize">logs/app_%i.log</Property>
<Property name="filePatternSizeAndTime">logs/$${date:yyyy-MM}/app_%d{yyyy-MM-dd}_%i.log</Property>
</Properties>
<!-- 定义Appender,即目的地 -->
<Appenders>
<!-- 定义输出到屏幕 -->
<Console name="console" target="SYSTEM_OUT">
<!-- 日志格式引用上面定义的log.pattern -->
<PatternLayout pattern="${logPattern}"/>
</Console>
<!-- 定义输出到文件-->
<RollingFile name="err" bufferedIO="true" fileName="${fileName}" filePattern="${filePatternSizeAndTime}">
<PatternLayout pattern="${logPattern}"/>
<Policies>
<!-- 根据时间切割日志 -->
<!-- 当小时可被 6 整除时,它将每 6 小时滚动一次 -->
<TimeBasedTriggeringPolicy interval="6" modulate="true"/>
<!-- 根据文件大小自动切割日志 -->
<!-- 文件模式必须包含%i,否则目标文件将在每次翻转时均被覆盖 -->
<SizeBasedTriggeringPolicy size="100KB"/>
</Policies>
<!-- 相同切割模式的日志最多保留10份 -->
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<!-- 写入数据库 -->
<JDBC name="databaseAppender" tableName="table">
<DriverManager connectionString="jdbc:mysql://ip:datebase/table?serverTimezone=Asia/Shanghai"
driverClassName="com.mysql.cj.jdbc.Driver"
username="username"
password="pasword" />
<Column name="level" pattern="%level" />
<Column name="logger" pattern="%logger" />
<Column name="message" pattern="%message" />
</JDBC>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="databaseAppender" level="info"/>
</Root>
</Loggers>
</Configuration>
PatternLayout
https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-layouts.html#PatternLayout
异步日志
<!-- 异步日志依赖 -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
AsyncLogger方式
- 全局异步
添加配置文件log4j2.component.properties
#log4j2.component.properties
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
- 混合异步
<!--
includeLocation="false" 不在打印位置信息,打印位置信息会急剧降低异步日志的性能
-->
<AsyncLogger name="cn.landsall" level="trace" includeLocation="false" additivity="false">
<AppendeRef ref="Console"/>
</AsyncLogger>