API Logging Platform Java 9

1. Perkenalan

Dalam tutorial ini, kita akan menjelajahi Logging API yang baru diperkenalkan di Java 9 dan menerapkan beberapa contoh untuk mencakup kasus yang paling umum.

API ini telah diperkenalkan di Java untuk menyediakan mekanisme umum untuk menangani semua log platform dan untuk mengekspos antarmuka layanan yang dapat disesuaikan oleh pustaka dan aplikasi. Dengan cara ini, log platform JDK dapat menggunakan kerangka kerja logging yang sama dengan aplikasi, dan dependensi proyek dapat dikurangi.

2. Membuat Implementasi Kustom

Di bagian ini, kami akan menunjukkan kelas utama dari Logging API yang harus kami terapkan untuk membuat logger baru. Kami akan melakukannya dengan menerapkan logger sederhana yang mencetak semua log ke konsol.

2.1. Membuat Logger

Kelas utama yang harus kita buat adalah Logger . Kelas ini harus mengimplementasikan antarmuka System.Logger dan setidaknya empat metode ini:

  • getName () : mengembalikan nama logger. Ini akan digunakan oleh JDK untuk membuat penebang berdasarkan nama
  • isLoggable () : menunjukkan untuk level apa logger diaktifkan
  • log () : ini adalah metode yang mencetak log ke sistem dasar apa pun yang digunakan aplikasi- konsol dalam kasus kami. Ada 2 metode log () untuk diterapkan, masing-masing menerima parameter yang berbeda

Mari kita lihat bagaimana implementasi kita akan terlihat:

public class ConsoleLogger implements System.Logger { @Override public String getName() { return "ConsoleLogger"; } @Override public boolean isLoggable(Level level) { return true; } @Override public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) { System.out.printf("ConsoleLogger [%s]: %s - %s%n", level, msg, thrown); } @Override public void log(Level level, ResourceBundle bundle, String format, Object... params) { System.out.printf("ConsoleLogger [%s]: %s%n", level, MessageFormat.format(format, params)); } }

Kelas ConsoleLogger kami mengganti empat metode yang disebutkan. Metode getName () mengembalikan String, sedangkan metode isLoggable () mengembalikan nilai true dalam semua kasus. Akhirnya, kami memiliki metode 2 log () yang menampilkan ke konsol.

2.2. Membuat LoggerFinder

Setelah kami membuat logger kami, kami perlu menerapkan LoggerFinder yang membuat instance ConsoleLogger kami .

Untuk melakukannya, kita harus memperluas kelas abstrak System.LoggerFinder dan mengimplementasikan metode getLogger () :

public class CustomLoggerFinder extends System.LoggerFinder { @Override public System.Logger getLogger(String name, Module module) { return new ConsoleLogger(); } }

Dalam kasus ini, kami selalu mengembalikan ConsoleLogger kami .

Terakhir, kita perlu mendaftarkan LoggerFinder kita sebagai Layanan sehingga dapat ditemukan oleh JDK . Jika kami tidak menyediakan implementasi, SimpleConsoleLogger akan digunakan secara default.

Mekanisme yang digunakan oleh JDK untuk memuat implementasi adalah ServiceLoader . Anda dapat menemukan informasi lebih lanjut tentang itu di tutorial ini.

Karena kami menggunakan Java 9, kami akan mengemas kelas kami dalam sebuah modul dan mendaftarkan layanan kami di file module-info.java :

module com.baeldung.logging { provides java.lang.System.LoggerFinder with com.baeldung.logging.CustomLoggerFinder; exports com.baeldung.logging; }

Untuk informasi lebih lanjut tentang modul Java, lihat tutorial lainnya ini.

2.3. Menguji Teladan Kami

Untuk menguji contoh kita, mari buat modul lain yang akan bertindak sebagai aplikasi. Ini hanya akan berisi kelas Utama yang menggunakan implementasi layanan kami.

Kelas ini akan mendapatkan instance ConsoleLogger kita dengan memanggil metode System.getLogger () :

public class MainApp { private static System.Logger LOGGER = System.getLogger("MainApp"); public static void main(String[] args) { LOGGER.log(Level.ERROR, "error test"); LOGGER.log(Level.INFO, "info test"); } }

Secara internal, JDK akan mengambil implementasi CustomLoggerFinder kami dan membuat instance ConsoleLogger kami .

Setelah itu, mari buat file module-info untuk modul ini:

module com.baeldung.logging.app { }

Pada titik ini, struktur proyek kita akan terlihat seperti ini:

├── src │   ├── modules │   │   ├── com.baeldung.logging │   │   │   ├── com │   │   │   │   └── baeldung │   │   │   │   └── logging │   │   │   │   ├── ConsoleLogger.java │   │   │   │   └── CustomLoggerFinder.java │   │   │   └── module-info.java │   │   ├── com.baeldung.logging.app │   │   │   ├── com │   │   │   │   └── baeldung │   │   │   │   └── logging │   │   │   │   └── app │   │   │   │   └── MainApp.java │   │   │   └── module-info.java └──

Terakhir, kami akan mengompilasi dua modul kami, dan kami akan menempatkannya di direktori mods :

