“哦,你來了!你還記得我們今天還有一節課嗎?”

“不是,我就是來找你的,差點……”

“太好了,那我們開始吧,今天我要給大家講講伐木。”

“日誌是已發生事件的列表。幾乎就像航海日誌或日記。或者推特——也許你能更好地理解它。毫不奇怪,記錄器是你用來記錄日誌的對象。”

“在編程中,習慣上記錄幾乎所有內容。而在 Java 中,我們記錄所有內容,甚至更多。”

“事實是,Java 程序通常是沒有 UI、控制台等的大型服務器應用程序。它們同時處理數以千計的用戶請求,並且經常出現各種錯誤。尤其是當不同的線程開始相互干擾時。”

“事實上,在這些情況下搜索很少重現的錯誤和故障的唯一方法是記錄每個線程上發生的一切。”

“大多數情況下,日誌包含有關方法參數的信息、任何捕獲的錯誤以及大量中間信息。”

“日誌越完整,重現事件序列和跟踪故障或錯誤的原因就越容易。”

“有時日誌每天達到幾千兆字節。這是正常的。”

“幾千兆字節?O_o”

“是的。大多數情況下,日誌文件會自動存檔,並註明相關日期。”

“哇哦。”

“嗯嗯,一開始Java是沒有自己的logger的,結果寫了幾個獨立的logger,其中最常見的就是log4j。”

“幾年後,Java 有了自己的記錄器,但它的功能遠不如它,並沒有被廣泛使用。”

“ Java 有官方記錄器是事實,但整個 Java 程序員社區更喜歡使用其他記錄器。 ”

“後來又基於log4j寫了幾個logger。”

“然後為所有這些編寫了現在廣泛使用的特殊通用記錄器 slf4j。它與 log4j 非常相似,因此我將在解釋日誌記錄時以它為例。”

“整個測井過程由三部分組成。”

首先,收集情報。”

第二,對收集到的信息進行過濾。”

第三,記錄選擇的信息。”

“讓我們從收集開始。這是一個記錄類的典型示例:”

帶日誌的類
class Manager
{
 private static final Logger logger = LoggerFactory.getLogger(Manager.class);

 public boolean processTask(Task task)
 {
  logger.debug("processTask id = " + task.getId());
  try
  {
   task.start();
   task.progress();
   task.complete();
   return true;
  }
  catch(Exception e)
  {
   logger.error("Unknown error", e);
   return false;
  }
 }
}

“注意以紅色突出顯示的詞。”

第 3 行 ——創建記錄器對象。幾乎每個類都會創建這樣一個靜態對象!好吧,除了那些除了存儲數據之外什麼都不做的類。”

" LoggerFactory是一個用於創建記錄器的特殊類,getLogger 是它的靜態方法之一。通常傳遞當前對象,但也可以有多種選擇。"

" Line 7 – 將方法調用的信息寫入記錄器。請注意,這是方法的第一行。一旦調用方法,我們立即將信息寫入日誌。"

“我們調用debug方法,就是說信息的重要性是DEBUG級別,這個是用來過濾的,過幾分鐘我會告訴你的。”

第 17 行——我們捕獲異常並……立即將其寫入日誌!這正是需要做的。”

“這次我們調用error方法,馬上提示信息為ERROR級別”

記錄器 - 1

“現在一切似乎都清楚了。好吧,就我們談話的過程中可以清楚的而言。”

“很好,那我們繼續進行消息過濾。”

“通常,每條日誌消息都有自己的重要性級別,您可以使用它來丟棄一些消息。以下是我提到的重要性級別:”

重要性等級 描述
全部 所有消息
痕跡 細粒度的調試消息
調試 重要的調試信息
信息 信息性消息
警告 警告
錯誤 錯誤
致命的 致命錯誤
離開 沒有消息

過濾消息時也會使用這些級別。

假設您將日誌記錄級別設置為 WARN。然後所有不如 WARN 重要的消息將被丟棄:TRACE、DEBUG、INFO。

如果將過濾級別設置為 FATAL,那麼即使是 ERROR 消息也會被丟棄。

“過濾時還有兩個重要級別:OFF,丟棄所有消息;ALL,顯示所有消息(不丟棄任何消息)。”

“如何以及在何處設置過濾?”

“我不多說了就告訴你。”

“通常,log4j 記錄器設置在 log4j.properties 文件中指定。”

