前言
工欲善其事必先利其器,首先先学会怎么用,流利的使用,然后再去明白原理,自己创作!
在项目中使用日志的过程中,最多使用的是log4j,在阿里巴巴JAVA开发手册 中异常日志 -> 日志处理中看到这样一句话
1.**【强制】**应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
logback我知道,那个 SLF4 是啥。本文重点搞清楚这两个
发展史
为什么要有日志
要知道程序运行起来之后就是一个黑盒子,你看不到处理的过程,一旦发生错误没发定位,也就不知道从何解决。定位问题只能是debug一步一步跟着,这显然在已经上生产环境的正式对外公布使用的环境下不太适合。
那么之前,在log4j没有诞生之前,用啥记录日志。说到这里你还记得你的第一次Hello world吗?
System.out.println("Hello world");
System.out.println() 把日志都输出到控制台,然后你的控制台里面乱七八糟的JDK 1.3及之前没有日志的。。。然后 大神就自己造了轮子 log4j。在讲日志之前,先想想如果是你,你如何写日志轮子。
基本需求
此处参考 《码农翻身》,感谢 刘欣 大佬
- 日志输出到控制台,输出到文件,甚至可以通过邮件发出去(总不可能每时每刻都有人盯着日志)
- 日志内容可以格式化,纯文本、xml、html之类的
- 不同的java class、package 输出到不同的目录
- 日志分级别,有些日志是因为bug,有些是调试需要
log4j
首先log4j 意思是 log for java(总是有人说 log 四 j 就感觉很难受)。log4j 从1996年初开始,作为EU SEMPER(欧洲安全电子市场)项目的跟踪API,他比java的 java.util.logging 出现的早。
log4j 经过无数的增强和体现,最初的API演变为log4j,这是Java的流行日志记录程序包
该软件包根据Apache Software License(Apache软件许可)进行分发
如果你有兴趣可以详细研究一下 tutorials log4j。本文这里直接简单的介绍一下。
优点
- 这是线程安全的。
- 它针对速度进行了优化。
- 它基于命名的记录器层次结构。
- 每个记录器支持多个输出附加程序。
- 它支持国际化。
- 它不限于一组预定义的设施。
- 可以在运行时使用配置文件设置日志记录行为。
- 它旨在从一开始就处理Java异常。
- 它使用多个级别,即ALL,TRACE,DEBUG,INFO,WARN,ERROR和FATAL。
- 通过扩展Layout类,可以轻松更改日志输出的格式。
- 日志输出的目标以及写入策略可以通过Appender接口的实现来更改。
- 这是失败停止。但是,尽管log4j肯定会努力确保交付,但并不能保证每个log语句都将交付到其目的地。
java.util.logging
java官方也出了记录log的工具类,那么就会有人用,那领导要求把log4j改成 jul ( java.util.logging)怎么搞
log4j的方式
import org.apache.log4j.Logger;
Logger logger = Logger.getLogger(Test.class);
logger.trace("trace");
jul的方式
import java.util.logging.Logger;
Logger loggger = Logger.getLogger(Test.class.getName());
logger.finest("finest");
老板要求改,怎么该,一个个改,费死劲了。这个时候春天出现了 Apache Commons Logging
Apache Commons Logging
Apache Commons Logging(之前叫 Jakarta Commons Logging 简称 JCL)。apache出品必属精品。jcl运用了抽象大法,码农用jcl的api,由jcl取调用实际的日志记录(slf4j 或是 jul),这样敲代码的负担就减轻了好多。但是log4j的作者觉得不好使,然后开发了个SLF4J。
SLF4J
The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time.
Simple Logging Facade for Java 就是他的简称。至于他怎么用,如下
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
// 官方建议 logger 为实例变量 而不是静态变量 https://www.slf4j.org/faq.html#declared_static
private Logger logger = LoggerFactory.getLogger(HelloWorld.class);
public static void main(String[] args) {
logger.info("Hello World");
}
}
谨记,SLF4J是日志记录框架的抽象,意思是他就是一个api,至于实际用什么日志框架logback或者是log4j那是你的选择!
官方推荐了一种快速记录日志的方案,因为本文最主要围绕slf4j,所以这里多说一点。通常我记录日志的方式是这种:
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
- 但是这种方式会产生和记录日志无关的开销 entry[i] 强转为String 然后是拼接字符串
推荐的方式是这样,使用占位符 {} ,想要获得更多你可以参考官网
Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
logger.debug("Value {} was inserted between {} and {}.", newVal, below, above);
或者你可以换个姿势,它和上面操作是等价的
logger.atDebug().addArgument(newT).addArgument(oldT).log("Temperature set to {}. Old temperature was {}.");
logback
至于logback是log4j的升级版,它也是log4j的作者开发的。在某些关键执行路径上的执行速度快大约十倍。Logback组件不仅速度更快,而且内存占用也较小。
Logback is intended as a successor to the popular log4j project, picking up where log4j leaves off.
logback分为三个模块
-
logback-core 为其他两个模块奠定了基础
-
logback-classic log4j的改进版本 原生实现了SLF4J API
-
logback-access 与Servlet容器(例如Tomcat和Jetty)集成,以提供HTTP访问日志功能
首先先学习slf4j和logback的组合,关于logback目前不需要了解更多,因为调用的是slf4j,具体如何调用logback由slf4j帮你解决。
Demo
slf4j+logback
slf4j可以理解为接口,它本身是不知道你实现日志的框架是log4j还是logback,需要你告诉它,理论上来说需要告诉pom logback和slf4j。
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
slf4j pom坐标从maven仓库获取
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bNvs9xsZ-1569742787865)(C:\Users\ADMINI~1\AppData\Local\Temp\1569548393230.png)]
宝宝不懂啥是 alpha0、啥是beta,可以参考下文 pom坐标中beta是啥意思,这里我们用
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
从2.0.0版本开始, SLF4J API版本2.0.0需要Java 8
SpringBoot默认
但是,需要注意一点 springboot已经默认引入了spring-boot-starter-logging
,在 pom中
,你可以使用idea,打开你的POM,按住 ctrl
键,鼠标左键点击 spring-boot-starter-parent
, 进入 spring-boot-starter-parent-2.1.8.RELEASE.pom
中后,再次点击 spring-boot-dependencies
,进入 spring-boot-dependencies-2.1.8RELEASE.pom
找到 spring-boot-starter-logging
当然也可以再次点击进入看看spring-boot-starter-logging
引入了什么,或者看下面这段代码:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>2.1.8.RELEASE</version>
</parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.1.8.RELEASE</version>
<name>Spring Boot Logging Starter</name>
<description>Starter for logging using Logback. Default logging starter</description>
<url>https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-logging</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>https://spring.io</url>
</organization>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
<developers>
<developer>
<name>Pivotal</name>
<email>info@pivotal.io</email>
<organization>Pivotal Software, Inc.</organization>
<organizationUrl>https://www.spring.io</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/spring-projects/spring-boot.git/spring-boot-starters/spring-boot-starter-logging</connection>
<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-boot.git/spring-boot-starters/spring-boot-starter-logging</developerConnection>
<url>https://github.com/spring-projects/spring-boot/spring-boot-starters/spring-boot-starter-logging</url>
</scm>
<issueManagement>
<system>Github</system>
<url>https://github.com/spring-projects/spring-boot/issues</url>
</issueManagement>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.11.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.28</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
SpringBoot默认引入了logback-classic 1.2.3
、log4j-to-slf4j
、jul-to-slf4j
,也就是 jul/log4j2/logback。
Default configurations are provided for Java Util Logging, Log4J2, and Logback.
这意味着,你不需要在你的pom中引入日志配置。直接启动项目,显示如下输出
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.8.RELEASE)
2019-09-29 10:41:26.689 INFO 1364 --- [ main] com.example.logt.demo.DemoApplication : Starting DemoApplication on BD9V0KF8N5N9WFV with PID 1364 (F:\workspace\exampleProject\test\logt\target\classes started by Administrator in F:\workspace\exampleProject\test\logt)
2019-09-29 10:41:26.691 INFO 1364 --- [ main] com.example.logt.demo.DemoApplication : No active profile set, falling back to default profiles: default
2019-09-29 10:41:27.936 INFO 1364 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-09-29 10:41:27.959 INFO 1364 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-09-29 10:41:27.959 INFO 1364 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.24]
2019-09-29 10:41:28.053 INFO 1364 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-09-29 10:41:28.053 INFO 1364 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1324 ms
2019-09-29 10:41:28.299 INFO 1364 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-09-29 10:41:28.475 INFO 1364 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-09-29 10:41:28.478 INFO 1364 --- [ main] com.example.logt.demo.DemoApplication : Started DemoApplication in 2.348 seconds (JVM running for 6.558)
彩色的日志
如果你的控制台支持 ANSI,输出的日志默认为彩色的。
日志输出到文件
默认情况下输出到控制台不输出到文件。 可以直接在application.properties
配置
logging.path=/logs
logging.file=testlog.log
这样输出的日志文件就到了项目的根目录。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
private static Logger logger = LoggerFactory.getLogger(DemoApplication.class);
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
logger.info("我是测试的");
}
}
启动项目,发现项目根目录生成日志文件
*****
2019-09-29 15:13:31.073 INFO 11788 --- [main] com.example.logt.demo.DemoApplication : No active profile set, falling back to default profiles: default
2019-09-29 15:13:32.062 INFO 11788 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-09-29 15:13:32.084 INFO 11788 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-09-29 15:13:32.085 INFO 11788 --- [main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.24]
2019-09-29 15:13:32.486 INFO 11788 --- [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-09-29 15:13:32.486 INFO 11788 --- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1353 ms
2019-09-29 15:13:32.669 INFO 11788 --- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-09-29 15:13:32.838 INFO 11788 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-09-29 15:13:32.841 INFO 11788 --- [main] com.example.logt.demo.DemoApplication : Started DemoApplication in 2.276 seconds (JVM running for 3.067)
2019-09-29 15:13:32.842 INFO 11788 --- [main] com.example.logt.demo.DemoApplication : 我是测试的
项目的日志文件生成是很频繁的,且默认输出ERROR
-level,WARN
-level和INFO
-level消息到文件,这里我们需要改一下,修改application.properties
增加
# 这里的 com.example.logt 是我的测试项目的包名
logging.level.com.example.logt=debug
# 这里是指的单个日志文件最大大小 默认为10MB
logging.file.max-size=20MB
# 这里是日志文件最长保存天数 不配置的话为无限制 永远存储 单位为天
logging.file.max-history=15
至于为什么保存15天,请参考阿里巴巴JAVA开发手册。
SpringBoot配置
Spring Environment | System Property | Comments |
---|---|---|
logging.exception-conversion-word | LOG_EXCEPTION_CONVERSION_WORD | The conversion word used when logging exceptions. |
logging.file | LOG_FILE | If defined, it is used in the default log configuration. |
logging.file.max-size | LOG_FILE_MAX_SIZE | Maximum log file size (if LOG_FILE enabled). (Only supported with the default Logback setup.) |
logging.file.max-history | LOG_FILE_MAX_HISTORY | Maximum number of archive log files to keep (if LOG_FILE enabled). (Only supported with the default Logback setup.) |
logging.path | LOG_PATH | If defined, it is used in the default log configuration. |
logging.pattern.console | CONSOLE_LOG_PATTERN | The log pattern to use on the console (stdout). (Only supported with the default Logback setup.) |
logging.pattern.dateformat | LOG_DATEFORMAT_PATTERN | Appender pattern for log date format. (Only supported with the default Logback setup.) |
logging.pattern.file | FILE_LOG_PATTERN | The log pattern to use in a file (if LOG_FILE is enabled). (Only supported with the default Logback setup.) |
logging.pattern.level | LOG_LEVEL_PATTERN | The format to use when rendering the log level (default %5p ). (Only supported with the default Logback setup.) |
PID | PID | The current process ID (discovered if possible and when not already defined as an OS environment variable). |
日志分级别输出
日志按照 TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF 级别进行输出,需要另行配置logback.xml。重要的是你应该将你的配置文件的名字改为 logback-spring.xml
。
Because the standard
logback.xml
configuration file is loaded too early, you cannot use extensions in it. You need to either uselogback-spring.xml
or define alogging.config
property.
参考链接
- https://www.cnblogs.com/rjzheng/p/10042911.html
- https://www.cnblogs.com/caoweixiong/p/11285748.html
- https://docs.spring.io/spring-boot/docs/2.1.8.RELEASE/reference/html/boot-features-logging.html
pom 坐标中 beta是啥意思
参考链接 https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8903
Alpha:是内部测试版,一般不向外部发布,会有很多Bug.一般只有测试人员使用。
Beta:也是测试版,这个阶段的版本会一直加入新的功能。在Alpha版之后推出。
RC:(Release Candidate) 顾名思义么 ! 用在软件上就是候选版本。系统平台上就是发行候选版本。RC版不会再加入新的功能了,主要着重于除错。
GA:General Availability,正式发布的版本,在国外都是用GA来说明release版本的。
RTM:(Release to Manufacture)是给工厂大量压片的版本,内容跟正式版是一样的,不过RTM版也有出限制、评估版的。但是和正式版本的主要程序代码都是一样的。