JavaRush /จาวาบล็อก /Random-TH /เหตุใดจึงต้องมีการบันทึก?

เหตุใดจึงต้องมีการบันทึก?

เผยแพร่ในกลุ่ม
สวัสดี! เวลาเขียนบรรยาย ผมจะสังเกตเป็นพิเศษว่าหัวข้อใดหัวข้อหนึ่งจะได้นำไปใช้งานจริงได้อย่างแน่นอน ทำไมคุณต้องมีการบันทึก - 1 ดังนั้นความสนใจ! หัวข้อที่เราจะพูดถึงในวันนี้จะเป็นประโยชน์กับคุณอย่างแน่นอนในทุกโครงการของคุณตั้งแต่วันแรกของการทำงาน เราจะพูดถึงการบันทึก หัวข้อนี้ไม่ยากเลย (ฉันจะบอกว่าง่ายด้วยซ้ำ) แต่ในงานแรกของคุณ ก็จะมีความเครียดมากพอที่จะจัดการกับสิ่งที่ชัดเจนอยู่แล้ว ดังนั้น ตอนนี้เรามาเริ่มกันเลยดีกว่า :) การบันทึกคืออะไร? การบันทึกเป็นการบันทึกข้อมูลเกี่ยวกับการทำงานของโปรแกรม สถานที่ที่เขียนข้อมูลนี้เรียกว่า " บันทึก " คำถามสองข้อเกิดขึ้นพร้อมกัน: บันทึกข้อมูลที่ไหนและข้อมูลใด? เริ่มจาก "ที่ไหน" กันก่อน คุณสามารถบันทึกข้อมูลการทำงานของโปรแกรมไว้ในที่ต่างๆ ได้มากมาย ตัวอย่างเช่น ในระหว่างการศึกษา คุณมักจะส่งข้อมูลไปยังคอนโซลโดยใช้System.out.println(). นี่คือการบันทึกจริง แม้ว่าจะเป็นวิธีที่ง่ายที่สุดก็ตาม แน่นอนว่าสิ่งนี้ไม่สะดวกสำหรับลูกค้าหรือทีมสนับสนุนผลิตภัณฑ์: เห็นได้ชัดว่าพวกเขาไม่ต้องการติดตั้ง IDE และตรวจสอบคอนโซล :) นอกจากนี้ยังมีรูปแบบการบันทึกข้อมูลที่คุ้นเคยมากกว่า - ในไฟล์ข้อความ ผู้คนจะอ่านข้อความเหล่านี้ได้ง่ายขึ้นมาก และจัดเก็บได้ง่ายกว่ามากอย่างแน่นอน! ตอนนี้คำถามที่สอง: ข้อมูลใดเกี่ยวกับการทำงานของโปรแกรมที่ควรบันทึกไว้ในบันทึก? แต่ที่นี่ทุกอย่างขึ้นอยู่กับคุณ! ระบบการบันทึก Java มีความยืดหยุ่นมาก คุณสามารถกำหนดค่าในลักษณะที่ความคืบหน้าทั้งหมดของโปรแกรมของคุณจะถูกบันทึกไว้ ในแง่หนึ่งนี่เป็นสิ่งที่ดี แต่ในทางกลับกัน ลองจินตนาการว่าบันทึกของ Facebook หรือ Twitter สามารถเข้าถึงได้ขนาดไหนหากทุกอย่างถูกเขียนไว้ที่นั่น บริษัทขนาดใหญ่ดังกล่าวอาจมีความสามารถในการจัดเก็บข้อมูลได้แม้กระทั่งข้อมูลจำนวนเท่านี้ แต่ลองจินตนาการดูว่าการค้นหาข้อมูลเกี่ยวกับข้อผิดพลาดร้ายแรงในบันทึกที่มีข้อความขนาด 500 กิกะไบต์จะยากแค่ไหน มันเลวร้ายยิ่งกว่าเข็มในกองหญ้าเสียอีก ดังนั้น การบันทึกใน Java จึงสามารถกำหนดค่าเพื่อให้เขียนเฉพาะข้อมูลข้อผิดพลาดลงในบันทึก (บันทึก) หรือแม้แต่ข้อผิดพลาดร้ายแรง! แม้ว่าการพูดว่า "การบันทึกใน Java" จะไม่ถูกต้องทั้งหมด ความจริงก็คือความจำเป็นในการบันทึกเกิดขึ้นในหมู่โปรแกรมเมอร์ก่อนที่จะเพิ่มฟังก์ชันนี้ลงในภาษา และเมื่อ Java มีไลบรารีการบันทึกของตัวเอง ทุกคนก็ใช้ไลบรารี log4j อยู่แล้ว ประวัติความเป็นมาของการปรากฏตัวของการบันทึกใน Java นั้นยาวมากและให้ข้อมูลในยามว่างคุณสามารถอ่านโพสต์นี้บน Habré กล่าวโดยสรุป Java มีไลบรารีการบันทึกของตัวเอง แต่แทบไม่มีใครใช้เลย :) ต่อมาเมื่อมีไลบรารีการบันทึกที่แตกต่างกันหลายแห่งปรากฏขึ้น และโปรแกรมเมอร์ทั้งหมดเริ่มใช้งานที่แตกต่างกัน ปัญหาความเข้ากันได้ก็เกิดขึ้น เพื่อป้องกันไม่ให้ผู้คนทำสิ่งเดียวกันโดยใช้ไลบรารีที่แตกต่างกันหลายสิบแห่งที่มีอินเทอร์เฟซต่างกันเฟรมเวิร์กนามธรรม slf4j จึงถูกสร้างขึ้น(“บริการ Logging Facade สำหรับ Java”) มันถูกเรียกว่านามธรรมเพราะถึงแม้ว่าคุณจะใช้คลาส slf4j และเรียกใช้เมธอดของคลาสเหล่านั้น แต่เบื้องหลังคลาสเหล่านี้มีเฟรมเวิร์กการบันทึกก่อนหน้านี้ทั้งหมดที่ทำงานอยู่: log4j, java.util.logging มาตรฐาน และอื่นๆ หากคุณต้องการคุณสมบัติเฉพาะของ log4j ในปัจจุบันซึ่งไลบรารีอื่นไม่มี แต่คุณไม่ต้องการเชื่อมโยงโปรเจ็กต์กับไลบรารีเฉพาะนี้อย่างเคร่งครัด เพียงใช้ slf4j และเธอจะ "ดึง" วิธี log4j แล้ว หากคุณเปลี่ยนใจและตัดสินใจว่าไม่ต้องการคุณสมบัติ log4j อีกต่อไป คุณเพียงแค่ต้องกำหนดค่า “wrapper” ใหม่ (นั่นคือ slf4j) เพื่อใช้ไลบรารีอื่น รหัสของคุณจะไม่หยุดทำงานเพราะในนั้นคุณเรียกใช้เมธอดของ slf4j และไม่ใช่ของไลบรารีเฉพาะ การพูดนอกเรื่องเล็กน้อย เพื่อให้ตัวอย่างต่อไปนี้ใช้งานได้ คุณต้องดาวน์โหลดไลบรารี slf4j จากที่นี่และไลบรารี log4j จากที่นี่ ต่อไป เราต้องแตกไฟล์เก็บถาวรและเพิ่มไฟล์ jar ที่เราต้องการลงใน classpath ผ่าน Intellij IDEA รายการเมนู: ไฟล์ -> โครงสร้างโครงการ -> ไลบรารี เลือกขวดที่จำเป็นและเพิ่มลงในโครงการ (มีขวดจำนวนมากในไฟล์เก็บถาวรที่เราดาวน์โหลด ดูสิ่งที่คุณต้องการในรูปภาพ) ทำไมคุณต้องมีการบันทึก - 2ทำไมคุณต้องมีการบันทึก - 3หมายเหตุ - คำแนะนำนี้มีไว้สำหรับสิ่งเหล่านั้น นักเรียนที่ไม่รู้วิธีใช้ Maven หากคุณรู้วิธีใช้มัน ควรลองเริ่มเลยดีกว่า เพราะโดยปกติแล้วจะง่ายกว่ามาก หากคุณใช้Mavenให้เพิ่มการขึ้นต่อกันนี้:
<dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.14.0</version>
</dependency>
เยี่ยมมาก เราได้จัดเรียงการตั้งค่าแล้ว :) มาดูกันว่า slf4j ทำงานอย่างไร เราจะแน่ใจได้อย่างไรว่าความคืบหน้าของโปรแกรมถูกบันทึกไว้ที่ไหนสักแห่ง? สำหรับสิ่งนี้ เราต้องการสองสิ่ง - คนตัดไม้และผู้ต่อท้าย เริ่มจากอันแรกกันก่อน คนตัดไม้เป็นวัตถุที่จัดการการเก็บบันทึกอย่างสมบูรณ์ การสร้างคนตัดไม้นั้นง่ายมาก: ทำได้โดยใช้วิธีคงที่ - 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 record!!!");
       LOGGER.error("В программе возникла ошибка!");
   }
}
เอาต์พุตคอนโซล: ข้อผิดพลาด StatusLogger ไม่พบไฟล์การกำหนดค่า Log4j 2 การใช้การกำหนดค่าเริ่มต้น (การบันทึกเฉพาะข้อผิดพลาดไปยังคอนโซล) หรือการกำหนดค่าที่ผู้ใช้จัดเตรียมโดยทางโปรแกรม ตั้งค่าคุณสมบัติระบบ 'log4j2.debug' เพื่อแสดงการบันทึกการเริ่มต้นภายใน Log4j 2 ดู https://logging.apache.org/log4j/2.x/manual/configuration.html สำหรับคำแนะนำเกี่ยวกับวิธีกำหนดค่า Log4j 2 15:49:08.907 [main] ERROR MyTestClass - เกิดข้อผิดพลาดในโปรแกรม! เราเห็นอะไรที่นี่? ขั้นแรกเราเห็นข้อความแสดงข้อผิดพลาด ปรากฏเนื่องจากขณะนี้เราขาดการตั้งค่าที่จำเป็น ดังนั้น ขณะนี้ตัวบันทึกของเราสามารถส่งออกเฉพาะข้อความแสดงข้อผิดพลาด (ERROR) และไปยังคอนโซลเท่านั้น logger.info()ไม่ได้ดำเนินการวิธีการนี้ แต่logger.error()มันก็ได้ผล! คอนโซลจะแสดงวันที่ปัจจุบัน วิธีการที่เกิดข้อผิดพลาด ( main) คำว่า ERROR และข้อความของเรา! ข้อผิดพลาดคือระดับการบันทึก โดยทั่วไป หากรายการบันทึกถูกทำเครื่องหมายด้วยคำว่า ERROR หมายความว่ามีข้อผิดพลาดเกิดขึ้นที่จุดนั้นในโปรแกรม หากรายการถูกทำเครื่องหมายด้วยคำว่า INFO หมายความว่าเป็นเพียงข้อมูลปัจจุบันเกี่ยวกับการทำงานปกติของโปรแกรม ไลบรารี SLF4J มีระดับการบันทึกที่แตกต่างกันค่อนข้างมาก ซึ่งช่วยให้คุณสามารถกำหนดค่าการบันทึกได้อย่างยืดหยุ่น ง่ายต่อการจัดการ: ตรรกะที่จำเป็นทั้งหมดรวมอยู่ในชั้นเรียนLoggerแล้ว คุณเพียงแค่ต้องเรียกวิธีการที่จำเป็น หากต้องการโพสต์ข้อความปกติ โปรดโทรไปlogger.info()ที่ ข้อความผิดพลาด - logger.error(). แสดงคำเตือน - logger.warn() ตอนนี้เรามาพูดถึงappender กันดี กว่า ภาคผนวกเป็นสถานที่ที่ข้อมูลของคุณมา คุณสามารถพูดได้ว่าสิ่งที่ตรงกันข้ามกับแหล่งข้อมูลคือ "จุด B" ตามค่าเริ่มต้น ข้อมูลจะถูกส่งออกไปยังคอนโซล โปรดทราบว่าในตัวอย่างก่อนหน้านี้ เราไม่จำเป็นต้องกำหนดค่าใดๆ ข้อความปรากฏในคอนโซล แต่ตัวบันทึกจากไลบรารี log4j สามารถส่งข้อความระดับ ERROR ไปยังคอนโซลเท่านั้น เห็นได้ชัดว่าสะดวกกว่าสำหรับผู้ใช้ในการอ่านบันทึกจากไฟล์ข้อความและจัดเก็บบันทึกในไฟล์เดียวกัน หากต้องการเปลี่ยนพฤติกรรมเริ่มต้นของตัวบันทึก เราจำเป็นต้องกำหนดค่าตัวผนวกไฟล์ของ เรา ขั้นแรก คุณต้องสร้าง ไฟล์ log4j.xml ในโฟลเดอร์ src หรือในโฟลเดอร์ทรัพยากร หากคุณใช้ Maven หรือในโฟลเดอร์ทรัพยากร ในกรณีที่คุณใช้ Maven คุณคุ้นเคยกับรูปแบบ 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">
นี่คือสิ่งที่เรียกว่าเครื่องบันทึกสถานะ ไม่เกี่ยวข้องกับตัวบันทึกของเราและถูกใช้เป็นการภายในโดย log4j คุณสามารถตั้งค่า status=”TRACE” แทน status=”INFO” ได้ และข้อมูลทั้งหมดเกี่ยวกับการทำงานภายในของ log4j จะถูกส่งออกไปยังคอนโซล (เครื่องบันทึกสถานะจะส่งออกข้อมูลไปยังคอนโซล แม้ว่าภาคผนวกของเราสำหรับโปรแกรมจะเป็นไฟล์ก็ตาม -ซึ่งเป็นรากฐาน). เราไม่ต้องการสิ่งนี้แล้ว ดังนั้นเราจะทิ้งทุกอย่างไว้เหมือนเดิม
<Appenders>
   <File name="MyFileAppender" fileName="C:\Users\Евгений\Desktop\testlog.txt" append="true">
       <PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
   </File>
