logback 优点
- 自定义日志级别过滤,日志名过滤输出到不同的文件
- 号称速度是log4j的十倍
- 可以配置到数据库
- SLF4J的实现,切换日志组建比较方便。
- 自动重新载入配置文件
- 文件管理更加强大, 自动清除旧的日志归档文件,自动压缩归档日志文件
- SiftingAppender,基于任何给定的实时属性分开(或者筛选)日志。例如,SiftingAppender可以基于用户会话分开日志事件
配置logback环境
加载包
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
配置文件logback.xml
在工程src目录下建立logback.xml
- logback首先会试着查找logback.groovy文件;
- 当没有找到时,继续试着查找logback-test.xml文件;
- 当没有找到时,继续试着查找logback.xml文件;
- 如果仍然没有找到,则使用默认配置(打印到控制台)
java类中使用
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static Logger log = LoggerFactory.getLogger(Test.class);
logback.xml 基础配置
configuration
根节点
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 其他配置省略-->
</configuration>
scan
: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。scanPeriod
: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。debug
: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
contextName
每个logger都关联到logger上下文,默认上下文名称为“default”,用于区分不同应用程序的记录。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>appName</contextName>
<!-- 其他配置省略-->
</configuration>
property
用来定义变量值的标签
property
有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值
<property name="APP_Name" value="myAppName" />
timestamp
将解析配置文件的时间作为上下文名称
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
appender
日志的输出配置,比如
ConsoleAppender
,FileAppender
等
loger
用来设置某一个包或者具体的某一个类的日志打印级别、以及指定
name
:用来指定受此loger约束的某一个包或者具体的某一个类。level
用来设置打印级别,大小写无关,TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,如果未设置此属性,那么当前loger将会继承上级的级别addtivity
是否向上级loger传递打印信息。默认是true
appender-ref
loger下面可以包含多个appender-ref标签
标识这个appender将会添加到这个loger
root
特殊的loger元素,根loger,只有一个level属性
日志级别TRACE
,DEBUG
,INFO
,WARN
,ERROR
最简单的配置
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoder 默认配置为PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Appender 详细描述
ConsoleAppender
控制台日志
以下子节点<encoder>
:对日志进行格式化。(具体参数稍后讲解 )<target>
:字符串 System.out 或者 System.err ,默认 System.out
FileAppender
把日志添加到文件
file
被写入的文件名,如果上级目录不存在会自动创建,没有默认值。append
如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是trueencoder
格式化日志prudent
如果是 true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是 false。
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>testFile.log</file>
<append>true</append>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
RollingFileAppender
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件
- 共同的配置见
FileAppender
描述 rollingPolicy
当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名triggeringPolicy
告知 RollingFileAppender 何时激活滚动
rollingPolicy
TimeBasedRollingPolicy
根据时间来制定滚动策略
fileNamePattern
必要节点,包含文件名及“%d”转换符maxHistory
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件
FixedWindowRollingPolicy
根据固定窗口算法重命名文件的滚动策略
minIndex
窗口索引最小值maxIndex
窗口索引最大值fileNamePattern
必须包含“%i”例如,假设最小值和最大值分别为1和2,命名模式为 mylog%i.log,会产生归档文件
triggeringPolicy
SizeBasedTriggeringPolicy
查看当前活动文件的大小,如果超过指定大小会告知 RollingFileAppender 触发当前活动文件滚动
maxFileSize
这是活动文件的大小,默认值是10MB
encoder 详细
负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。
使用“%”加“转换符”方式,如果要输出“%”,则必须用“\”对“%”进行转义
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder
logger,c,lo
输出日志的logger名,可有一个整形参数,功能是缩短logger名
%logger | mainPackage.sub.sample.Bar | mainPackage.sub.sample.Bar |
---|---|---|
%logger{0} | mainPackage.sub.sample.Bar | Bar |
%logger{5} | mainPackage.sub.sample.Bar | m.s.s.Bar |
%logger{16} | mainPackage.sub.sample.Bar | m.sub.sample.Bar |
C,class
contextName,cn 输出上下文名称
d ,date
输出日志的打印日志,模式语法与java.text.SimpleDateFormat 兼容。
- %date{dd MMM yyyy ;HH:mm:ss.SSS}
- %date{HH:mm:ss.SSS}
- %date{ISO8601}
F / file
输出执行记录请求的java源文件名。尽量避免使用,除非执行速度不造成任何问题
caller{depth}
输出生成日志的调用者的代码执行位置信息,整数选项表示输出信息深度
L / line
输出执行日志请求的行号。尽量避免使用,除非执行速度不造成任何问题。
m / msg / message
输出应用程序提供的信息。
M / method
输出执行日志请求的方法名。尽量避免使用,除非执行速度不造成任何问题。
n
输出平台先关的分行符“\n”或者“\r\n”。
p / le / level
输出日志级别。
r / relative
输出从程序启动到创建日志记录的时间,单位是毫秒
t / thread
输出产生日志的线程名
replace(p ){r, t}
p 为日志内容,r 是正则表达式,将p 中符合r 的内容替换为t 。
例如, “%replace(%msg){‘\s’, ‘’}”
filter
LevelFilter
级别过滤器,根据日志级别进行过滤
如果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志
level
设置过滤级别 TRACE, DEBUG, INFO, WARN, ERRORonMatch
用于配置符合过滤条件的操作,ACCEPT,DENY,NEUTRAL- 用于配置不符合过滤条件的操作
ThresholdFilter
临界值过滤器,过滤掉低于指定临界值的日志。
<!-- 过滤掉 TRACE 和 DEBUG 级别的日志-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
EvaluatorFilter
求值过滤器,评估、鉴别日志是否符合指定条件
需要额外的两个JAR包,commons-compiler.jar和janino.jar
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- 默认为 ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return message.contains("billing");</expression>
</evaluator>
<OnMatch>ACCEPT </OnMatch>
<OnMismatch>DENY</OnMismatch>
</filter>
补充
例子
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2010-2011 The myBatis Team
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration debug="false">
<contextName>weixin-web</contextName>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="C:\\home\\log\\weixin" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%-4relative %date [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/INFO.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%-4relative %date [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>100MB</MaxFileSize>
</triggeringPolicy>
</appender>
<appender name="ERR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--
返回DENY,日志将立即被抛弃不再经过其他过滤器;
返回NEUTRAL,有序列表里的下个过滤器过接着处理日志;
返回ACCEPT,日志会被立即处理,不再经过剩余过滤器
-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/ERROR.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%-4relative %date [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 数据库输出 -->
<appender name="db" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource
class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://localhost:3306/weixin_web</url>
<user>root</user>
<password>123456</password>
</connectionSource>
</appender>
<!-- 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" />
<!--myibatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别 -->
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="ERR_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="db" />
</root>
</configuration>
db日志的建表语句
BEGIN;
DROP TABLE IF EXISTS logging_event_property;
DROP TABLE IF EXISTS logging_event_exception;
DROP TABLE IF EXISTS logging_event;
COMMIT;
BEGIN;
CREATE TABLE logging_event
(
timestmp BIGINT NOT NULL,
formatted_message TEXT NOT NULL,
logger_name VARCHAR(254) NOT NULL,
level_string VARCHAR(254) NOT NULL,
thread_name VARCHAR(254),
reference_flag SMALLINT,
arg0 VARCHAR(254),
arg1 VARCHAR(254),
arg2 VARCHAR(254),
arg3 VARCHAR(254),
caller_filename VARCHAR(254) NOT NULL,
caller_class VARCHAR(254) NOT NULL,
caller_method VARCHAR(254) NOT NULL,
caller_line CHAR(4) NOT NULL,
event_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
COMMIT;
BEGIN;
CREATE TABLE logging_event_property
(
event_id BIGINT NOT NULL,
mapped_key VARCHAR(254) NOT NULL,
mapped_value TEXT,
PRIMARY KEY(event_id, mapped_key),
FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
);
COMMIT;
BEGIN;
CREATE TABLE logging_event_exception
(
event_id BIGINT NOT NULL,
i SMALLINT NOT NULL,
trace_line VARCHAR(254) NOT NULL,
PRIMARY KEY(event_id, i),
FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
);
COMMIT;
分文件保存日志
github 参考项目
pom
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>2.7.8</version>
</dependency>
java
public class ServiceCtrl {
private Logger log = LoggerFactory.getLogger(ServiceCtrl.class);
private Logger syslog = LoggerFactory.getLogger("syslog");
public void login(){
String userName = "admin";
String password = "123";
log.info("service方法 进入登陆方法");
log.info("client方法 登陆账户{} ,登陆密码{}",userName,password);
log.error("service方法 账户{}登陆失败",userName);
syslog.info("我是syslog 我只记录在syslog.txt里面");
}
}
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<contextName>weixin-web</contextName>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="C:\\home\\log\\test_logback" />
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<property name="print_pattern" value="%date [%thread] %-5level %logger{50} - %msg%n" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${print_pattern}</pattern>
</encoder>
</appender>
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--
返回DENY,日志将立即被抛弃不再经过其他过滤器;
返回NEUTRAL,有序列表里的下个过滤器过接着处理日志;
返回ACCEPT,日志会被立即处理,不再经过剩余过滤器
-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<!-- 按照每天生成日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/info.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${print_pattern}</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>100MB</MaxFileSize>
</triggeringPolicy>
</appender>
<appender name="ERR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/error.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${print_pattern}</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<appender name="SERVICE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<expression>return message.contains("service方法");</expression>
</evaluator>
<OnMatch>ACCEPT</OnMatch>
<OnMismatch>DENY</OnMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/service.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${print_pattern}</pattern>
</encoder>
</appender>
<appender name="syslogFile" class="ch.qos.logback.core.FileAppender">
<file>${LOG_HOME}/syslogFile.log</file>
<append>true</append>
<encoder>
<pattern>${print_pattern}</pattern>
</encoder>
</appender>
<!-- 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" />
<!--myibatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<logger name="syslog" level="INFO" additivity="false">
<appender-ref ref="syslogFile" />
</logger>
<!-- 日志输出级别 -->
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="SERVICE_FILE" />
<appender-ref ref="ERR_FILE" />
<appender-ref ref="INFO_FILE" />
</root>
</configuration>
log4j 转logback
<!-- LOGGING begin -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
<scope>runtime</scope>
</dependency>
<!-- 代码直接调用log4j会被桥接到slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<!-- 代码直接调用common-logging会被桥接到slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<!-- 代码直接调用java.util.logging会被桥接到slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4</artifactId>
<version>1.15</version>
<scope>runtime</scope>
</dependency>
<!-- LOGGING end -->