2.1 คนตัดไม้คนแรก - log4j

ดังที่คุณทราบแล้ว ประวัติของบันทึกเริ่มต้นด้วยSystem.err.println()เอาต์พุตของบันทึกไปยังคอนโซล ยังคงใช้สำหรับการดีบัก เช่น Intellij IDEA ใช้เพื่อแสดงข้อความแสดงข้อผิดพลาดไปยังคอนโซล แต่ตัวเลือกนี้ไม่มีการตั้งค่าใด ๆ ดังนั้นไปกันเลย

คนตัดไม้คนแรกและได้รับความนิยมมากที่สุดถูกเรียกLog4jว่า เป็นโซลูชันที่ดีและปรับแต่งได้สูง เนื่องจากสถานการณ์ต่าง ๆ การตัดสินใจนี้จึงไม่ได้รับการพิจารณาจาก JDK ซึ่งทำให้ทั้งชุมชนไม่พอใจอย่างมาก

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

ดังที่คุณทราบแล้ว บันทึกจะถูกเขียนในตอนท้ายเพื่อให้บางคนอ่านและพยายามเข้าใจว่าเกิดอะไรขึ้นระหว่างการทำงานของโปรแกรม - อะไรและเมื่อใดที่ผิดพลาดตามที่คาดไว้

มีlog4jสามสิ่งสำหรับสิ่งนี้:

  • การบันทึกแพ็คเกจย่อย
  • ชุดของ appenders (ผล);
  • การตั้งค่าโหลดร้อน

ประการแรก การตั้งค่าlog4jสามารถเขียนในลักษณะที่เปิดใช้งานการเข้าสู่ระบบในแพ็คเกจหนึ่งและปิดใช้งานในอีกแพ็คเกจหนึ่ง ตัวอย่างเช่น เป็นไปได้ที่จะเปิดใช้งานการเข้าสู่ระบบในcom.codegym.serverแต่ปิดใช้งานcom.codegym.server.paymentใน สิ่งนี้ทำให้สามารถลบข้อมูลที่ไม่จำเป็นออกจากบันทึกได้อย่างรวดเร็ว

ประการที่สองlog4jอนุญาตให้เขียนผลลัพธ์การบันทึกลงในไฟล์บันทึกหลายไฟล์พร้อมกัน และเอาต์พุตสำหรับแต่ละรายการสามารถกำหนดค่าแยกกันได้ ตัวอย่างเช่นในไฟล์หนึ่งคุณสามารถเขียนเฉพาะข้อมูลเกี่ยวกับข้อผิดพลาดร้ายแรงในไฟล์อื่น - บันทึกจากโมดูลเฉพาะและในบันทึกที่สามในช่วงเวลาหนึ่ง

ไฟล์บันทึกแต่ละไฟล์จึงได้รับการปรับให้เข้ากับประเภทปัญหาที่คาดไว้โดยเฉพาะ สิ่งนี้ทำให้ชีวิตของโปรแกรมเมอร์ที่ไม่สนุกกับการดูผ่านไฟล์บันทึกกิกะไบต์ด้วยตนเองง่ายขึ้นอย่างมาก

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

สำคัญ! บันทึกมีสองเวอร์ชันlog4j: 1.2.xและ2.xxซึ่งเข้ากันไม่ได้

คุณสามารถเชื่อมต่อคนตัดไม้กับโครงการโดยใช้รหัส:

<dependencies>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version>
  </dependency>

  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
  </dependency>
</dependencies>

2.2 คนตัดไม้อย่างเป็นทางการคนแรก - JUL: java.util.logging

หลังจากที่ Zoo of loggers ปรากฏขึ้นในชุมชน Java นักพัฒนาJDKตัดสินใจที่จะสร้างตัวบันทึกมาตรฐานเดียวที่ทุกคนจะใช้ นี่คือลักษณะของคนตัดไม้: JULpackagejava.util.logging

อย่างไรก็ตาม ในระหว่างการพัฒนา ผู้สร้างตัวตัดไม้ไม่ได้ยึดเป็นพื้นฐานlog4jแต่เป็นตัวแปรของตัวตัดไม้จาก IBM ซึ่งมีอิทธิพลต่อการพัฒนา ข่าวดีก็คือมีคนตัดไม้JULรวมอยู่ด้วยJDKข่าวร้ายคือมีคนใช้ไม่กี่คน

ก.ค

นักพัฒนาไม่เพียงJULสร้าง"มาตรฐานสากลอื่น" เท่านั้น แต่พวกเขายังสร้างระดับการบันทึกสำหรับมาตรฐานนี้ด้วย ซึ่งแตกต่างจากมาตรฐานที่ยอมรับโดยนักบันทึกยอดนิยมในขณะนั้น

และนั่นเป็นปัญหาใหญ่ ท้ายที่สุดแล้ว ผลิตภัณฑ์ต่างๆJavaมักจะถูกรวบรวมจากห้องสมุดจำนวนมาก และแต่ละห้องสมุดดังกล่าวก็มีตัวบันทึกของตนเอง ดังนั้นจึงจำเป็นต้องกำหนดค่าตัวบันทึกทั้งหมดที่อยู่ในแอปพลิเคชัน

