真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java 日志框架學(xué)習(xí)筆記

日志概念

1. 日志文件

日志文件是用于記錄系統(tǒng)操作事件的文件集合

創(chuàng)新互聯(lián)主營赫山網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP開發(fā)公司,赫山h5小程序開發(fā)搭建,赫山網(wǎng)站營銷推廣歡迎赫山等地區(qū)企業(yè)咨詢

1.1 調(diào)試日志
1.2 系統(tǒng)日志

系統(tǒng)日志是記錄系統(tǒng)中硬件、軟件和系統(tǒng)問題的信息,同時還可以監(jiān)視系統(tǒng)中發(fā)生的事件。用戶可以通過它來檢查錯誤發(fā)生的原因,或者尋找受到攻擊時攻擊者留下的痕跡


日志門面

當(dāng)我們的系統(tǒng)變的更加復(fù)雜的時候,我們的日志就容易發(fā)生混亂。隨著系統(tǒng)開發(fā)的進(jìn)行,可能會更新不同的日志框架,造成當(dāng)前系統(tǒng)中存在不同的日志依賴,讓我們難以統(tǒng)一的管理和控制。所以我們需要借鑒 JDBC 的思想,為日志系統(tǒng)也提供一套門面,那么我們就可以面向這些接口規(guī)范來開發(fā),避免了直接依賴具體的日志框架。這樣我們的系統(tǒng)在日志中,就存在了日志的門面和日志的實(shí)現(xiàn)

常見的日志門面:JCL、Slf4j

常見的日志實(shí)現(xiàn):JUL、log4j、logback、log4j2

日志門面和日志實(shí)現(xiàn)的關(guān)系:

使用日志門面的優(yōu)勢:

  • 面向接口開發(fā),不再依賴具體的實(shí)現(xiàn)類,減少代碼的耦合
  • 項(xiàng)目通過導(dǎo)入不同的日志實(shí)現(xiàn)類,可以靈活的切換日志框架
  • 統(tǒng)一 API,方便開發(fā)者學(xué)習(xí)和使用
  • 統(tǒng)一配置便于項(xiàng)目日志的管理

JUL

JUL(Java util Logging)是 Java 原生的日志實(shí)現(xiàn)框架,使用時不需要另外引用第三方類庫,相對其他日志框架使用方便,學(xué)習(xí)簡單,能夠在小型應(yīng)用中靈活使用

1. 架構(gòu)

  • Loggers:記錄器,應(yīng)用程序通過獲取 Logger 對象,調(diào)用其 API 來發(fā)布日志信息
  • Appenders:也稱為 Handlers,每個 Logger 都會關(guān)聯(lián)一組 Handlers,Logger 會將日志交給關(guān)聯(lián) Handlers 處理,由 Handlers 負(fù)責(zé)將日志做記錄。Handlers 在此是一個抽象,其具體的實(shí)現(xiàn)決定了 日志記錄的位置可以是控制臺、文件、網(wǎng)絡(luò)上的其他日志服務(wù)或操作系統(tǒng)日志等
  • Layouts:也稱為 Formatters,它負(fù)責(zé)對日志事件中的數(shù)據(jù)進(jìn)行轉(zhuǎn)換和格式化。Layouts 決定了數(shù)據(jù)在一條日志記錄中的最終形式
  • Level:每條日志消息都有一個關(guān)聯(lián)的日志級別,該級別粗略指導(dǎo)了日志消息的重要性和緊迫,可以將Level 和 Loggers、Appenders 做關(guān)聯(lián)以便于我們過濾消息
  • Filters:過濾器,根據(jù)需要定制哪些信息會被記錄,哪些信息會被放過

總結(jié)一下就是:

  • 用戶使用 Logger 來進(jìn)行日志記錄,Logger 持有若干個 Handler,日志的輸出操作是由 Handler 完成的
  • Handler 在輸出日志前,會經(jīng)過 Filter 的過濾,判斷哪些日志級別過濾放行哪些攔截,Handler 會將日志內(nèi)容輸出到指定位置(日志文件、控制臺等)
  • Handler 在輸出日志時會使用 Layout,將輸出內(nèi)容進(jìn)行排版

2. 入門案例

public class JULTest {
    
    @Test
    public void testQuick() throws Exception {
        // 1.創(chuàng)建日志記錄器對象
        Logger logger = Logger.getLogger("com.itheima.log.JULTest");
        // 2.日志記錄輸出
        logger.info("hello jul");
        logger.log(Level.INFO, "info msg");
        String name = "jack";
        Integer age = 18;
        logger.log(Level.INFO, "用戶信息:{0},{1}", new Object[]{name, age});
    }
}

3. 日志級別

JUL 中定義的日志級別:SEVERE(最高值)、WARNING、INFO(默認(rèn)級別)、CONFIG、FINE、FINER、FINEST(最低值)

還有兩個特殊的級別:OFF,可用來關(guān)閉日志記錄、ALL,啟用所有消息的日志記錄

@Test
public void testLogLevel() throws Exception {
    // 1.獲取日志對象
    Logger logger = Logger.getLogger("com.itheima.log.QuickTest");
    // 2.日志記錄輸出
    logger.severe("severe");
    logger.warning("warning");
    logger.info("info");
    logger.config("cofnig");
    logger.fine("fine");
    logger.finer("finer");
    logger.finest("finest");
}

雖然我們測試了 7 個日志級別,但是默認(rèn)只實(shí)現(xiàn) info 以上的級別,info 以下不會輸出,我們可以自定義日志級別配置

@Test
public void testLogConfig() throws Exception {
    
    // 創(chuàng)建日志記錄器對象
    Logger logger = Logger.getLogger("com.itheima.log.JULTest");
    
    // 一、自定義日志級別
    // a.關(guān)閉系統(tǒng)默認(rèn)配置
    logger.setUseParentHandlers(false);
    // b.創(chuàng)建handler對象
    ConsoleHandler consoleHandler = new ConsoleHandler();
    // c.創(chuàng)建formatter對象
    SimpleFormatter simpleFormatter = new SimpleFormatter();
    // d.進(jìn)行關(guān)聯(lián)
    consoleHandler.setFormatter(simpleFormatter);
    logger.addHandler(consoleHandler);
    // e.設(shè)置日志級別
    logger.setLevel(Level.ALL);
    consoleHandler.setLevel(Level.ALL);
    
    // 二、輸出到日志文件
    FileHandler fileHandler = new FileHandler("d:/logs/jul.log");
    fileHandler.setFormatter(simpleFormatter);
    
    // 日志記錄輸出
    logger.severe("severe");
    logger.warning("warning");
    logger.info("info");
    logger.config("config");
    logger.fine("fine");
    logger.finer("finer");
    logger.finest("finest");
}

4. logger 之間的父子關(guān)系

JUL 中 Logger 之間存在父子關(guān)系,這種父子關(guān)系通過樹狀結(jié)構(gòu)存儲,JUL 在初始化時會創(chuàng)建一個頂層 RootLogger 作為所有 Logger 父 Logger,存儲上作為樹狀結(jié)構(gòu)的根節(jié)點(diǎn),父子關(guān)系通過包路徑來關(guān)聯(lián)

@Test
public void testLogParent() throws Exception {
    
    // 日志記錄器對象父子關(guān)系
    Logger logger1 = Logger.getLogger("com.itheima");
    Logger logger2 = Logger.getLogger("com");
    // true
    System.out.println(logger1.getParent() == logger2);
    
    // 所有日志記錄器對象的頂級父元素 class 為 java.util.logging.LogManager$RootLogger
    // logger2 parent:java.util.logging.LogManager$RootLogger,name:
    System.out.println("logger2 parent:" + logger2.getParent() + ",name" +
    logger2.getParent().getName());
    
    // 一、自定義日志級別
    // a.關(guān)閉系統(tǒng)默認(rèn)配置
    logger2.setUseParentHandlers(false);
    // b.創(chuàng)建handler對象
    ConsoleHandler consoleHandler = new ConsoleHandler();
    // c.創(chuàng)建formatter對象
    SimpleFormatter simpleFormatter = new SimpleFormatter();
    // d.進(jìn)行關(guān)聯(lián)
    consoleHandler.setFormatter(simpleFormatter);
    logger2.addHandler(consoleHandler);
    // e.設(shè)置日志級別
    logger2.setLevel(Level.ALL);
    consoleHandler.setLevel(Level.ALL);
    
    // 測試日志記錄器對象父子關(guān)系,這里會全部輸出,因?yàn)閘ogger1繼承l(wèi)ogger2的級別配置
    logger1.severe("severe");
    logger1.warning("warning");
    logger1.info("info");
    logger1.config("config");
    logger1.fine("fine");
    logger1.finer("finer");
    logger1.finest("finest");
}

5. 日志的配置文件

默認(rèn)配置文件路徑 $JAVAHOME\jre\lib\logging.properties

