"อ้าว จำได้ไหมว่าวันนี้เรามีเรียนอีกคาบ"

“เปล่า ฉันแค่ตามหาเธอ เกือบ…”

“ดี งั้นมาเริ่มกันเลย วันนี้ฉันอยากจะบอกคุณเกี่ยวกับการเข้าสู่ระบบ”

"บันทึกเป็นรายการของเหตุการณ์ที่เกิดขึ้น เกือบจะเหมือนกับบันทึกของเรือหรือบันทึกประจำวัน หรือ Twitter — บางทีคุณอาจเกี่ยวข้องกับเรื่องนั้นได้ดีกว่า ไม่น่าแปลกใจเลยที่คนตัดไม้เป็นวัตถุที่คุณใช้สำหรับบันทึก"

"ในการเขียนโปรแกรม เป็นเรื่องปกติที่จะบันทึกเกือบทุกอย่าง และใน Java เราบันทึกทุกอย่างและอื่นๆ อีกเล็กน้อย"

"ความจริงก็คือ โปรแกรม Java มักจะเป็นเซิร์ฟเวอร์แอปพลิเคชันขนาดใหญ่ที่ไม่มี UI, คอนโซล และอื่นๆ โปรแกรมเหล่านี้ประมวลผลคำขอของผู้ใช้หลายพันรายการพร้อมกัน และมักมีข้อผิดพลาดต่างๆ เกิดขึ้น โดยเฉพาะอย่างยิ่งเมื่อเธรดต่างๆ เริ่มรบกวนซึ่งกันและกัน"

"ความจริงแล้ว วิธีเดียวที่จะค้นหาข้อบกพร่องและความล้มเหลวที่เกิดขึ้นได้ยากในสถานการณ์เหล่านี้คือการบันทึกทุกสิ่งที่เกิดขึ้นในแต่ละเธรด"

"โดยมากแล้ว บันทึกจะมีข้อมูลเกี่ยวกับอาร์กิวเมนต์ของเมธอด ข้อผิดพลาดที่ตรวจจับได้ และข้อมูลขั้นกลางจำนวนมาก"

"ยิ่งบันทึกสมบูรณ์มากเท่าใด ก็ยิ่งสร้างลำดับเหตุการณ์และติดตามสาเหตุของความล้มเหลวหรือข้อบกพร่องได้ง่ายขึ้นเท่านั้น"

"บางครั้งบันทึกถึงหลายกิกะไบต์ต่อวัน ซึ่งเป็นเรื่องปกติ"

"ไม่กี่กิกะไบต์เหรอ O_o"

"ใช่ ส่วนใหญ่ไฟล์บันทึกจะถูกเก็บถาวรโดยอัตโนมัติพร้อมระบุวันที่ที่เกี่ยวข้อง"

"โว้ว."

"อืม เริ่มแรก Java ไม่มีตัวบันทึกของตัวเอง ผลก็คือมีการเขียนตัวบันทึกอิสระหลายตัว ตัวที่พบมากที่สุดคือ log4j"

"ไม่กี่ปีต่อมา Java มีตัวบันทึกเป็นของตัวเอง แต่ฟังก์ชันการทำงานด้อยกว่ามาก และไม่ได้ถูกใช้อย่างแพร่หลาย"

"เป็นความจริงที่Java มีตัวบันทึกอย่างเป็นทางการ แต่ชุมชนโปรแกรมเมอร์ Java ทั้งหมดชอบที่จะใช้ตัวบันทึกอื่น ๆ "

"ต่อมา คนตัดไม้อีกหลายคนเขียนโดยใช้ log4j"

"จากนั้น 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.compleate();
   return true;
  }
  catch(Exception e)
  {
   logger.error("Unknown error", e);
   return false;
  }
 }
}

"ให้ความสนใจกับคำที่เน้นด้วยสีแดง"

" บรรทัดที่ 3  – สร้าง ออบเจกต์ loggerวัตถุสแตติกดังกล่าวถูกสร้างขึ้นในเกือบทุกคลาส! ยกเว้นคลาสที่ไม่ได้ทำอะไรนอกจากเก็บข้อมูล"

" LoggerFactoryเป็นคลาสพิเศษสำหรับสร้างตัวบันทึก และ getLogger เป็นหนึ่งในเมธอดแบบสแตติก โดยทั่วไป อ็อบเจ็กต์ปัจจุบันจะถูกส่งผ่าน แต่มีตัวเลือกที่หลากหลาย"

" บรรทัดที่ 7 – ข้อมูลเกี่ยวกับการเรียกใช้เมธอดถูกเขียนไปยังคนบันทึก โปรดทราบว่านี่คือบรรทัดแรกของเมธอด ทันทีที่เรียกใช้เมธอด เราจะเขียนข้อมูลลงในบันทึกทันที"

