ทำไมไม่ใช้ java.util.logging?


351

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

สำหรับการบันทึกฉัน (และแน่นอนคนที่ฉันทำงานด้วย) มักจะใช้ JUL (java.util.logging) และไม่เคยมีปัญหาใด ๆ อย่างไรก็ตามตอนนี้ฉันต้องเข้าใจในรายละเอียดเพิ่มเติมสิ่งที่ฉันควรทำเพื่อการพัฒนา API ของฉัน ฉันได้ทำการวิจัยเกี่ยวกับเรื่องนี้และข้อมูลที่ฉันได้รับฉันเพิ่งสับสนมากขึ้น ดังนั้นโพสต์นี้

ตั้งแต่ฉันมาจาก JUL ฉันลำเอียง ความรู้ที่เหลือของฉันไม่ใหญ่มาก

จากการวิจัยที่ฉันทำฉันได้พบกับเหตุผลเหล่านี้ว่าทำไมคนถึงไม่ชอบ JUL:

  1. "ผมเริ่มพัฒนาในชวานานก่อนที่ดวงอาทิตย์ปล่อยออกกรกฎาคมและมันก็เป็นเพียงแค่ง่ายสำหรับผมที่จะดำเนินการกับการเข้าสู่ระบบกรอบ-X มากกว่าที่จะเรียนรู้สิ่งใหม่" อืมมม ฉันไม่ได้ล้อเล่นนี่เป็นสิ่งที่ผู้คนพูด ด้วยเหตุผลนี้เราทุกคนสามารถทำได้ COBOL (อย่างไรก็ตามฉันสามารถเกี่ยวข้องกับการเป็นเพื่อนขี้เกียจอย่างแน่นอน)

  2. "ผมไม่ชอบชื่อของระดับการเข้าสู่ระบบในกรกฎาคมว่า" ตกลงอย่างจริงจังนี่เป็นเพียงเหตุผลไม่เพียงพอที่จะแนะนำการพึ่งพาใหม่

  3. "ผมไม่ชอบรูปแบบมาตรฐานของการส่งออกจากกรกฎาคม" อืมมม นี่เป็นเพียงการกำหนดค่า คุณไม่จำเป็นต้องทำอะไรกับโค้ดที่ชาญฉลาด (จริงแล้วย้อนกลับไปในสมัยก่อนคุณอาจต้องสร้างคลาส Formatter ของคุณเองเพื่อทำให้ถูกต้อง)

  4. "ผมใช้ห้องสมุดอื่น ๆ ที่ยังใช้การบันทึกกรอบ-X ดังนั้นฉันคิดว่ามันง่ายขึ้นเพียงเพื่อการใช้งานที่หนึ่ง" นี่คือการโต้แย้งแบบวงกลมใช่ไหม? เหตุใด 'ทุกคน' จึงใช้การบันทึกเฟรมเวิร์ก X และไม่ใช่ JUL

  5. "ทุกคนอื่นใช้การบันทึกกรอบ-X" สำหรับฉันนี่เป็นกรณีพิเศษที่กล่าวมา ส่วนใหญ่ไม่ถูกต้องเสมอไป

ดังนั้นคำถามใหญ่ที่แท้จริงคือทำไมไม่ JUL . ฉันพลาดอะไรไป raison d'êtreสำหรับการบันทึกหน้าไม้ (SLF4J, JCL) คือการใช้งานการบันทึกหลายครั้งมีอยู่ในอดีตและเหตุผลที่ย้อนกลับไปสู่ยุคก่อน JUL อย่างที่เห็น ถ้า JUL นั้นสมบูรณ์แบบแล้วการบันทึกด้านหน้าจะไม่มีอยู่จริง ในการทำให้เรื่องที่สับสนมากขึ้น JUL นั้นจะต้องมีด้านหน้าเป็นส่วนหนึ่งซึ่งอนุญาตให้ตัวจัดการรูปแบบและแม้แต่ LogManager เปลี่ยนได้

แทนที่จะสวมกอดหลายวิธีในการทำสิ่งเดียวกัน (บันทึก) เราไม่ควรตั้งคำถามว่าทำไมพวกเขาจึงจำเป็นในตอนแรก? (และดูว่าเหตุผลเหล่านั้นยังคงมีอยู่)

