การกำหนดค่า Log4j Loggers โดยทางโปรแกรม


191

ฉันกำลังพยายามใช้ SLF4J (มีlog4jผลผูกพัน) เป็นครั้งแรก

ฉันต้องการกำหนดค่า Loggers 3 ชื่อที่แตกต่างกันซึ่งสามารถส่งคืนโดย LoggerFactory ซึ่งจะบันทึกระดับต่าง ๆ และส่งข้อความไปยัง appenders ที่ต่างกัน:

  • Logger 1 "FileLogger" บันทึก DEBUG และต่อท้าย DailyRollingFileAppender
  • Logger 2 "TracingLogger" บันทึกการสืบค้นกลับ + และผนวกเข้ากับ JmsAppender
  • Logger 3 "ErrorLogger" จะบันทึก ERROR + และต่อท้ายไปอีกอัน JmsAppender

นอกจากนี้ฉันต้องการให้พวกเขากำหนดค่าทางการเขียนโปรแกรม (ใน Java, ตรงข้ามกับ XML หรือlog4j.propertiesไฟล์)

ฉันคิดว่าปกติฉันจะกำหนดLoggerบางสิ่งเหล่านี้ในรหัส bootstrapping เช่นinit()วิธีการ อย่างไรก็ตามเนื่องจากฉันต้องการใช้slf4j-log4jฉันสับสนเกี่ยวกับที่ฉันสามารถกำหนด loggers และทำให้พวกเขาสามารถใช้ classpath

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

แต่ฉันจะกำหนดค่า log4j Loggers เหล่านั้นบน classpath ... ใน Java ได้อย่างไร!



3
สำหรับ log4j 1.x ใช้คำตอบที่ได้รับการยอมรับด้านล่างสำหรับ 2.x เห็นlogging.apache.org/log4j/2.x/manual/customconfig.html
earcam

คำตอบ:


279

คุณสามารถเพิ่ม / ลบ Appender โดยทางโปรแกรมไปที่ Log4j:

  ConsoleAppender console = new ConsoleAppender(); //create appender
  //configure the appender
  String PATTERN = "%d [%p|%c|%C{1}] %m%n";
  console.setLayout(new PatternLayout(PATTERN)); 
  console.setThreshold(Level.FATAL);
  console.activateOptions();
  //add appender to any Logger (here is root)
  Logger.getRootLogger().addAppender(console);

  FileAppender fa = new FileAppender();
  fa.setName("FileLogger");
  fa.setFile("mylog.log");
  fa.setLayout(new PatternLayout("%d %-5p [%c{1}] %m%n"));
  fa.setThreshold(Level.DEBUG);
  fa.setAppend(true);
  fa.activateOptions();

  //add appender to any Logger (here is root)
  Logger.getRootLogger().addAppender(fa);
  //repeat with all other desired appenders

ฉันขอแนะนำให้คุณใส่ไว้ใน init () ที่ไหนสักแห่งที่คุณแน่ใจว่าจะดำเนินการก่อนสิ่งอื่นใด จากนั้นคุณสามารถลบ appenders ที่มีอยู่ทั้งหมดใน root logger ด้วย

 Logger.getRootLogger().getLoggerRepository().resetConfiguration();

และเริ่มต้นด้วยการเพิ่มของคุณเอง คุณต้อง log4j ใน classpath แน่นอนเพื่อให้ทำงานได้

หมายเหตุ:
คุณสามารถLogger.getLogger(...)เพิ่มสิ่งที่คุณต้องการได้ ฉันเพิ่งใช้ root logger เพราะอยู่ด้านล่างของทุกสิ่งและจะจัดการทุกอย่างที่ส่งผ่าน appenders อื่น ๆ ในหมวดหมู่อื่น ๆ (ยกเว้นกำหนดค่าไว้เป็นอย่างอื่นโดยการตั้งค่าการตั้งค่า additivity)

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

  Logger fizz = LoggerFactory.getLogger("com.fizz")

จะให้คนตัดไม้สำหรับหมวดหมู่ "com.fizz"
สำหรับตัวอย่างด้านบนนี่หมายความว่าทุกสิ่งที่บันทึกไว้จะถูกอ้างถึงคอนโซลและตัวเพิ่มไฟล์ในตัวบันทึกราก
ถ้าคุณเพิ่ม appender เพื่อ Logger.getLogger ( "com.fizz"). addAppender (newAppender) แล้วเข้าสู่ระบบจากfizzจะถูกจัดการโดย alle appenders newAppenderจากคนตัดไม้และรากที่
คุณไม่ได้สร้าง Loggers ด้วยการกำหนดค่าคุณเพียงแค่ให้ตัวจัดการหมวดหมู่ที่เป็นไปได้ทั้งหมดในระบบของคุณ


2
ขอบคุณนะครับ! คำถามด่วน - ฉันสังเกตเห็นว่าคุณกำลังเพิ่มผู้ผนวกเข้าไปในรูตล็อกเกอร์ มีเหตุผลสำหรับสิ่งนี้หรือไม่?
IAmYourFaja

และที่สำคัญฉันจะต้องระบุ Logger ที่จะดึงข้อมูลจาก LoggerFactory ของ SLF4J เป็นไปได้ไหมที่จะขอ SLF4J สำหรับ logger รูทของ log4j?
IAmYourFaja

3
@AdamTannon คุณสามารถนำ Logger.getLogger (... ) ใด ๆ ที่คุณต้องการ ฉันเพิ่งใช้ root logger เพราะอยู่ด้านล่างของทุกสิ่งและจะจัดการทุกอย่างที่ส่งผ่าน appenders อื่น ๆ ในหมวดหมู่อื่น ๆ (ยกเว้นกำหนดค่าไว้เป็นอย่างอื่น) ดูลำดับชั้นของคนตัดไม้
oers

@ AdamTannon คุณไม่สามารถใช้โรงงาน sl4j เพื่อรับ logger ราก log4j SL4j เป็นส่วนควบคุมการบันทึก คุณจะไม่ได้รับอะไร log4j เฉพาะจากมัน
oers

2
oers - ฉันขอขอบคุณข้อเสนอแนะที่ยอดเยี่ยมของคุณ แต่ฉันไม่ได้เชื่อมต่อทุกจุดที่นี่ คุณสามารถแก้ไขตัวอย่างของคุณเพื่อแสดงการเพิ่มตัวบันทึกใหม่ (ไม่ใช่ตัวบันทึกราก) ที่เพิ่มเมื่อเข้าสู่ระบบจะมีให้กับคลาสอื่นที่ขอได้หรือไม่ ตัวอย่างเช่นคนตัดไม้ที่ปกติจะเข้าถึงได้โดยพูดLogger fizz = LoggerFactory.getLogger("com.fizz");ขอบคุณ!
IAmYourFaja

47

ดูเหมือนว่าคุณกำลังพยายามใช้ log4j จาก "ปลายทั้งสอง" (สิ้นผู้บริโภคและสิ้นสุดการกำหนดค่า)

หากคุณต้องการรหัสกับ API slf4j แต่ตรวจสอบก่อนเวลา (และโปรแกรม) การกำหนดค่าของ Loggers log4j ที่ classpath จะกลับคุณอย่างต้องมีการจัดเรียงของการปรับตัวเข้าสู่ระบบบางอย่างที่ทำให้การใช้งานของการก่อสร้างขี้เกียจ

public class YourLoggingWrapper {
    private static boolean loggingIsInitialized = false;

    public YourLoggingWrapper() {
        // ...blah
    }

    public static void debug(String debugMsg) {
        log(LogLevel.Debug, debugMsg);
    }

    // Same for all other log levels your want to handle.
    // You mentioned TRACE and ERROR.

    private static void log(LogLevel level, String logMsg) {
        if(!loggingIsInitialized)
            initLogging();

        org.slf4j.Logger slf4jLogger = org.slf4j.LoggerFactory.getLogger("DebugLogger");

        switch(level) {
        case: Debug:
            logger.debug(logMsg);
            break;
        default:
            // whatever
        }
    }

    // log4j logging is lazily constructed; it gets initialized
    // the first time the invoking app calls a log method
    private static void initLogging() {
        loggingIsInitialized = true;

        org.apache.log4j.Logger debugLogger = org.apache.log4j.LoggerFactory.getLogger("DebugLogger");

        // Now all the same configuration code that @oers suggested applies...
        // configure the logger, configure and add its appenders, etc.
        debugLogger.addAppender(someConfiguredFileAppender);
    }

ด้วยวิธีการนี้คุณไม่ต้องกังวลว่าที่ไหน / เมื่อ log4j loggers ของคุณได้รับการกำหนดค่า ครั้งแรกที่ classpath ถามพวกเขาพวกเขาจะสร้างอย่างเกียจคร้านส่งคืนและเผยแพร่ผ่าน slf4j หวังว่านี่จะช่วยได้!


2
ถูกจับมัน! ขอบคุณมากสำหรับตัวอย่างที่เป็นประโยชน์! @Oers - ขอบคุณที่พยายามคัดท้ายฉันในทิศทางที่ถูกต้อง - ฉันจะให้คุณตรวจสอบสีเขียวสำหรับการอุทิศตนของคุณ แต่ต้องให้รางวัล zharvey เพราะมันเป็นสิ่งที่ฉันกำลังมองหา ขอบคุณทุกคนอีกครั้ง!
IAmYourFaja

4

ในกรณีที่คุณกำหนด appender ในคุณสมบัติ log4j และต้องการอัปเดตโดยทางโปรแกรมให้ตั้งชื่อในคุณสมบัติ log4j และรับตามชื่อ

นี่คือตัวอย่างรายการ log4j.properties:

log4j.appender.stdout.Name=console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO

หากต้องการอัปเดตให้ทำดังต่อไปนี้:

((ConsoleAppender) Logger.getRootLogger().getAppender("console")).setThreshold(Level.DEBUG);

1

หากใครบางคนกำลังมองหาการกำหนดค่า log4j2 โดยทางโปรแกรมใน Java ลิงก์นี้อาจช่วยได้: ( https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class )

นี่คือรหัสพื้นฐานสำหรับการกำหนดค่า Console Appender:

ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

builder.setStatusLevel(Level.DEBUG);
// naming the logger configuration
builder.setConfigurationName("DefaultLogger");

// create a console appender
AppenderComponentBuilder appenderBuilder = builder.newAppender("Console", "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
// add a layout like pattern, json etc
appenderBuilder.add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d %p %c [%t] %m%n"));
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
rootLogger.add(builder.newAppenderRef("Console"));

builder.add(appenderBuilder);
builder.add(rootLogger);
Configurator.reconfigure(builder.build());

นี้จะกำหนดค่าเริ่มต้นrootLoggerและยังจะสร้าง appender

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.