</Appenders>
ที่นี่เราสร้าง appender ของเรา แท็ก<File>ระบุว่าจะเป็นไฟล์ name="MyFileAppender"- ชื่อผู้ผนวกของเรา fileName="C:\Users\Username\Desktop\testlog.txt"— เส้นทางไปยังไฟล์บันทึกที่ข้อมูลทั้งหมดจะถูกเขียน append="true"— จำเป็นต้องเขียนข้อมูลเพิ่มเติมต่อท้ายไฟล์หรือไม่ ในกรณีของเราจะเป็นเช่นนี้ หากตั้งค่าเป็นfalseเนื้อหาบันทึกเก่าจะถูกลบทุกครั้งที่โปรแกรมเริ่มทำงานอีกครั้ง <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() เท่านั้นที่จะถูกบันทึก นอกจากนี้ ลิงก์ไปยังผู้ผนวกจะอยู่ที่นี่ หากต้องการสร้างลิงก์ดังกล่าว คุณจะต้อง<Root>สร้างแท็ก ภายในแท็ก <ApprenderRef>และเพิ่มพารามิเตอร์ลงref=”Name твоего аппендера”ไป เราสร้างชื่อของ appender ที่นี่ ในกรณีที่คุณลืม: <File name="MyFileAppender" และนี่คือโค้ดของโปรแกรมของเรา!
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("Начало работы программы!!!");

       try {
           LOGGER.warn("Внимание! Программа пытается разделить одно число на другое");
           System.out.println(12/0);
       } catch (ArithmeticException x) {

           LOGGER.error("Ошибка! Произошло деление на ноль!");
       }
   }
}
แน่นอนว่ามันค่อนข้างจะคดเคี้ยวเล็กน้อย (การจับ RuntimeException เป็นแนวคิดที่ธรรมดา) แต่มันสมบูรณ์แบบสำหรับจุดประสงค์ของเรา :) ลองใช้เมธอดของเราmain()4 ครั้งติดต่อกันแล้วดูไฟล์ testlog.txt ของเรา ไม่จำเป็นต้องสร้างไว้ล่วงหน้า ห้องสมุดจะดำเนินการโดยอัตโนมัติ ทุกอย่างได้ผล! :) ตอนนี้คุณมีตัวบันทึกที่กำหนดค่าแล้ว คุณสามารถลองเล่นกับบางโปรแกรมที่คุณเขียนไว้ก่อนหน้านี้ โดยเพิ่มการเรียกตัวบันทึกไปยังวิธีการทั้งหมด และดูบันทึกผลลัพธ์ :) สำหรับการอ่านเพิ่มเติม ฉันขอแนะนำบทความนี้ ที่นั่นมีการพูดคุยกันถึงหัวข้อการตัดไม้อย่างเจาะลึก และไม่ใช่เรื่องง่ายที่จะอ่านรวดเดียว แต่มีข้อมูลเพิ่มเติมที่เป็นประโยชน์มากมาย ตัวอย่างเช่น คุณจะได้เรียนรู้วิธีกำหนดค่าตัวบันทึกเพื่อให้สร้างไฟล์ข้อความใหม่หากไฟล์ testlog.txt ของเราถึงขนาดที่กำหนด :) และนี่คือจุดสิ้นสุดของบทเรียนของเรา! วันนี้คุณได้เรียนรู้เกี่ยวกับหัวข้อที่สำคัญมากและความรู้นี้จะเป็นประโยชน์กับคุณอย่างแน่นอนในการทำงานในอนาคต แล้วพบกันอีก! :)
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION