คุณต้องการดูเฟรมเวิร์กการบันทึกและอาจเป็นเฟรมเวิร์กซุ้มการบันทึก
มีเฟรมเวิร์กการบันทึกข้อมูลหลายเฟรมที่มักจะมีฟังก์ชันการทับซ้อนกันมากดังนั้นเมื่อเวลาผ่านไปหลายคนจึงต้องพึ่งพา API ทั่วไปหรือมีการใช้งานผ่านเฟรมเวิร์กของซุ้มเพื่อสรุปการใช้งานและอนุญาตให้สลับ หากมีความจำเป็น.
กรอบ
กรอบการบันทึกบางอย่าง
อาคารที่บันทึกไว้บางส่วน
การใช้
ตัวอย่างพื้นฐาน
เฟรมเวิร์กเหล่านี้ส่วนใหญ่จะอนุญาตให้คุณเขียนบางสิ่งในแบบฟอร์ม (ที่นี่ใช้slf4j-api
และlogback-core
):
package chapters.introduction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// copied from: http://www.slf4j.org/manual.html
public class HelloWorld {
public static void main(String[] args) {
final Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.debug("Hello world, I'm a DEBUG level message");
logger.info("Hello world, I'm an INFO level message");
logger.warn("Hello world, I'm a WARNING level message");
logger.error("Hello world, I'm an ERROR level message");
}
}
สังเกตการใช้คลาสปัจจุบันเพื่อสร้างตัวบันทึกเฉพาะซึ่งจะอนุญาตให้ SLF4J / LogBack จัดรูปแบบเอาต์พุตและระบุตำแหน่งที่ข้อความการบันทึกมาจาก
ดังที่ระบุไว้ในคู่มือ SLF4Jรูปแบบการใช้งานทั่วไปในคลาสนั้นมักจะ:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass {
final Logger logger = LoggerFactory.getLogger(MyCLASS.class);
public void doSomething() {
// some code here
logger.debug("this is useful");
if (isSomeConditionTrue()) {
logger.info("I entered by conditional block!");
}
}
}
แต่ในความเป็นจริงมันเป็นเรื่องธรรมดามากที่จะประกาศตัวบันทึกด้วยแบบฟอร์ม:
private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);
สิ่งนี้อนุญาตให้ใช้ตัวบันทึกจากภายในวิธีการแบบคงที่เช่นกันและจะใช้ร่วมกันระหว่างอินสแตนซ์ทั้งหมดของคลาส นี่เป็นแบบฟอร์มที่คุณต้องการ อย่างไรก็ตามตามที่เบรนแดนลองระบุไว้ในความคิดเห็นคุณต้องการให้แน่ใจว่าได้เข้าใจความหมายและตัดสินใจได้อย่างถูกต้อง (สิ่งนี้ใช้กับกรอบการบันทึกทั้งหมดตามหลังสำนวนเหล่านี้)
มีวิธีอื่นในการสร้างอินสแตนซ์ตัวบันทึกตัวอย่างเช่นโดยใช้พารามิเตอร์สตริงเพื่อสร้างตัวบันทึกชื่อ:
Logger logger = LoggerFactory.getLogger("MyModuleName");
แก้ไขระดับ
ระดับการดีบักแตกต่างจากกรอบงานหนึ่งไปอีกกรอบหนึ่ง แต่ระดับทั่วไปคือ (เรียงตามลำดับความสำคัญจากความอ่อนโยนและไม่ดีต่อค้างคาวและอาจเป็นเรื่องธรรมดามากที่จะหายากมาก):
TRACE
ข้อมูลรายละเอียดมาก ควรเขียนลงในบันทึกเท่านั้น ใช้เพื่อติดตามโฟลว์ของโปรแกรมที่จุดตรวจเท่านั้น
DEBUG
รายละเอียดข้อมูล. ควรเขียนลงในบันทึกเท่านั้น
INFO
เหตุการณ์รันไทม์ที่สังเกตเห็นได้ ควรมองเห็นได้ทันทีบนคอนโซลดังนั้นใช้อย่าง จำกัด
WARNING
Runtime แปลกประหลาดและข้อผิดพลาดที่กู้คืนได้
ERROR
ข้อผิดพลาดรันไทม์อื่น ๆ หรือเงื่อนไขที่ไม่คาดคิด
FATAL
ข้อผิดพลาดรุนแรงที่ทำให้เกิดการยกเลิกก่อนกำหนด
บล็อกและยาม
ตอนนี้สมมติว่าคุณมีส่วนของรหัสที่คุณกำลังจะเขียนคำสั่ง debug จำนวนหนึ่ง สิ่งนี้อาจส่งผลกระทบต่อประสิทธิภาพการทำงานของคุณอย่างรวดเร็วเนื่องจากทั้งผลกระทบของการบันทึกและการสร้างพารามิเตอร์ใด ๆ ที่คุณอาจส่งผ่านไปยังวิธีการบันทึก
เพื่อหลีกเลี่ยงปัญหาประเภทนี้คุณมักจะต้องการเขียนอะไรบางอย่างของแบบฟอร์ม:
if (LOGGER.isDebugEnabled()) {
// lots of debug logging here, or even code that
// is only used in a debugging context.
LOGGER.debug(" result: " + heavyComputation());
}
หากคุณไม่ได้ใช้การ์ดป้องกันนี้ก่อนที่จะบล็อกคำสั่ง debug แม้ว่าข้อความอาจไม่ได้รับการส่งออก (ตัวอย่างเช่นในปัจจุบัน logger ของคุณได้รับการกำหนดค่าให้พิมพ์เฉพาะสิ่งที่เหนือINFO
ระดับ)heavyComputation()
วิธีการดังกล่าวจะยังคงดำเนินการอยู่ .
องค์ประกอบ
การกำหนดค่าค่อนข้างขึ้นอยู่กับกรอบการบันทึกของคุณ แต่ส่วนใหญ่จะนำเสนอเทคนิคที่เหมือนกันสำหรับสิ่งนี้:
- การกำหนดค่าแบบเป็นโปรแกรม (ที่รันไทม์ผ่าน API - อนุญาตสำหรับการเปลี่ยนแปลงรันไทม์ ),
- การกำหนดค่าประกาศคงที่ (ณ เวลาเริ่มต้นมักจะผ่านทาง XML หรือไฟล์คุณสมบัติ - น่าจะเป็นสิ่งที่คุณต้องการในตอนแรก )
พวกเขายังมีความสามารถส่วนใหญ่เหมือนกัน:
- การกำหนดค่าของรูปแบบข้อความที่ส่งออก (การประทับเวลาเครื่องหมาย ฯลฯ ... )
- การกำหนดค่าของระดับเอาท์พุท
- การกำหนดค่าของตัวกรองละเอียด (ตัวอย่างเช่นเพื่อรวม / ไม่รวมแพ็คเกจหรือคลาส)
- การกำหนดค่าของ appenders เพื่อกำหนดตำแหน่งที่จะบันทึก (ไปยังคอนโซลไปยังไฟล์ไปยังบริการบนเว็บ ... ) และอาจจะทำอย่างไรกับบันทึกเก่า ๆ (ตัวอย่างเช่นกับไฟล์กลิ้งอัตโนมัติ)
นี่คือตัวอย่างทั่วไปของการกำหนดค่าที่ประกาศโดยใช้logback.xml
ไฟล์
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
ตามที่กล่าวมานี้ขึ้นอยู่กับกรอบงานของคุณและอาจมีทางเลือกอื่น ๆ (เช่น LogBack ยังอนุญาตให้ใช้ Groovy script) รูปแบบการกำหนดค่า XML อาจแตกต่างจากการใช้งานหนึ่งไปยังอีก
สำหรับตัวอย่างการกำหนดค่าเพิ่มเติมโปรดดู (ในหมู่อื่น ๆ ) เพื่อ:
สนุกกับประวัติศาสตร์
โปรดทราบว่าLog4Jจะเห็นการปรับปรุงที่สำคัญในขณะนี้เปลี่ยนจากรุ่น1.xเพื่อ2.x คุณอาจต้องการดูทั้งสองอย่างเพื่อความสนุกสนานในอดีตหรือความสับสนและหากคุณเลือกLog4Jอาจต้องการไปกับรุ่น 2.x
เป็นที่น่าสังเกตว่า Mike Partridge ได้กล่าวถึงความคิดเห็นไว้ว่า LogBack นั้นถูกสร้างขึ้นโดยอดีตสมาชิกทีม Log4J ซึ่งถูกสร้างขึ้นเพื่อแก้ไขข้อบกพร่องของเฟรมเวิร์ก Java Logging และที่สำคัญรุ่น Log4J 2.x ตอนนี้กำลังรวมคุณลักษณะบางอย่างที่นำมาจาก LogBack
คำแนะนำ
ที่บรรทัดล่างพัก decoupled ให้มากที่สุดเท่าที่จะทำได้เล่นกับคนรอบข้างและดูว่าอะไรดีที่สุดสำหรับคุณ ในท้ายที่สุดมันก็เป็นเพียงกรอบการเข้าสู่ระบบ ยกเว้นถ้าคุณมีเหตุผลที่เฉพาะเจาะจงนอกเหนือจากความสะดวกในการใช้งานและความชอบส่วนตัวสิ่งเหล่านี้จะทำได้ดีกว่าปกติดังนั้นจึงไม่มีเหตุผลที่จะแขวนมัน ส่วนใหญ่สามารถขยายได้ตามความต้องการของคุณ
ยังถ้าฉันต้องเลือกชุดวันนี้ฉันจะไปกับ LogBack + SLF4J แต่ถ้าคุณถามฉันไม่กี่ปีต่อมาฉันขอแนะนำ Log4J กับ Apache Commons Logging ดังนั้นโปรดคอยติดตามการพึ่งพาของคุณและพัฒนาไปกับพวกเขา