日志的作用
- 方便定位排查系统存在的问题
- 了解当前系统运行状态
- 了解系统历史运行结果
- 根据消耗时间,优化系统性能
- 通过日志分析,了解系统的安全隐患
常用的java日志框架
- Log4j
- JUL
- JCL((Java Common Logging)
- Simplelog
- SLF4J(Simple Logging Facade for Java)
- logback
- Log4j2
日志 level
共有 8 个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。
All:最低等级的,用于打开所有日志记录
Trace:是追踪,就是程序推进以下,就可以写个 trace 输出,因此 trace 应该会特别多,不过没关系,我们可以设置最低日志级别不让它输出
Debug:指出细粒度信息事件对调试应用程序是非常有帮助的
info:消息在粗粒度级别上突出强调应用程序的运行过程Warn:输出警告及 Warn 以下级别的日志
Error:输出错误信息日志
Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志
OFF:最高等级的,用于关闭所有日志记录
Log4j的用法
- 引入jar包
举例:maven项目
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- 配置log4j.properties
配置根:
#配置根 Logger
#指定日志文件输出级别:输出 info 级别以上的日志,文件分别输出,一个是 file,一个是 error,一个是A1(A1代替控制台)
log4j.rootLogger=info,file,error,A1
通过配置配置文件的Appender可以指定日志输出到什么地方,常用的输出地有控制台,文件,数据库,远程服务器等。
配置file输出:
#定义名为 file 的输出端是每天产生一个日志文件
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
#指定日志信息的最低输出级别位 INFO,默认为 DEBUG
log4j.appender.file.Threshold=INFO
#指定当前消息输出到 jpm/log4j/log.log 文件中
log4j.appender.file.File=/log4j/log.log
#指定按天来滚动日志文件
log4j.appender.file.DatePattern=yyyy-MM-dd
#配置日志信息的格式(布局)Layout 是可以灵活地指定布局模式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
#格式化日志,Log4j 采用类似 C 语言中的 printf 函数的打印格式格式化日志信息
log4j.appender.file.layout.ConversionPattern=[%d{yyyy-MM-ddHH:mm:ss}][%-5p][logStudy-%c{1}-%M(%L)]-%m%n
#指定输出信息的编码
log4j.appender.file.encoding=UTF-8
注:文件地址可使用相对路径、参数化
配置控制台输出:
#指定输出级别:本记录器为DEBUG级别
log4j.category.com.log4j.test=DEBUG
#控制台输出
log4j.appender.A1=org.apache.log4j.ConsoleAppender
#DEBUG以上级别是输出
log4j.appender.A1.Threshold=DEBUG
#编码方式
log4j.appender.A1.Encoding=UTF-8
#是否立即输出
log4j.appender.A1.ImmediateFlush=true
#使用System.err输出
log4j.appender.A1.Target=System.err
#输出格式,表达式配置
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-d HH:mm:ss, SSS}[%C]-[%p] %m%n
配置指定file输出:
#自定义输出到指定的日志文件(如saveUserLog)
log4j.logger.saveUserLog=INFO,saveUserLog
#该配置就是让 job 的日志只输出到自己指定的日志文件中,表示 Logger 不会在父 Logger 的 appender 里输出,默认为 true
log4j.additivity.saveUserLog=false
log4j.appender.saveUserLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.saveUserLog.File=/log4j/saveUserLog.log
log4j.appender.saveUserLog.DatePattern=yyyy-MM-dd
log4j.appender.saveUserLog.Append=true
log4j.appender.saveUserLog.layout=org.apache.log4j.PatternLayout
log4j.appender.saveUserLog.layout.ConversionPattern=[%d{yyyy-MM-ddHH:mm:ss}][%-5p][logStudy-%c{1}-%M(%L)]-%m%n
log4j.appender.error.encoding=UTF-8
- 日志用法
举例:
import org.apache.log4j.Logger;
public class Log4jTest {
public static void main(String[] args){
final Logger LOGGER = Logger.getLogger(Log4jTest.class);
final Logger SAVEUSERLOG = Logger.getLogger("saveUserLog");
if(LOGGER.isDebugEnabled()){
LOGGER.info("debug"); //配置文件等级设置为all、debug时才打印
}
LOGGER.info("info"); //配置文件等级为all,info,debug时输出
LOGGER.warn("warn"); //配置文件等级为all,info,warn时输出
LOGGER.error("error"); //如在配置文件配置了error文件,则会在error文件输出,配置文件等级为all,info,warn,error时输出
SAVEUSERLOG.info("my name is menfang."); //仅输出在自定义的saveUserLog输出文件中
}
}
logback的用法
- 引入jar包
需要依赖三个 jar 包,分别是 slf4j-api、logback-core、logback-classic,其中 slf4j-api 并不是 Logback 的一部分,建议将 SLF4J 与 Logback 结合使用。
举例:maven项目
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.2.3</version>
</dependency>
- 配置logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!-- status 用来指定打印日志的级别 -->
<!--monitorInterval自动检测修改配置文件和重新配置本身,设置间隔秒数 -->
<configuration status="DEBUG" monitorInterval="30">
<!-- 定义日志的根目录 -->
<property name="LOG_HOME" value="/logs/logback" />
<!-- 定义日志文件名称 -->
<property name="appName" value="logTest"></property>
<!-- 配置控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 配置输出文件 -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${LOG_HOME}/log.log</file> //文件目录
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名称 -->
<file>${LOG_HOME}/${appName}.log</file>
<!--
当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
%i:当文件大小超过maxFileSize时,按照i进行文件滚动
-->
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!--
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
那些为了归档而创建的目录也会被删除。
-->
<MaxHistory>365</MaxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!--
日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符
-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
</layout>
</appender>
<!--
logger主要用于存放日志对象,也可以定义日志类型、级别
name:表示匹配的logger类型前缀,也就是包的前半部分
level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,false:表示只用当前logger的appender-ref,true:表示当前logger的appender-ref和rootLogger的appender-ref都有效
-->
<!-- hibernate logger -->
<logger name="org.hibernate" level="error" />
<!-- Spring framework logger -->
<logger name="org.springframework" level="error" additivity="false"></logger>
<!--
root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。
-->
<root level="debug">
<appender-ref ref="appLogAppender" />
</root>
<!-- show parameters for hibernate sql 专为 Hibernate 定制 -->
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
<logger name="org.hibernate.SQL" level="DEBUG" />
<logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
<logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />
<!--日志异步到数据库 -->
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<!--日志异步到数据库 -->
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<!--连接池 -->
<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
<user>root</user>
<password>root</password>
</dataSource>
</connectionSource>
</appender>
</configuration>
坑:logback.xml文件在target里才代表生效了,否则请检查所在位置的正确性。
- 日志用法
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackTest {
public static void main(String[] args) {
final Logger LOGGER = LoggerFactory.getLogger(LogbackTest.class);
LOGGER.info("This is info log.");
LOGGER.warn("This is warn log.");
LOGGER.error("This is error log.");
LOGGER.debug("This is debug log.");
}
}
log4j2的用法
- 引入jar包
举例:maven项目
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
- log4j2.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!-- status 用来指定 Log4j 本身的打印日志的级别 -->
<!--monitorInterval:Log4j 能够自动检测修改配置文件和重新配置本身,设置间隔秒数 -->
<configuration status="WARN" monitorInterval="30">
<!--先定义所有的 Appender -->
<appenders>
<!--这个输出控制台的配置 -->
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式 -->
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %logger{36} - %msg%n" />
</console>
<!--定义输出到指定位置的文件 -->
<File name="log" fileName="/logs/log4j2/log.log" append="true">
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %logger{36} - %msg%n" />
</File>
<!-- 这个会打印出所有的 info 及以下级别的信息,每次大小超过 size,则这 size 大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
<RollingFile name="RollingFileInfo" fileName="/logs/log4j2/info.log"
filePattern="/logs/log4j2/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
<!--控制台只输出 level 及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<ThresholdFilter level="info" onMatch="ACCEPT"
onMismatch="DENY" />
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %logger{36} - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
<!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了 30 -->
<DefaultRolloverStrategy max="30" />
</RollingFile>
<RollingFile name="RollingFileError" fileName="/logs/log4j2/error.log"
filePattern="/logs/log4j2/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="error" onMatch="ACCEPT"
onMismatch="DENY" />
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %logger{36} - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
</RollingFile>
</appenders>
<!--只有定义了 logger 并引入的 Appender,才会生效 -->
<loggers>
<!--过滤掉 Spring 和 MyBatis 的一些无用的 DEBUG 信息 -->
<logger name="org.springframework" level="INFO"></logger>
<logger name="org.mybatis" level="INFO"></logger>
<root level="INFO">
<appender-ref ref="Console" />
<appender-ref ref="log" />
<appender-ref ref="RollingFileInfo" />
<appender-ref ref="RollingFileError" />
</root>
</loggers>
</configuration>
注意:将配置文件放在target会输出的地方
- 日志用法
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Test {
public static void main(String[] args) {
final Logger LOGGER = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
LOGGER.info("I'm info.");
LOGGER.debug("I'm debug.");
LOGGER.error("I'm error.");
}
}
JCL+Log4j用法
用 commons-logging 的 Log 接口,并由 commons-logging 在运行时决定使用哪种日志架构(如 Log4j)。现在,Apache 通用日志工具 commons-logging 和 Log4j 已经成为 Java 日志的标准工具,这个组合是比较常用的一个日志框架组合
- 引入jar包
举例:maven项目
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
- 配置配置文件
可以选择两种配置文件中的一种:common-logging.properties和log4j.properties
举例:common-logging.properties
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
举例: log4j.properties参见Log4j用法
- 日志用法
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JCLAndLog4jTest {
public static void main(String[] args) {
final Log LOGGER = LogFactory.getLog(JCLAndLog4jTest.class);
LOGGER.info("info1");
LOGGER.debug("debug2");
LOGGER.error("error3");
}
}
SLF+Log4j用法
- 引用jarb
举例:maven项目
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
-
配置配置文件
举例: log4j.properties参见Log4j用法 -
日志用法
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLFAndLog4jTest {
public static void main(String[] args) {
final Logger LOGGER = LoggerFactory.getLogger(SLFAndLog4jTest.class);
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.error("error");
}
}
**最后的说明:**选择日志框架优先选用SLF+Log4j
原因:
- 独立于任意一个日志API
- 使用的是绑定包的方式,简便
- 输出日志参数用{},简便且能避免字符串拼接节省性能空间