"อ้าว จำได้ไหมว่าวันนี้เรามีเรียนอีกคาบ"
“เปล่า ฉันแค่ตามหาเธอ เกือบ…”
“ดี งั้นมาเริ่มกันเลย วันนี้ฉันอยากจะบอกคุณเกี่ยวกับการเข้าสู่ระบบ”
"บันทึกเป็นรายการของเหตุการณ์ที่เกิดขึ้น เกือบจะเหมือนกับบันทึกของเรือหรือบันทึกประจำวัน หรือ 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"
"ทุกอย่างดูเหมือนจะชัดเจนในตอนนี้ เอาล่ะ เท่าที่มันจะชัดเจนในระหว่างการสนทนาของเรา"
"เยี่ยมมาก ถ้าอย่างนั้นเรามากรองข้อความกัน"
"โดยปกติแล้ว ข้อความในบันทึกแต่ละรายการจะมีระดับความสำคัญของตัวเอง ซึ่งคุณสามารถใช้เพื่อละทิ้งข้อความบางข้อความได้ ต่อไปนี้เป็นระดับความสำคัญที่ฉันกล่าวถึง:"
ระดับความสำคัญ | คำอธิบาย |
---|---|
ทั้งหมด | ข้อความทั้งหมด |
ติดตาม | ข้อความดีบักแบบละเอียด |
ดีบัก | ข้อความแก้ไขข้อบกพร่องที่สำคัญ |
ข้อมูล | ข้อความที่ให้ข้อมูล |
เตือน | คำเตือน |
ข้อผิดพลาด | ข้อผิดพลาด |
ร้ายแรง | ข้อผิดพลาดร้ายแรง |
ปิด | ไม่มีข้อความ |
ระดับเหล่านี้ยังใช้เมื่อกรองข้อความ
สมมติว่าคุณตั้งค่าระดับการบันทึกเป็น 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 "
"เอาล่ะ ก็พอแล้ว ไปพักผ่อนเถอะ โปรแกรมเมอร์"
GO TO FULL VERSION