เหตุใดข้อความบันทึก Level.FINE จึงไม่แสดง


110

JavaDocs สำหรับjava.util.logging.Levelรัฐ:


ระดับจากมากไปหาน้อยคือ:

  • SEVERE (ค่าสูงสุด)
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST (ค่าต่ำสุด)

ที่มา

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        logger.setLevel(Level.FINER);
        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

เอาต์พุต

Logging level is: FINER
Jun 11, 2011 9:39:23 PM LoggingLevelsBlunder main
INFO: 0 0
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 1 1
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 2 4
Press any key to continue . . .

คำชี้แจงปัญหา

ตัวอย่างของฉันชุดLevelไปFINERดังนั้นผมจึงได้รับการคาดหวังว่าจะดู 2 ข้อความสำหรับแต่ละวง แต่ฉันเห็นข้อความเดียวสำหรับแต่ละลูป ( Level.FINEข้อความหายไป)

คำถาม

สิ่งที่ต้องเปลี่ยนแปลงเพื่อดูFINE( FINERหรือFINEST) เอาต์พุต

อัปเดต (โซลูชัน)

ขอบคุณคำตอบของ Vineet Reynoldsเวอร์ชันนี้ทำงานได้ตามความคาดหมายของฉัน จะแสดงINFOข้อความ 3 x และ 3 x FINEข้อความ

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        // LOG this level to the log
        logger.setLevel(Level.FINER);

        ConsoleHandler handler = new ConsoleHandler();
        // PUBLISH this level
        handler.setLevel(Level.FINER);
        logger.addHandler(handler);

        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

10
สำหรับฉันแล้วดูเหมือนว่าคุณจะมีข้อความที่พิมพ์สองครั้งบนคอนโซลสำหรับ INFO ขึ้นไป: อันดับแรกโดยคนตัดไม้ที่ไม่ระบุชื่อจากนั้นโดยผู้ปกครองคือคนตัดไม้ส่วนกลางซึ่งมี ConsoleHandler ตั้งค่าเป็น INFO ตามค่าเริ่มต้น ในการปิดใช้งาน global logger คุณต้องเพิ่มโค้ดบรรทัดนี้: logger.setUseParentHandlers (false);
นาทีที่

ฉันแค่ต้องการยืนยันความคิดเห็นเกี่ยวกับคู่ผสม คุณจะได้รับสองเอาต์พุตเว้นแต่คุณจะใช้. setUseParentHandlers (false);
xpagesbeast

คำตอบ:


124

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

คุณอาจจะใช้ConsoleHandler(ฉันไม่สามารถสรุปที่ส่งออกของคุณเป็น System.err หรือไฟล์ แต่ผมจะคิดว่ามันเป็นอดีต) Level.INFOที่เริ่มต้นจากการเผยแพร่ข้อมูลบันทึกของระดับ คุณจะต้องกำหนดค่าตัวจัดการนี้เพื่อเผยแพร่บันทึกบันทึกในระดับLevel.FINERและสูงกว่าสำหรับผลลัพธ์ที่ต้องการ

ฉันขอแนะนำให้อ่านคู่มือภาพรวมการบันทึก Javaเพื่อทำความเข้าใจกับการออกแบบพื้นฐาน คู่มือนี้ครอบคลุมความแตกต่างระหว่างแนวคิดของ Logger และ Handler

การแก้ไขระดับตัวจัดการ

1. การใช้ไฟล์ Configuration

ไฟล์คุณสมบัติ java.util.logging (โดยดีฟอลต์นี่คือlogging.propertiesไฟล์ในJRE_HOME/lib) สามารถแก้ไขได้เพื่อเปลี่ยนระดับดีฟอลต์ของ ConsoleHandler:

java.util.logging.ConsoleHandler.level = FINER

2. การสร้างตัวจัดการที่รันไทม์

ไม่แนะนำให้ทำเช่นนี้เนื่องจากจะส่งผลให้เกิดการลบล้างการกำหนดค่าส่วนกลาง การใช้สิ่งนี้ตลอดฐานรหัสของคุณจะส่งผลให้การกำหนดค่าคนตัดไม้ไม่สามารถจัดการได้

Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);