@Test
public void testProperties() throws Exception {
    // 讀取自定義配置文件
    InputStream in = JULTest.class.getClassLoader().getResourceAsStream("logging.properties");
    // 獲取日志管理器對象
    LogManager logManager = LogManager.getLogManager();
    // 通過日志管理器加載配置文件
    logManager.readConfiguration(in);
    Logger logger = Logger.getLogger("com.itheima.log.JULTest");
    logger.severe("severe");
    logger.warning("warning");
    logger.info("info");
    logger.config("config");
    logger.fine("fine");
    logger.finer("finer");
    logger.finest("finest");
}

配置文件:

## RootLogger使用的處理器(獲取時設(shè)置)
handlers= java.util.logging.ConsoleHandler
# RootLogger日志等級
.level= INFO

# 自定義Logger
com.itheima.handlers= java.util.logging.FileHandler
# 自定義Logger日志等級
com.itheima.level= INFO
# 忽略父日志設(shè)置
com.itheima.useParentHandlers=false

## 控制臺處理器
# 輸出日志級別
java.util.logging.ConsoleHandler.level = ALL
# 輸出日志格式
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# 指定handler對象的字符集
java.util.logging.ConsoleHandler.encoding = UTF-8

# 指定日志消息格式
java.util.logging.SimpleFormatter.format = %4$s: %5$s [%1$tc]%n

## 文件處理器
# 輸出日志級別
java.util.logging.FileHandler.level=INFO
# 輸出日志格式
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
# 輸出日志文件路徑
# /logs/java0.log
java.util.logging.FileHandler.pattern = /logs/java%u.log
# 輸出日志文件限制大小(50000字節(jié))
java.util.logging.FileHandler.limit = 50000
# 輸出日志文件限制個數(shù)
java.util.logging.FileHandler.count = 10
# 輸出日志文件是否是追加
java.util.logging.FileHandler.append=true

6. 日志原理解析

  1. 初始化 LogManager
    • LogManager 加載 logging.properties 配置
    • 添加 Logger 到 LogManager
  2. 從單例 LogManager 獲取 Logger
  3. 設(shè)置級別 Level,并指定日志記錄 LogRecord
  4. Filter 提供了日志級別之外更細(xì)粒度的控制
  5. Handler 是用來處理日志輸出位置
  6. Formatter 是用來格式化 LogRecord 的

Log4J

Log4j 是Apache 下的一款開源的日志實(shí)現(xiàn)框架,通過在項(xiàng)目中使用 Log4J,我們可以控制日志信息輸出到控制臺、文件、甚至是數(shù)據(jù)庫中。我們可以控制每一條日志的輸出格式,通過定義日志的輸出級別,可以更靈活的控制日志的輸出過程,方便項(xiàng)目調(diào)試

1. 入門案例


    
        log4j
        log4j
        1.2.17
    

public class Log4jTest {
    
    @Test
    public void testQuick() throws Exception {
        
        // 初始化系統(tǒng)配置,不需要配置文件
        BasicConfigurator.configure();
        
        // 創(chuàng)建日志記錄器對象
        Logger logger = Logger.getLogger(Log4jTest.class);
        
        // 日志記錄輸出
        logger.info("hello log4j");
        
        // 日志級別
        logger.fatal("fatal"); // 嚴(yán)重錯誤,一般會造成系統(tǒng)崩潰和終止運(yùn)行
        logger.error("error"); // 錯誤信息,但不會影響系統(tǒng)運(yùn)行
        logger.warn("warn"); // 警告信息,可能會發(fā)生問題
        logger.info("info"); // 程序運(yùn)行信息,數(shù)據(jù)庫的連接、網(wǎng)絡(luò)、IO操作等
        logger.debug("debug"); // 調(diào)試信息,一般在開發(fā)階段使用,記錄程序的變量、參數(shù)等
        logger.trace("trace"); // 追蹤信息,記錄程序的所有流程信息
    }
}

2. 日志級別

每個 Logger 都被定義了一個日志級別,用來控制日志信息的輸出,日志級別從高到低分為:

  • fatal:指出每個嚴(yán)重的錯誤事件將會導(dǎo)致應(yīng)用程序的退出
  • error:指出雖然發(fā)生錯誤事件,但仍然不影響系統(tǒng)的繼續(xù)運(yùn)行
  • warn:表明會出現(xiàn)潛在的錯誤情形
  • info:一般和在粗粒度級別上,強(qiáng)調(diào)應(yīng)用程序的運(yùn)行全程
  • debug:一般用于細(xì)粒度級別上,對調(diào)試應(yīng)用程序非常有幫助
  • trace 是程序追蹤,可以用于輸出程序運(yùn)行中的變量,顯示執(zhí)行的流程