ตกลงการวิจัยของฉันได้นำไปสู่บางสิ่งที่ฉันเห็นอาจเป็นปัญหาจริงกับ JUL:

  1. การปฏิบัติ บางคนบอกว่าประสิทธิภาพใน SLF4J นั้นเหนือกว่าที่เหลือ นี่ดูเหมือนว่าฉันจะเป็นกรณีของการเพิ่มประสิทธิภาพก่อนวัยอันควร หากคุณต้องการบันทึกหลายร้อยเมกะไบต์ต่อวินาทีแล้วฉันไม่แน่ใจว่าคุณอยู่ในเส้นทางที่ถูกต้องแล้ว JUL พัฒนาขึ้นด้วยและการทดสอบที่คุณทำบน Java 1.4 อาจไม่เป็นจริงอีกต่อไป คุณสามารถอ่านได้ที่นี่และการแก้ไขนี้ทำให้มันเป็น Java 7 หลายคนยังพูดคุยเกี่ยวกับค่าใช้จ่ายของการต่อสตริงในวิธีการบันทึก อย่างไรก็ตามการบันทึกตามเทมเพลตหลีกเลี่ยงค่าใช้จ่ายนี้และมีอยู่ใน JUL ด้วย ส่วนตัวฉันไม่เคยเขียนบันทึกตามแม่แบบจริงๆ ขี้เกียจเกินไปสำหรับสิ่งนั้น เช่นถ้าฉันทำกับ JUL:

    log.finest("Lookup request from username=" + username 
       + ", valueX=" + valueX
       + ", valueY=" + valueY));

    IDE ของฉันจะเตือนฉันและขออนุญาตว่าควรเปลี่ยนเป็น:

    log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", 
       new Object[]{username, valueX, valueY});

    .. ซึ่งแน่นอนฉันจะยอมรับ ได้รับอนุญาต ! ขอขอบคุณสำหรับความช่วยเหลือของคุณ.

    ดังนั้นฉันไม่ได้เขียนข้อความเหล่านี้ด้วยตัวเองที่ทำโดย IDE

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

  2. กำหนดค่าจาก classpath J-Out-of-the-box JUL ไม่สามารถโหลดไฟล์การกำหนดค่าจาก classpath มันเป็นโค้ดสองสามบรรทัดเพื่อให้มันทำ ฉันเห็นว่าทำไมสิ่งนี้ถึงน่ารำคาญ แต่วิธีแก้ปัญหานั้นสั้นและง่าย

  3. ความพร้อมของรถขนเอาท์พุท JUL มาพร้อมกับตัวจัดการเอาต์พุต 5 ตัวนอก: คอนโซลไฟล์สตรีมซ็อกเก็ตและหน่วยความจำ สามารถขยายได้หรือเขียนใหม่ได้ ตัวอย่างนี้อาจจะเขียนไปยัง UNIX / Linux Syslog และ Windows Event Log ฉันไม่เคยมีข้อกำหนดนี้มาก่อนและไม่เคยเห็นมันใช้มาก่อน แต่ฉันสามารถบอกได้ว่าทำไมมันถึงมีประโยชน์ Logback มาพร้อมกับ appender สำหรับ Syslog เป็นต้น ยังฉันจะเถียงว่า

    1. 99.5% ของความต้องการปลายทางปลายทางจะได้รับการคุ้มครองโดยสิ่งที่อยู่ใน JUL นอกกรอบ
    2. ความต้องการพิเศษสามารถรองรับโดยตัวจัดการแบบกำหนดเองที่ด้านบนของ JUL แทนที่จะเป็นด้านบน ไม่มีอะไรสำหรับฉันที่แนะนำว่าต้องใช้เวลาในการเขียนตัวจัดการเอาต์พุต Syslog สำหรับ JUL มากกว่าที่จะทำกับเฟรมเวิร์กการบันทึกอื่น

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

ดังนั้นฉันควรทำอย่างไรกับ API ของฉัน ฉันต้องการให้มันประสบความสำเร็จ แน่นอนว่าฉันสามารถ "ไปตามกระแส" และใช้ SLF4J (ซึ่งดูเหมือนว่าจะเป็นที่นิยมมากที่สุดในวันนี้) แต่เพื่อประโยชน์ของตัวเองฉันยังต้องเข้าใจว่า JUL ในวันนี้มีอะไรผิดปกติหรือไม่? ฉันจะก่อวินาศกรรมตัวเองโดยเลือก JUL สำหรับห้องสมุดของฉัน?

