CodeGym /Java Blog /Acak /Penebangan: apa, bagaimana, di mana, dan dengan apa?
John Squirrels
Level 41
San Francisco

Penebangan: apa, bagaimana, di mana, dan dengan apa?

Dipublikasikan di grup Acak
Halo semuanya di komunitas CodeGym! Penebangan: apa, bagaimana, di mana, dan dengan apa?  - 1 Hari ini mari kita bicara tentang logging:
  1. Apa itu, mengapa itu ada, kapan Anda harus menggunakannya, kapan Anda harus menghindarinya.
  2. Implementasi logging apa yang tersedia di Java, dan apa yang harus Anda lakukan dengan semua opsi logging ini.
  3. Dan tingkat log. Kami akan membahas apa itu appender dan cara mengkonfigurasinya dengan benar.
  4. Mencatat node dan cara mengonfigurasinya dengan benar agar semuanya berjalan sesuai keinginan kita.
Materi ini ditujukan untuk khalayak luas. Akan jelas bagi siapa saja yang baru mengenal Java, maupun orang yang sudah bekerja tapi baru mendalami logger.info("log something"); Ayo!

Mengapa Anda perlu login?

Mari kita lihat beberapa kasus nyata di mana logging dapat menyelesaikan masalah. Ini adalah contoh dari pekerjaan saya. Ada poin di mana aplikasi terintegrasi dengan layanan lain. Saya menggunakan logging pada titik-titik ini untuk membuat semacam "alibi" : jika integrasi tidak berfungsi, maka mudah untuk mengetahui sisi mana yang bermasalah. Juga diinginkan untuk mencatat informasi penting yang disimpan dalam database. Misalnya, pembuatan pengguna admin. Ini adalah hal yang baik untuk dicatat.

Alat untuk login di Jawa

Di antara solusi logging terkenal di Jawa, kami dapat menyoroti yang berikut ini:
  • Log4j
  • JUL — java.util.logging
  • JCL — Jakarta Commons Logging
  • Logback
  • SLF4J — Fasad Logging Sederhana untuk Java
Kami akan memberikan ikhtisar masing-masing. Kemudian kita akan mengambil pengikatan slf4j - log4j sebagai dasar diskusi praktis. Ini mungkin tampak aneh sekarang, tetapi jangan khawatir: di akhir artikel, semuanya akan menjadi jelas.

System.err.println

Awalnya ada System.err.println (menampilkan entri log di konsol). Bahkan saat ini, teknik ini digunakan untuk membuat log dengan cepat saat melakukan debug. Tentu saja, tidak ada pengaturan untuk dibahas di sini, jadi ingatlah metode ini dan kita akan melanjutkan.

Log4j

Ini adalah solusi lengkap yang dibuat pengembang karena kebutuhan. Hasilnya adalah alat yang sangat menarik yang dapat Anda gunakan. Karena berbagai keadaan, solusi ini tidak berakhir di JDK, fakta yang sangat mengecewakan seluruh komunitas. Log4j memiliki opsi konfigurasi yang memungkinkan Anda mengaktifkan masuk paket com.example.typedan mematikannya di com.example.type.genericsubpaket. Ini memungkinkan untuk dengan cepat mengecualikan kode yang tidak perlu dicatat. Penting untuk dicatat di sini bahwa ada dua versi Log4j: 1.2.x dan 2.xx, dan keduanya tidak kompatibel satu sama lain . Log4j menambahkan konsep appender(alat yang digunakan untuk menulis log) dan tata letak (pemformatan log). Ini memungkinkan Anda mencatat hanya apa yang Anda butuhkan dan mencatatnya sesuai kebutuhan Anda. Kami akan berbicara lebih banyak tentang appender nanti.

JUL — java.util.logging

Salah satu manfaat utama dari solusi ini adalah JUL disertakan dalam JDK (Java Development Kit). Sayangnya, ketika dikembangkan, pembuatnya tidak mendasarkannya pada utilitas populer Log4j, melainkan solusi dari IBM. Keputusan itu memiliki konsekuensi. Kenyataannya adalah tidak ada yang menggunakan JUL sekarang. Level log di JUL berbeda dari yang dimiliki Logback, Log4j, dan Slf4j. Ini membuat mereka lebih sulit untuk memahami satu sama lain. Membuat logger kurang lebih serupa. Untuk melakukan ini, Anda perlu melakukan impor:

java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Nama kelas diteruskan, jadi kami tahu dari mana log kami akan berasal. Dimulai dengan Java 8, Anda dapat melewati Supplier<String>. Ini membantu kita membaca dan membuat baris hanya saat kita benar-benar membutuhkannya, bukan setiap saat, seperti yang terjadi sebelumnya. Hanya dengan dirilisnya Java 8, pengembang akhirnya memecahkan masalah penting dan membuat JUL benar-benar dapat digunakan. Yaitu, metode dengan Supplier<String> msgSupplierparameter, seperti yang ditunjukkan di bawah ini:

public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL — Jakarta Commons Logging

Karena tidak ada standar industri mengenai logging untuk waktu yang lama dan banyak orang membuat logger kustom mereka sendiri, keputusan dibuat untuk merilis JCL, pembungkus umum yang dapat digunakan di atas yang lain. Mengapa? Terkadang dependensi yang ditambahkan ke proyek menggunakan logger yang berbeda dari yang ada di proyek. Karena itu, mereka ditambahkan ke proyek sebagai dependensi transitif, dan ini menimbulkan masalah nyata saat mencoba menggabungkan semuanya. Sayangnya, pembungkusnya tidak terlalu berfungsi dan tidak menambahkan apa pun. Mungkin akan nyaman jika semua orang menggunakan JCL. Tapi bukan itu yang terjadi, jadi menggunakan JCL bukanlah ide terbaik saat ini.

Logback

Jalur sumber terbuka sangat sulit ... Pengembang yang sama yang menulis Log4j juga menulis Logback sebagai kerangka kerja logging penerus. Itu didasarkan pada ide yang sama dengan Log4j. Perbedaan Logback adalah:
  • peningkatan kinerja
  • menambahkan dukungan asli untuk Slf4j
  • opsi penyaringan yang diperluas
Secara default, Logback tidak memerlukan konfigurasi apa pun, dan mencatat semua kejadian pada tingkat DEBUG dan yang lebih tinggi. Jika Anda memerlukan beberapa penyesuaian, Anda dapat mencapainya melalui konfigurasi XML:

<configuration> 
    <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
        <file>app.log</file> 
        <encoder> 
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern> 
        </encoder> 
    </appender> 
    <logger name="org.hibernate.SQL" level="DEBUG" /> 
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" /> 
    <root level="info"> 
        <appender-ref ref="FILE" /> 
    </root> 
</configuration>

SLF4J — Fasad Logging Sederhana untuk Java

Suatu saat di tahun 2006, salah satu bapak pendiri Log4j meninggalkan proyek dan membuat Slf4j (Simple Logging Facade for Java), pembungkus untuk Log4j, JUL, common-logging, dan Logback. Seperti yang Anda lihat, kami telah maju ke titik membuat pembungkus di atas pembungkus... Dalam hal ini, dibagi menjadi dua bagian: API yang digunakan dalam aplikasi, dan implementasi yang ditambahkan dengan terpisah dependensi untuk setiap jenis logging. Misalnya, slf4j-log4j12.jardan slf4j-jdk14.jar. Anda perlu menghubungkan implementasi yang benar dan hanya itu: seluruh proyek Anda akan menggunakannya. Slf4j mendukung semua fitur terbaru, seperti pemformatan string untuk logging. Sebelumnya, ada masalah seperti itu. Katakanlah kita membuat entri log seperti ini:

log.debug("User " + user + " connected from " + request.getRemoteAddr());
Karena operator penggabungan, userobjek diam-diam menjadi string berkat user.toString(). Ini membutuhkan waktu dan memperlambat sistem. Dan itu mungkin baik-baik saja jika kita sedang men-debug aplikasi. Kami mulai menemui masalah jika level log untuk kelas ini adalah INFO atau lebih tinggi. Dengan kata lain, kita tidak boleh menulis entri log ini (untuk INFO atau yang lebih tinggi), dan kita tidak boleh menggunakan penggabungan string. Secara teori, perpustakaan logging itu sendiri harus mengatasi hal ini. Ternyata, ini ternyata menjadi masalah terbesar di versi pertama Log4j. Itu tidak memberikan solusi yang layak, tetapi menyarankan melakukan sesuatu seperti ini:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Artinya, alih-alih satu baris kode untuk logging, mereka menyarankan untuk menulis 3! Logging harus meminimalkan perubahan kode, dan tiga baris jelas melanggar pendekatan umum itu. Slf4j tidak memiliki masalah kompatibilitas dengan JDK dan API, jadi solusi yang bagus segera muncul:

log.debug("User {} connected from {}", user, request.getRemoteAddr());
di mana {}menunjukkan placeholder untuk argumen yang diteruskan ke metode. Artinya, yang pertama {}berkorespondensi dengan user, dan yang kedua {}berkorespondensi dengan request.getRemoteAddr(). Dengan melakukannya dengan cara ini, kami akan melakukan penggabungan string hanya jika level log mengharuskan kami untuk menulis entri log. Setelah itu, Sjf4j mulai berkembang pesat popularitasnya. Saat ini, itu adalah solusi terbaik. Oleh karena itu, mari kita lihat logging menggunakan slf4j-log4j12pengikatan.

Apa yang perlu dicatat

Tentu saja, Anda tidak boleh mencatat semuanya. Ini seringkali tidak diperlukan dan terkadang bahkan berbahaya. Misalnya, jika Anda mencatat data pribadi seseorang dan entah bagaimana data tersebut bocor, akan ada masalah nyata, terutama dalam proyek yang berfokus pada pasar Barat. Tetapi ada juga hal-hal yang harus Anda catat :
  1. Awal/akhir aplikasi. Kita perlu mengetahui apakah aplikasi benar-benar dimulai dan diakhiri seperti yang diharapkan.
  2. masalah keamanan. Di sini akan baik untuk mencatat upaya menebak kata sandi seseorang, contoh saat admin masuk, dll.
  3. Status aplikasi tertentu . Misalnya, transisi dari satu keadaan ke keadaan lain dalam proses bisnis.
  4. Informasi debug tertentu bersama dengan tingkat log yang sesuai.
  5. Skrip SQL tertentu. Ada kasus dunia nyata saat ini diperlukan. Tetapi sekali lagi, dengan menyesuaikan level log dengan terampil, Anda dapat mencapai hasil yang sangat baik.
  6. Utas yang berjalan dapat dicatat saat memverifikasi bahwa semuanya berfungsi dengan benar.

Kesalahan populer dalam pencatatan

Ada banyak nuansa di sini, tetapi kami akan menyebutkan secara khusus beberapa kesalahan umum:
  1. Pencatatan yang berlebihan. Anda tidak boleh mencatat setiap langkah yang secara teoritis bisa menjadi penting. Di sini aturan praktis yang bagus: Log tidak boleh melebihi 10% dari beban. Jika tidak, akan ada masalah kinerja.
  2. Mencatat semua data ke dalam satu file. Pada titik tertentu, ini akan membuat sangat sulit untuk membaca/menulis log, belum lagi fakta bahwa sistem tertentu memiliki batasan ukuran file.
  3. Menggunakan level log yang salah. Setiap level log memiliki batasan yang jelas, dan harus dihormati. Jika batasnya tidak jelas, Anda dapat mencapai kesepakatan tentang level mana yang akan digunakan.

Tingkat log

