日志管理
1.Log 日志组件能干什么
- 日志能干的事情很多,对于学习程序,测试的工程师来说,日志能够定位问题,解决问题,是最大的功能点。
- 记录一切 日志帮助我们记录程序功能都干了什么,无论是正常的输入输出还是出现异常,都可以用日志记录
- 定位问题 日志可以帮助程序员调试问题,帮助测试人员定位问题
- 记录分析用户行为 统计分析师用来记录用户的一起行为,用于分析用户的习惯和商业价值
- 备份和还原实时数据 数据库工程师用来作为一种特殊的数据库
- …
2.常用日志框架
- Log4j Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一
- Log4j 2 Apache Log4j 2是apache开发的一款Log4j的升级产品
- Commons Logging Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging
- Slf4j 类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)
- Logback 一套日志组件的实现(slf4j阵营)。
- Jul (Java Util Logging),自Java1.4以来的官方日志实现。
常用日志框架:logback+sl4j
通过将相应的库添加到classpath可以激活各种日志系统,然后在classpath根目录下提供合适的配置文件可以进一步定制日志系统,配置文件也可以通过Spring Environment的logging.config属性指定。
Java 中的日志框架主要分为两大类:日志门面和日志实现。
日志门面:日志门面定义了一组日志的接口规范,它并不提供底层具体的实现逻辑。Apache Commons Logging 和 Slf4j 就属于这一类。
日志实现:日志实现则是日志具体的实现,包括日志级别控制、日志打印格式、日志输出形式(输出到数据库、输出到文件、输出到控制台等)。Log4j、Log4j2、Logback 以及 Java Util Logging 则属于这一类。
将日志门面和日志实现分离其实是一种典型的门面模式,这种方式可以让具体业务在不同的日志实现框架之间*切换,而不需要改动任何代码,开发者只需要掌握日志门面的 API 即可。
3.配置文件
日志系统 | 定制配置 |
---|---|
Logback | logback-spring.xml,logback-spring.groovy,logback.xml,logback.groovy |
Log4j | log4j.properties或log4j.xml |
Log4j2 | log4j2-spring.xml或log4j2.xml |
JDK | (Java Util Logging) logging.properties |
1.如果可能的话,建议你使用-spring变种形式定义日志配置(例如,使用logback-spring.xml而不是logback.xml)。如果你使用标准的配置路径,Spring可能不能够完全控制日志初始化。
2.Java Util Logging从可执行jar运行时会导致一些已知的类加载问题,我们建议尽可能不使用它。
3.lombok的神组合,使用lombok的@Slf4j 注解,省去配置声明log的繁琐,提高开发效率。
4.日志级别及使用
日志级别从低到高分为: TRACE < DEBUG < INFO < WARN < ERROR < FATAL
默认级别是 INFO,因此 INFO 级别以下的日志,不会被打印出来
<!--大多数情况都是配合Slf4j使用-->
//Logger和LoggerFactory导入的是org.slf4j包
private final static Logger logger = LoggerFactory.getLogger(Xxxx.class);
//Logger和LogManager导入的是org.apache.logging包
private static final Logger LOG = LogManager.getLogger(Xxxx.class);
5.日志输出
通常日志以文本流的形式存储在磁盘,也可以把日志存储在关系型数据库中或 No Sql 中
- 文本
- 关系型数据库
<!--logbakck文件中添加配置-->
<appender name="mysql" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<dataSource class="com.alibaba.druid.pool.DruidDataSource">
<url>jdbc:mysql://localhost:3306/log?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8</url>
<driverClassName>com.mysql.cj.jdbc.Driver</driverClassName>
<username>root</username>
<password>xxxxxx</password>
</dataSource>
</connectionSource>
</appender>
<!--数据库ddl sql-->
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;
- No Sql
- Console 控制台
- 一般日志组件都可以自定义输出格式
6.日志配置
创建logback-spring.xm文件。一般放置于resources目录下
配置:
error级别保留三天,其余级别均保留一天
日志文件格式: yyyy-MM-dd- i − {i}- i−{level}.log
默认level级别为 info, 若想修改,在配置文件中配置 :
logging:
level:
org.springframework.web: debug
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<springProperty scope="context" name="log.path" source="log.path"/>
<!-- 0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- 彩色日志格式 控制台日志格式:带有颜色 -->
<property name="CONSOLE_LOG_PATTERN1"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--普通日志格式-->
<property name="CONSOLE_LOG_PATTERN2" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!--dev环境配置-->
<springProfile name="dev">
<!--输出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN1}</Pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<root level="info">
<appender-ref ref="console"/>
</root>
</springProfile>
<!--输出到debug-->
<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}-%i-debug.log</fileNamePattern>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
<!-- 日志文档保留天数 -->
<maxHistory>1</maxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<append>true</append>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN2}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印DEBUG日志 -->
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--输出到info-->
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}-%i-info.log</fileNamePattern>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
<maxHistory>1</maxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<append>true</append>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN2}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印INFO日志 -->
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--输出到warn-->
<appender name="warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}-%i-warn.log</fileNamePattern>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
<maxHistory>1</maxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>20MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<append>true</append>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN2}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印WARN日志 -->
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--输出到error-->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}-%i-error.log</fileNamePattern>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
<maxHistory>3</maxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<append>true</append>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN2}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印ERROR日志 -->
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为INHERITED或者同义词NULL。默认是DEBUG
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->
<root level="info">
<appender-ref ref="debug"/>
<appender-ref ref="info"/>
<appender-ref ref="warn"/>
<appender-ref ref="error"/>
</root>
<!--测试pre环境:输出到文档-->
<springProfile name="pre">
<root level="info">
<appender-ref ref="debug"/>
<appender-ref ref="info"/>
<appender-ref ref="warn"/>
<appender-ref ref="error"/>
</root>
</springProfile>
<!--4.2 生产环境:输出到文档 -->
<springProfile name="pro">
<root level="info">
<appender-ref ref="debug"/>
<appender-ref ref="info"/>
<appender-ref ref="warn"/>
<appender-ref ref="error"/>
</root>
</springProfile>
</configuration>
7.使用方式
- 复制上文 logback-spring.xml 文件到 resource文件夹下
- 修改启动脚本start.sh ,指定log.path目录即可
nohup java -Dlog.path="${logs_dir}" -Dserver.port="${port}" -Dlog.home="${logs_dir}" -Dapp.name="${appname}" -Dspring.profiles.active="${profile}" -Dspring.datasource.default.password="${pwd_ds1}" -Xms2g -Xmx2g -jar ${lib_dir}/${jarname} ${classname} > "${logs_dir}/${appname}.out" 2>&1 &