Java日誌框架

2020-08-12 20:18:15

JAVA 日誌框架

問題:

  1. 控制日誌輸出的內容和格式
  2. 控制日誌輸出的位置
  3. 日誌優化:非同步日誌,日誌檔案的歸檔和壓縮
  4. 日誌系統的維護
  5. 面向介面開發 – 日誌的門面
    1.1 爲什麼要用日誌框架
    因爲軟件系統發展到今天已經很複雜了,特別是伺服器端軟體,涉及到的知識,內容,問題太多。在某
    些方面使用別人成熟的框架,就相當於讓別人幫你完成一些基礎工作,你只需要集中精力完成系統的業
    務邏輯設計 。而且框架一般是成熟,穩健的,他可以處理系統很多細節問題,比如,事務處理,安全
    性,數據流控制等問題。還有框架一般都經過很多人使用,所以結構很好,所以擴充套件性也很好,而且它
    是不斷升級的,你可以直接享受別人升級程式碼帶來的好處。
    1.2 現有的日誌框架
    JUL(java util logging)、logback、log4j、log4j2
    JCL(Jakarta Commons Logging)、slf4j( Simple Logging Facade for Java)
    日誌門面
    JCL、slf4j
    日誌實現
    JUL、logback、log4j、log4j2
  6. JUL 學習
    JUL全稱Java util Logging是java原生的日誌框架,使用時不需要另外參照第三方類庫,相對其他日誌框
    架使用方便,學習簡單,能夠在小型應用中靈活使用。
    2.1 JUL入門
    2.1.1 架構介紹
    Loggers :被稱爲記錄器,應用程式通過獲取Logger物件,呼叫其API來來發布日誌資訊。Logger
    通常時應用程式存取日誌系統的入口程式。
    Appenders :也被稱爲Handlers,每個Logger都會關聯一組Handlers,Logger會將日誌交給關聯
    Handlers處理,由Handlers負責將日誌做記錄。Handlers在此是一個抽象,其具體的實現決定了
    日誌記錄的位置可以是控制檯、檔案、網路上的其他日誌服務或操作系統日誌等。
    Layouts :也被稱爲Formatters,它負責對日誌事件中的數據進行轉換和格式化。Layouts決定了
    數據在一條日誌記錄中的最終形式。
    Level :每條日誌訊息都有一個關聯的日誌級別。該級別粗略指導了日誌訊息的重要性和緊迫,我
    可以將Level和Loggers,Appenders做關聯以便於我們過濾訊息。
    Filters :過濾器,根據需要定製哪些資訊會被記錄,哪些資訊會被放過。
    總結一下就是:
    使用者使用Logger來進行日誌記錄,Logger持有若幹個Handler,日誌的輸出操作是由Handler完成的。
    在Handler在輸出日誌前,會經過Filter的過濾,判斷哪些日誌級別過濾放行哪些攔截,Handler會將日
    志內容輸出到指定位置(日誌檔案、控制檯等)。Handler在輸出日誌時會使用Layout,將輸出內容進
    行排版。
    3.1.2 入門案例
    3.2 日誌的級別
    jul中定義的日誌級別
    public class JULTest {
    @Test
    public void testQuick() throws Exception {
    // 1.建立日誌記錄器物件
    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});
    }
    }
    雖然我們測試了 7個日誌級別但是預設只實現info以上的級別
    自定義日誌級別設定
  • java.util.logging.Level中定義了日誌的級別:
    SEVERE(最高值)
    WARNING
    INFO (預設級別)
    CONFIG
    FINE
    FINER
    FINEST(最低值)
  • 還有兩個特殊的級別:
    OFF,可用來關閉日誌記錄。
    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」);
    }
    @Test
    public void testLogConfig() throws Exception {
    // 1.建立日誌記錄器物件
    Logger logger = Logger.getLogger(「com.itheima.log.JULTest」);
    // 一、自定義日誌級別
    // a.關閉系統預設設定
    logger.setUseParentHandlers(false);
    // b.建立handler物件
    ConsoleHandler consoleHandler = new ConsoleHandler();
    // c.建立formatter物件
    SimpleFormatter simpleFormatter = new SimpleFormatter();
    // d.進行關聯
    consoleHandler.setFormatter(simpleFormatter);
    logger.addHandler(consoleHandler);
    // e.設定日誌級別
    logger.setLevel(Level.ALL);
    consoleHandler.setLevel(Level.ALL);
    // 二、輸出到日誌檔案
    FileHandler fileHandler = new FileHandler(「d:/logs/jul.log」);
    fileHandler.setFormatter(simpleFormatter);
    3.3 Logger之間的父子關係
    JUL中Logger之間存在父子關係,這種父子關係通過樹狀結構儲存,JUL在初始化時會建立一個頂層
    RootLogger作爲所有Logger父Logger,儲存上作爲樹狀結構的根節點。並父子關係通過路徑來關聯。
    logger.addHandler(fileHandler);
    // 2.日誌記錄輸出
    logger.severe(「severe」);
    logger.warning(「warning」);
    logger.info(「info」);
    logger.config(「config」);
    logger.fine(「fine」);
    logger.finer(「finer」);
    logger.finest(「finest」);
    }
    @Test
    public void testLogParent() throws Exception {
    // 日誌記錄器物件父子關係
    Logger logger1 = Logger.getLogger(「com.itheima.log」);
    Logger logger2 = Logger.getLogger(「com.itheima」);
    System.out.println(logger1.getParent() == logger2);
    // 所有日誌記錄器物件的頂級父元素 class爲java.util.logging.LogManagerKaTeX parse error: Expected 'EOF', got '}' at position 695: …est("finest"); }̲ 3.4 日誌的組態檔 預設…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使用的處理器(獲取時設定)

handlers= java.util.logging.ConsoleHandler

RootLogger日誌等級

.level= INFO

自定義Logger

com.itheima.handlers= java.util.logging.FileHandler

自定義Logger日誌等級

com.itheima.level= INFO

忽略父日誌設定

com.itheima.useParentHandlers=false

控制檯處理器

輸出日誌級別

java.util.logging.ConsoleHandler.level = INFO

輸出日誌格式

java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

檔案處理器

輸出日誌級別

java.util.logging.FileHandler.level=INFO

輸出日誌格式

java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter

輸出日誌檔案路徑

java.util.logging.FileHandler.pattern = /java%u.log

輸出日誌檔案限制大小(50000位元組)

3.5 日誌原理解析

  1. 初始化LogManager
  2. LogManager載入logging.properties設定
  3. 新增Logger到LogManager
  4. 從單例LogManager獲取Logger
  5. 設定級別Level,並指定日誌記錄LogRecord
  6. Filter提供了日誌級別之外更細粒度的控制
  7. Handler是用來處理日誌輸出位置
  8. Formatter是用來格式化LogRecord的
  9. LOG4J 學習
    Log4j是Apache下的一款開源的日誌框架,通過在專案中使用 Log4J,我們可以控制日誌資訊輸出到控
    制臺、檔案、甚至是數據庫中。我們可以控制每一條日誌的輸出格式,通過定義日誌的輸出級別,可以
    更靈活的控制日誌的輸出過程。方便專案的偵錯。
    官方網站: http://logging.apache.org/log4j/1.2/
    4.1 Log4j入門
  10. 建立maven工程
  11. 新增依賴
    java.util.logging.FileHandler.limit = 50000

輸出日誌檔案限制個數

java.util.logging.FileHandler.count = 10

輸出日誌檔案 是否是追加

java.util.logging.FileHandler.append=true
3 . java程式碼
4. 日誌的級別


log4j
log4j
1.2.17


junit
junit
4.12


public class Log4jTest {
@Test
public void testQuick() throws Exception {
// 初始化系統設定,不需要組態檔
BasicConfigurator.configure();
// 建立日誌記錄器物件
Logger logger = Logger.getLogger(Log4jTest.class);
// 日誌記錄輸出
logger.info(「hello log4j」);
// 日誌級別
logger.fatal(「fatal」); // 嚴重錯誤,一般會造成系統崩潰和終止執行
logger.error(「error」); // 錯誤資訊,但不會影響系統執行
logger.warn(「warn」); // 警告資訊,可能會發生問題
logger.info(「info」); // 程式執行資訊,數據庫的連線、網路、IO操作等
logger.debug(「debug」); // 偵錯資訊,一般在開發階段使用,記錄程式的變數、參
數等
logger.trace(「trace」); // 追蹤資訊,記錄程式的所有流程資訊
}
}

  • 每個Logger都被了一個日誌級別(log level),用來控制日誌資訊的輸出。日誌級別從高到低分
    爲:
    fatal 指出每個嚴重的錯誤事件將會導致應用程式的退出。
    error 指出雖然發生錯誤事件,但仍然不影響系統的繼續執行。
    warn 表明會出現潛在的錯誤情形。
    info 一般和在粗粒度級別上,強調應用程式的執行全程。
    debug 一般用於細粒度級別上,對偵錯應用程式非常有幫助。
    trace 是程式追蹤,可以用於輸出程式執行中的變數,顯示執行的流程。
  • 還有兩個特殊的級別:
    OFF,可用來關閉日誌記錄。
    ALL,啓用所有訊息的日誌記錄。
    注:一般只使用 4個級別,優先順序從高到低爲 ERROR > WARN > INFO > DEBUG
    4.2 Log4j元件
    Log4J 主要由 Loggers (日誌記錄器)、Appenders(輸出端)和 Layout(日誌格式化器)組成。其中
    Loggers 控制日誌的輸出級別與日誌是否輸出;Appenders 指定日誌的輸出方式(輸出到控制檯、檔案
    等);Layout 控制日誌資訊的輸出格式。
    4.2.1 Loggers
    日誌記錄器,負責收集處理日誌記錄,範例的命名就是類「XX」的full quailied name(類的全限定名),
    Logger的名字大小寫敏感,其命名有繼承機制 機製:例如:name爲org.apache.commons的logger會繼承
    name爲org.apache的logger。
    Log4J中有一個特殊的logger叫做「root」,他是所有logger的根,也就意味着其他所有的logger都會直接
    或者間接地繼承自root。root logger可以用Logger.getRootLogger()方法獲取。
    但是,自log4j 1.2版以來, Logger 類已經取代了 Category 類。對於熟悉早期版本的log4j的人來說,
    Logger 類可以被視爲 Category 類的別名。
    4.2.2 Appenders
    Appender 用來指定日誌輸出到哪個地方,可以同時指定日誌的輸出目的地。Log4j 常用的輸出目的地
    有以下幾種:
    輸出端型別 作用
    ConsoleAppender 將日誌輸出到控制檯
    FileAppender 將日誌輸出到檔案中
    DailyRollingFileAppender 將日誌輸出到一個日誌檔案,並且每天輸出到一個新的檔案
    RollingFileAppender
    將日誌資訊輸出到一個日誌檔案,並且指定檔案的尺寸,當檔案大
    小達到指定尺寸時,會自動把檔案改名,同時產生一個新的檔案
    JDBCAppender 把日誌資訊儲存到數據庫中
    格式化器型別 作用
    HTMLLayout 格式化日誌輸出爲HTML表格形式
    SimpleLayout 簡單的日誌輸出格式化,列印的日誌格式爲(info - message)
    PatternLayout
    最強大的格式化期,可以根據自定義格式輸出日誌,如果沒有指定轉換格式,
    就是用預設的轉換格式
    4.2.3 Layouts
    佈局器 Layouts用於控制日誌輸出內容的格式,讓我們可以使用各種需要的格式輸出日誌。Log4j常用
    的Layouts:
    4.3 Layout的格式
    在 log4j.properties 組態檔中,我們定義了日誌輸出級別與輸出端,在輸出端中分別設定日誌的輸出
    格式。
  • log4j 採用類似 C 語言的 printf 函數的列印格式格式化日誌資訊,具體的佔位符及其含義如下:
    %m 輸出程式碼中指定的日誌資訊
    %p 輸出優先順序,及 DEBUG、INFO 等
    %n 換行符(Windows平臺的換行符爲 「\n」,Unix 平臺爲 「\n」)
    %r 輸出自應用啓動到輸出該 log 資訊耗費的毫秒數
    %c 輸出列印語句所屬的類的全名
    %t 輸出產生該日誌的執行緒全名
    %d 輸出伺服器當前時間,預設爲 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日
    HH:mm:ss}
    %l 輸出日誌時間發生的位置,包括類名、執行緒、及在程式碼中的行數。如:
    Test.main(Test.java:10)
    %F 輸出日誌訊息產生時所在的檔名稱
    %L 輸出程式碼中的行號
    %% 輸出一個 「%」 字元
  • 可以在 % 與字元之間加上修飾符來控制最小寬度、最大寬度和文字的對其方式。如:
    %5c 輸出category名稱,最小寬度是5,category<5,預設的情況下右對齊
    %-5c 輸出category名稱,最小寬度是5,category<5,"-"號指定左對齊,會有空格
    %.5c 輸出category名稱,最大寬度是5,category>5,就會將左邊多出的字元截掉,<5不
    會有空格
    %20.30c category名稱<20補空格,並且右對齊,>30字元,就從左邊交遠銷出的字元截掉
    4.4 Appender的輸出
    控制檯,檔案,數據庫
    #指定日誌的輸出級別與輸出端
    log4j.rootLogger=INFO,Console

控制檯輸出設定

log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
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 ‘目項名’,
create_date varchar(255) DEFAULT NULL COMMENT ‘建立時間’,
level varchar(255) DEFAULT NULL COMMENT ‘優先順序’,
category varchar(255) DEFAULT NULL COMMENT ‘所在類的全名’,
file_name varchar(255) DEFAULT NULL COMMENT '輸出日誌訊息產生時所在的檔名稱 ',
thread_name varchar(255) DEFAULT NULL COMMENT ‘日誌事件的執行緒名’,
line varchar(255) DEFAULT NULL COMMENT ‘號行’,
all_category varchar(255) DEFAULT NULL COMMENT ‘日誌事件的發生位置’,
message varchar(4000) DEFAULT NULL COMMENT ‘輸出程式碼中指定的訊息’,
PRIMARY KEY (log_id)
);
4.5 自定義Logger
5. JCL 學習
全稱爲Jakarta Commons Logging,是Apache提供的一個通用日誌API。
它是爲 "所有的Java日誌實現"提供一個統一的介面,它自身也提供一個日誌的實現,但是功能非常常弱
(SimpleLog)。所以一般不會單獨使用它。他允許開發人員使用不同的具體日誌實現工具: Log4j, Jdk
自帶的日誌(JUL)
JCL 有兩個基本的抽象類:Log(基本記錄器)和LogFactory(負責建立Log範例)。

RootLogger設定

log4j.rootLogger = trace,console

自定義Logger

log4j.logger.com.itheima = info,file
log4j.logger.org.apache = error
@Test
public void testCustomLogger() throws Exception {
// 自定義 com.itheima
Logger logger1 = Logger.getLogger(Log4jTest.class);
logger1.fatal(「fatal」); // 嚴重錯誤,一般會造成系統崩潰和終止執行
logger1.error(「error」); // 錯誤資訊,但不會影響系統執行
logger1.warn(「warn」); // 警告資訊,可能會發生問題
logger1.info(「info」); // 程式執行資訊,數據庫的連線、網路、IO操作等
logger1.debug(「debug」); // 偵錯資訊,一般在開發階段使用,記錄程式的變數、參數等
logger1.trace(「trace」); // 追蹤資訊,記錄程式的所有流程資訊
// 自定義 org.apache
Logger logger2 = Logger.getLogger(Logger.class);
logger2.fatal(「fatal logger2」); // 嚴重錯誤,一般會造成系統崩潰和終止執行
logger2.error(「error logger2」); // 錯誤資訊,但不會影響系統執行
logger2.warn(「warn logger2」); // 警告資訊,可能會發生問題
logger2.info(「info logger2」); // 程式執行資訊,數據庫的連線、網路、IO操作等
logger2.debug(「debug logger2」); // 偵錯資訊,一般在開發階段使用,記錄程式的變數、參
數等
logger2.trace(「trace logger2」); // 追蹤資訊,記錄程式的所有流程資訊
}
5.1 JCL入門

  1. 建立maven工程
  2. 新增依賴
    3 . 入門程式碼
    我們爲什麼要使用日誌門面:
  3. 面向介面開發,不再依賴具體的實現類。減少程式碼的耦合
  4. 專案通過匯入不同的日誌實現類,可以靈活的切換日誌框架
  5. 統一API,方便開發者學習和使用

    commons-logging
    commons-logging
    1.2

    public class JULTest {
    @Test
    public void testQuick() throws Exception {
    // 建立日誌物件
    Log log = LogFactory.getLog(JULTest.class);
    // 日誌記錄輸出
    log.fatal(「fatal」);
    log.error(「error」);
    log.warn(「warn」);
    log.info(「info」);
    log.debug(「debug」);
    }
    }
    4 . 統一設定便於專案日誌的管理
    5.2 JCL原理
  6. 通過LogFactory動態載入Log實現類
    2 . 日誌門面支援的日誌實現陣列
    3 . 獲取具體的日誌實現
    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.createLogFr