แม้ว่าคนตัดไม้จะค่อนข้างดี การสร้างคนตัดไม้นั้นเหมือนกันมากหรือน้อย ในการทำเช่นนี้ คุณต้องนำเข้า:


java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());

ชื่อคลาสจะถูกส่งผ่านเป็นพิเศษเพื่อให้ทราบว่าการบันทึกมาจากที่ใด

เฉพาะกับการเปิดตัวเท่านั้นนักพัฒนาได้แก้ไขปัญหาที่สำคัญหลังจากนั้นจึงJULใช้งานได้สะดวกจริงๆ ก่อนหน้านั้นเป็นคนตัดไม้อัตราที่สอง

คนตัดไม้นี้ยังรองรับการแสดงออกของแลมบ์ดาและการประเมินแบบขี้เกียจ เริ่มต้นด้วยJava 8คุณสามารถSupplier<String>ผ่าน สิ่งนี้ช่วยในการอ่านและสร้างสตริงในเวลาที่จำเป็นจริง ๆ เท่านั้น ไม่ใช่ทุกครั้งเหมือนเมื่อก่อน

วิธีการที่มีอาร์กิวเมนต์Supplier<String> msgSupplierมีลักษณะดังนี้:

public void info(Supplier msgSupplier) {
   log(Level.INFO, msgSupplier);
}

2.3 ตัวตัดบันทึกตัวแรก - JCL: จาการ์ตาบันทึกทั่วไป

เป็นเวลานานแล้วที่ไม่มีมาตรฐานเดียวในหมู่คนตัดไม้ มันJULควรจะเป็นหนึ่งเดียว แต่มันแย่กว่าlog4jนั้น มาตรฐานเดียวไม่เคยปรากฏ แต่คนตัดไม้ทั้งสวนสัตว์ปรากฏขึ้นซึ่งแต่ละคนต้องการที่จะเหมือนกัน

เจ.ซี.แอล

อย่างไรก็ตาม นักพัฒนา Java ทั่วไปไม่ชอบที่ห้องสมุดเกือบทุกแห่งมีตัวบันทึกของตัวเองและจำเป็นต้องกำหนดค่าด้วยวิธีพิเศษ ดังนั้น ชุมชนจึงตัดสินใจสร้าง wrapper พิเศษเหนือคนตัดไม้รายอื่น - นี่คือวิธีการJCL: jakarta commons logging

และอีกครั้งโครงการที่สร้างขึ้นเพื่อเป็นผู้นำไม่ได้กลายเป็นหนึ่งเดียว คุณไม่สามารถสร้างผู้ชนะได้ คุณสามารถเป็นผู้ชนะได้เท่านั้น ฟังก์ชันการทำงานJCLแย่มากและไม่มีใครอยากใช้ คนตัดไม้ซึ่งออกแบบมาเพื่อแทนที่คนตัดไม้ทั้งหมด ประสบชะตากรรมเดียวกับที่JULไม่ได้ใช้งาน

แม้ว่ามันจะถูกเพิ่มเข้าไปในไลบรารีมากมายที่เผยแพร่โดยชุมชน Apache แต่สวนสัตว์แห่งคนตัดไม้ก็เติบโตขึ้นเท่านั้น

2.4 คนตัดไม้คนสุดท้ายคนแรก - การกลับเข้าระบบ

แต่นั่นไม่ใช่ทั้งหมด นักพัฒนาlog4jตัดสินใจว่าเขาฉลาดที่สุด (เพราะคนส่วนใหญ่ใช้คนตัดไม้ของเขา) และตัดสินใจเขียนตัวตัดไม้ที่ได้รับการปรับปรุงใหม่ซึ่งจะรวมเอาข้อดีของlog4jคนตัดไม้อื่นๆ

คนตัดไม้ใหม่ถูกเรียกLogbackว่า คนตัดไม้นี้ควรจะกลายเป็นคนตัดไม้คนเดียวในอนาคตที่ทุกคนจะใช้ มันขึ้นอยู่กับแนวคิดเดียวกันกับในlog4j.

คุณสามารถเชื่อมต่อตัวบันทึกนี้กับโครงการโดยใช้รหัส:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.6</version>
</dependency>

ความแตกต่างอยู่ในLogback:

  • ปรับปรุงประสิทธิภาพ
  • เพิ่มการสนับสนุนแบบเนทีฟslf4j;
  • ตัวเลือกการกรองแบบขยาย

ข้อดีอีกอย่างของตัวบันทึกนี้คือมีการตั้งค่าเริ่มต้นที่ดีมาก และคุณต้องกำหนดค่าคนตัดไม้เฉพาะเมื่อคุณต้องการเปลี่ยนบางอย่างในนั้น นอกจากนี้ ไฟล์การตั้งค่ายังได้รับการปรับให้เข้ากับซอฟต์แวร์ขององค์กรได้ดีขึ้น - การกำหนดค่าทั้งหมดถูกตั้งค่าเป็นxml/.