x: Terlihat
FATAL KESALAHAN MEMPERINGATKAN INFO DEBUG JEJAK SEMUA
MATI
FATAL X
KESALAHAN X X
MEMPERINGATKAN X X X
INFO X X X X
DEBUG X X X X X
JEJAK X X X X X X
SEMUA X X X X X X X
Apa itu level log? Untuk membuat hierarki entri log, konvensi dan batasan tertentu diperlukan. Inilah mengapa level log diperkenalkan. Level diatur dalam aplikasi. Jika sebuah entri berada di bawah level yang ditentukan, maka entri tersebut tidak dicatat. Misalnya, kami memiliki log yang kami gunakan saat men-debug aplikasi. Selama pengoperasian normal (saat aplikasi digunakan untuk tujuan yang dimaksudkan), log semacam itu tidak diperlukan. Oleh karena itu, level log lebih tinggi daripada untuk debugging. Mari kita lihat level log menggunakan Log4j. Selain JUL, solusi lain menggunakan level log yang sama. Di sini mereka dalam urutan menurun:
  • OFF: Tidak ada entri log yang direkam; semuanya diabaikan.
  • FATAL: Kesalahan yang mencegah aplikasi untuk terus berjalan. Misalnya, "JVM kehabisan memori".
  • KESALAHAN: Kesalahan pada level ini menunjukkan masalah yang perlu diselesaikan. Kesalahan tidak menghentikan aplikasi secara keseluruhan. Permintaan lain mungkin berfungsi dengan benar.
  • PERINGATAN: Entri log yang mewakili peringatan. Sesuatu yang tidak terduga terjadi, tetapi sistem dapat mengatasi dan memenuhi permintaan tersebut
  • INFO: Entri log yang menunjukkan tindakan penting dalam aplikasi. Ini bukan kesalahan atau peringatan. Itu adalah peristiwa sistem yang diharapkan.
  • DEBUG: Entri log perlu men-debug aplikasi. Untuk memastikan bahwa aplikasi melakukan apa yang diharapkan, atau untuk menjelaskan tindakan yang diambil oleh aplikasi, yaitu "Entered method1".
  • TRACE: Entri log dengan prioritas lebih rendah untuk debugging. Tingkat log terendah.
  • ALL: Level log untuk menulis semua entri log aplikasi.
Dalam level log INFO diaktifkan di suatu tempat di aplikasi, maka entri untuk setiap level akan dicatat, dari INFO hingga FATAL. Jika level log FATAL diatur, hanya entri log dengan level tersebut yang akan ditulis.

Mencatat dan mengirim log: Appender

Mari pertimbangkan bagaimana semua ini bekerja saat kita menggunakan Log4j, yang memberikan banyak kesempatan untuk menulis/mengirim log:
  • untuk menulis ke file -DailyRollingFileAppender
  • untuk menulis informasi ke konsol —ConsoleAppender
  • untuk menulis log ke database —JDBCAppender
  • untuk mengelola pengiriman log melalui TCP/IP —TelnetAppender
  • untuk memastikan bahwa logging tidak berdampak negatif terhadap kinerja —AsyncAppender
Ada beberapa penerapan lagi: daftar lengkap tersedia di sini . Omong-omong, jika appender yang Anda butuhkan tidak ada, tidak masalah. Anda dapat menulis appender Anda sendiri dengan mengimplementasikan antarmuka Appender , yang didukung oleh Log4j.

Node pencatatan

Untuk tujuan demonstrasi, kami akan menggunakan antarmuka Slf4j, dengan implementasi dari Log4j. Membuat logger sangat sederhana: di kelas bernama MainDemo, yang akan melakukan beberapa pencatatan, kita perlu menambahkan yang berikut ini:

org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Ini akan membuat logger untuk kita. Untuk membuat entri log, ada beberapa metode yang tersedia yang namanya mencerminkan level log mana yang akan digunakan. Misalnya:

logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find the log4j.properties file. Please fix this.");
logger.error("Connection refused to host = {}", host);
Meskipun kita melewati kelas, nama akhir adalah nama lengkap kelas, termasuk paket. Ini dilakukan agar nanti Anda dapat membagi logging menjadi node dan mengkonfigurasi level logging dan appender untuk setiap node. Misalnya, logger dibuat di com.github.romankh3.logginglecture.MainDemokelas. Nama memberikan dasar untuk membuat hierarki node logging. Node utama adalah RootLogger tingkat atas . Ini adalah node yang menerima semua entri log untuk seluruh aplikasi. Node yang tersisa dapat digambarkan seperti yang ditunjukkan di bawah ini: Penebangan: apa, bagaimana, di mana, dan dengan apa?  - 3Appender dikonfigurasikan untuk node logging tertentu. Sekarang kita akan melihat file log4j.properties untuk melihat contoh cara mengkonfigurasinya.

