java 日誌&SpringBoot 日誌

前言

​ 工欲善其事必先利其器,首先先學會怎麼用,流利的使用,然後再去明白原理,自己創作!

​ 在項目中使用日誌的過程中,最多使用的是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。在講日誌之前,先想想如果是你,你如何寫日誌輪子。

基本需求

此處參考 《碼農翻身》,感謝 劉欣 大佬

  1. 日誌輸出到控制檯,輸出到文件,甚至可以通過郵件發出去(總不可能每時每刻都有人盯着日誌)
  2. 日誌內容可以格式化,純文本、xml、html之類的
  3. 不同的java class、package 輸出到不同的目錄
  4. 日誌分級別,有些日誌是因爲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>[email protected]</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://[email protected]/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.3log4j-to-slf4jjul-to-slf4j,也就是 jul/log4j2/logback。

Default configurations are provided for Java Util LoggingLog4J2, 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 use logback-spring.xml or define a logging.config property.

參考鏈接

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版也有出限制、評估版的。但是和正式版本的主要程序代碼都是一樣的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章