SpringBoot日志存储路径和设置日志格式
1、分析
1.1 需求
在开发过程这种,我们经常要调试和打印一些信息,这样的帮助和我辅助我们进行问题排查和数据的跟踪。
一般传统的方式是使用
System.out.printltn("xxxxx")
1.2 存在问题
- 仅仅只是一种控制台打印的方式。
- 不方便后续生产环境的调试和查看。
- 性能角度,存在一定性能问题。会影响方法的执行速度。虽然影响很小,但也不容小觑。
1.3 解决方案
考虑:把打印的信息写入文件中。
也就所谓的日志
2、Springboot的日志的解决方案
在springboot的底层日志结构中对应:spring-boot-starter-logging
可以看出,它依赖了三个框架分别是:
spring-boot-starter-logging
依赖已经被
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
囊括其中。
3、查看Springboot的日志的整个体系
在springboot的底层日志结构中对应:spring-boot-starter-logging
可以看出,它依赖了三个框架分别是:
- slf4j
- logback
- log4j
4、slf4j、logback和log4j三者的关系
- logback和log4j是日志实现框架,就是实现怎么记录日志的。
- slf4j:提供了java所有的日志框架的简单抽象(使用了日志的门面设计模式),说白了就是一个日志API(
没有实现类
), 它不能单独使用;必须要结合logback和log4j日志框架来实现结合使用。
5、springboot的日志搭配
springboot2.x以后默认采用了:slf4j+logback的日志搭配。
在开发过程中,我们可以采用slf4j的api去记录日志,底层的实现就是根据配置来决定使用logback还是log4j日志框架。
5.1 样例
package com.example.controller;
import com.example.service.WeiXinPayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
// 初始化一个日志对象
private static final Logger log = LoggerFactory.getLogger(IndexController.class);
@Autowired
private WeiXinPayService weixinPayService;
@GetMapping("/index")
public String test(){
weixinPayService.testValue();
console();
return "success";
}
// 打印日志
@GetMapping("/log")
public void console(){
log.trace("----------trace--------");
log.debug("----------debug--------");
log.info("----------info--------");
log.warn("----------warn--------");
log.error("----------error--------");
}
}
5.2 核心代码
// 初始化一个日志对象
private static final Logger log = LoggerFactory.getLogger(IndexController.class);
5.3 打印结果
2021-07-20 10:06:50.962(日志时间) INFO(日志级别) 15780(编号) --- [p-nio-80-exec-1](线程名) com.example.controller.IndexController(日志打印类) : ----------info--------(日志信息)
2021-07-20 10:06:50.963 WARN 15780 --- [p-nio-80-exec-1] com.example.controller.IndexController : ----------warn--------
2021-07-20 10:06:50.963 ERROR 15780 --- [p-nio-80-exec-1] com.example.controller.IndexController : ----------error--------
上面为什么仅仅打印了: info > warn > error
springboot默认日志级别是:info
5.4 日志级别
log.trace("----------trace--------");
log.debug("----------debug--------");
log.info("----------info--------");
log.warn("----------warn--------");
log.error("----------error--------");
顺序:trace>debug>info>warn>error
5.5 小结
springboot默认日志级别是:info
springboot2.x以后默认采用了:slf4j+logback的日志搭配。
日志级别:trace>debug>info>warn>error
6、日志级别的修改
springboot、mybatis、hibernate这些框架都是采用日志管理信息的打印
整体修改:
# 指定日志级别 把springboot的所有日志修改成为debug
logging:
level:
root: debug
局部修改:
# 指定日志级别 把springboot的指定日志修改成为debug
logging:
level:
com:
exmaple: debug
7、日志输出文件和日志格式
7.1 日志输出文件
默认情况:springboot日志打印是在console(控制台中),开发和查看。建议在开发时使用:debug日志,在生成环境中使用:error 。
日志输出文件:默认情况下关闭。
在开发中建议打开,不打开也没有关系,可以项目的发布制定日志输出文件:
nohup java -jar xxxx.jar >>log.txt &
使用path
的方式
path: output/logs
默认情况下:会在项目的根目录下生成/output/logs/spring.log, 默认的日志名是: spring. log
如果不想把日志存放在logging. file. path目录下,可以采用name 来重新定义存储的位置和日志文件的名称
name: D:/output/logs/console.log
7.2 日志格式
logging:
level:
root: debug
logging:
level:
com:
example: debug
file:
path: output/log
name: D:/ouput/logs/console.log
pattern:
console: "%d{yyyy/MM/ dd-HH: mm:ss} [%thread] %-5level %Logger{50}- %msg%n"
file: "%d{yyyy/MM/ dd-HH:mm:ss} ---- [%thread] %-5level %Logger{50}- %msg%n"
%c 输出logger名称
%C 输出类名
%d{HH:mm:ss.SSS} 表示输出到毫秒的时间
%t 输出当前线程名称
%-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
%logger 输出logger名称,因为Root Logger没有名称,所以没有输出
%msg 日志文本
%n 换行
其他常用的占位符有:
%F 输出所在的类文件名,如Log4j2Test.java
%L 输出行号
%M或%method 输出所在方法名
%l 输出完整的错误位置, 包括类名、方法名、文件名、行数
%p 该条日志的优先级
%replace{pattern}{regex}{substitution} 将pattern的输出结果pattern按照正则表达式regex替换成substitution
一般不建议修改,除非有特殊场景
8、日志的使用方式和注意事项
8.1 日志使用
package com.example.controller;
import com.example.entity.Course;
import com.example.entity.User;
import com.example.service.WeiXinPayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
// 初始化一个日志对象
private static final Logger log = LoggerFactory.getLogger(IndexController.class);
@Autowired
private WeiXinPayService weixinPayService;
@GetMapping("/index")
public String test(){
User user = new User();
user.setId(120);
Course course = new Course();
course.setCourseName("高数");
course.setPrice("$120");
weixinPayService.testValue(user, course);
return "success";
}
}
8.2 具体实现
package com.example.service;
import com.example.config.WeixinPayProperties;
import com.example.entity.Course;
import com.example.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class WeiXinPayService {
private static Logger log = LoggerFactory.getLogger(WeixinPayProperties.class);
@Autowired
private WeixinPayProperties weixinPayProperties;
public void testValue(User user, Course course){
try {
log.info("当前支付用户:{},课程:{},金额:{}", user.getId(), course.getCourseName(), course.getPrice());
log.info("当前支付appId:{},回调地址:{}", weixinPayProperties.getAppId(),weixinPayProperties. getCallbackUrl());
} catch (Exception e) {
log.error("支付出现异常,异常信息是:{}", e.getMessage());
}
}
}
8.3 实现结果
9、lombok优化日志的定义
在lombok中提供了两个日志注解的支持:@Slf4j
和@Log4j2
建议在开发过程中默认选择:@Slf4j
前提:必须要安装lombok的插件和依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
package com.example.service;
import com.example.config.WeixinPayProperties;
import com.example.entity.Course;
import com.example.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
@Slf4j // 相当于: private static Logger log = LoggerFactory.getLogger(WeixinPayService.class);
public class WeiXinPayService {
@Autowired
private WeixinPayProperties weixinPayProperties;
public void testValue(User user, Course course){
try {
log.info("当前支付用户:{},课程:{},金额:{}", user.getId(), course.getCourseName(), course.getPrice());
log.info("当前支付appId:{},回调地址:{}", weixinPayProperties.getAppId(),weixinPayProperties. getCallbackUrl());
} catch (Exception e) {
log.error("支付出现异常,异常信息是:{}", e.getMessage());
}
}
}
编译后结果:
10、在开发中日志级别隔离
在开发中,分为生成环境和开发环境。
开发环境级别一般建议使用:debug
或info
。但在生产环境中建议使用:error
可以使用环境隔离的机制,进行解决
10.1 application-dev.yml
开发环境:一般在控制台打印即可。
日志级别:debug
server:
port: 80
#自定义属性
ksd:
weixin:
appid: 456453sdfsd52342
mcid: 48878787
callbackurl: https://www.train.com
apisecret: SDFLKSDJFKLSJKLJ23423423
# 指定日志级别 把springboot的所有日志修改成为debug
logging:
level:
root: debug
pattern:
# console是控制台的日志的格式
console: "【exmaple-console】%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger{50} --%M- %msg%n"
10.2 application-prod.yml
生产环境:输出到文件。
日志级别:error
server:
port: 9999
# 指定日志级别 把springboot的所有日志修改成为error
logging:
level:
root: error
file:
# 如果不想把日志存放在logging.file.path目录下,可以采用name来重新定义存储的位置和日志文件的名称
name: /www/logs/exmaple.log
pattern:
# file 是指日志文件中日志的格式
file: "【KuangStudy-file】%d{yyyy/MM/dd-HH:mm:ss} -- [%thread] %-5level %logger{50} -- %M - %msg%n"
10.3 application.yml
# 环境激活
spring:
profiles:
active: dev