2
ขอบคุณ. นั่นเป็นเคล็ดลับ ตอนนี้ฉันรู้แล้วว่าทำไมตอนแรกฉันรู้สึกสับสน ก่อนหน้านี้ฉันเคยทำงานกับระดับการบันทึก แต่การใช้งานของฉันในเวลานั้นเพียงแค่ทิ้งทุกข้อความที่บันทึกไว้ในรายการที่แสดงโดยไม่คำนึงถึงไฟล์Handler.
Andrew Thompson

3
ยินดีต้อนรับ ใช่แล้วการออกแบบจะเหมาะกับคุณหากมีคนเขียนคนตัดไม้ที่ทิ้งสตริงลงในไฟล์คอนโซล ฯลฯ
Vineet Reynolds

7
และการเปลี่ยน logging.properties ในไลบรารี JRE ส่วนกลางสามารถจัดการได้หรือไม่?
James Anderson

2
โปรดทราบว่าระดับของคนตัดไม้จะต้องมีข้อ จำกัด น้อยกว่าระดับของผู้ดูแล ก่อนบันทึก Java ให้ตรวจสอบระดับสูงสุดระหว่างตัวบันทึกและตัวจัดการ ดังนั้นหากคุณตั้งค่าเฉพาะ handler.setLevel (Level.FINER); คุณจะไม่เห็นอะไรเลยเนื่องจากระดับคนตัดไม้เริ่มต้นคือ Level.INFO คุณต้องตั้งค่าเป็น FINER FINEST หรือ ALL พูด logger.setLevel (Level.ALL);
Jeff_Alieffson

ฉันเดาว่านี่จะช่วยแก้ปัญหาได้ในฐานะหนึ่งซับแม้ว่าคุณจะใช้คนตัดไม้ที่ไม่ระบุชื่อและตั้งชื่อในสภาพแวดล้อมเริ่มต้น:Logger.getGlobal().getParent().getHandlers()[0].setLevel(Level.FINER);
Mark Jeronimus

28

ทำไม

java.util.logging มี root logger ที่เป็นค่าเริ่มต้นLevel.INFOและ ConsoleHandler ที่แนบมาซึ่งเป็นค่าเริ่มต้นLevel.INFOด้วย FINEต่ำกว่าINFOดังนั้นข้อความที่ดีจะไม่แสดงตามค่าเริ่มต้น


โซลูชันที่ 1

สร้างคนตัดไม้สำหรับแอปพลิเคชันทั้งหมดของคุณเช่นจากชื่อแพ็กเกจหรือการใช้งานLogger.getGlobal()และเชื่อมต่อ ConsoleLogger ของคุณเอง จากนั้นขอให้ root logger ปิดการทำงาน (เพื่อหลีกเลี่ยงเอาต์พุตที่ซ้ำกันของข้อความระดับสูงกว่า) หรือขอให้คนตัดไม้ของคุณอย่าส่งต่อบันทึกไปยัง root

public static final Logger applog = Logger.getGlobal();
...

// Create and set handler
Handler systemOut = new ConsoleHandler();
systemOut.setLevel( Level.ALL );
applog.addHandler( systemOut );
applog.setLevel( Level.ALL );

// Prevent logs from processed by default Console handler.
applog.setUseParentHandlers( false ); // Solution 1
Logger.getLogger("").setLevel( Level.OFF ); // Solution 2

โซลูชันที่ 2

หรือคุณอาจลดแถบของ root logger ลง

คุณสามารถตั้งค่าได้ด้วยรหัส:

Logger rootLog = Logger.getLogger("");
rootLog.setLevel( Level.FINE );
rootLog.getHandlers()[0].setLevel( Level.FINE ); // Default console handler

หรือด้วยการบันทึกไฟล์คอนฟิกูเรชันหากคุณกำลังใช้งาน :

.level = FINE
java.util.logging.ConsoleHandler.level = FINE

ด้วยการลดระดับส่วนกลางคุณอาจเริ่มเห็นข้อความจากไลบรารีหลักเช่นจากส่วนประกอบ Swing หรือ JavaFX ในกรณีนี้คุณอาจตั้งค่าตัวกรองบน root logger เพื่อกรองข้อความที่ไม่ได้มาจากโปรแกรมของคุณ


applog.setUseParentHandlers (เท็จ) รหัสเหล่านี้ช่วยฉันด้วยขอบคุณมาก
aolphn

4

เหตุใดการบันทึก java ของฉันจึงไม่ทำงาน

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


นี่คือความคิดเห็นไม่ใช่คำตอบ
hfontanez