การทดสอบประสิทธิภาพ

(ส่วนเพิ่มโดย nolan600 เมื่อวันที่ 07 -JUL-2012)

มีการอ้างอิงด้านล่างจาก Ceki เกี่ยวกับการ parametrization ของ SLF4J ซึ่งเร็วกว่า JUL 10 เท่าหรือมากกว่า ดังนั้นฉันจึงเริ่มทำการทดสอบง่ายๆ ได้อย่างรวดเร็วก่อนการเรียกร้องถูกต้องแน่นอน นี่คือผลการทดสอบเบื้องต้น (แต่อ่านต่อ!):

  • เวลาดำเนินการ SLF4J แบ็กเอนด์แบ็กเอนด์: 1515
  • เวลาดำเนินการ SLF4J แบ็กเอนด์ JUL: 12938
  • เวลาดำเนินการ JUL: 16911

ตัวเลขข้างต้นเป็นมิลลิวินาทีจึงน้อยกว่าดีกว่า ดังนั้นความแตกต่างด้านประสิทธิภาพถึง 10 เท่าโดยตอนแรกก็ใกล้กัน ปฏิกิริยาเริ่มต้นของฉัน: นั่นเยอะมาก!

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

    for (int i = 0; i < noOfExecutions; i++) {
        for (char x=32; x<88; x++) {
            String someString = Character.toString(x);
            // here we log 
        }
    }

(ฉันต้องการให้คำสั่งบันทึกมีทั้งชนิดข้อมูลดั้งเดิม (ในกรณีนี้คือ int) และชนิดข้อมูลที่ซับซ้อนมากขึ้น (ในกรณีนี้คือสตริง) ไม่แน่ใจว่ามันสำคัญ แต่มีอยู่แล้วที่นั่น)

คำสั่งบันทึกสำหรับ SLF4J:

logger.info("Logging {} and {} ", i, someString);

คำสั่งบันทึกสำหรับ JUL:

logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});

JVM คือ 'อุ่นเครื่อง' ด้วยการทดสอบเดียวกันดำเนินการหนึ่งครั้งก่อนที่การวัดจริงจะเสร็จสิ้น ใช้ Java 1.7.03 บน Windows 7 SLF4J (v1.6.6) รุ่นล่าสุดและใช้ Logback (v1.0.6) Stdout และ stderr ถูกเปลี่ยนเส้นทางไปยังอุปกรณ์ null

อย่างไรก็ตามอย่างระมัดระวังตอนนี้ปรากฎว่า JUL ใช้เวลาส่วนใหญ่ในการทำงานgetSourceClassName()เนื่องจาก JUL โดยค่าเริ่มต้นจะพิมพ์ชื่อคลาสต้นทางในเอาต์พุตขณะที่ Logback ไม่ ดังนั้นเรากำลังเปรียบเทียบแอปเปิ้ลและส้ม ฉันต้องทำการทดสอบอีกครั้งและกำหนดค่าการใช้งานการบันทึกในลักษณะที่คล้ายกันเพื่อให้พวกเขาออกสิ่งเดียวกันจริง ๆ อย่างไรก็ตามฉันสงสัยว่า SLF4J + Logback จะยังคงอยู่ด้านบน แต่ไกลจากตัวเลขเริ่มต้นตามที่ระบุข้างต้น คอยติดตาม.

Btw: การทดสอบครั้งแรกที่ฉันได้ทำงานกับ SLF4J หรือ Logback เป็นประสบการณ์ที่น่ารื่นรมย์ JUL ต้อนรับอย่างอบอุ่นน้อยลงเมื่อคุณเริ่มต้น

ประสิทธิภาพการทดสอบ (ตอนที่ 2)

(ส่วนเพิ่มโดย nolan600 เมื่อวันที่ 08-JUL-2012)

ตามที่ปรากฎมันไม่สำคัญสำหรับประสิทธิภาพที่คุณกำหนดค่ารูปแบบของคุณใน JUL หรือไม่รวมถึงชื่อแหล่งที่มาหรือไม่ ฉันลองด้วยรูปแบบที่เรียบง่ายมาก:

java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"

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