javac --module-path mods -d mods/com.baeldung.logging \ src/modules/com.baeldung.logging/module-info.java \ src/modules/com.baeldung.logging/com/baeldung/logging/*.java javac --module-path mods -d mods/com.baeldung.logging.app \ src/modules/com.baeldung.logging.app/module-info.java \ src/modules/com.baeldung.logging.app/com/baeldung/logging/app/*.java

Terakhir, mari kita jalankan kelas Utama dari modul aplikasi :

java --module-path mods \ -m com.baeldung.logging.app/com.baeldung.logging.app.MainApp

Jika kita melihat pada keluaran konsol, kita dapat melihat bahwa log kita dicetak menggunakan ConsoleLogger kita :

ConsoleLogger [ERROR]: error test ConsoleLogger [INFO]: info test

3. Menambahkan Kerangka Kerja Pencatatan Eksternal

Dalam contoh kami sebelumnya, kami mencatat semua pesan kami ke konsol, yang sama dengan yang dilakukan logger default. Salah satu penggunaan Logging API yang paling berguna di Java 9 adalah membiarkan aplikasi merutekan log JDK ke framework logging yang sama dengan yang digunakan aplikasi , dan itulah yang akan kita lakukan di bagian ini.

Kami akan membuat modul baru yang menggunakan SLF4J sebagai fasad logging dan Logback sebagai framework logging.

Karena kita sudah menjelaskan dasar-dasarnya di bagian sebelumnya, sekarang kita bisa fokus pada cara menambahkan kerangka logging eksternal.

3.1. Implementasi Kustom Menggunakan SLF4J

Pertama, kami akan menerapkan Logger lain yang akan membuat logger SLF4J baru untuk setiap instance:

public class Slf4jLogger implements System.Logger { private final String name; private final Logger logger; public Slf4jLogger(String name) { this.name = name; logger = LoggerFactory.getLogger(name); } @Override public String getName() { return name; } //... }

Perhatikan bahwa Logger ini adalah sebuah org.slf4j.Logger .

Untuk metode lainnya, kami akan mengandalkan implementasi pada instance logger SLF4J . Oleh karena itu, Logger kami akan diaktifkan jika logger SLF4J diaktifkan:

@Override public boolean isLoggable(Level level) { switch (level) { case OFF: return false; case TRACE: return logger.isTraceEnabled(); case DEBUG: return logger.isDebugEnabled(); case INFO: return logger.isInfoEnabled(); case WARNING: return logger.isWarnEnabled(); case ERROR: return logger.isErrorEnabled(); case ALL: default: return true; } }

Dan metode log akan memanggil metode logger SLF4J yang sesuai tergantung pada level log yang digunakan:

@Override public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) { if (!isLoggable(level)) { return; } switch (level) { case TRACE: logger.trace(msg, thrown); break; case DEBUG: logger.debug(msg, thrown); break; case INFO: logger.info(msg, thrown); break; case WARNING: logger.warn(msg, thrown); break; case ERROR: logger.error(msg, thrown); break; case ALL: default: logger.info(msg, thrown); } } @Override public void log(Level level, ResourceBundle bundle, String format, Object... params) { if (!isLoggable(level)) { return; } String message = MessageFormat.format(format, params); switch (level) { case TRACE: logger.trace(message); break; // ... // same as the previous switch } }

Terakhir, mari buat LoggerFinder baru yang menggunakan Slf4jLogger kita :

public class Slf4jLoggerFinder extends System.LoggerFinder { @Override public System.Logger getLogger(String name, Module module) { return new Slf4jLogger(name); } }

3.2. Module Configuration

Once we have all our classes implemented, let's register our service in our module and add the dependency of the SLF4J module:

module com.baeldung.logging.slf4j { requires org.slf4j; provides java.lang.System.LoggerFinder with com.baeldung.logging.slf4j.Slf4jLoggerFinder; exports com.baeldung.logging.slf4j; }

This module will have the following structure:

├── src │   ├── modules │   │   ├── com.baeldung.logging.slf4j │   │   │   ├── com │   │   │   │   └── baeldung │   │   │   │   └── logging │   │   │   │   └── slf4j │   │   │   │   ├── Slf4jLoggerFinder.java │   │   │   │   └── Slf4jLogger.java │   │   │   └── module-info.java └──

Now we can compile this module into the mods directory as we did in the previous section.

Notice that we have to place the slf4j-api jar in the mods directory to compile this module. Also, keep in mind to use a modularized version of the library. The latest version can be found in Maven Central.

3.3. Adding Logback

We're almost done, but we still need to add the Logback dependencies and configuration. To do so, place the logback-classic and logback-core jars in the mods directory.

As before, we have to make sure we're using a modularized version of the library. Again, the latest version can be found in Maven Central.

Finally, let's create a Logback configuration file and place it in our mods directory:

    %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} -- %msg%n       

3.4. Running Our Application

At this point, we can run our app using our SLF4J module.

In this case, we also need to specify our Logback configuration file:

java --module-path mods \ -Dlogback.configurationFile=mods/logback.xml \ -m com.baeldung.logging.app/com.baeldung.logging.app.MainApp

Finally, if we check the output we can see that our logs are printed using our Logback configuration:

2018-08-25 14:02:40 [main] ERROR MainApp -- error test 2018-08-25 14:02:40 [main] INFO MainApp -- info test

4. Conclusion

Kami telah menunjukkan di artikel ini cara membuat logger kustom di Java 9 dengan menggunakan API Logger Platform baru. Selain itu, kami telah menerapkan contoh menggunakan kerangka kerja logging eksternal, yang merupakan salah satu kasus penggunaan paling berguna dari API baru ini.

Seperti biasa, kode sumber lengkap dari contoh tersedia di GitHub.