您可以在此文件中指定多個附加程序對象。數據被寫入這些對象。有數據源,也有附加程序——目的相反的對象。數據像水一樣流入的對象。

“這裡有些例子:”

登錄到控制台
# Root logger option
log4j.rootLogger = INFO, stdout

# Direct log messages to stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}

第 1 行和第 4 行——這些是註釋

第 2 行——我們指出我們想要的日誌記錄級別。所有不太重要的級別(DEBUG、TRACE)都將被丟棄。

在同一個地方,我們添加一個逗號,然後指示將寫入日誌的對象的名稱(這是我們自己提出的)。第 5-9 行包含其設置。

第 5 行——我們指定附加程序的類型 ( ConsoleAppender )。

第 6 行——我們準確指出我們正在寫入的位置(System.out.)。

第 7 行——我們設置將管理轉換模式 (PatternLayout) 的類。

第 8 行——我們設置將用於寫入的轉換模式。在上面的示例中,它是日期和時間。

“這是寫入文件的樣子:”

記錄到文件
# Root logger option
log4j.rootLogger = INFO, file

# Direct log messages to a log file
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = C:\\loging.log
log4j.appender.file.MaxFileSize = 1MB
log4j.appender.file.MaxBackupIndex = 1
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-5p %c{1}:%L - %m%n

“第 2 行設置消息過濾級別和 appender 對象(sink)的名稱。”

“第 5 行——我們指定文件附加程序類型 ( RollingFileAppender )。”

“第 6 行 – 我們指定將寫入日誌的文件的名稱。”

“第 7 行 – 我們指定最大日誌大小。當超過此大小限制時,將創建一個新文件。”

“第 8 行 – 我們指定要存儲的舊日誌文件的數量。”

“第 9-10 行——設置轉換模式。”

“我不知道這裡發生了什麼,但我可以猜到。這令人鼓舞。”

“那太好了。下面是一個如何將日誌寫入文件和控制台的示例:”

記錄到控制台和文件
# Root logger option
log4j.rootLogger = INFO, file, stdout

# Direct log messages to a log file
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = C:\\loging.log
log4j.appender.file.MaxFileSize = 1MB
log4j.appender.file.MaxBackupIndex = 1
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-5p %c{1}:%L - %m%n

# Direct log messages to stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}

“啊,那你就可以了?太好了!”

“是的。您可以根據需要聲明任意數量的附加程序並自定義每個附加程序。”

此外,每個附加程序都可以有非常靈活的消息過濾設置。我們不僅可以為每個附加程序分配一個單獨的消息過濾級別,而且我們還可以按包過濾消息!這就是為什麼您需要在創建記錄器時指定一個類(我說的是LoggerFactory.getLogger)。

“例如:”

記錄到控制台和文件
# Root logger option
log4j.rootLogger = INFO, file, stdout

# Direct log messages to a log file
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.threshold = DEBUG
log4j.appender.file.File = C:\\loging.log
log4j.appender.file.MaxFileSize = 1MB
log4j.appender.file.MaxBackupIndex = 1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-5p %c{1}:%L - %m%n

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.threshold = ERROR
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}

log4j.logger.org.springframework = ERROR
log4j.logger.org.hibernate = ERROR
log4j.logger.com.codegym = DEBUG
log4j.logger.org.apache.cxf = ERROR

“第 6 行和第 15 行——我們為每個附加程序設置了自己的過濾級別。”

“第 20-23 行——我們為其消息指定包名稱和過濾級別。Log4j.logger 是一個前綴:包名稱以橙色突出顯示。”

“真的嗎?你甚至可以那樣做。嗯,酷!”

“順便說一句,log4j 和 slf4j 都不包含在 JDK 中。您需要單獨下載它們。您可以在此處下載。但還有另一種方法:”

第 1 步。將導入添加到類中:”

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

第 2 步。將光標放在這些行上,然後在 IntelliJ IDEA 中按 Alt+Enter”

"第 3 步。選擇“Web 上的文件 jar» 菜單項。

第 4 步。選擇‘slf4j-log4j13.jar’”

第 5 步。指定下載庫 (jar) 的位置”

第 6 步。使用您需要的課程。”

“哇!今天過得真好。有那麼多新鮮事,還有那麼多酷事!”

“這是另一篇關於日誌記錄的好文章:https://docs.oracle.com/javase/10/core/java-logging-overview.htm#JSCOR-GUID-48004124-2C00-49F7-A640-0C0DDA271DBC

“好了,夠了,放鬆點吧,程序員。”