還有兩個特殊的級別:OFF 可用來關(guān)閉日志記錄、ALL 啟用所有消息的日志記錄

3. Log4j 組件

3.1 Loggers

日志記錄器,負(fù)責(zé)收集處理日志記錄,實(shí)例的命名就是類的全限定名

Logger 的名字大小寫敏感,其命名有繼承機(jī)制,例如:name 為 org.apache.commons 的 logger 會繼承 name 為 org.apache 的 logger

Log4J 中有一個特殊的 logger 叫做 root,他是所有 logger 的根,可以用 Logger.getRootLogger() 方法獲取,其他所有的 logger 都會直接或間接地繼承自 root

3.2 Appenders

Appender 用來指定日志輸出到哪個地方,可以同時指定日志的輸出目的地。Log4j 常用的輸出目的地有以下幾種:

  • ConsoleAppender:將日志輸出到控制臺
  • FileAppender:將日志輸出到文件中
  • DailyRollingFileAppender:將日志輸出到一個日志文件,并且每天輸出到一個新的文件
  • RollingFileAppender:將日志信息輸出到一個日志文件,并且指定文件的尺寸,當(dāng)文件大小達(dá)到指定尺寸時,會自動把文件改名,同時產(chǎn)生一個新的文件
  • JDBCAppender:把日志信息保存到數(shù)據(jù)庫中
3.3 Layouts

布局器 Layouts 用于控制日志輸出內(nèi)容的格式,讓我們可以使用各種需要的格式輸出日志。Log4j 常用的 Layouts:

  • HTMLLayout:格式化日志輸出為 HTML 表格形式
  • SimpleLayout:簡單的日志輸出格式化,打印的日志格式為(info - message)
  • PatternLayout:最強(qiáng)大的格式化期,可以根據(jù)自定義格式輸出日志,如果沒有指定轉(zhuǎn)換格式,就使用默認(rèn)的轉(zhuǎn)換格式

4. 配置文件詳解

#指定日志的輸出級別與輸出端
log4j.rootLogger=INFO,Console

# 自定義Logger
# com.itheima包下的logger使用文件輸出配置
log4j.logger.com.itheima = info,file
# apache包下的logger輸出error級別日志
log4j.logger.org.apache = error

# 控制臺輸出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
# log4j 采用類似 C 語言的 printf 函數(shù)的打印格式格式化日志信息,具體的占位符及其含義如下:
# %m 輸出代碼中指定的日志信息
# %p 輸出優(yōu)先級,及 DEBUG、INFO 等
# %n 換行符(Windows平臺的換行符為 "\n",Unix 平臺為 "\n")
# %r 輸出自應(yīng)用啟動到輸出該 log 信息耗費(fèi)的毫秒數(shù)
# %c 輸出打印語句所屬的類的全名
# %t 輸出產(chǎn)生該日志的線程全名
# %d 輸出服務(wù)器當(dāng)前時間,默認(rèn)為 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日
# HH:mm:ss}
# %l 輸出日志時間發(fā)生的位置,包括類名、線程、及在代碼中的行數(shù)。如:
# Test.main(Test.java:10)
# %F 輸出日志消息產(chǎn)生時所在的文件名稱
# %L 輸出代碼中的行號
# %% 輸出一個 "%" 字符
# 可以在 % 與字符之間加上修飾符來控制最小寬度、最大寬度和文本的對其方式。如:
# %5c 輸出category名稱,最小寬度是5,category<5,默認(rèn)的情況下右對齊
# %-5c 輸出category名稱,最小寬度是5,category<5,"-"號指定左對齊,會有空格
# %.5c 輸出category名稱,最大寬度是5,category>5,就會將左邊多出的字符截掉,<5不會有空格
# %20.30c category名稱<20補(bǔ)空格,并且右對齊,>30字符,就從左邊交遠(yuǎn)銷出的字符截掉
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

# 文件輸出配置
log4j.appender.A = org.apache.log4j.DailyRollingFileAppender
#指定日志的輸出路徑
log4j.appender.A.File = D:/log.txt
log4j.appender.A.Append = true
#使用自定義日志格式化器
log4j.appender.A.layout = org.apache.log4j.PatternLayout
#指定日志的輸出格式
log4j.appender.A.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] -
[%p] %m%n
#指定日志的文件編碼
log4j.appender.A.encoding=UTF-8