ฉันจึงสรุปประเด็นของประสิทธิภาพการทำงานว่าอย่างน้อยสำหรับคำสั่งบันทึกที่ใช้เทมเพลตที่ทดสอบแล้วดูเหมือนว่าจะมีปัจจัยประมาณ 10 ในความแตกต่างของประสิทธิภาพที่แท้จริงระหว่าง JUL (ช้า) และ SLF4J + Logback (ด่วน) เหมือนที่เซกิพูด

ฉันยังสามารถเห็นอีกสิ่งหนึ่งคือการgetLogger()โทรของ SLF4J นั้นแพงกว่า ditto ของ JUL มาก (95 ms เทียบกับ 0.3 ms ถ้า profiler ของฉันถูกต้อง) มันสมเหตุสมผลแล้ว SLF4J ต้องทำบางครั้งในการเชื่อมโยงของการใช้งานการบันทึกพื้นฐาน มันไม่ทำให้ฉันกลัว การโทรเหล่านี้ควรจะค่อนข้างหายากในช่วงชีวิตของแอปพลิเคชัน ความคงทนควรอยู่ในการเรียกบันทึกจริง

ข้อสรุปสุดท้าย

(ส่วนเพิ่มโดย nolan600 เมื่อวันที่ 08-JUL-2012)

ขอบคุณสำหรับคำตอบทั้งหมดของคุณ ตรงกันข้ามกับสิ่งที่ฉันคิดในตอนแรกว่าฉันตัดสินใจใช้ SLF4J สำหรับ API ของฉัน สิ่งนี้ขึ้นอยู่กับหลาย ๆ สิ่งและการป้อนข้อมูลของคุณ:

  1. มันให้ความยืดหยุ่นในการเลือกการใช้งานบันทึกเวลาใช้งาน

  2. ปัญหาเกี่ยวกับการขาดความยืดหยุ่นในการกำหนดค่าของ JUL เมื่อทำงานภายในแอปพลิเคชันเซิร์ฟเวอร์

  3. SLF4J นั้นเร็วกว่ามากโดยเฉพาะถ้าคุณจับคู่กับ Logback แม้ว่านี่เป็นเพียงการทดสอบคร่าวๆ แต่ฉันก็มีเหตุผลที่เชื่อได้ว่ามีความพยายามมากขึ้นในการปรับแต่ง SLF4J + Logback มากกว่า JUL

  4. เอกสาร เอกสารสำหรับ SLF4J นั้นครอบคลุมและแม่นยำกว่ามาก

  5. ความยืดหยุ่นของรูปแบบ ในขณะที่ฉันทำการทดสอบฉันได้กำหนดให้ JUL เลียนแบบรูปแบบเริ่มต้นจาก Logback รูปแบบนี้มีชื่อของเธรด ปรากฎว่า JUL ไม่สามารถทำสิ่งนี้ได้นอกกรอบ ตกลงฉันยังไม่ได้พลาดจนถึงตอนนี้ แต่ฉันไม่คิดว่ามันเป็นสิ่งที่ควรพลาดจากกรอบการทำงานของบันทึก ระยะเวลา!

  6. โครงการ Java ส่วนใหญ่ (หรือหลายโครงการ) ในปัจจุบันใช้ Maven ดังนั้นการเพิ่มการพึ่งพาไม่ได้เป็นเรื่องใหญ่โดยเฉพาะอย่างยิ่งหากการพึ่งพานั้นค่อนข้างคงที่นั่นคือไม่เปลี่ยนแปลง API ตลอดเวลา นี่น่าจะเป็นจริงสำหรับ SLF4J นอกจากนี้โถ SLF4J และเพื่อน ๆ ยังมีขนาดเล็ก

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


8
ฉันจะไม่ขอปิดเพราะคำถามที่นำเสนอมานี้น่าสนใจ แต่มันก็เป็นขอบเขตถ้าคุณอ่านคำถามที่พบบ่อย: มันจะยากที่จะหาคำตอบที่ไม่ซ้ำใครซึ่งไม่ได้ขึ้นอยู่กับความคิดเห็น
Denys Séguret

สิ่งที่คุณอาจพลาดคือผู้เขียนกรอบการทำงานหลายรายยอมเลิกใช้ JUL และดังนั้นจึงเป็นการยากที่จะใช้หากคุณไม่ได้สร้าง vanilla java
Denys Séguret

