Mengkonfigurasi Log4j Loggers Secara Programatis

191

Saya mencoba menggunakan SLF4J (dengan log4jikatan) untuk pertama kalinya.

Saya ingin mengonfigurasi 3 Logger bernama berbeda yang dapat dikembalikan oleh LoggerFactory yang akan mencatat level yang berbeda dan mendorong pesan ke appenders yang berbeda:

  • Logger 1 "FileLogger" mencatat DEBUG dan menambahkannya ke DailyRollingFileAppender
  • Logger 2 "TracingLogger" mencatat TRACE + dan menambahkan ke a JmsAppender
  • Logger 3 "ErrorLogger" mencatat ERROR + dan menambahkan ke yang berbeda JmsAppender

Selanjutnya saya ingin mereka dikonfigurasi secara pemrograman (di Jawa, sebagai lawan dari XML atau log4j.propertiesfile).

Saya membayangkan bahwa, biasanya, saya akan mendefinisikan ini Loggerdi suatu tempat dalam beberapa kode bootstrap, seperti init()metode. Namun, karena saya ingin menggunakan slf4j-log4j, saya bingung tentang di mana saya bisa mendefinisikan logger dan membuatnya tersedia untuk classpath.

Saya tidak percaya ini merupakan pelanggaran tujuan SLF4J yang mendasari (sebagai fasad), karena kode saya menggunakan SLF4J API tidak akan pernah tahu bahwa ada penebang ini. Kode saya hanya membuat panggilan normal ke API SLF4J, yang kemudian meneruskannya ke log4j Loggers yang ditemukannya di classpath.

Tapi bagaimana cara mengkonfigurasi Log4j Loggers itu di classpath ... di Java ?!

IAmYourFaja
sumber
3
Untuk log4j 1.x gunakan jawaban yang diterima di bawah untuk 2.x lihat logging.apache.org/log4j/2.x/manual/customconfig.html
earcam

Jawaban:

279

Anda dapat menambah / menghapus Appender secara terprogram ke 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

Saya sarankan Anda memasukkannya ke init () di suatu tempat, di mana Anda yakin, bahwa ini akan dieksekusi sebelum yang lain. Anda kemudian dapat menghapus semua appender yang ada di root logger dengan

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

dan mulai dengan menambahkan milik Anda. Anda perlu log4j di classpath, tentu saja agar ini berfungsi.

Komentar:
Anda dapat mengambil yang Logger.getLogger(...)Anda suka untuk menambahkan appenders. Saya hanya mengambil root logger karena berada di bagian bawah dari semua hal dan akan menangani semua yang dilewatkan oleh appenders lain dalam kategori lain (kecuali jika dikonfigurasi sebaliknya dengan mengatur flag additivity).

Jika Anda perlu tahu cara logging dan bagaimana diputuskan di mana log ditulis, baca manual ini untuk info lebih lanjut tentang itu.
Pendeknya:

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

akan memberi Anda logger untuk kategori "com.fizz".
Untuk contoh di atas, ini berarti bahwa semua yang masuk dengan itu akan dirujuk ke konsol dan file appender pada root logger.
Jika Anda menambahkan appender ke Logger.getLogger ("com.fizz"). AddAppender (newAppender), maka login dari fizzakan ditangani oleh mengurangi appenders dari root logger dan newAppender.
Anda tidak membuat Logger dengan konfigurasi, Anda hanya menyediakan penangan untuk semua kategori yang mungkin di sistem Anda.

oers
sumber
2
Terima kasih oers! Pertanyaan cepat - Saya perhatikan Anda menambahkan appenders ke root Logger. Apakah ada alasan untuk ini?
IAmYourFaja
Dan, yang lebih penting, saya harus menentukan Logger mana yang akan diambil dari LoggerFactory SLF4J. Apakah mungkin untuk meminta logger root log4j dari SLF4J?
IAmYourFaja
3
@AdamTannon Anda dapat mengambil Logger.getLogger (...) yang Anda suka. Saya hanya mengambil root logger karena berada di bagian paling bawah dari semua hal dan akan menangani semua yang dilewatkan oleh append lain dalam kategori lain (kecuali jika dikonfigurasi sebaliknya). Lihat hierarki logger
oers
@AdamTannon Anda tidak dapat menggunakan pabrik sl4j untuk mendapatkan log4j root logger. SL4j adalah fasad logging. Anda tidak akan mendapatkan sesuatu yang spesifik dari log4j itu.
oers
2
oers - Saya menghargai umpan balik Anda yang luar biasa, tetapi saya tidak menghubungkan semua titik di sini. Bisakah Anda memodifikasi contoh Anda untuk menunjukkan penambahan Logger baru (bukan root logger) yang, setelah ditambahkan ke sistem, akan tersedia untuk kelas lain yang memintanya? Misalnya, seorang Logger yang biasanya diakses oleh, katakan, Logger fizz = LoggerFactory.getLogger("com.fizz");Terima kasih!
IAmYourFaja
47

Sepertinya Anda mencoba menggunakan log4j dari "kedua ujungnya" (ujung konsumen dan ujung konfigurasi).

Jika Anda ingin membuat kode terhadap api slf4j tetapi menentukan sebelumnya (dan secara terprogram) konfigurasi log4j Loggers yang akan dikembalikan oleh classpath, Anda benar-benar harus memiliki semacam adaptasi logging yang menggunakan konstruksi malas.

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);
    }

Dengan pendekatan ini, Anda tidak perlu khawatir tentang di mana / kapan log4j logger Anda dikonfigurasi. Pertama kali classpath meminta mereka, mereka dengan malas dibangun, dilewatkan kembali dan tersedia melalui slf4j. Semoga ini bisa membantu!

IAmYourFaja
sumber
2
Berhasil! Terima kasih banyak atas contoh yang bermanfaat! @Oers - terima kasih telah mencoba mengarahkan saya ke arah yang benar - Saya akan memberi Anda cek hijau untuk dedikasi Anda tetapi harus memberi zharvey hadiah karena itulah yang saya cari. Terima kasih sekali lagi semuanya!
IAmYourFaja
4

Jika Anda telah mendefinisikan appender di properti log4j dan ingin memperbaruinya secara program, atur nama di properti log4j dan dapatkan dengan nama.

Berikut ini contoh entri 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

Untuk memperbaruinya, lakukan hal berikut:

((ConsoleAppender) Logger.getRootLogger().getAppender("console")).setThreshold(Level.DEBUG);
Kyle Shrader
sumber
1

Jika seseorang datang mencari untuk mengonfigurasi log4j2 secara terprogram di Jawa, maka tautan ini dapat membantu: ( https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class )

Berikut adalah kode dasar untuk mengonfigurasi Appole 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());

Ini akan mengkonfigurasi ulang rootLogger default dan juga akan membuat appender baru .

iamabhishek
sumber