#mysql
log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
log4j.appender.logDB.Driver=com.mysql.jdbc.Driver
log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/test
log4j.appender.logDB.User=root
log4j.appender.logDB.Password=root
log4j.appender.logDB.Sql=INSERT INTO
log(project_name,create_date,level,category,file_name,thread_name,line,all_categ
ory,message) values('itcast','%d{yyyy-MM-dd
HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
CREATE TABLE `log` (
    `log_id` int(11) NOT NULL AUTO_INCREMENT,
    `project_name` varchar(255) DEFAULT NULL COMMENT '目項(xiàng)名',
    `create_date` varchar(255) DEFAULT NULL COMMENT '創(chuàng)建時間',
    `level` varchar(255) DEFAULT NULL COMMENT '優(yōu)先級',
    `category` varchar(255) DEFAULT NULL COMMENT '所在類的全名',
    `file_name` varchar(255) DEFAULT NULL COMMENT '輸出日志消息產(chǎn)生時所在的文件名稱 ',
    `thread_name` varchar(255) DEFAULT NULL COMMENT '日志事件的線程名',
    `line` varchar(255) DEFAULT NULL COMMENT '號行',
    `all_category` varchar(255) DEFAULT NULL COMMENT '日志事件的發(fā)生位置',
    `message` varchar(4000) DEFAULT NULL COMMENT '輸出代碼中指定的消息',
    PRIMARY KEY (`log_id`)
);

JCL

全稱為 Jakarta Commons Logging,是 Apache 提供的一個日志門面實(shí)現(xiàn),為所有的 Java 日志實(shí)現(xiàn)提供一個統(tǒng)一的接口,它自身也提供一個日志的實(shí)現(xiàn),但是功能較弱,它允許開發(fā)人員使用不同的具體日志實(shí)現(xiàn)工具,如:Log4J,JUL

JCL 有兩個基本的抽象類:Log(基本記錄器)和 LogFactory(負(fù)責(zé)創(chuàng)建 Log 實(shí)例)

1. 入門案例


	commons-logging
	commons-logging
	1.2

public class JULTest {
    
    @Test
    public void testQuick() throws Exception {
        // 創(chuàng)建日志對象
        Log log = LogFactory.getLog(JULTest.class);
        // 日志記錄輸出
        log.fatal("fatal");
        log.error("error");
        log.warn("warn");
        log.info("info");
        log.debug("debug");
    }
}

2. JCL 原理

JCL 通過 LogFactory 動態(tài)加載 Log 實(shí)現(xiàn)類

. 獲取具體的日志實(shí)現(xiàn)的源碼如下:

private static final String[] classesToDiscover =
	new String[]{"org.apache.commons.logging.impl.Log4JLogger",
					"org.apache.commons.logging.impl.Jdk14Logger",
					"org.apache.commons.logging.impl.Jdk13LumberjackLogger",
					"org.apache.commons.logging.impl.SimpleLog"};


for(int i = 0; i < classesToDiscover.length && result == null; ++i) {
	result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
}

classesToDiscover 數(shù)組是 JCL 支持的日志實(shí)現(xiàn)數(shù)組,對它進(jìn)行遍歷,嘗試通過反射去實(shí)現(xiàn)


SLF4J

SLF4J(Simple Logging Facade For Java)主要是為了給 Java 日志訪問提供一套標(biāo)準(zhǔn)、規(guī)范的 API 框架,其主要意義在于提供接口,具體的實(shí)現(xiàn)可以交由其他日志框架,例如 log4j 和 logback 等

SLF4J 也提供了功能較為簡單的實(shí)現(xiàn),但是一般很少用到。對于一般的 Java 項(xiàng)目而言,日志框架會選擇 slf4j-api 作為門面,配上具體的實(shí)現(xiàn)框架(log4j、logback 等),中間使用橋接器完成橋接

SLF4J 的優(yōu)勢:

  • SLF4J 提供了對所有流行的日志框架的綁定,可以在部署時切換到所需的日志記錄框架
  • 無論使用哪種綁定,SLF4J 都支持參數(shù)化日志記錄消息
  • SLF4J 提供了一個稱為橋接器的工具,可以將現(xiàn)有項(xiàng)目的使用日志框架(JCL、JUL、Log4j)遷移到 SLF4J

1. 入門案例



    org.slf4j
    slf4j-api
    1.7.27



    org.slf4j
    slf4j-simple
    1.7.27

public class Slf4jTest {
    
    // 聲明日志對象
    public final static Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);
    
    @Test
    public void testQuick() throws Exception {
        
        // 打印日志信息
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.info("info");
        LOGGER.debug("debug");
        LOGGER.trace("trace");
        
        // 使用占位符輸出日志信息
        String name = "jack";
        Integer age = 18;
        LOGGER.info("用戶:{},{}", name, age);
        
        // 將系統(tǒng)異常信息寫入日志
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            // e.printStackTrace();
            LOGGER.info("出現(xiàn)異常:", e);
        }
    }
}

2. 綁定日志的實(shí)現(xiàn)

SLF4J 提供了用于綁定日志實(shí)現(xiàn)框架的 Jar 文件,每個綁定對應(yīng)一個受支持的框架

使用 SLF4J 的日志綁定流程如下:

  1. 添加 slf4j-api 的依賴
  2. 使用 slf4j 的 API 在項(xiàng)目中進(jìn)行統(tǒng)一的日志記錄
  3. 綁定具體的日志實(shí)現(xiàn)框架
    • 綁定已經(jīng)實(shí)現(xiàn)了 slf4j 的日志框架,可直接添加對應(yīng)依賴
    • 綁定沒有實(shí)現(xiàn) slf4j 的日志框架,先添加日志的適配器,再添加實(shí)現(xiàn)類的依賴
  4. slf4j 有且僅有一個日志實(shí)現(xiàn)框架的綁定(如果出現(xiàn)多個默認(rèn)使用第一個依賴日志實(shí)現(xiàn))

通過 maven 引入常見的日志實(shí)現(xiàn)框架:



    org.slf4j
    slf4j-api
    1.7.27




    org.slf4j
    slf4j-log4j12
    1.7.27



    log4j
    log4j
    1.2.17




    org.slf4j
    slf4j-jdk14
    1.7.27





    ch.qos.logback
    logback-classic
    1.2.3

要切換日志框架,只需替換類路徑上的 slf4j 綁定,例如,要從 java.util.logging 切換到 log4j,只需將 java.util.logging 的依賴替換為 log4j 的依賴即可

如果出現(xiàn)多個日志實(shí)現(xiàn)。默認(rèn)加載第一個實(shí)現(xiàn),也就是會使用 log4j

3. 橋接舊的日志框架

項(xiàng)目初期使用了一個簡單的日志實(shí)現(xiàn)框架,如 Log4J,后續(xù)需要升級成 Slf4J + Logback,但又不想修改原有 Log4J 的代碼,因此可以使用橋接器,將原本對 Log4J 的 API 調(diào)用重定向到 Slf4J 的實(shí)現(xiàn)

例如,最初的項(xiàng)目使用了 Log4J


    log4j
    log4j
    1.2.17

public class Log4jTest {
    
    // 聲明日志對象
    public final static Logger LOGGER = Logger.getLogger(Log4jTest.class);
    
    @Test
    public void test01() throws Exception {
        // 打印日志信息
        LOGGER.info("hello log4j");
    }
}

如果我們要使用 SLF4J 的橋接器,替換原有的日志框架,那么我們需要做的第一件事情,就是刪除掉原有項(xiàng)目中的日志框架的依賴,然后替換成 SLF4J 提供的橋接器





    org.slf4j
    log4j-over-slf4j
    1.7.27

注意的問題:

  • log4j-over-slf4j.jar 和 slf4j-log4j12.jar 不能同時出現(xiàn),前一個 jar 文件將導(dǎo)致 log4j 將日志系統(tǒng)的選擇委托給 slf4j,后一個 jar 文件將導(dǎo)致 slf4j 將日志系統(tǒng)的選擇委托給 log4j,從而導(dǎo)致無限循環(huán),其他日志實(shí)現(xiàn)框架同理
  • 所有的橋接都只對 Logger 日志記錄器對象有效,如果程序中調(diào)用了內(nèi)部的配置類或者是 Appender、Filter 等對象,將無法產(chǎn)生效果

4. SLF4J 原理解析

  1. SLF4J 通過 LoggerFactory 加載日志具體的實(shí)現(xiàn)對象
  2. LoggerFactory 在初始化的過程中,會通過 performInitialization() 方法綁定具體的日志實(shí)現(xiàn)
  3. 在綁定具體實(shí)現(xiàn)的時候,通過類加載器,加載 org/slf4j/impl/StaticLoggerBinder.class
  4. 所以,只要是一個日志實(shí)現(xiàn)框架,在 org.slf4j.impl 包中提供一個自己的StaticLoggerBinder類,在其中提供具體日志實(shí)現(xiàn)的 LoggerFactory 就可以被 SLF4J 所加載

Logback

Logback 是由 log4j 創(chuàng)始人設(shè)計(jì)的另一個開源日志組件,性能優(yōu)于 log4j

Logback 主要分為三個模塊:

  • logback-core:其它兩個模塊的基礎(chǔ)模塊
  • logback-classic:它是 log4j 的一個改良版本,同時它完整實(shí)現(xiàn)了 slf4j API
  • logback-access:訪問模塊與 Servlet 容器集成提供通過 Http 來訪問日志的功能

1. 入門案例


    org.slf4j
    slf4j-api
    1.7.25


    ch.qos.logback
    logback-classic
    1.2.3

public class LogBackTest {
    
    //定義日志對象
	public final static Logger LOGGER = LoggerFactory.getLogger(LogBackTest.class);

    @Test
    public void testSlf4j(){
        //打印日志信息
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.info("info");
        LOGGER.debug("debug");
        LOGGER.trace("trace");
    }
}

2. Logback 配置

Logback 會依次讀取以下類型配置文件,如果均不存在會采用默認(rèn)配置:

  • logback.groovy
  • logback-test.xml
  • logback.xml

基本配置信息如下:



	
	
    
	
    
        
        System.err
        
        
        	${pattern}
        
    

	
	

    
    
        
        
        	${pattern}
        
        
        ${log_dir}/logback.log
    
    
    
    
        
        
        	
        		${pattern}
        	
        
        
        ${log_dir}/logback.html
    
    
    
    
        
        
        	${pattern}
        
        
        ${log_dir}/roll_logback.log
        
        
            
            ${log_dir}/rolling.%d{yyyy-MMdd}.log%i.gz
            
            1MB
        
        
        
            
            error
            
            ACCEPT
            
			DENY
		
    
    
    
    
    	
    
    
    
    
    
    
        
        
        
    
    
    
    
    
    
    
    	
    
    


Log4j2

Log4j2 也是日志門面,因?yàn)樗娜罩緦?shí)現(xiàn)功能非常強(qiáng)大,性能優(yōu)越,所以一般還是將 Log4j2 看作是日志的實(shí)現(xiàn)

1. 入門案例



    org.apache.logging.log4j
    log4j-api
    2.11.1



    org.apache.logging.log4j
    log4j-core
    2.11.1

public class Log4j2Test {
    
    // 定義日志記錄器對象
    public static final Logger LOGGER = LogManager.getLogger(Log4j2Test.class);
    
    @Test
    public void testQuick() throws Exception {
        LOGGER.fatal("fatal");
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.info("info");
        LOGGER.debug("debug");
        LOGGER.trace("trace");
    }
}

也可以使用 slf4j 作為日志的門面,log4j2 作為日志的實(shí)現(xiàn)



    org.slf4j
    slf4j-api
    1.7.25



    org.apache.logging.log4j
    log4j-slf4j-impl
    2.10.0




    org.apache.logging.log4j
    log4j-api
    2.11.1



    org.apache.logging.log4j
    log4j-core
    2.11.1

2. Log4j2 配置

log4j2 默認(rèn)加載 classpath 下的 log4j2.xml 文件中的配置




    
    
	
		D:/logs
	
    
    
    
        
        
		
			
		
        
        
		
			
		
        
        
		
			
		
        
        
		
            
			
            
			
            
            
                
                
                
                
                
                
            
            
			
		
        
        
        
            
            
            	
                
                
                
            
        
        

3. Log4j2 異步日志

Log4j2 提供了兩種實(shí)現(xiàn)日志的方式,一個是通過 AsyncAppender,一個是通過 AsyncLogger,分別對應(yīng)前面的 Appender 組件和 Logger 組件

配置異步日志需要添加依賴



    com.lmax
    disruptor
    3.3.4

使用 AsyncAppender 的方式



    
	
		D:/logs
	
    
	
		
			
				%d %p %c{1.} [%t] %m%n
			
		
		
			
		
	
    
	
		
			
		
	
    

AsyncLogger 是官方推薦的異步方式,它可以使得調(diào)用 Logger.log 返回得更快,并且有兩種選擇:全局異步和混合異步

  • 全局異步:所有的日志都異步記錄,配置文件上不用做任何改動,只需要在類路徑添加一個名為 log4j2.component.properties 配置文件,并包含如下內(nèi)容:

    Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
    
  • 混合異步:可以在應(yīng)用中同時使用同步日志和異步日志,這使得日志的配置方式更加靈活,如下配置: com.itheima 日志是異步的,root 日志是同步的

    
    
        
    	
    		D:/logs
    	
        
    	
    		
    			
    				%d %p %c{1.} [%t] %m%n
    			
    		
    	
        
    	
            
            
    		
    			
    		
    		
    			
    		
    	
        
    
    