3
มันเป็นความเข้าใจผิดที่จะใช้คำทั่วไป "การบันทึกกรอบ - X" เมื่ออ้างถึงกรอบการบันทึกยอดนิยม (s) predating jul คุณควรใช้ "log4j" ในกรณีนี้ เฟรมเวิร์กยอดนิยมอื่น ๆ เช่น SLF4J และ logback ก็ดีหลังจาก jul เปิดตัว
Ceki

1
@Acuariano โครงการ Netty ใช้การสะท้อนเพื่อทดสอบว่ากรอบการบันทึกมีอยู่ใน classpath ดูที่นี่สำหรับแหล่งที่มา InternalLoggerFactory.javaดู
เตอร์

1
@xenoterracide สำคัญยิ่งกว่านั้นก็คือการอัปเดตของ Java 9 ตามที่แนะนำjava.lang.System.Loggerซึ่งเป็นอินเตอร์เฟสซึ่งสามารถเปลี่ยนเส้นทางไปยังเฟรมเวิร์กการบันทึกที่แท้จริงที่คุณต้องการตราบใดที่เฟรมเวิร์กติดตั้งและให้การใช้อินเตอร์เฟสนั้น เมื่อรวมกับการทำให้เป็นโมดูลคุณสามารถปรับใช้แอ็พพลิเคชันด้วยบันเดิล JRE ที่ไม่มีอยู่java.util.loggingหากคุณต้องการเฟรมเวิร์กอื่น
Holger

คำตอบ:


207

ข้อจำกัดความรับผิดชอบ : ฉันเป็นผู้ก่อตั้งโครงการ log4j, SLF4J และ logback

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

อย่างไรก็ตามในฐานะนักพัฒนา oss คุณต้องคำนึงถึงความต้องการของผู้ใช้ของคุณไม่ใช่เฉพาะของคุณเอง เป็นไปตามที่คุณควรใช้ SLF4J ไม่ใช่เพราะคุณมั่นใจว่า SLF4J นั้นดีกว่า jul แต่เนื่องจากผู้พัฒนาจาวาส่วนใหญ่ในปัจจุบัน (กรกฎาคม 2012) ชอบ SLF4J เป็น API การเข้าสู่ระบบของพวกเขา หากท้ายที่สุดคุณตัดสินใจที่จะไม่สนใจความเห็นยอดนิยมให้พิจารณาข้อเท็จจริงต่อไปนี้:

  1. ผู้ที่ชื่นชอบการทำ jul ทำเพื่อความสะดวกเพราะ jul นั้นมาพร้อมกับ JDK สำหรับความรู้ของฉันไม่มีข้อโต้แย้งวัตถุประสงค์อื่น ๆ ในความโปรดปรานของกรกฎาคม
  2. การตั้งค่าของคุณเองสำหรับกรกฎาคมเป็นเพียงที่การตั้งค่า

ดังนั้นการถือ "ข้อเท็จจริงอย่างหนัก" เหนือความคิดเห็นของประชาชนในขณะที่กล้าหาญดูเหมือนจะเป็นความเข้าใจผิดอย่างมีเหตุผลในกรณีนี้

หากยังไม่มั่นใจJB Nizetจะทำการโต้แย้งเพิ่มเติมและมีอำนาจ:

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

หากมีเหตุผลอะไรก็ตามที่คุณเกลียด SLF4J API และการใช้ก็จะรสชาติสนุกออกจากการทำงานของคุณแล้วโดยทั้งหมดไปสำหรับกรกฎาคมหลังจากที่ทุกคนมีวิธีการที่จะเปลี่ยนเส้นทางไป SLF4J

โดยวิธีการที่ jul parametrization ช้ากว่า SLF4J อย่างน้อย 10 เท่าซึ่งทำให้เกิดความแตกต่างที่เห็นได้ชัดเจน


2
@Ceki คุณอาจต้องการอธิบายเพิ่มเติมเกี่ยวกับข้อจำกัดความรับผิดชอบของคุณดังนั้นจึงกล่าวถึงบทบาทปัจจุบันของคุณในโครงการ log4j, slf4j และ logback เหตุผลก็คือเพื่ออธิบายอคติของคุณ
Thorbjørn Ravn Andersen

2
มีการสนับสนุนการอ้างสิทธิ์ที่นักพัฒนา Java ส่วนใหญ่ต้องการ SLF4J เป็น API การบันทึกหรือไม่?
Olivier Cailloux