Panduan langkah demi langkah untuk file log4j.properties

Kami akan mengatur semuanya selangkah demi selangkah dan melihat apa yang mungkin:

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Baris ini mengatakan bahwa kita mendaftarkan appender CONSOLE, yang menggunakan implementasi org.apache.log4j.ConsoleAppender. Appender ini menulis informasi ke konsol. Selanjutnya, kami mendaftarkan appender lain. Yang ini akan menulis ke file:

log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Penting untuk dicatat bahwa appender itu sendiri masih perlu dikonfigurasi. Setelah kami mendaftarkan appender kami, kami dapat menentukan level log mana dan appender mana yang akan digunakan di node.

log4j.rootLogger=DEBUG, KONSOL, FILE

  • log4j.rootLogger berarti kita sedang mengonfigurasi simpul akar, yang berisi semua entri log
  • Kata pertama setelah tanda sama dengan menunjukkan level log minimum untuk menulis (dalam kasus kami, ini adalah DEBUG)
  • Mengikuti koma, kami menunjukkan semua appender yang akan digunakan.
Untuk mengonfigurasi node logging yang lebih spesifik, Anda akan menggunakan entri seperti ini:

log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
where log4j.logger.digunakan untuk mereferensikan node tertentu. Dalam kasus kami, com.github.romankh3.logginglecture. Sekarang mari kita bicara tentang mengonfigurasi appender CONSOLE:

# CONSOLE appender customization
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Di sini kita melihat bahwa dimungkinkan untuk mengatur level spesifik di mana appender akan mulai bekerja. Berikut adalah contoh dari apa yang sebenarnya terjadi: misalkan pesan dengan level INFO diterima oleh node logging dan diteruskan ke appender yang ditugaskan padanya. Jika ambang appender disetel ke WARN, maka ia menerima entri log tetapi tidak melakukan apa pun dengannya. Selanjutnya, kita perlu memutuskan tata letak mana yang akan digunakan pesan. Saya menggunakan PatternLayout sebagai contoh, tetapi ada banyak opsi lain. Kami tidak akan membahasnya di artikel ini. Contoh konfigurasi appender FILE:

# File appender customization
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Anda dapat mengonfigurasi file spesifik tempat entri log akan ditulis, seperti yang dapat dilihat dari baris ini:

log4j.appender.FILE.File=./target/logging/logging.log
Entri ditulis ke logging.logfile. Untuk menghindari masalah dengan ukuran file, Anda dapat mengonfigurasi maksimum, yang dalam hal ini adalah 1 MB. MaxBackupIndexmenunjukkan berapa banyak file log yang akan ada. Jika kita perlu membuat lebih banyak file dari ini, maka file pertama akan dihapus. Untuk melihat contoh nyata di mana logging dikonfigurasi, Anda dapat membuka repositori publik di GitHub.

Perkuat apa yang telah kita diskusikan

Cobalah sendiri untuk melakukan semua yang telah kami jelaskan:
  • Buat proyek Anda sendiri mirip dengan contoh kami di atas.
  • Jika Anda tahu cara menggunakan Maven, gunakanlah. Jika tidak, baca tutorial ini , yang menjelaskan cara menghubungkan perpustakaan.

Singkatnya

  1. Kami berbicara tentang solusi logging yang ada di Jawa.
  2. Hampir semua pustaka logging terkenal ditulis oleh satu orang :D
  3. Kami belajar apa yang harus dan tidak boleh dicatat.
  4. Kami menemukan level log.
  5. Kami diperkenalkan ke node logging.
  6. Kami melihat apa itu appender dan untuk apa itu.
  7. Kami membuat file log4j.proterties langkah demi langkah.

Bahan tambahan

  1. CodeGym: pelajaran Logger
  2. Mingguan Geekly: Java logging. Halo Dunia
  3. Coding Horror: Masalah Dengan Logging
  4. YouTube: Memahami Java Logging Hell - Dasar-dasarnya. Java Logging Hell & Cara menghindarinya
  5. Log4j: Menambahkan
  6. Log4j: Tata letak
Lihat juga artikel saya yang lain:
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION