日誌框架 log4j2 全解析

来源:https://www.cnblogs.com/yangyuanhu/archive/2020/02/20/12336999.html

概述 logging翻譯為日誌記錄 那問題是什麼是日誌? 日誌實際上是日記的一種,用於記錄某個時間點發生了什麼事情,比如大學老師的教學日誌,工作日誌等 為什麼要記錄日誌? 在實際生活中記錄日誌主要為了日後複查, 比如某個大學老師每天記錄自己講的什麼內容,後面有學生某科成績優異獲獎了,校長想要獎勵對應 ...


概述

logging翻譯為日誌記錄

那問題是什麼是日誌?

日誌實際上是日記的一種,用於記錄某個時間點發生了什麼事情,比如大學老師的教學日誌,工作日誌等

為什麼要記錄日誌?

在實際生活中記錄日誌主要為了日後複查,

比如某個大學老師每天記錄自己講的什麼內容,後面有學生某科成績優異獲獎了,校長想要獎勵對應的老師,但由於每個老師教的班級都很多,並不一定記得是誰教的,這時候就可以查看教學日誌來獲取需要的信息了

再比如,工廠的生產日誌,如果某個產品除了因為某個零件出現了故障,通過生成日誌,可以找到與這個產品同批次的其他產品,進行返工,或是通過日誌找到該零件的供應商,進行溝通解決!

程式中的日誌

我們的程式開發完成後會被不同系統環境的用戶下載使用,期間可能就會出現問題,直接把錯誤信息展示給用戶看是沒有任何意義的,用戶看不懂也不會解決,那這時候就可以將用戶執行的所有操作,以及代碼運行的過程,記錄到日誌中,程式員通過分析日誌內容,可以快速的定位問題

綜上: 日誌就是用來記錄發生的事件的

日誌並不會立即產生作用,而是當程式出現了問題時在去分析日誌文件提取有用信息

java下的日誌框架

門面

門面是Facade(外觀模式)的實現,也稱為門面模式,

是對內部多個子系統的封裝,並對外提供一套統一的使用介面,從而屏蔽各個子系統在使用上的不同,大大降低了系統的使用難度,同時提高了系統的可維護性和擴展性;

實際上真正幹活的還是是內部的子系統;就像給這些子系統加了一層裝飾,Facede也得名於此;

圖示:

因其性能優越性,實際開發中log4j是使用最多一個日誌框架,也是我們需要掌握的目標;

官方性能對比:

Peak throughput comparison

log4j

日誌級別:

日誌級別其實指的就是日誌信息應用場景,我們的程式會在不同的環境中運行,某些日誌只有用在某些特殊場景中,例如:在開發階段,我們為了檢查錯誤,會輸出一些調試信息,但是這些信息在生產環境下是不需要的,當然.我們可以在發佈前刪除這些調試代碼,但這就顯得非常low了,通過對日誌信息區別對待,我們可以很方便的控制哪些日誌在哪些場景下正常輸出;
日誌級別也在後續的問題定位中發揮著重要作用,當程式出現了問題,我們要根據日誌來定位問題,這時便可以通過日誌級別來快速過濾掉不需要的記錄;

log4j日誌級別:

log4j定義了8個級別,優先順序從高到低依次為:

OFF>FATAL> ERROR> WARN> INFO> DEBUG> TRACE> ALL

  • ALL 最低等級的 用於打開所有日誌記錄
  • TRACE 很低的日誌級別 一般不會使用
  • DEBUG 該級別信息對調試應用程式是非常有幫助的 主要用於開發過程中列印 一些運行信息
  • INFO 突出強調應用程式的運行過程。列印一些你感興趣的或者重要的信息 可用於生產環境中輸出程式運行的一些重要信息,但是不能濫用 避免列印過多的日誌
  • WARN 表明會出現潛在錯誤的情形 有些信息不是錯誤信息 但是也要給程式員的一些提示
  • ERROR 指出雖然發生錯誤事件 但仍然不影響系統的繼續運行。列印錯誤和異常信息 如果不想輸出太多日誌 太多數情況下可以使用這個級別
  • FATAL 指出嚴重的錯誤事件,將會導致應用程式的退出。
  • OFF 最高等級的,用於關閉所有日誌記錄

依賴包:

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.5</version>
    </dependency>

配置文件:

2.x往後的版本不在支持properties作為配置文件,因其無法表達較為複雜的語法結構

log4j2會在classpath下查找配置文件,如果找不到則使用基礎配置(輸出到控制台),log4j支持 xml,json,jsn三種格式的配置文件,並可為測試環境和生產環境編寫不同的配置文件;若有多個配置文件log4j將按照以下順序讀取:

  1. classpath下的名為log4j2-test.json 或者log4j2-test.jsn的文件.
  2. classpath下的名為log4j2-test.xml的文件.
  3. classpath下名為log4j2.json 或者log4j2.jsn的文件.
  4. classpath下名為log4j2.xml的文件.

示例log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!--   status="WARN" 用於設置log4j框架本身的日誌級別-->
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="all">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

測試代碼:

@Test
    public void test1(){
        Logger myLogger = LogManager.getLogger("myLogger");
        myLogger.debug("debug msg");
    }

Appenders節點:

該節點配置日誌信息的輸出目的地,可以是控制台,文件,郵件或資料庫,控制台和文件是表常用的兩個目的地;

上述案例既將日誌信息輸出到控制台,其子節點PatternLayout用於設置日誌輸出的字元傳格式;

PatternLayout可用的格式化字元:

%d{HH:mm:ss.SSS}    表示輸出到毫秒的時間
%t              輸出當前線程名稱
%-5level    輸出日誌級別,-5表示左對齊並且固定輸出5個字元,如果不足在右邊補空格
%logger     輸出logger名稱,因為Root Logger沒有名稱
%msg            日誌文本
%n              換行
%F              輸出所在的類文件名,如Client.java
%L              輸出行號
%M              輸出所在方法名
%C                          產生log事件的java完全限定類名
%l              輸出語句所在的行數, 包括類名、方法名、文件名、行數

輸出到文件:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
        </Console>
        <File name="fileAppender" fileName="logs/app.log" append="false"><!--預設以當前項目為相對路徑-->
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
        </File>
        
    </Appenders>
    <Loggers>
        <Root level="all">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="fileAppender"/><!--一個logger可配置對個appender輸出到不同位置-->
        </Root>
    </Loggers>
</Configuration>
<!--File屬性:
name用於給appender指定名字,以便logger引用 
fileName預設以當前項目為相對路徑   
append參數表示是否將是追加到文件末尾 預設為true  為false即直接覆蓋原文件-->

上面的配置會將所有日誌輸出到同一個文件,隨著時間的推移該文件會越來越大,甚至無法打開,但是實際有用的日誌都是近期的產生的,太久遠的日誌大多數是無用的,這就用到了滾動日誌,其可以幫助我們實現日誌文件的切割,以及無用日誌的刪除操作;

滾動日誌配置:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <!--自定義屬性信息-->
    <properties>
        <property name="LOG_HOME">logs</property>
        <property name="FILE_NAME">applog</property>
    </properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <!--滾動日誌配置
            filePattern用於設置滾動文件的命名規則                                        
                        若以.zip為結尾則會自動歸檔日誌文件 也支持其他的格式.gz, .zip, .bz2, 等-->
        <RollingRandomAccessFile name="RollingAppender"
                                 fileName="${LOG_HOME}/${FILE_NAME}.log"
                                 filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log">
            <PatternLayout
                    pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            <Policies>
                <!--滾動時間間隔 該參數需結合filePattern中的時間格式 此時表示為1分鐘更換一個新文件
                    若時間格式為%d{yyyy-MM-dd HH}則表示每小時更換一個新文件-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <!--單個日誌文件最大容量                -->
                <SizeBasedTriggeringPolicy size="1 MB"/>
            </Policies>
            <!--最大保留的日誌文件個數  預設為7個          -->
            <DefaultRolloverStrategy max="20"/>
        </RollingRandomAccessFile>
    </Appenders>
    <Loggers>
        <Root level="all">
            <AppenderRef ref="RollingAppender"/>
        </Root>
    </Loggers>
</Configuration>

上述配置的整體含義:統一使用rootLogger,所有級別日誌都會被記錄到文件中,文件位於項目目錄下的logs中,當單個文件超過1MB或是時間超過1分鐘後則更換日誌文件,最多保存20個日誌文件;

補充:RollingFile也是做滾動日誌的,但是據官方說效率沒有RollingRandomAccessFile高;

Loggers節點:

需求:某個類或模塊中產生的需要同時輸出到控制台和文件,其他模塊則僅輸出到控制台,當遇到類似需求時,就需要定義不同的logger了,然後在程式中根據名稱獲取所需的logger

如果在配置中找不到名稱匹配的logger時使用rootLogger;

logger配置:

註意:appender使用的還是上面的例子中的

<Loggers>
    <Root level="all">
        <AppenderRef ref="Console" />
    </Root>
    <Logger name="fileAndConsole" level="all" additivity="false">
        <AppenderRef ref="Console" />
        <AppenderRef ref="RollingAppender" />
    </Logger>
</Loggers>
<!-- additivity表示是否將日誌傳遞給root繼續輸出 預設為true-->

測試代碼:

@Test
public void test1(){
    Logger myLogger = LogManager.getLogger("myLogger");//rootlogger
    Logger myLogger2 = LogManager.getLogger("fileAndConsole");//fileAndConsole

    for (int i = 0;i < 50;i++){
        myLogger.debug("debug msg1");
    }
    for (int i = 0;i < 50;i++){
        myLogger2.debug("debug msg2");
    }
}

msg1將只出現在控制台,而msg2同時出現在控制台和日誌文件;

Filter節點:

Filter用於對日誌進行過濾,一些情況下我們可能需要對日誌進行更加個性化的限制,

例如:

輸出日誌消息包含某個字元串的

按照時間不同輸出到不同文件

日誌的生命周期 :

一個日誌事件(LogEvent)產生後到最終輸出到目的地會經過以下環節:

全局過濾器 -> logger過濾器 -> logger -> appender過濾器 -> appender->輸出

無論哪個環節的過濾器,每個過濾器在匹配或是不匹配時都要明確該日誌事件的處理方式,包含三種:

  • ACCEPT接受(繼續傳遞該LogEvent)
  • DENY拒絕(直接丟棄該LogEvent)
  • NEUTRAL中立(不清楚該怎麼辦繼續往後傳遞LogEvent)

全局過濾器:評估結果為接受時,其他全局過濾器將不會再對該事件進行評估,且不再交給Logger過濾器評估

Logger過濾器:評估為拒絕時不再交給Appdener過濾器

Appdener過濾器:最終決定改日誌是否輸出

通常需要根據實際需求來配置過濾器:

下例配置列出了三種過濾器的示例(無實意義):

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE" monitorInterval="5" packages="com.kanq.extend.cat.log4j2">
    <Filters>
        <!-- 全局級別Filter -->
        <BurstFilter level="INFO" rate="16" maxBurst="100"/>
    </Filters>
    <Appenders>
        <RollingFile name="RollingFile" fileName="logs/app.log"
                     filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
            <!-- Appender級別的Filter -->
            <BurstFilter level="INFO" rate="16" maxBurst="100"/>
            <PatternLayout>
                <pattern>%d %p %c{1.} [%t] %m%n</pattern>
            </PatternLayout>
            <TimeBasedTriggeringPolicy />
        </RollingFile>
    </Appenders>
    <Loggers>
        <!-- Logger級別的Filter -->
        <Root level="error">
            <BurstFilter level="INFO" rate="16" maxBurst="100"/>
            <AppenderRef ref="RollingFile"/>
        </Root>
    </Loggers>
</Configuration>

過濾器案例:

通過時間過濾器實現將白天和夜晚的是指寫入不同位置:

<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <File name="DayAppender" fileName="logs/appDay.log" append="true">
            <TimeFilter start="06:00:00" end="24:00:00" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
        </File>
        <File name="NightAppender" fileName="logs/appNight.log" append="true">
            <TimeFilter start="24:00:00" end="06:00:00" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
        </File>
    </Appenders>
    <Loggers>
        <Root level="all">
            <AppenderRef ref="Console" />
            <AppenderRef ref="DayAppender" />
            <AppenderRef ref="NightAppender" />
        </Root>
    </Loggers>
</Configuration>

當然官網還有其他的過濾器,如正則過濾等,大家根據需求選擇即可;地址:官方手冊

web項目中的使用

web環境下需要額外的依賴包:

<!-- web容器中需要添加log4j-web -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
    <version>2.5</version>
</dependency>

controller中的使用:

@Controller
@RequestMapping("/customer")
public class CustomerController {
//為controller添加屬性 用於獲取一個日誌記錄器(Logger)
private Logger logger = LogManager.getLogger(this.getClass().getPackage().getName());
@RequestMapping("/list")
    public String getCustomerList(Model model, SearchInfo searchInfo){
        logger.info("request this /list interface");
        //...
    }
}

若配置文件名稱不是預設的跨域通過以下代碼來載入:

File file = new File("/Users/jerry/LOGfj/src/main/resources/log4j3.xml");
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
ConfigurationSource source = new ConfigurationSource(in);
Configurator.initialize(null, source);

您的分享是我們最大的動力!