3
สาระสำคัญของโพสต์ของฉันคือผู้พัฒนาที่แตกต่างกันมีความชอบที่แตกต่างกันซึ่งดูเหมือนว่าเหนือข้อโต้แย้ง ใช่?
Ceki

1
แม้ว่าโดยสุจริตฉันชอบที่จะเห็นมาตรฐาน 2018 ใน Java 11 (หรืออะไรก็ตามที่สิ้นสุดลง) และเทียบกับ log4j2 ในโหมด async
xenoterracide

5
ที่นี่ฉันใช้ SLF4J และฉันยังต้องจัดการกับกรอบการบันทึกอื่น ๆ ทั้งหมดที่ห้องสมุดอื่นใช้ การใช้ SLF4J ไม่ได้แก้ปัญหาของตัวบันทึกที่ต่างกันมันแค่ทำให้แย่ลง xkcd.com/927
Charlie

34
  1. java.util.loggingถูกนำมาใช้ใน Java 1.4 มีการใช้สำหรับการบันทึกก่อนหน้านั้นจึงเป็นเหตุผลว่าทำไม API การเข้าสู่ระบบอื่น ๆ จึงมีอยู่มากมาย API เหล่านั้นที่ใช้อย่างหนักก่อน Java 1.4 และมีตลาดที่ยอดเยี่ยมที่ไม่เพียงแค่ลดลงเหลือ 0 เมื่อ 1.4 ถูกปล่อยออกมา

  2. JUL ไม่ได้เริ่มต้นทุกสิ่งที่ยอดเยี่ยมหลายสิ่งที่คุณพูดถึงซึ่งแย่กว่านั้นใน 1.4 และทำได้ดีกว่าใน 1.5 (และฉันเดาใน 6 ด้วย แต่ฉันไม่แน่ใจเกินไป)

  3. JUL ไม่เหมาะสำหรับหลายแอปพลิเคชันที่มีการกำหนดค่าที่แตกต่างกันใน JVM เดียวกัน (คิดว่าเว็บแอปพลิเคชั่นหลายตัวที่ไม่ควรโต้ตอบ) Tomcat ต้องผ่านห่วงบางอย่างเพื่อให้ได้งานนั้น (ใช้ JUL ใหม่ได้อย่างมีประสิทธิภาพหากฉันเข้าใจอย่างถูกต้อง)

  4. คุณไม่สามารถมีอิทธิพลต่อกรอบการบันทึกที่ไลบรารีของคุณใช้อยู่ ดังนั้นการใช้ SLF4J (ซึ่งจริง ๆ แล้วเป็นเพียงเลเยอร์ API บาง ๆ ที่เหนือไลบรารีอื่น ๆ ) ช่วยรักษาภาพที่ค่อนข้างสม่ำเสมอของโลกการบันทึกทั้งหมด (เพื่อให้คุณสามารถตัดสินใจเฟรมเวิร์กการบันทึกต้นแบบในขณะที่ยังคงมีการบันทึกไลบรารีในระบบเดียวกัน)

  5. ห้องสมุดไม่สามารถเปลี่ยนแปลงได้ง่าย หากไลบรารีรุ่นก่อนหน้านี้เคยใช้ logging-library-X จะไม่สามารถสลับไปยัง logging-library-Y ได้อย่างง่ายดาย (ตัวอย่างเช่น JUL) แม้ว่าหลังนั้นจะมีความสำคัญอย่างยิ่ง: ผู้ใช้ห้องสมุดรายนั้นจะต้องเรียนรู้ เฟรมเวิร์กการบันทึกใหม่และ (อย่างน้อย) กำหนดค่าการบันทึกใหม่ นั่นเป็นเรื่องใหญ่ที่ไม่ต้องทำโดยเฉพาะอย่างยิ่งเมื่อคนส่วนใหญ่ไม่เห็นประโยชน์

ต้องบอกว่าทั้งหมดที่ฉันคิดว่าอย่างน้อย JUL เป็นทางเลือกที่ถูกต้องสำหรับกรอบการบันทึกอื่น ๆ ในปัจจุบัน