4. 無垃圾模式

垃圾收集暫停是延遲峰值的常見原因,并且對于許多系統(tǒng)而言,花費(fèi)大量精力來控制這些暫停

許多日志庫(包括以前版本的 Log4j)在穩(wěn)態(tài)日志記錄期間分配臨時對象,如日志事件對象、字符串、字符數(shù)組、字節(jié)數(shù)組等。這會對垃圾收集器造成壓力并增加 GC 暫停發(fā)生的頻率

從 2.6 版本開始,默認(rèn)情況下 Log4j 以無垃圾模式運(yùn)行,重用對象和緩沖區(qū),盡可能不分配臨時對象

還有一個低垃圾模式,它不是完全無垃圾,但不使用 ThreadLocal 字段,Log4j 2.6 中的無垃圾日志記錄部分通過重用 ThreadLocal 字段中的對象來實(shí)現(xiàn),部分通過在將文本轉(zhuǎn)換為字節(jié)時重用緩沖區(qū)來實(shí)現(xiàn)

有兩個單獨(dú)的系統(tǒng)屬性可用于手動控制 Log4j 用于避免創(chuàng)建臨時對象的機(jī)制:

  • log4j2.enableThreadlocals:如果為 true(默認(rèn)),對象存儲在 ThreadLocal 字段中并重新使用,否則將為每個日志事件創(chuàng)建新對象
  • log4j2.enableDirectEncoders:如果為 true(默認(rèn)),日志事件轉(zhuǎn)換為文本,則將此文本轉(zhuǎn)換為字節(jié)而不創(chuàng)建臨時對象。注意:由于共享緩沖區(qū)上的同步,在此模式下多線程應(yīng)用程序的同步日志記錄性能可能更差,如果您的應(yīng)用程序是多線程的并且日志記錄性能很重要,請考慮使用異步記錄器

SpringBoot 日志使用

Springboot 默認(rèn)使用 SLF4J 作為日志門面,logback 作為日志實(shí)現(xiàn)來記錄日志

1. SpringBoot 的日志設(shè)計(jì)


    spring-boot-starter-logging
    org.springframework.boot

依賴關(guān)系圖:

  1. Springboot 底層默認(rèn)使用 logback 作為日志實(shí)現(xiàn),并提供了其他日志實(shí)現(xiàn)框架的橋接器進(jìn)行轉(zhuǎn)換
  2. Springboot 使用了 SLF4J 作為日志門面,也可以使用如 Log4j2 等日志門面,但最終還是通過 slf4j 進(jìn)行調(diào)用 logback

2. SpringBoot 日志使用

在 springboot 中測試打印日志

@SpringBootTest
class SpringbootLogApplicationTests {
	//記錄器
	public static final Logger LOGGER = LoggerFactory.getLogger(SpringbootLogApplicationTests.class);
    
    @Test
    public void contextLoads() {
        // 打印日志信息
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.info("info"); // 默認(rèn)日志級別
        LOGGER.debug("debug");
        LOGGER.trace("trace");
    }
}

修改默認(rèn)日志配置

logging.level.com.itheima=trace
# 在控制臺輸出的日志的格式 同logback
logging.pattern.console=%d{yyyy-MM-dd} [%thread] [%-5level] %logger{50} - %msg%n
# 指定文件中日志輸出的格式
logging.file=D:/logs/springboot.log
logging.pattern.file=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n

給類路徑下放上每個日志框架自己的配置文件,SpringBoot 就不使用默認(rèn)配置的了

  • Logback :logback-spring.xml,logback.xml
  • Log4j2:log4j2-spring.xml ,log4j2.xml
  • JUL:logging.properties

使用 SpringBoot 可以切換不同環(huán)境的日志配置,如在 logback-spring.xml 添加如下內(nèi)容:

...

	
		${pattern}
	
	
		%d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level %msg%n
	

...

application.properties 配置如下:

spring.profiles.active=dev

如果希望將日志切換為 log4j2


    org.springframework.boot
    spring-boot-starter-web
    
        
        
            spring-boot-starter-logging
            org.springframework.boot
        
	



	org.springframework.boot
	spring-boot-starter-log4j2



當(dāng)前名稱:Java 日志框架學(xué)習(xí)筆記
轉(zhuǎn)載來于:http://weahome.cn/article/dsoiddp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部