4

ทำไม

ดังที่ได้กล่าวไว้โดย @Sheepy สาเหตุที่มันใช้งานไม่ได้คือjava.util.logging.Loggerมี root logger ที่เป็นค่าเริ่มต้นLevel.INFOและสิ่งที่ConsoleHandlerแนบมากับ root logger นั้นจะมีค่าเริ่มต้นLevel.INFOด้วย ดังนั้นเพื่อที่จะเห็นFINE( FINERหรือFINEST) การส่งออกคุณจะต้องตั้งค่าเริ่มต้นของคนตัดไม้รากและมันConsoleHandlerจะLevel.FINEเป็นดังนี้:

Logger.getLogger("").setLevel(Level.FINE);
Logger.getLogger("").getHandlers()[0].setLevel(Level.FINE);


ปัญหาในการอัปเดตของคุณ (วิธีแก้ไข)

ดังที่ได้กล่าวไว้โดย @mins คุณจะมีข้อความที่พิมพ์สองครั้งบนคอนโซลสำหรับINFOและสูงกว่า: อันดับแรกโดยผู้ตัดไม้ที่ไม่ระบุชื่อจากนั้นโดยผู้ปกครองคือผู้บันทึกรูทซึ่งมีการConsoleHandlerตั้งค่าเป็นค่าINFOเริ่มต้นด้วย ในการปิดใช้งาน root logger คุณต้องเพิ่มโค้ดบรรทัดนี้:logger.setUseParentHandlers(false);

มีวิธีอื่นในการป้องกันไม่ให้ประมวลผลบันทึกโดยตัวจัดการคอนโซลเริ่มต้นของตัวบันทึกรูทที่กล่าวถึงโดย @Sheepy เช่น:

Logger.getLogger("").getHandlers()[0].setLevel( Level.OFF );

แต่Logger.getLogger("").setLevel( Level.OFF );จะใช้ไม่ได้เพราะบล็อกข้อความที่ส่งตรงไปยัง root logger เท่านั้นไม่ใช่ข้อความที่มาจากคนตัดไม้เด็ก เพื่อแสดงให้เห็นถึงวิธีการLogger Hierarchyทำงานฉันวาดแผนภาพต่อไปนี้:

ใส่คำอธิบายภาพที่นี่

public void setLevel(Level newLevel)ตั้งค่าระดับการบันทึกเพื่อระบุระดับข้อความที่จะบันทึกโดยผู้บันทึกนี้ ระดับข้อความที่ต่ำกว่าค่านี้จะถูกละทิ้ง ค่าระดับ Level.OFF สามารถใช้เพื่อปิดการบันทึก หากระดับใหม่เป็นโมฆะหมายความว่าโหนดนี้ควรสืบทอดระดับจากบรรพบุรุษที่ใกล้ที่สุดโดยมีค่าระดับเฉพาะ (ไม่ใช่ค่าว่าง)


0

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


0

ลองใช้รูปแบบอื่น ๆ ซึ่งอาจเหมาะสม

    Logger logger = Logger.getLogger(MyClass.class.getName());        
    Level level = Level.ALL;
    for(Handler h : java.util.logging.Logger.getLogger("").getHandlers())    
        h.setLevel(level);
    logger.setLevel(level);
// this must be shown
    logger.fine("fine");
    logger.info("info");

0

โซลูชันนี้ดูเหมือนจะดีกว่าสำหรับฉันเกี่ยวกับความสามารถในการบำรุงรักษาและการออกแบบเพื่อการเปลี่ยนแปลง:

  1. สร้างไฟล์คุณสมบัติการบันทึกโดยฝังไว้ในโฟลเดอร์โครงการทรัพยากรที่จะรวมไว้ในไฟล์ jar:

    # Logging
    handlers = java.util.logging.ConsoleHandler
    .level = ALL
    
    # Console Logging
    java.util.logging.ConsoleHandler.level = ALL
  2. โหลดไฟล์คุณสมบัติจากรหัส:

    public static java.net.URL retrieveURLOfJarResource(String resourceName) {
       return Thread.currentThread().getContextClassLoader().getResource(resourceName);
    }
    
    public synchronized void initializeLogger() {
       try (InputStream is = retrieveURLOfJarResource("logging.properties").openStream()) {
          LogManager.getLogManager().readConfiguration(is);
       } catch (IOException e) {
          // ...
       }
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.