1
ขอบคุณ Joachim ฉันขอบคุณโพสต์ของคุณ (1) และ (2) ของคุณสำหรับฉันเป็นเพียงแค่ประวัติศาสตร์ นานแสนนาน. (4) ของคุณเป็นผลมาจากสิ่งนั้นและจากนั้นก็กลายเป็นสิ่งที่ฉันเรียกว่าการโต้แย้งแบบวงกลม (3) ของคุณนั้นน่าสนใจจริงๆ บางทีคุณกำลังจะไปบางอย่าง? แต่สิ่งนี้จะส่งผลกระทบต่อผู้ที่กำลังสร้างคอนเทนเนอร์ของแอปพลิเคชันซึ่งในตอนท้ายของวันจะมีคนน้อยมาก หรืออะไร?
เตอร์

3
ดีที่ละเว้นประวัติศาสตร์จะถึงวาระที่จะยกเลิก ;-) ประวัติมีความเกี่ยวข้องมากในการพัฒนาซอฟต์แวร์ ผู้คนไม่ย้ายเร็วเกินไปและแทนที่ห้องสมุดบุคคลที่สามที่มีอยู่ด้วย API มาตรฐานจะทำงานได้ดีถ้า API มาตรฐานทำงานอย่างน้อยดีเท่ากับห้องสมุดบุคคลที่สาม และพวกเขาไม่ได้เริ่มต้น (และเนื้อหายังไม่ได้ในบางกรณี)
โจอาคิมซาวเออร์

โจอาคิมฉันสนใจในสิ่งเหล่านั้น "ยังไม่มีในบางกรณี" ที่คุณพูดถึง นั่นคือเนื้อต้องเป็น การเปลี่ยนห้องสมุดคนตัดไม้ในรหัสที่มีอยู่ของคุณค่อนข้างน่าสนใจและสามารถเป็นไปโดยอัตโนมัติในวันนี้ SLF4J มีเครื่องมือสำหรับสิ่งที่พิสูจน์จุดของฉัน ดังนั้นฉันคิดว่าไลบรารี่ขนาดใหญ่ที่เขียนในปี 2002 ด้วย log4j สามารถแปลงเป็น JUL ได้ภายในไม่กี่นาทีด้วยเครื่องมืออัตโนมัติ (ฉันไม่รู้ว่ามีอยู่จริง) แล้วทำไมมันไม่เกิดขึ้นล่ะ?
เตอร์

3
@ nolan6000: ฉันไม่รู้เพียงพอเกี่ยวกับรายละเอียดเฉพาะเกี่ยวกับรายละเอียดเกี่ยวกับวลีนั้นและมันไม่ใช่จุดที่ฉันกำลังทำจริงๆ แม้ว่า JUL จะอยู่ในกรอบของบุคคลที่สาม แต่ความเฉื่อยและโครงสร้างพื้นฐานที่มีอยู่ยังคงเป็นเหตุผลที่ดีที่จะไม่เปลี่ยน ตัวอย่างเช่นหาก library X ใช้ slf4j ในเวอร์ชัน 1.1 การเปลี่ยนเป็น JUL ใน 1.2 (หรือ 2.0) จะเป็นปัญหาสำคัญสำหรับผู้ใช้หลายคน (ซึ่งกำหนดค่าระบบเก่าไว้อย่างถูกต้องแล้วและจะต้องทำซ้ำเพื่อไม่ให้ปรากฏชัดเจน) .
Joachim Sauer

@ nolan6000 แม้ว่าคุณจะไม่สนใจประวัติห้องสมุดที่คุณใช้ในแอพพลิเคชั่นของคุณก็ทำอย่างแน่นอน ไม่สนุกกับการทิ้งไลบรารีเพียงเพราะใช้กรอบการบันทึกที่แตกต่างจากคุณ
Thorbjørn Ravn Andersen

29

IMHO ข้อได้เปรียบหลักในการใช้ซุ้มการบันทึกเช่น slf4j คือให้ผู้ใช้ปลายทางของไลบรารีเลือกการดำเนินการบันทึกที่เป็นรูปธรรมที่เขาต้องการแทนที่จะกำหนดทางเลือกของคุณให้กับผู้ใช้