ตามค่าเริ่มต้นLogbackไม่จำเป็นต้องตั้งค่าใดๆ และบันทึกบันทึกทั้งหมดตั้งแต่ระดับDEBUGขึ้นไป หากคุณต้องการลักษณะการทำงานที่แตกต่างกัน คุณสามารถกำหนดค่าได้ผ่านxmlการกำหนดค่า:

<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>app.log</file>
        <encoder>
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" />
    <root level="info">
        <appender-ref ref="FILE" />
    </root>
</configuration>

2.5 ตัวบันทึกสากลล่าสุด - SLF4J: Simple Logging Facade สำหรับ Java

อีกนานแค่ไหนกว่าจะหาค่าเฉลี่ยทองได้...

ในปี 2549 ผู้สร้างคนหนึ่งlog4jออกจากโครงการและตัดสินใจลองอีกครั้งเพื่อสร้างเครื่องบันทึกสากล แต่คราวนี้ไม่ใช่ตัวตัดไม้ใหม่ แต่เป็นมาตรฐานสากลใหม่ (wrapper) ที่อนุญาตให้คนตัดไม้ที่แตกต่างกันโต้ตอบกันได้

คน ตัดไม้นี้ถูกเรียกslf4j — Simple Logging Facade for Javaว่า คนตัดไม้นี้แก้ปัญหาที่แท้จริง - การจัดการสวนสัตว์ของคนตัดไม้ ดังนั้นทุกคนจึงเริ่มใช้มันทันทีlog4jJULcommon-loggins and logback

เราแก้ปัญหาที่เราสร้างขึ้นเองอย่างกล้าหาญ อย่างที่คุณเห็น ความคืบหน้ามาถึงจุดที่เราสร้างกระดาษห่อหุ้มไว้เหนือกระดาษห่อหุ้ม ...

ตัวห่อประกอบด้วยสองส่วน:

  • APIซึ่งใช้ในแอปพลิเคชัน
  • การใช้งานที่เพิ่มเป็นการขึ้นต่อกันแยกต่างหากสำหรับตัวบันทึกแต่ละตัว

คุณสามารถเชื่อมต่อคนตัดไม้กับโครงการโดยใช้รหัส:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.17.2</version>
</dependency>

การเชื่อมต่อกับการใช้งานที่ถูกต้องก็เพียงพอแล้ว: โครงการทั้งหมดจะใช้งานได้

2.6 การเพิ่มประสิทธิภาพใน slf4j

Slf4jรองรับคุณสมบัติใหม่ทั้งหมด เช่น การจัดรูป แบบสตริงสำหรับการบันทึก ก่อนหน้านี้มีปัญหาดังกล่าว สมมติว่าคุณต้องการพิมพ์ข้อความไปยังบันทึก:

log.debug("User " + user + " connected from " + request.getRemoteAddr());

มีปัญหากับรหัสนี้ สมมติว่าแอปพลิเคชันของคุณทำงานอยู่productionและไม่ได้เขียนใดๆ ลงในบันทึกDEBUG-messagesอย่างไรก็ตาม เมธอดlog.debug()จะยังคงถูกเรียก และเมื่อถูกเรียกใช้ เมธอดต่อไปนี้จะถูกเรียกด้วย:

  • user.toString();
  • request.getRemoteAddr();

การเรียกใช้เมธอดเหล่านี้ทำให้แอปพลิเคชันช้าลง การโทรของพวกเขาจำเป็นในระหว่างการดีบักเท่านั้น แต่พวกเขาจะถูกเรียกอยู่ดี

จากมุมมองของลอจิก ปัญหานี้ต้องได้รับการแก้ไขในไลบรารีการบันทึกเอง และในเวอร์ชันแรกของ log4j วิธีแก้ปัญหาก็ปรากฏขึ้น:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}

แทนที่จะเขียนบันทึกหนึ่งบรรทัด ตอนนี้จำเป็นต้องเขียนสามบรรทัด ซึ่งทำให้ความสามารถในการอ่านโค้ดแย่ลงอย่างมาก และลดความนิยมของlog4j.

คนตัดไม้slf4jสามารถปรับปรุงสถานการณ์ได้เล็กน้อยโดยนำเสนอการบันทึกแบบอัจฉริยะ ดูเหมือนว่า:

log.debug("User {} connected from {}", user, request.getRemoteAddr());

โดยที่{}แสดงถึงการแทรกอาร์กิวเมนต์ที่ส่งผ่านในเมธอด นั่นคือ อันแรก{}ตรงกับผู้ใช้ อันที่สอง{}ถึงrequest.getRemoteAddr()

พารามิเตอร์เหล่านี้จะเชื่อมต่อกันเป็นข้อความเดียวก็ต่อเมื่อระดับการบันทึกอนุญาตการบันทึก ไม่สมบูรณ์แบบ แต่ดีกว่าตัวเลือกอื่น ๆ ทั้งหมด

หลังจากนั้นSLF4Jก็เริ่มได้รับความนิยมเพิ่มขึ้นอย่างรวดเร็ว ในขณะนี้เป็นทางออกที่ดีที่สุด

slf4j-log4j12ดังนั้น เราจะพิจารณา การบันทึกโดยใช้ตัวอย่างของบันเดิล