1、java日志使用模式
- 直接调用java日志实现
- 门面模式调用日志
当前有众多日志选择,大部分组合是:
- slf4j + log4j-slf4j-iml + log4j-core (2.x)
- slf4j + slf4j-log4j2 + log4j (1.x)
- log4j (1.x)
- log4j-api + log4j-core
- log4j-api + log4j-1.2-api + log4j(1.x)
- slf4j + logback
也有 JCL + jul组合使用但是比较少 - common-log + log4j(1.x)
- common-log + log4j-jcl + log4j-core
- common-log + sample-log
log4j说明.png
大图http://asdu.cn/log4j-info.png
2、直接使用日志实现方式
这种方式有缺点,项目包引用带有日志输出的依赖时会导致日志输出不统一
image.png
2.1、代码实现,以log4j为例
pom.xml
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
log4j2.properties
status = warn
appender.console.type = Console
appender.console.name = LogToConsole
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
rootLogger.level = debug
rootLogger.appenderRef.stdout.ref = LogToConsole
java 代码
import org.apache.logging.log4j.Logger;
/**
* Hello world!
*
*/
public class App
{
private static Logger logger = Logger.getLogger(App.class);
public static void main( String[] args )
{
logger.info("asdasd {}",123);
logger.error("asdasd {}",123);
}
}
3、通过接口调用
三个日志接口:commons-logging(JCL)、slf4j、log4j-api
常用日志实现:logging(java util logging),log4j、log4j-core、logback、simplelog
备注:通过接口调用日志可以并且保证项目中只有一个日志实现,如果依赖包中有可以将项目的日志统一输出到指定位置
image.png
4、动态查找路径
4.1、commons-logging动态查找
动态查找原理:Log 是一个接口声明。LogFactory 的内部会去装载具体的日志系统,并获得实现该Log 接口的实现类。LogFactory 内部装载日志系统的流程如下:
- 首先,寻找org.apache.commons.logging.LogFactory 属性配置。
- 否则,利用JDK1.3 开始提供的service 发现机制,会扫描classpah 下的META-INF/services/org.apache.commons.logging.LogFactory文件,若找到则装载里面的配置,使用里面的配置。
- 否则,从Classpath 里寻找commons-logging.properties ,找到则根据里面的配置加载。
- 否则,使用默认的配置:如果能找到Log4j 则默认使用log4j 实现,如果没有则使用JDK14Logger 实现,再没有则使用commons-logging 内部提供的SimpleLog 实现。
5. commons-logging常用集成demo
5.1、commons-logging与jul集成(simplelog)
pom.xml
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
commons-logging.properties
告诉commons-logging用哪个日志实现类
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
simplelog.properties
告诉simplelog的日志登记等配置
org.apache.commons.logging.simplelog.defaultlog=TRACE
java
代码使用
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class App
{
private static Log logger1 = LogFactory.getLog(App .class);
public static void main( String[] args )
{
//使用logger输出日志
logger1.trace("TRACE...");
logger1.debug("DEBUG ...");
logger1.info("INFO ...");
logger1.error("ERROR ...");
logger1.warn("WARN...");
}
}
5.2、commons-logging与log4j集成
根据上面的动态查找路径,可以只有一个log4j.properties文件即可。log4j配置文件详解
log4j.properties
log4j.rootLogger=DEBUG,console,dailyFile,im
log4j.additivity.org.apache=true
# 控制台(console)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.ImmediateFlush=true
log4j.appender.console.Target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 日志文件(logFile)
log4j.appender.logFile=org.apache.log4j.FileAppender
log4j.appender.logFile.Threshold=DEBUG
log4j.appender.logFile.ImmediateFlush=true
log4j.appender.logFile.Append=true
log4j.appender.logFile.File=D:/logs/log.log4j
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 回滚文件(rollingFile)
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.Threshold=DEBUG
log4j.appender.rollingFile.ImmediateFlush=true
log4j.appender.rollingFile.Append=true
log4j.appender.rollingFile.File=D:/logs/log.log4j
log4j.appender.rollingFile.MaxFileSize=200KB
log4j.appender.rollingFile.MaxBackupIndex=50
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 定期回滚日志文件(dailyFile)
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.Threshold=DEBUG
log4j.appender.dailyFile.ImmediateFlush=true
log4j.appender.dailyFile.Append=true
log4j.appender.dailyFile.File=D:/logs/log.log4j
log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 应用于socket
log4j.appender.socket=org.apache.log4j.RollingFileAppender
log4j.appender.socket.RemoteHost=localhost
log4j.appender.socket.Port=5001
log4j.appender.socket.LocationInfo=true
# Set up for Log Factor 5
log4j.appender.socket.layout=org.apache.log4j.PatternLayout
log4j.appender.socket.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
# 发送日志到指定邮件
log4j.appender.mail=org.apache.log4j.net.SMTPAppender
log4j.appender.mail.Threshold=FATAL
log4j.appender.mail.BufferSize=10
log4j.appender.mail.From = xxx@mail.com
log4j.appender.mail.SMTPHost=mail.com
log4j.appender.mail.Subject=Log4J Message
log4j.appender.mail.To= xxx@mail.com
log4j.appender.mail.layout=org.apache.log4j.PatternLayout
log4j.appender.mail.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 应用于数据库
log4j.appender.database=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.database.URL=jdbc:mysql://localhost:3306/test
log4j.appender.database.driver=com.mysql.jdbc.Driver
log4j.appender.database.user=root
log4j.appender.database.password=
log4j.appender.database.sql=INSERT INTO LOG4J (Message) VALUES('=[%-5p] %d(%r) --> [%t] %l: %m %x %n')
log4j.appender.database.layout=org.apache.log4j.PatternLayout
log4j.appender.database.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 自定义Appender
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = corlin@cybercorlin.net
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
java
代码使用
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class App
{
private static Log logger1 = LogFactory.getLog(App .class);
public static void main( String[] args )
{
//使用logger输出日志
logger1.trace("TRACE...");
logger1.debug("DEBUG ...");
logger1.info("INFO ...");
logger1.error("ERROR ...");
logger1.warn("WARN...");
}
}
5.3、commons-logging与log4j2集成
pom.xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
log4j2.properties
appender.console.type = Console
appender.console.name = LogToConsole
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
rootLogger.level = debug
rootLogger.appenderRef.stdout.ref = LogToConsole
5.4、log4j-api+ log4j-core
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--status:Log4j2内部日志的输出级别,设置为TRACE对学习Log4j2非常有用 -->
<!--monitorInterval:定时检测配置文件的修改,有变化则自动重新加载配置,时间单位为秒,最小间隔为5s -->
<Configuration status="WARN" monitorInterval="600">
<!--properties:设置全局变量 -->
<properties>
<!--LOG_HOME:指定当前日志存放的目录 -->
<property name="LOG_HOME">/app/logs</property>
<!--FILE_NAME:指定日志文件的名称 -->
<property name="FILE_NAME">log4j2_info</property>
</properties>
<!--Appenders:定义日志输出目的地,内容和格式等 -->
<Appenders>
<!--Console:日志输出到控制台标准输出 -->
<Console name="Console" target="SYSTEM_OUT">
<!--
%d表示日期,
%-5level 表示日志级别,另外在显示时占5个字符,不足的地方用空格补齐,
%t 表示线程名
%c{1.} 表示显示调用者的时候,只显示包名最后一截及方法名,前面的几段只取首字母
比如:调用logger.info的方法是com.kittycoder.Log4j2Test.test,只显示成c.k.Log4j2Test.test
%L 表示调用者所在代码的行号
%msg 表示需要打印的日志信息
%n 表示系统换行符
-->
<!--pattern:日期,日志级别,线程名,调用者,行号,日志信息,换行 -->
<!--<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%t] %c{1.} [%L] : %msg%n"/>-->
<!--日志高亮 需要设置IDEA中,点击右上角->Edit Configurations,在VM options中添加 -Dlog4j.skipJansi=false-->
<PatternLayout charset="UTF-8"
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight{%-5level}{ERROR=Bright RED, WARN=Bright Yellow, INFO=Bright Green,
DEBUG=Bright Cyan, TRACE=Bright White} %style{[%t]}{bright,magenta} %style{%c{1.}.%M(%L)}{cyan} : %msg%n"/>
</Console>
<!--RollingFile:日志输出到文件,下面的文件都使用相对路径 -->
<!--fileName:当前日志输出的文件名称 -->
<!--filePattern:备份日志文件名称,备份目录为logs下面以年月命名的目录,备份时使用gz格式压缩 -->
<RollingFile name="RollingFile" fileName="${LOG_HOME}/${FILE_NAME}.log"
filePattern="${LOG_HOME}/${FILE_NAME}-%d{yyyy-MM-dd-HH-mm}-%i.log.gz">
<!--pattern:日期,日志级别,线程名,调用者,行号,日志信息,换行 -->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%t] %c{1.} [%L] : %msg%n"/>
<!--Policies:触发策略决定何时执行备份 -->
<Policies>
<!--TimeBasedTriggeringPolicy:日志文件按照时间备份 -->
<!--interval:每1天生成一个新文件,时间单位需要结合filePattern时间%d{yyyy-MM-dd} -->
<!--同理,如果要每1小时生成一个新文件,则改成%d{yyyy-MM-ddHH} -->
<!--modulate:对备份日志的生成时间纠偏,纠偏以0为基准进行,"0+interval"决定启动后第一次备份时间 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!--SizeBasedTriggeringPolicy:日志文件按照大小备份 -->
<!--size:指定日志文件最大为100MB,单位可以为KB、MB或GB -->
<SizeBasedTriggeringPolicy size="200MB"/>
</Policies>
<!--DefaultRolloverStrategy:翻转策略决定如何执行备份 -->
<!--max:最多保存5个备份文件,结合时间使用后,在每个时间段内最多有5个备份,多出来的会被覆盖 -->
<!--compressionLevel:配置日志压缩级别,范围0-9,0不压缩,1压缩速度最快,9压缩率最好,目前只对于zip压缩文件类型有效 -->
<DefaultRolloverStrategy max="5" compressionLevel="1">
<!--Delete:删除匹配到的过期备份文件 -->
<!--maxDepth:由于备份文件保存在${LOG_HOME}/$${date:yyyy-MM},所以目录深度设置为2 -->
<Delete basePath="${LOG_HOME}" maxDepth="1">
<!--IfFileName:匹配文件名称 -->
<!--glob:匹配2级目录深度下的以.log.gz结尾的备份文件 -->
<IfFileName glob="*/*.log.gz"/>
<!--IfLastModified:匹配文件修改时间 -->
<!--age:匹配超过180天的文件,单位D、H、M、S分别表示天、小时、分钟、秒-->
<IfLastModified age="7D"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<!--Loggers:定义日志级别和使用的Appenders -->
<Loggers>
<!--name: 打印日志的类的包路径 -->
<!--additivity: true当前的Logger打印的日志附加到Root,false仅仅打印到RollingFile -->
<Logger name="org.apache.logging.log4j" level="ERROR" additivity="true">
<AppenderRef ref="RollingFile"/>
</Logger>
<!--Root:日志默认打印到控制台 -->
<!--level日志级别: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF -->
<Root level="INFO">
<!--输出到控制台-->
<AppenderRef ref="Console"/>
<!--输出到文件-->
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
pom.xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
java
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public class App
{
private static Logger logger = LogManager.getLogger(App.class);
public static void main( String[] args ) throws InterruptedException {
logger.info("asd");
logger.info("111111111111111");
int i =0;
while(i < 20){
Thread.sleep(2);
long a = System.currentTimeMillis();
logger.info("asd");
logger.info(String.valueOf(a));
logger.error(String.valueOf(a));
i++;
}
}
}
5.4、slf4j + logback
pom
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="log.path" value="/app/logs"/>
<property name="log_info_file" value="info"/>
<contextName>logback</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="INFO_ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}[%L] - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<file>${log.path}/${log_info_file}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每分钟生成一个滚动文件 , 生产环境请调成天-->
<fileNamePattern>${log.path}/${log_info_file}-%d{yyyy-MM-dd-HH-mm}.%i.log</fileNamePattern>
<!-- 每分钟生成一个滚动文件 , 生产环境请调成天-->
<!-- <fileNamePattern>${log.path}/${log_info_file}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>-->
<!-- 限制日志总文件大小 不能写G -->
<totalSizeCap>2048mb</totalSizeCap>
<!-- 请修改保留个数,这个个数是跟时间相关,如果是天 就是保留7天,如果是分钟就是保留7分钟-->
<maxHistory>7</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 限制单个日志文件大小 -->
<maxFileSize>1mb</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<append>true</append>
</appender>
<root level="INFO">
<!-- <appender-ref ref="STDOUT"/>-->
<appender-ref ref="INFO_ROLLING"/>
</root>
</configuration>
java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class App
{
private static Logger logger = LoggerFactory.getLogger(App.class);
public static void main( String[] args ) throws InterruptedException {
logger.info("asd");
logger.info("111111111111111");
int i =0;
while(i < 20){
Thread.sleep(2);
long a = System.currentTimeMillis();
logger.info("asd");
logger.info(String.valueOf(a));
logger.error(String.valueOf(a));
i++;
}
}
}
5.5、slf4j + log4j(1.x)
pom.xml
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
log4j.properties
log4j.rootLogger = debug,stdout,file
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
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.Threshold=INFO
log4j.appender.file.File=/app/logs/log4j_test_info.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c -%F(%L) -%m%n
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=5
java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class App
{
private static Logger logger = LoggerFactory.getLogger(App.class);
public static void main( String[] args ) throws InterruptedException {
logger.info("asd");
logger.info("111111111111111");
int i =0;
while(i < 20){
Thread.sleep(2);
long a = System.currentTimeMillis();
logger.info("asd");
logger.info(String.valueOf(a));
logger.error(String.valueOf(a));
i++;
}
}
}
5.6、 slf4j + log4j-slf4j-iml + log4j-core
pom.xml
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.2</version>
</dependency>
<!-- log4j2 日志实面 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
log4j2.xml 同上
java 同上
网友评论