บางทีเขาอาจลงทุนเวลาและเงินใน Log4j หรือ LogBack (ตัวจัดรูปแบบพิเศษผู้ต่อท้าย ฯลฯ ) และต้องการใช้ Log4j หรือ LogBack ต่อไปมากกว่าการกำหนดค่า jul ไม่มีปัญหา: slf4j อนุญาตให้ มันเป็นทางเลือกที่ฉลาดที่จะใช้ Log4j มากกว่า jul หรือไม่? อาจจะอาจจะไม่. แต่คุณไม่สนใจ ให้ผู้ใช้เลือกสิ่งที่เขาต้องการ


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

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

6

ฉันเริ่มเหมือนที่คุณสงสัยว่าใช้ JUL เพราะเป็นวิธีที่ง่ายที่สุดที่จะไปทันที อย่างไรก็ตามในช่วงหลายปีที่ผ่านมาฉันหวังว่าจะได้ใช้เวลาเพิ่มขึ้นเล็กน้อยในการเลือก

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

วิธีแก้ไขปัญหาของเราคือการเพิ่มส่วนหน้าให้กับรหัสห้องสมุดซึ่งหมายความว่าการเรียกบันทึกไลบรารีไม่เปลี่ยนแปลง แต่ถูกเปลี่ยนเส้นทางแบบไดนามิกไปยังกลไกการบันทึกที่มีอยู่ เมื่อรวมอยู่ในเครื่องมือ POJO พวกเขาจะถูกนำไปยัง JUL แต่เมื่อมีการปรับใช้เป็นเว็บแอปพวกเขาจะถูกเปลี่ยนเส้นทางไปยัง LogBack

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

เราใช้ slf4j เพื่อสร้างส่วนหน้า


1
เหตุผลใดที่คุณไม่ได้ใช้เพียงแค่ "จาวาเปลี่ยนเส้นทาง java.util.logging เพื่อ slf4j" แพ็คเกจในการกระจาย slf4j?
Thorbjørn Ravn Andersen

2
เราทำไปแล้ว แต่มีค่าน้อยเพราะประโยชน์หลักของการย้ายไปที่ slf4j คือการบันทึกที่มีประสิทธิภาพ ถ้าเราใช้มันตั้งแต่เริ่มต้นเราคงไม่มีงานทำอีกแล้ว
OldCurmudgeon

1
ฉันยอมรับว่านี่คือผลไม้แขวนต่ำของ slf4j
Thorbjørn Ravn Andersen

3

ฉันวิ่ง jul กับ slf4j-1.7.21 ผ่าน logback-1.1.7, ส่งออกเป็น SSD, Java 1.8, Win64

jul วิ่ง 48449 ms, logback 27185 ms สำหรับ 1M วน

ถึงกระนั้นความเร็วที่เพิ่มขึ้นเล็กน้อยและ bit nicer API ก็ไม่คุ้มกับ 3 ไลบรารี่และ 800K สำหรับฉัน

package log;

import java.util.logging.Level;
import java.util.logging.Logger;

public class LogJUL
{
    final static Logger logger = Logger.getLogger(LogJUL.class.getSimpleName());

    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            Object[] o = { lc };

            logger.log(Level.INFO,"Epoch time {0}", o);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }
}

และ

package log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogSLF
{
    static Logger logger = LoggerFactory.getLogger(LogSLF.class);


    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            logger.info("Epoch time {}", lc);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }

}

3
คุณไม่ได้เปรียบเทียบแบบที่ชอบ เหตุใดคุณจึงสร้างอาร์เรย์สำหรับ Jul อย่างชัดเจน ฉันเดาว่าเป็นเพราะ slf4j ขาดการโต้แย้งหนึ่งlogger.info()ครั้ง ดังนั้นคุณจงใจทำลายประสิทธิภาพการทำงานของจูลเพื่อชดเชยข้อบกพร่องในอินเทอร์เฟซของ slf4j คุณควรเขียนโค้ดทั้งสองวิธีแทนวิธีการใช้รหัส
Klitos Kyriacou

2
คุณเข้าใจผิด คุณไม่ต้องใช้ 800K เพิ่มเติม ฉันทามติคือSLI บางตัวที่มีค่า SLF4J บางอันมีค่าควรใช้เพราะคุณ (หรือคนอื่น ๆ ที่อาจใช้โค้ดของคุณในวันเดียว!) สามารถสลับระหว่าง JUL, Logback, Log4j และ SLF4J เพียง ~ 28K เท่านั้น SLF4J ไปยังสะพาน JUL (slf4j-jdk ... jar) มีค่า ~ 9K
riskop
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.