一、日志的作用
程序中的日志是记录程序的运行情况,包括用户的各种操作、程序的运行状态等信息。类似于飞机的黑匣子。
二、日志的级别
表:日志级别及其描述
日志级别 | 描述 |
OFF | 关闭:不输出日志 |
FATAL | 致命:用于输出可能会导致应用程序终止的错误 |
ERROR | 错误:用于输出程序的错误(这些错误不会导致程序崩溃) |
WARN | 警告:用于输出警告信息,提示可能出现的问题 |
INFO | 信息:用于输出程序运行过程的详细信息 |
DEBUG | 调试:用于输出调试应用有用的信息 |
TRACE | 跟踪:用于输出更细致的程序运行轨迹 |
ALL | 所有:用于输出所有级别的信息 |
常用日志级别:
我们在日常使用中的常用日志级别是DEBUG、INFO、WARN、ERROR。
ERROR
ERROR级别虽然不至于程序立刻奔溃,但是也影响了用户的正常使用了,当出现这个级别的日志的时候我们应该立即处理。
WARN
WARN级别的日志通常用来记录用户操作不当,或者网络不稳定而出现的非预期情况。
INFO
INFO是默认的日志级别,用来记录程序的正常运行记录。
DEBUG
DEBUG级别的日志会非常详细的输出程序的运行情况。但是这个级别过多的日志输出会严重消耗资源,影响程序性能。
三、日志配置
我们的日志配置主要有两种方式:一种是直接在application.yml文件中配置,另外一种是在外置logback-spring.xml文件中配置。
2023-07-24 15:09:42.580 INFO 7532 --- [nio-8080-exec-5] c.e.f.exception.GlobalExceptionHandler : 全局异常处理...
可以看到,默认的情况下一条日志由下面几个部分组成。
日期时间
日志级别
进程ID
--分隔符
[xxx]线程名
类路径
日志消息
application.yml文件配置方式:
#自定义日志配置
logging.pattern.console="%d - %m"%n
控制台输出了我们自定义的日志格式
"2023-07-24 15:20:38,322 - Tomcat started on port(s): 8080 (http) with context path ''"
"2023-07-24 15:20:38,333 - Started FunlyDemoApplication in 4.744 seconds (JVM running for 6.767)"
"2023-07-24 15:20:44,923 - Initializing Spring DispatcherServlet 'dispatcherServlet'"
"2023-07-24 15:20:44,923 - Initializing Servlet 'dispatcherServlet'"
"2023-07-24 15:20:44,924 - Completed initialization in 1 ms"
"2023-07-24 15:20:44,949 - info日志..."
logback-spring.xml文件配置方式:
<?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="10 seconds">
<contextName>logback</contextName>
<!-- 4. 最终的策略 -->
<!-- 4.1 开发环境:打印控制台-->
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<property name="log.path" value="./dzzh_logs"/>
<!--指定对应环境的日志的地址,下面的会覆盖上面的-->
<springProfile name="dev">
<logger name="com" level="debug"/>
<logger name="spepc" level="debug"/>
</springProfile>
<!--指定对应环境的日志的地址,下面的会覆盖上面的-->
<springProfile name="test">
<property name="log.path" value="D:/spepc_iot_test/dzzh_logs_test"/>
<logger name="com" level="info"/>
<logger name="org" level="info"/>
<logger name="spepc" level="info"/>
</springProfile>
<!--指定对应环境的日志的地址,下面的会覆盖上面的-->
<springProfile name="prod">
<property name="log.path" value="./dzzh_logs_prod"/>
<logger name="spepc" level="info"/>
<logger name="com" level="info"/>
</springProfile>
<springProfile name="yongzhou">
<property name="log.path" value="./dzzh_logs_yongzhou"/>
<logger name="spepc" level="info"/>
<logger name="com" level="info"/>
</springProfile>
<!--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_PATTERN"
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}}"/>
<!--1. 输出到控制台-->
<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_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--2. 输出到文档-->
<!-- 2.1 level为 CONSOLE_FILE 日志,时间滚动输出 -->
<appender name="CONSOLE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/console.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/console-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="SySErr" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/sysErr.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/sysErr-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="Protocol" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator
class="ch.qos.logback.classic.boolex.JaninoEventEvaluator"> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>logger.contains("Protocol")</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/protocol.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/protocol-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="Mqtt" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator
class="ch.qos.logback.classic.boolex.JaninoEventEvaluator"> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>logger.contains("Mqtt")</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/mqtt.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/mqtt-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="rocketmq" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator
class="ch.qos.logback.classic.boolex.JaninoEventEvaluator"> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>logger.contains("rocketmq")</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/rocketmq.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/rocketmq-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="Unistrong" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator
class="ch.qos.logback.classic.boolex.JaninoEventEvaluator"> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>logger.contains("Unistrong")</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/unistrong.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/unistrong-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="Paiguang" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator
class="ch.qos.logback.classic.boolex.JaninoEventEvaluator"> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>logger.contains("Paiguang")</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/paiguang.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/paiguang-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="RocketmqClientAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/rocketmq_client.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/rocketmq_client.log.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<TimeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<MaxFileSize>30MB</MaxFileSize>
</TimeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>%d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0} %X{ServiceId} - %m%n</pattern>
</encoder>
</appender>
<logger name="RocketmqClient" additivity="false">
<level value="info" />
<appender-ref ref="RocketmqClientAppender"/>
</logger>
<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="CONSOLE_FILE"/>
<appender-ref ref="Protocol"/>
<appender-ref ref="rocketmq"/>
<appender-ref ref="SySErr"/>
<appender-ref ref="Unistrong"/>
<appender-ref ref="Paiguang"/>
</root>
<springProfile name="prod">
<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="CONSOLE_FILE"/>
<appender-ref ref="Protocol"/>
<appender-ref ref="rocketmq"/>
<appender-ref ref="SySErr"/>
<appender-ref ref="Unistrong"/>
<appender-ref ref="Paiguang"/>
</root>
</springProfile>
</configuration>
我们配置了日志的输出路径、日志输出格式、日志保留时间和日志文件大小等。还可以根据不同的环境使用不同的日志配置。
四、日志规范
使用占位符:
log.info("username:{},password:{}","admin","123456");
控制台输出:
2023-07-24 15:36:28.571 INFO 8876 --- [ main] c.e.funlydemo.FunlyDemoApplicationTests : username:admin,password:123456
完整的堆栈信息:
log.error("发生错误:{}",e.getMessage(),e);
正确的使用日志级别:
对于普通的日志记录我们需要INFO级别,而对于错误异常的日志我们不能使用INFO级别日志。
使用Lombok自带的@Slf4j注解
我们使用这个注解可以规范我们的日志书写。