สวัสดี! เมื่อเขียนบทเรียน ฉันเน้นย้ำเป็นพิเศษหากมีหัวข้อเฉพาะที่จำเป็นอย่างยิ่งในการทำงานจริง ดังนั้น ฟังหูไว้หู! หัวข้อที่เราจะกล่าวถึงในวันนี้จะมีประโยชน์ในทุกโครงการของคุณตั้งแต่วันแรกของการจ้างงาน เราจะพูดถึง Java Logging หัวข้อนี้ไม่ซับซ้อนเลย (จะบอกว่าง่ายด้วยซ้ำ) แต่คุณจะมีสิ่งที่ชัดเจนมากพอที่จะเน้นเกี่ยวกับงานแรกของคุณ ดังนั้นควรทำความเข้าใจให้ละเอียดตอนนี้จะดีกว่า :) เอาล่ะ เริ่มกันเลย
การเข้าสู่ระบบใน Java คืออะไร
การบันทึกคือการบันทึกข้อมูลเกี่ยวกับการทำงานของโปรแกรม สถานที่ที่เราบันทึกข้อมูลนี้เรียกว่า "บันทึก" คำถามสองข้อเกิดขึ้นทันที: ข้อมูลใดที่เขียนและที่ใด เริ่มจาก "ที่ไหน" กันก่อน คุณสามารถเขียนข้อมูลเกี่ยวกับการทำงานของโปรแกรมในที่ต่างๆ ตัวอย่างเช่น ในระหว่างที่คุณเรียน คุณมักจะSystem.out.println()เพื่อส่งออกข้อมูลไปยังคอนโซล นี่คือการบันทึกจริง ๆ แม้ว่าจะอยู่ในรูปแบบที่ง่ายที่สุดก็ตาม แน่นอนว่าสิ่งนี้ไม่สะดวกสำหรับผู้ใช้หรือทีมสนับสนุนผลิตภัณฑ์: เห็นได้ชัดว่าพวกเขาไม่ต้องการติดตั้ง IDE และตรวจสอบคอนโซล :) มีรูปแบบการบันทึกข้อมูลที่เป็นธรรมเนียมมากขึ้น: ไฟล์ข้อความ มนุษย์มีความสะดวกสบายในการอ่านข้อมูลในรูปแบบนี้ และแน่นอนว่าสะดวกกว่ามากสำหรับการจัดเก็บข้อมูล! คำถามที่สอง: ควรบันทึกข้อมูลโปรแกรมใด นั่นขึ้นอยู่กับคุณทั้งหมด! ระบบบันทึกของ Java มีความยืดหยุ่นมาก คุณสามารถกำหนดค่าให้บันทึกทุกอย่างที่โปรแกรมของคุณทำ ในแง่หนึ่งนี่เป็นสิ่งที่ดี แต่ในทางกลับกัน ลองนึกดูว่าบันทึกของ Facebook หรือ Twitter จะใหญ่ขนาดไหนหากพวกเขาเขียนทุกอย่างลงในนั้น บริษัทขนาดใหญ่เหล่านี้อาจมีความสามารถในการจัดเก็บข้อมูลได้มากขนาดนั้น แต่ลองนึกดูว่าการค้นหาข้อมูลเกี่ยวกับข้อผิดพลาดร้ายแรงหนึ่งรายการในบันทึกข้อความ 500 กิกะไบต์จะยากเพียงใด นั่นจะเลวร้ายยิ่งกว่าการงมเข็มในมหาสมุทร ดังนั้นจึงสามารถกำหนดค่า Java ให้บันทึกเฉพาะข้อมูลข้อผิดพลาดได้ หรือแม้แต่ข้อผิดพลาดร้ายแรง! ที่กล่าวว่า การพูดถึงระบบการบันทึกแบบเนทีฟของ Java ไม่ถูกต้องทั้งหมด ความจริงก็คือโปรแกรมเมอร์จำเป็นต้องเข้าสู่ระบบก่อนที่จะเพิ่มฟังก์ชันนี้ลงในภาษา เมื่อถึงเวลาที่ Java เปิดตัวไลบรารีการบันทึกของตัวเอง ทุกคนก็ใช้ไลบรารี log4j อยู่แล้ว ประวัติการเข้าสู่ระบบใน Java นั้นยาวและให้ข้อมูลมาก กล่าวโดยย่อ Java มีไลบรารีการบันทึกของตัวเอง แต่แทบไม่มีใครใช้เลย :) ต่อมา เมื่อไลบรารีการบันทึกต่างๆ ปรากฏขึ้นและเริ่มใช้งานโดยโปรแกรมเมอร์ ปัญหาความเข้ากันได้ก็เกิดขึ้น เพื่อหยุดไม่ให้ผู้คนสร้างวงล้อขึ้นมาใหม่ในไลบรารีต่างๆ ที่มีอินเทอร์เฟซที่แตกต่างกัน เฟรมเวิร์ก SLF4J แบบนามธรรม ("Service Logging Facade For Java") จึงถูกสร้างขึ้น มันเรียกว่านามธรรม เพราะแม้ว่าคุณจะใช้และเรียกใช้เมธอดของคลาส SLF4J แต่ภายใต้ประทุนนั้น จริงๆ แล้วพวกเขาใช้เฟรมเวิร์กการบันทึกทั้งหมดที่มีมาก่อน: log4j, java.util.logging มาตรฐาน และอื่นๆ หากถึงจุดหนึ่ง คุณต้องการคุณลักษณะเฉพาะบางอย่างของ Log4j ที่ขาดในไลบรารีอื่น แต่คุณไม่ต้องการเชื่อมโยงโปรเจ็กต์ของคุณกับไลบรารีนี้โดยตรง ให้ใช้ SLF4J แล้วให้มันเรียกเมธอด Log4j หากคุณเปลี่ยนใจและตัดสินใจว่าไม่ต้องการฟีเจอร์ Log4j อีกต่อไป คุณจะต้องกำหนดค่า "ที่นี่และห้องสมุด Log4j ที่นี่ ถัดไป แตกไฟล์เก็บถาวรและใช้ IntelliJ IDEA เพื่อเพิ่มไฟล์ JAR ไปยัง classpath รายการเมนู: ไฟล์ -> โครงสร้างโครงการ -> ไลบรารี เลือกไฟล์ JAR ที่จำเป็นและเพิ่มลงในโครงการ (ไฟล์เก็บถาวรที่เราดาวน์โหลดมีไฟล์ JAR จำนวนมาก — ดูรูปภาพเพื่อดูไฟล์ที่คุณต้องการ) โปรดทราบว่าคำสั่งนี้สำหรับนักเรียนเหล่า นั้น ที่ไม่รู้วิธีใช้ Maven หากคุณรู้วิธีใช้ Maven มักจะดีกว่า (ง่ายกว่ามาก) ในการพยายามเริ่มต้นที่นั่น หากคุณใช้Mavenให้เพิ่มการพึ่งพานี้:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.14.0</version>
</dependency>
ยอดเยี่ยม! เราเข้าใจการตั้งค่าแล้ว :) มาดูกันว่า SLF4J ทำงานอย่างไร เราจะแน่ใจได้อย่างไรว่าการทำงานของโปรแกรมนั้นถูกบันทึกไว้ที่ไหนสักแห่ง? ในการทำเช่นนี้ เราต้องการสองสิ่ง: คนตัดไม้และผู้ผนวก เริ่มกันที่ข้อแรก คนตัดไม้เป็นวัตถุที่ให้การควบคุมการบันทึกอย่างสมบูรณ์ การสร้าง LoggerFactory.getLogger() ทำได้ง่ายมาก: เราใช้วิธี Static LoggerFactory.getLogger() พารามิเตอร์เมธอดคือคลาสที่การดำเนินการจะถูกบันทึก เรียกใช้รหัสของเรา:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyTestClass {
public static final Logger LOGGER = LoggerFactory.getLogger(MyTestClass.class);
public static void main(String[] args) {
LOGGER.info("Test log entry!!!");
LOGGER.error("An error occurred!");
}
}
เอาต์พุตคอนโซล:
ERROR StatusLogger No Log4j 2 configuration file found. Using default configuration (logging only errors to the console), or user programmatically provided configurations. Set system property 'log4j2.debug' to show Log4j 2 internal initialization logging. See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2 15:49:08.907 [main] ERROR MyTestClass - An error occurred!
เราเห็นอะไรที่นี่? อันดับแรก เราเห็นข้อความแสดงข้อผิดพลาด นี่เป็นผลจากความจริงที่ว่าตอนนี้เราขาดการตั้งค่าที่จำเป็น ดังนั้น ขณะนี้คนตัดไม้ของเราสามารถแสดงผลข้อความแสดงข้อผิดพลาด (ERROR) และเฉพาะกับคอนโซลเท่านั้น เมธอดlogger.info()ใช้งานไม่ได้ แต่logger.error()ทำ! บนคอนโซล เราจะเห็นวันที่ปัจจุบัน วิธีการที่เกิดข้อผิดพลาด ( main) คำว่า "ข้อผิดพลาด" และข้อความของเรา! ERROR คือระดับการบันทึก โดยทั่วไป หากรายการบันทึกถูกทำเครื่องหมายด้วยคำว่า "ERROR" แสดงว่ามีข้อผิดพลาดเกิดขึ้นในจุดนี้ในโปรแกรม หากรายการถูกทำเครื่องหมายด้วยคำว่า "INFO" ข้อความจะแสดงข้อมูลปัจจุบันเกี่ยวกับการทำงานปกติของโปรแกรม ไลบรารี SLF4J มีระดับการบันทึกที่แตกต่างกันมากมาย ซึ่งช่วยให้คุณกำหนดค่าการบันทึกได้อย่างยืดหยุ่น ทุกอย่างจัดการง่ายมาก: ตรรกะที่จำเป็นทั้งหมดอยู่ในคลาส Java Logger แล้ว คุณเพียงแค่ต้องเรียกวิธีการที่เกี่ยวข้อง หากคุณต้องการบันทึกข้อความประจำ ให้ เรียก เมธอดlogger.info() สำหรับข้อความแสดงข้อผิดพลาด ให้ใช้logger.error( ) สำหรับคำเตือน ให้ใช้logger.warn()
ตอนนี้เรามาพูดถึง appender กัน
appender เป็นสถานที่ที่ข้อมูลของคุณไป ในทางตรงข้ามกับแหล่งข้อมูล เช่น "จุด B" ตามค่าเริ่มต้น ข้อมูลจะถูกส่งออกไปยังคอนโซล โปรดทราบว่าในตัวอย่างก่อนหน้านี้ เราไม่ต้องกำหนดค่าอะไรเลย: ข้อความปรากฏในคอนโซล และตัวบันทึกของไลบรารี Log4j สามารถส่งออกข้อความระดับ ERROR ไปยังคอนโซลเท่านั้น เห็นได้ชัดว่าผู้คนสามารถอ่านและเขียนบันทึกในไฟล์ข้อความได้สะดวกกว่า หากต้องการเปลี่ยนพฤติกรรมเริ่มต้นของคนตัดไม้ เราจำเป็นต้องกำหนดค่าส่วนต่อท้ายไฟล์ของเรา ในการเริ่มต้น คุณต้องสร้างไฟล์ log4j.xml โดยตรงในโฟลเดอร์ src คุณคุ้นเคยกับรูปแบบ XML ดีอยู่แล้ว เราเพิ่งมีบทเรียนเกี่ยวกับรูปแบบนี้ :) นี่คือเนื้อหาของไฟล์:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<File name="MyFileAppender" fileName="C:\Users\Username\Desktop\testlog.txt" immediateFlush="false" append="false">
<PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="MyFileAppender"/>
</Root>
</Loggers>
</Configuration>
ไม่มีอะไรพิเศษหรือยากเป็นพิเศษที่นี่ :) แต่ถึงกระนั้นเรามาดูเนื้อหากัน
<Configuration status="INFO">
นี่คือสิ่งที่เรียกว่า StatusLogger ไม่เกี่ยวข้องกับคนตัดไม้ของเราและใช้ในกระบวนการภายในของ Log4j หากคุณตั้งค่า status="TRACE" แทน status="INFO" และข้อมูลทั้งหมดเกี่ยวกับงานภายในของ Log4j จะแสดงบนคอนโซล (StatusLogger แสดงข้อมูลบนคอนโซล แม้ว่า appender ของเราจะเป็นไฟล์ก็ตาม) ตอนนี้เราไม่ต้องการมันแล้ว ดังนั้นปล่อยให้มันเหมือนเดิม
<Appenders>
<File name="MyFileAppender" fileName="C:\Users\Evgeny\Desktop\testlog.txt" append="true">
<PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
ที่นี่เราสร้าง appender ของเรา แท็ ก <ไฟล์>ระบุว่าจะเป็นตัวผนวกไฟล์ name="MyFileAppender"ตั้งชื่อของผู้ผนวก fileName="C:\Users\Username\Desktop\testlog.txt"ระบุเส้นทางไปยังไฟล์บันทึกที่จะเขียนข้อมูลทั้งหมด append="true"ระบุว่าควรเขียนข้อมูลต่อท้ายไฟล์หรือไม่ ในกรณีของเรา นี่คือสิ่งที่เราจะทำ หากคุณตั้งค่าเป็นเท็จ เนื้อหาเก่าของไฟล์บันทึกจะถูกลบทุกครั้งที่เริ่มโปรแกรม <PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>ระบุการตั้งค่าการจัดรูปแบบ ที่นี่ เราสามารถใช้นิพจน์ทั่วไปเพื่อปรับแต่งรูปแบบข้อความในบันทึกของเรา
<Loggers>
<Root level="INFO">
<AppenderRef ref="MyFileAppender"/>
</Root>
</Loggers>
ที่นี่เราระบุระดับราก เราได้ตั้งค่าระดับ "INFO" ซึ่งหมายความว่าข้อความทั้งหมดที่มีระดับสูงกว่า INFO (ตามตารางที่เราดูด้านบน) จะไม่ถูกบันทึก โปรแกรมของเราจะมี 3 ข้อความ: หนึ่ง INFO, หนึ่งคำเตือน และ หนึ่งข้อผิดพลาด ด้วยการกำหนดค่าปัจจุบัน ข้อความทั้ง 3 จะถูกบันทึก หากคุณเปลี่ยนระดับรูทเป็น ERROR เฉพาะข้อความสุดท้ายจากการเรียกเมธอด LOGGER.error() เท่านั้นที่จะสิ้นสุดในบันทึก นอกจากนี้ การอ้างอิงถึงผู้ต่อท้ายยังไปที่นี่ด้วย ในการสร้างข้อมูลอ้างอิง คุณต้องสร้าง แท็ก <ApprenderRef>ภายใน แท็ก <Root>และเพิ่ม แอตทริบิวต์ ref='your appender's name'ลงไป ในกรณีที่คุณลืม นี่คือที่ที่เราตั้งชื่อผู้ต่อท้าย: <. และนี่คือรหัสของเรา!
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyTestClass {
public static final Logger LOGGER = LoggerFactory.getLogger(MyTestClass.class);
public static void main(String[] args) {
LOGGER.info("The program is starting!!!");
try {
LOGGER.warn("Attention! The program is trying to divide a number by another.
System.out.println(12/0);
} catch (ArithmeticException x) {
LOGGER.error("Error! Division by zero!");
}
}
}
แน่นอนว่ามันออกจะแปลกๆ เล็กน้อย (การตรวจจับ RuntimeException เป็นแนวคิดที่น่าสงสัย) แต่มันสมบูรณ์แบบสำหรับวัตถุประสงค์ของเรา :) ลองเรียกใช้ เมธอด main() ของเรา 4 ครั้งติดต่อกันแล้วดูที่ไฟล์ testlog.txt ของเรา คุณไม่จำเป็นต้องสร้างล่วงหน้า: ห้องสมุดจะดำเนินการให้โดยอัตโนมัติ ทุกอย่างได้ผล! :) ตอนนี้คุณมีตัวบันทึกที่กำหนดค่าแล้ว คุณสามารถเล่นกับโปรแกรมเก่าบางโปรแกรมของคุณ โดยเพิ่มการเรียกคนตัดไม้ให้กับแต่ละวิธี จากนั้นดูบันทึกผลลัพธ์ :) พิจารณาหัวข้อการบันทึกเชิงลึก มันคงเป็นเรื่องท้าทายที่จะอ่านทั้งหมดในคราวเดียว ที่กล่าวว่ามีข้อมูลที่เป็นประโยชน์เพิ่มเติมมากมาย ตัวอย่างเช่น คุณจะได้เรียนรู้วิธีกำหนดค่าตัวบันทึกเพื่อสร้างไฟล์ข้อความใหม่หากไฟล์ testlog.txt ของเราถึงขนาดที่กำหนด :) และนั่นก็เป็นการสรุปคลาสของเรา! วันนี้คุณคุ้นเคยกับหัวข้อที่สำคัญมากและความรู้นี้จะเป็นประโยชน์กับคุณในการทำงานในอนาคตอย่างแน่นอน จนกว่าจะถึงครั้งต่อไป! :)
GO TO FULL VERSION