"เราเรียกวิธีการแก้ไขจุดบกพร่อง ซึ่งหมายความว่าข้อมูลมีความสำคัญในระดับ DEBUG ซึ่งใช้สำหรับการกรอง ฉันจะบอกคุณเกี่ยวกับเรื่องนี้ในไม่กี่นาที"

" บรรทัดที่ 17 – เราพบข้อยกเว้นและ... เขียนลงในบันทึกทันที! นี่คือสิ่งที่ต้องทำ"

"คราวนี้เราเรียกเมธอดข้อผิดพลาด ซึ่งบ่งชี้ทันทีว่าข้อมูลอยู่ในระดับ ERROR"

คนตัดไม้ - 1

"ทุกอย่างดูเหมือนจะชัดเจนในตอนนี้ เอาล่ะ เท่าที่มันจะชัดเจนในระหว่างการสนทนาของเรา"

"เยี่ยมมาก ถ้าอย่างนั้นเรามากรองข้อความกัน"

"โดยปกติแล้ว ข้อความในบันทึกแต่ละรายการจะมีระดับความสำคัญของตัวเอง ซึ่งคุณสามารถใช้เพื่อละทิ้งข้อความบางข้อความได้ ต่อไปนี้เป็นระดับความสำคัญที่ฉันกล่าวถึง:"

ระดับความสำคัญ คำอธิบาย
ทั้งหมด ข้อความทั้งหมด
ติดตาม ข้อความดีบักแบบละเอียด
ดีบัก ข้อความแก้ไขข้อบกพร่องที่สำคัญ
ข้อมูล ข้อความที่ให้ข้อมูล
เตือน คำเตือน
ข้อผิดพลาด ข้อผิดพลาด
ร้ายแรง ข้อผิดพลาดร้ายแรง
ปิด ไม่มีข้อความ

ระดับเหล่านี้ยังใช้เมื่อกรองข้อความ

สมมติว่าคุณตั้งค่าระดับการบันทึกเป็น WARN จากนั้นข้อความทั้งหมดที่มีความสำคัญน้อยกว่า WARN จะถูกยกเลิก: TRACE, DEBUG, INFO

หากคุณตั้งค่าระดับการกรองเป็น FATAL แม้แต่ข้อความ ERROR ก็จะถูกยกเลิก

"มีระดับความสำคัญอีกสองระดับที่ใช้เมื่อกรอง: ปิด ซึ่งจะละทิ้งข้อความทั้งหมด และทั้งหมด ซึ่งแสดงข้อความทั้งหมด (ไม่มีอะไรถูกละทิ้ง)"

"ฉันจะตั้งค่าการกรองได้อย่างไรและที่ไหน"

“ฉันจะบอกคุณโดยไม่ต้องกังวลใจอีกต่อไป”

"โดยปกติแล้ว การตั้งค่าตัวบันทึก log4j จะถูกระบุในไฟล์ log4j.properties"

คุณสามารถระบุวัตถุ appender ได้หลายรายการในไฟล์นี้ ข้อมูลถูกเขียนไปยังวัตถุเหล่านี้ มีแหล่งข้อมูลและมีส่วนต่อท้าย - วัตถุที่มีจุดประสงค์ตรงกันข้าม วัตถุที่ข้อมูลไหลเป็นน้ำ

"นี่คือตัวอย่างบางส่วน:"

เข้าสู่ระบบคอนโซล
# 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 – เราระบุประเภทของ appender ( 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 – เราระบุประเภท appender ไฟล์ ( 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}

"อา คุณทำได้อย่างนั้นหรือ เยี่ยมมาก!"

"ใช่ คุณสามารถประกาศผู้ต่อได้มากเท่าที่คุณต้องการและปรับแต่งแต่ละคน"

นอกจากนี้ appender แต่ละรายสามารถมีการตั้งค่าที่ยืดหยุ่นมากสำหรับการกรองข้อความ ไม่เพียงแต่เรากำหนดระดับการกรองข้อความให้กับ appender แต่ละคนเท่านั้น แต่เรายังสามารถกรองข้อความตามแพ็คเกจได้อีกด้วย! นั่นเป็นเหตุผลที่คุณต้องระบุคลาสเมื่อสร้างคนตัดไม้ (ฉันกำลังพูดถึง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วางเคอร์เซอร์บนบรรทัดเหล่านี้แล้วกด Alt+Enter ใน IntelliJ IDEA"

" ขั้นตอนที่ 3เลือกรายการเมนู 'File jar on web»'

" ขั้นตอนที่ 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 "

"เอาล่ะ ก็พอแล้ว ไปพักผ่อนเถอะ โปรแกรมเมอร์"