更多相關文章
  • 1.Object類 equals方法 2.Date類 構造方法 成員方法 DateFormat類 Calendar類 3.System類 StringBuilder原理 構造方法 toString方法 4.包裝類 裝箱&拆箱 自動裝箱&自動拆箱 基本類型和字元串類型的 轉換 5.Collection ...
  • 11、Filter (重點) Filter:過濾器 ,用來過濾網站的數據; 處理中文亂碼 登錄驗證…. Filter開發步驟: 1. 導包 2. 編寫過濾器 1. 導包不要錯 實現Filter介面,重寫對應的方法即可 3. 在web.xml中配置 Filter 12、監聽器 實現一個監聽器的介面;( ...
  • 方法一:直接使用已知的cookie訪問 優點: 簡單,但需要先在瀏覽器登錄 原理: 簡單地說,cookie保存在發起請求的客戶端中,伺服器利用cookie來區分不同的客戶端。因為http是一種無狀態的連接,當伺服器一下子收到好幾個請求時,是無法判斷出哪些請求是同一個客戶端發起的。而“訪問登錄後才能看 ...
  • 簡介: JPA(java Persistence API)和SpringData是兩個範疇的概念。spring data jpa是spring公司下的spring data項目的一個模塊。 spring data jpa定義了介面來進行持久層的編寫規範,同時還大大簡化了持久層的CRUD操作。 從此可 ...
  • 前情提要 "Scala函數式編程指南(一) 函數式思想介紹" "scala函數式編程(二) scala基礎語法介紹" "Scala函數式編程(三) scala集合和函數" "Scala函數式編程(四)函數式的數據結構 上" "Scala函數式編程(四)函數式的數據結構 下" 1.面向對象的錯誤處理 ...
  • 最近不知怎麼的,想研究一下圖表。先上效果圖: 功能代碼: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, TeeEdit, E ...
  • python3-cookbook中每個小節以問題、解決方案和討論三個部分探討了Python3在某類問題中的最優解決方式,或者說是探討Python3本身的數據結構、函數、類等特性在某類問題上如何更好地使用。這本書對於加深Python3的使用和提升Python編程能力的都有顯著幫助,特別是對怎麼提高Py ...
  • 如何定義python源文件的文件編碼 如果想要定義文件代碼的編碼,一個特殊的註釋應該放到源文件的第一或第二行,例如: # coding=<encoding name> 或 使用一種大多數編輯器都能識別的方式 # -*- coding: <encoding name> -*- 或 # vim: set ...
一周排行
  • 一:背景 1. 講故事 如果你常翻看FCL的源碼,你會發現這裡面有不少方法藉助了C/C++的力量讓C#更快更強悍,如下所示: [DllImport("QCall", CharSet = CharSet.Unicode)] [SecurityCritical] [SuppressUnmanagedCo ...
  • 上一篇(https://www.cnblogs.com/meowv/p/12966092.html)文章使用AutoMapper來處理對象與對象之間的映射關係,本篇主要圍繞定時任務和數據抓取相關的知識點並結合實際應用,在定時任務中迴圈處理爬蟲任務抓取數據。 開始之前可以刪掉之前測試用的幾個Hello ...
  • 首先創建實體類 1 public class MacState 2 { 3 /// <summary> 4 /// 請求狀態 5 /// </summary> 6 public string success { get; set; } 7 /// <summary> 8 /// 錯誤信息 9 /// ...
  • 0. 前言 前幾天FreeSql的作者向我推薦了FreeSql框架,想讓我幫忙寫個文章介紹一下。嗯,想不到我也能帶個貨了。哈哈,開個玩笑~看了下覺得設計的挺有意思的,所以就謝了這篇文章。 簡單介紹一下,FreeSql 是NCC組織的沙盒級項目,是一款功能強大的 ORM 組件,支持 .NET Core ...
  • 0. 前言 這是一個新的系列,名字是《ASP.NET Core 入門到實戰》。這個系列主講ASP.NET Core MVC,輔助一些前端的基礎知識(能用來實現我們需要的即可,並非主講)。同時這個系列也會在後續介紹ASP.NET Core 平臺的其它類型的項目,並帶領大家以各個類型的項目為主要架構開發 ...
  • 我寫了一個Winform測試程式,用的System.Timers.Timer,在事件里,設置label1.Text,然後,居然句柄泄漏、用戶對象泄漏! 百思不得其解,最後換成System.Windows.Forms.Timer,居然不泄漏了! 最近睡眠不足,哪怕一個很小的問題,隨便搞搞,都半夜了! ...
  • leetcode-7. 整數反轉。 給出一個 32 位的有符號整數,你需要將這個整數中每位上的數字進行反轉。 示例 1: 輸入: 123 輸出: 321 示例 2: 輸入: -123 輸出: -321 示例 3: 輸入: 120 輸出: 21 註意: 假設環境只能存儲得下 32 位的有符號整數,則其 ...
  • 1. Java 虛擬機是什麼? 1.1 虛擬機 虛擬機:虛擬的電腦,一個用來執行虛擬電腦指令的軟體。 虛擬機分為系統虛擬機和程式虛擬機。 系統虛擬機:提供一個可運行完整操作系統的軟體平臺,如 Visual Box、VMware。 程式虛擬機:專門執行單個程式的,典型代表 Java 虛擬機。Jav ...
  • 前言 - strlen 概述 無意間掃到 glibc strlen.c 中代碼, 久久不能忘懷. 在一無所知的編程生涯中又記起點點滴滴: 編程可不是兒戲 ❀, 有些難, 也有些不捨. 隨軌跡一同重溫, 曾經最熟悉的 strlen 手感吧 ~ /* Copyright (C) 1991-2020 Fr ...
  • 背景 隊列[Queue]:是一種限定僅在表頭進行刪除操作,僅在表尾進行插入操作的線性表;即先進先出(FIFO-first in first out):最先插入的元素最先出來。 本文通過編碼實現鏈式隊列類,並模擬一個有趣的應用,能夠幫助我們對鏈式隊列有更深度的理解。 基本概念 結點 每個元素,除了存儲 ...