hello 大家好我是Monday,今天我们开启SpringBoot的学习的系列文章之SpringBoot日志处理。
Springboot的日志的框架比较丰富,而且Springboot本身就内置了日志功能,不过实际项目中会出现:只记录想要的日志,日志输出到磁盘,按天归档,日志信息同步到其他系统等功能。这些是Springboot本身就内置了日志功能不具备的。
logback日志SpringBoot自带的,所以依赖什么的就不用引了!首先我们在resources下面创建一个官方推荐:logback-spring.xml大家按照这个名字创建,不要其他名字。因为带spring后缀的可以使用《springProfile》这个标签而且SpringBoot会自动查找。
下面我们就以logback讲讲Spring Boot中的日志收集。
为什么要统一日志
前面我们说了Springboot 本身就可以日志功能,为什么还需要统一规范日志?
1、日志统一,方便查阅管理。
2、日志分割归档功能。
3、日志持久化功能。
4、方便日志系统(ELK)收集。
我们在resources 文件夹下创建logback-spring.xml文件,文件内容如下(来源于网络):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
| <?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds"> <contextName>logback</contextName>
<property name="log.path" value="log" />
<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}}"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> <encoder> <Pattern>${CONSOLE_LOG_PATTERN}</Pattern> <charset>UTF-8</charset> </encoder> </appender>
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}/edu_debug.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}/web-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>15</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>debug</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender>
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}/edu_info.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}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>15</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender>
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}/edu_warn.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}/web-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>15</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>warn</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}/edu_error.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}/web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>15</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender>
<springProfile name="dev"> <logger name="com.cms" level="info"/> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> </root> </springProfile>
<springProfile name="pro"> <logger name="com.cms" level="warn"/> <root level="info"> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="WARN_FILE" /> </root> </springProfile>
</configuration>
|
配置日志目录
1
| <property name="log.path" value="log" />
|
以下内容,就是我们开头所说的,带spring后缀的可以使用《springProfile》这个标签,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<springProfile name="dev"> <logger name="com.cms" level="info"/> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> </root> </springProfile>
<springProfile name="pro"> <logger name="com.cms" level="warn"/> <root level="info"> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="WARN_FILE" /> </root> </springProfile>
|
他可以区分你的不同生产环境的配置需求
配置application.properties
在application.properties或者其他使用的自定义配置文件中配置logback
1 2 3 4 5 6 7
| # # logback 配置,日志管理 #日志配置,输出到文本, logging.config=classpath:logback-spring.xml #控制台默认日志级别修改 logging.level.root=info # 指定输出日志的文件名,默认输出至当前项目目录下 logging.file.path=springboot.log
|
程序中记录日志
在项目中创建LoggingController 控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.example.demo.controller;
import com.example.demo.bases.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController @RequestMapping("/log") public class LoggingController { Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/write") public Result writeLog(){ logger.trace("这是一个trace日志"); logger.debug("这是一个debug日志"); logger.info("这是一个info日志"); logger.warn("这是一个warn日志"); logger.error("这是一个error日志"); return Result.success("write log success"); } }
|
测试
启动项目,
在浏览器输入:http://localhost:8081/log/write ,(我的项目端口已经更改)
去相关目录下查看日志文件
进一步基于slf4j封装日志类输出日志
新建package包utils,创建Log类,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| package com.example.demo.utils;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import java.util.HashMap; import java.util.Map;
public class Log { private static String logPrefix = "demo log -> "; private static Log instance; private static Logger logger = null; private static Map<Class, Logger> loggerList = new HashMap<Class, Logger>();
private Log() {
}
public synchronized static Log getInst(Object obj) {
if (instance == null) { instance = new Log(); } Log.logger = loggerList.get(obj.getClass()); if (Log.logger == null) { Log.logger = LoggerFactory.getLogger(obj.getClass()); loggerList.put(obj.getClass(), Log.logger); } return instance; }
public synchronized static Log getInst(Class clazz) {
if (instance == null) { instance = new Log(); } Log.logger = loggerList.get(clazz); if (Log.logger == null) { Log.logger = LoggerFactory.getLogger(clazz); loggerList.put(clazz, Log.logger); } return instance; }
public synchronized static Log getInst() {
if (instance == null) { instance = new Log(); } Log.logger = loggerList.get(Log.class); if (Log.logger == null) { Log.logger = LoggerFactory.getLogger(Log.class); loggerList.put(Log.class, Log.logger); } return instance; }
public void trace(String message) { Log.logger.trace(logPrefix + message); }
public void trace(String message, Throwable t) { Log.logger.trace(logPrefix + message, t); }
public void debug(String message) { Log.logger.debug(logPrefix + message); }
public void debug(String message, Throwable t) { Log.logger.debug(logPrefix + message, t); }
public void info(String message) { Log.logger.info(logPrefix + message); }
public void info(String message, Throwable t) { Log.logger.info(logPrefix + message, t); }
public void warn(String message) { Log.logger.warn(logPrefix + message); }
public void warn(String message, Throwable t) { Log.logger.warn(logPrefix + message, t); }
public void error(String message,Object... arguments) { Log.logger.error(logPrefix + message,arguments); }
public void error(String message, Throwable t, Object... arguments) { Log.logger.error(logPrefix + message,t,arguments); } }
|
在刚才的测试接口导入包
1
| import com.example.demo.utils.Log;
|
增加使用代码:
1
| Log.getInst(this).info("测试成功===============!");
|
调用接口,会发现日志写入了info文件下,封装成功
其他测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.example.demo; import com.alibaba.fastjson.JSON; import com.example.demo.utils.Log; import com.alibaba.fastjson.JSONObject; import java.util.HashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestDemo {
public static void main(String[] args) { HashMap<String,String> paramsMap=new HashMap<>(); paramsMap.put("name","哈哈"); paramsMap.put("client","Android"); paramsMap.put("id","3243598"); String jsonStr = JSONObject.toJSONString(paramsMap); System.out.println(jsonStr);
Log.getInst(TestDemo.class).info("测试成功!");
} }
|
参考文献:
1 2 3
| https://cloud.tencent.com/developer/article/1646435 https://www.w3cschool.cn/article/2632622.html https://www.w3cschool.cn/article/2632622.html
|
结束语:
今天的分享就到这里了,欢迎大家关注微信公众号”菜鸟童靴“