CodeGym /Blog Java /rawak /Pembalakan: apa, bagaimana, di mana, dan dengan apa?
John Squirrels
Tahap
San Francisco

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

Diterbitkan dalam kumpulan
Hello semua dalam komuniti CodeGym! Pembalakan: apa, bagaimana, di mana, dan dengan apa?  - 1 Hari ini mari kita bercakap tentang pembalakan:
  1. Apakah itu, mengapa ia wujud, bila anda harus menggunakannya, bila anda harus mengelakkannya.
  2. Apakah pelaksanaan pembalakan yang tersedia di Java, dan perkara yang perlu anda lakukan dengan semua pilihan pembalakan ini.
  3. Dan tahap log. Kami akan membincangkan apa itu appender dan cara mengkonfigurasinya dengan betul.
  4. Mengelog nod dan cara mengkonfigurasinya dengan betul supaya semuanya berfungsi seperti yang kita mahu.
Bahan ini bertujuan untuk khalayak yang luas. Ia akan menjadi jelas kepada sesiapa sahaja yang baru mengenali Jawa, serta mereka yang sudah bekerja tetapi hanya meneroka logger.info("log something"); Jom!

Mengapa anda memerlukan pembalakan?

Mari kita lihat beberapa kes sebenar di mana pembalakan boleh menyelesaikan masalah. Berikut adalah contoh dari kerja saya. Terdapat titik di mana aplikasi disepadukan dengan perkhidmatan lain. Saya menggunakan pengelogan pada titik ini untuk mewujudkan sejenis "alibi" : jika penyepaduan tidak berfungsi, maka menjadi mudah untuk mengetahui pihak mana yang mempunyai masalah. Ia juga wajar untuk log maklumat penting yang disimpan dalam pangkalan data. Sebagai contoh, penciptaan pengguna pentadbir. Ini adalah jenis perkara yang baik untuk dilog.

Alat untuk log masuk dalam Java

Antara penyelesaian pembalakan yang terkenal di Jawa, kami boleh menyerlahkan perkara berikut:
  • Log4j
  • JUL — java.util.logging
  • JCL — Pembalakan Jakarta Commons
  • Log balik
  • SLF4J — Fasad Pembalakan Mudah untuk Java
Kami akan memberikan gambaran keseluruhan tentang setiap daripada mereka. Kemudian kita akan mengambil slf4j - log4j mengikat sebagai asas perbincangan praktikal. Ini mungkin kelihatan pelik sekarang, tetapi jangan risau: pada akhir artikel, semuanya akan menjadi jelas.

System.err.println

Pada mulanya, terdapat System.err.println (memaparkan entri log pada konsol). Malah pada hari ini, teknik ini digunakan untuk log pantas apabila menyahpepijat. Sudah tentu, tiada tetapan untuk dibincangkan di sini, jadi ingat kaedah ini dan kami akan meneruskan.

Log4j

Ini adalah penyelesaian lengkap yang dicipta oleh pembangun kerana keperluan. Hasilnya adalah alat yang sangat menarik yang boleh anda gunakan. Disebabkan oleh pelbagai keadaan, penyelesaian ini tidak berakhir di JDK, satu fakta yang sangat mengecewakan seluruh masyarakat. Log4j mempunyai pilihan konfigurasi yang membolehkan anda mendayakan log masuk pakej com.example.typedan mematikannya dalam com.example.type.genericsubpakej. Ini memungkinkan untuk mengecualikan kod yang tidak perlu dilog dengan cepat. Adalah penting untuk ambil perhatian di sini bahawa terdapat dua versi Log4j: 1.2.x dan 2.xx, dan ia tidak serasi antara satu sama lain . Log4j menambah konsep appender(alat yang digunakan untuk menulis log) dan susun atur (pemformatan log). Ini membolehkan anda log hanya apa yang anda perlukan dan log ia mengikut cara anda memerlukannya. Kita akan bercakap lebih lanjut tentang appender sedikit kemudian.

JUL — java.util.logging

Salah satu faedah utama penyelesaian ini ialah JUL disertakan dalam JDK (Java Development Kit). Malangnya, apabila ia dibangunkan, penciptanya tidak mendasarkannya pada utiliti Log4j yang popular, sebaliknya penyelesaian daripada IBM. Keputusan itu ada akibatnya. Realitinya tiada siapa yang menggunakan JUL sekarang. Tahap log dalam JUL berbeza daripada apa yang Logback, Log4j dan Slf4j ada. Ini menjadikan mereka lebih sukar untuk memahami antara satu sama lain. Mencipta pembalak adalah lebih kurang serupa. Untuk melakukan ini, anda perlu melakukan import:

java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Nama kelas diluluskan, jadi kami tahu dari mana pembalakan kami akan datang. Bermula dengan Java 8, anda boleh lulus Supplier<String>. Ini membantu kami membaca dan mencipta baris hanya apabila kami benar-benar memerlukannya, bukannya setiap masa, seperti yang berlaku sebelum ini. Hanya dengan keluaran Java 8, pembangun akhirnya menyelesaikan masalah penting dan menjadikan JUL benar-benar boleh digunakan. Iaitu, kaedah dengan Supplier<String> msgSupplierparameter, seperti yang ditunjukkan di bawah:

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

JCL — Pembalakan Jakarta Commons

Oleh kerana tiada piawaian industri mengenai pembalakan untuk masa yang lama dan ramai orang mencipta pembalak tersuai mereka sendiri, keputusan dibuat untuk mengeluarkan JCL, pembungkus umum yang boleh digunakan di atas yang lain. kenapa? Kadangkala kebergantungan yang ditambahkan pada projek menggunakan pembalak yang berbeza daripada yang ada dalam projek. Oleh sebab itu, mereka telah ditambahkan pada projek sebagai kebergantungan transitif, dan ini menimbulkan masalah sebenar apabila cuba menggabungkan semuanya. Malangnya, pembalut itu tidak begitu berfungsi dan tidak menambah apa-apa. Ia mungkin lebih mudah jika semua orang menggunakan JCL. Tetapi bukan itu yang berlaku, jadi menggunakan JCL bukanlah idea terbaik buat masa ini.

Log balik

Laluan sumber terbuka adalah berduri... Pembangun yang sama yang menulis Log4j juga menulis Logback sebagai rangka kerja pembalakan pengganti. Ia berdasarkan idea yang sama seperti Log4j. Perbezaan dalam Logback ialah:
  • prestasi yang bertambah baik
  • menambah sokongan asli untuk Slf4j
  • pilihan penapisan yang diperluaskan
Secara lalai, Log Balik tidak memerlukan sebarang konfigurasi dan merekodkan semua peristiwa pada tahap DEBUG dan lebih tinggi. Jika anda memerlukan beberapa penyesuaian, anda boleh 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 Pembalakan Mudah untuk Java

Suatu ketika pada tahun 2006, salah seorang bapa pengasas Log4j meninggalkan projek itu dan mencipta Slf4j (Simple Logging Facade for Java), pembungkus untuk Log4j, JUL, common-logging dan Logback. Seperti yang anda lihat, kami telah maju ke peringkat mencipta pembungkus di atas pembungkus... Dalam kes ini, ia dibahagikan kepada dua bahagian: API yang digunakan dalam aplikasi dan pelaksanaan yang ditambah dengan berasingan kebergantungan bagi setiap jenis pembalakan. Contohnya, slf4j-log4j12.jardan slf4j-jdk14.jar. Anda perlu menyambung pelaksanaan yang betul dan itu sahaja: keseluruhan projek anda akan menggunakannya. Slf4j menyokong semua ciri terkini, seperti memformat rentetan untuk pengelogan. Sebelum ini, ada masalah seperti itu. Katakan kita mencipta entri log seperti ini:

log.debug("User " + user + " connected from " + request.getRemoteAddr());
Disebabkan oleh operator penggabungan, userobjek secara senyap menjadi rentetan terima kasih kepada user.toString(). Ini mengambil masa dan melambatkan sistem. Dan itu mungkin OK jika kami menyahpepijat aplikasi. Kami mula menghadapi masalah jika tahap log untuk kelas ini adalah INFO atau lebih tinggi. Dalam erti kata lain, kita tidak sepatutnya menulis entri log ini (untuk INFO atau lebih tinggi), dan kita tidak seharusnya menggunakan penggabungan rentetan. Secara teorinya, perpustakaan pembalakan itu sendiri harus menangani perkara ini. Seperti yang berlaku, ini ternyata menjadi masalah terbesar dalam versi pertama Log4j. Ia tidak memberikan penyelesaian yang baik, tetapi sebaliknya mencadangkan melakukan sesuatu seperti ini:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Iaitu, bukannya satu baris kod untuk pengelogan, mereka mencadangkan menulis 3! Pembalakan harus meminimumkan perubahan kod, dan tiga baris jelas melanggar pendekatan umum itu. Slf4j tidak mempunyai masalah keserasian dengan JDK dan API, jadi penyelesaian yang bagus segera muncul:

log.debug("User {} connected from {}", user, request.getRemoteAddr());
di mana {}menandakan ruang letak untuk hujah yang dihantar kepada kaedah. Iaitu, yang pertama {}sepadan dengan user, dan yang kedua {}sepadan dengan request.getRemoteAddr(). Dengan melakukannya dengan cara ini, kami akan melakukan penggabungan rentetan hanya jika tahap log memerlukan kami menulis entri log. Selepas itu, Sjf4j mula berkembang pesat dalam populariti. Pada masa ini, ia adalah penyelesaian terbaik. Sehubungan itu, mari kita lihat pembalakan menggunakan slf4j-log4j12binding.

Apa yang perlu dilog

Sudah tentu, anda tidak sepatutnya log semua. Ini selalunya tidak perlu dan kadang-kadang berbahaya. Contohnya, jika anda log data peribadi seseorang dan entah bagaimana ia bocor, akan ada masalah sebenar, terutamanya dalam projek yang tertumpu pada pasaran Barat. Tetapi ada juga perkara yang anda mesti log masuk :
  1. Mula/akhir permohonan. Kita perlu tahu sama ada permohonan itu benar-benar bermula dan berakhir seperti yang diharapkan.
  2. Isu keselamatan. Di sini adalah baik untuk mencatat percubaan meneka kata laluan seseorang, contoh apabila pentadbir log masuk, dsb.
  3. Negeri permohonan tertentu . Contohnya, peralihan dari satu negeri ke negeri lain dalam proses perniagaan.
  4. Maklumat nyahpepijat tertentu bersama-sama dengan tahap log yang sepadan.
  5. Skrip SQL tertentu. Terdapat kes dunia sebenar apabila ini perlu. Tetapi sekali lagi, dengan mahir menyesuaikan tahap log, anda boleh mencapai keputusan yang sangat baik.
  6. Benang berjalan boleh dilog apabila mengesahkan bahawa perkara berfungsi dengan betul.

Kesilapan popular dalam pembalakan

Terdapat banyak nuansa di sini, tetapi kami akan menyebut secara khusus beberapa kesilapan biasa:
  1. Pembalakan yang berlebihan. Anda tidak sepatutnya log setiap langkah yang secara teorinya boleh menjadi penting. Di sini peraturan yang baik: Log tidak boleh melebihi 10% daripada beban. Jika tidak, masalah prestasi akan berlaku.
  2. Log semua data ke dalam satu fail. Pada satu ketika, ini akan menjadikannya sangat sukar untuk membaca/menulis log, apatah lagi fakta bahawa sistem tertentu mempunyai had pada saiz fail.
  3. Menggunakan tahap log yang salah. Setiap peringkat log mempunyai sempadan yang jelas, dan mereka harus dihormati. Jika sempadan tidak jelas, anda boleh mencapai persetujuan tentang tahap yang hendak digunakan.

Tahap log

x: Kelihatan
MAUT RALAT AMARAN INFO DEBUG JEJAK SEMUA
DIMATIKAN
MAUT x
RALAT x x
AMARAN 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
Apakah tahap log? Untuk mencipta hierarki entri log, konvensyen dan persempadanan tertentu diperlukan. Inilah sebabnya tahap log diperkenalkan. Tahap ditetapkan dalam aplikasi. Jika entri berada di bawah tahap yang ditentukan, maka ia tidak dilog. Sebagai contoh, kami mempunyai log yang kami gunakan semasa menyahpepijat aplikasi. Semasa operasi biasa (apabila aplikasi digunakan untuk tujuan yang dimaksudkan), log sedemikian tidak diperlukan. Oleh itu, tahap log adalah lebih tinggi daripada untuk nyahpepijat. Mari lihat tahap log menggunakan Log4j. Selain JUL, penyelesaian lain menggunakan tahap log yang sama. Di sini mereka berada dalam susunan yang semakin berkurangan:
  • MATI: Tiada entri log direkodkan; semuanya diabaikan.
  • FATAL: Ralat yang menghalang aplikasi daripada terus berjalan. Contohnya, "JVM out of memory error".
  • RALAT: Ralat pada tahap ini menunjukkan masalah yang perlu diselesaikan. Ralat tidak menghentikan aplikasi secara keseluruhan. Permintaan lain mungkin berfungsi dengan betul.
  • AMARAN: Log masukan yang mewakili amaran. Sesuatu yang tidak dijangka berlaku, tetapi sistem dapat mengatasi dan memenuhi permintaan itu
  • INFO: Log masukan yang menunjukkan tindakan penting dalam aplikasi. Ini bukan kesilapan atau amaran. Ia adalah peristiwa sistem yang dijangkakan.
  • DEBUG: Entri log perlu menyahpepijat aplikasi. Untuk memastikan bahawa aplikasi melakukan apa yang diharapkan, atau untuk menerangkan tindakan yang diambil oleh aplikasi, iaitu "Memasukkan kaedah1".
  • TRACE: Entri log keutamaan rendah untuk penyahpepijatan. Tahap log terendah.
  • SEMUA: Tahap log untuk menulis semua entri log aplikasi.
Dalam tahap log INFO didayakan di suatu tempat dalam aplikasi, maka entri untuk setiap peringkat akan dilog, dari INFO kepada FATAL. Jika tahap log FATAL ditetapkan, hanya entri log dengan tahap itu akan ditulis.

Pembalakan dan penghantaran log: Lampiran

Mari kita pertimbangkan bagaimana semua ini berfungsi apabila kita menggunakan Log4j, yang menyediakan banyak peluang untuk menulis/menghantar log:
  • untuk menulis ke fail -DailyRollingFileAppender
  • untuk menulis maklumat ke konsol -ConsoleAppender
  • untuk menulis log ke pangkalan data —JDBCAppender
  • untuk menguruskan penghantaran log melalui TCP/IP —TelnetAppender
  • untuk memastikan pembalakan tidak memberi kesan negatif terhadap prestasi —AsyncAppender
Terdapat beberapa lagi pelaksanaan: senarai lengkap tersedia di sini . By the way, jika appender yang anda perlukan tidak wujud, itu tidak menjadi masalah. Anda boleh menulis appender anda sendiri dengan melaksanakan antara muka Appender , yang disokong oleh Log4j.

Nod pembalakan

Untuk tujuan demonstrasi, kami akan menggunakan antara muka Slf4j, dengan pelaksanaan daripada Log4j. Mencipta pembalak adalah sangat mudah: dalam kelas bernama MainDemo, yang akan melakukan beberapa pengelogan, kita perlu menambah yang berikut:

org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Ini akan mencipta pembalak untuk kita. Untuk membuat entri log, terdapat beberapa kaedah tersedia yang namanya mencerminkan tahap log yang akan digunakan. Sebagai contoh:

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);
Walaupun kami lulus kelas, nama akhir ialah nama penuh kelas, termasuk pakej. Ini dilakukan supaya kemudian anda boleh membahagikan pengelogan ke dalam nod dan mengkonfigurasi tahap pengelogan dan pelengkap untuk setiap nod. Sebagai contoh, pembalak telah dicipta dalam com.github.romankh3.logginglecture.MainDemokelas. Nama itu menyediakan asas untuk mencipta hierarki nod pembalakan. Nod utama ialah RootLogger peringkat atas . Ini adalah nod yang menerima semua entri log untuk keseluruhan aplikasi. Nod yang selebihnya boleh digambarkan seperti yang ditunjukkan di bawah: Pembalakan: apa, bagaimana, di mana, dan dengan apa?  - 3Penambah dikonfigurasikan untuk nod pengelogan tertentu. Sekarang kita akan melihat fail log4j.properties untuk melihat contoh cara mengkonfigurasinya.

Panduan langkah demi langkah untuk fail log4j.properties

Kami akan menyediakan segala-galanya satu langkah pada satu masa dan melihat perkara yang mungkin:

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Baris ini mengatakan bahawa kami sedang mendaftarkan appender CONSOLE, yang menggunakan pelaksanaan org.apache.log4j.ConsoleAppender. Penambah ini menulis maklumat ke konsol. Seterusnya, kami mendaftarkan pelengkap lain. Yang ini akan menulis ke fail:

log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Adalah penting untuk ambil perhatian bahawa pelengkap itu sendiri masih perlu dikonfigurasikan. Sebaik sahaja kami telah mendaftarkan penambah kami, kami boleh menentukan tahap log yang mana dan penambah yang akan digunakan pada nod.

log4j.rootLogger=DEBUG, CONSOLE, FAIL

  • log4j.rootLogger bermakna kami sedang mengkonfigurasi nod akar, yang mengandungi semua entri log
  • Perkataan pertama selepas tanda sama menunjukkan tahap log minimum untuk ditulis (dalam kes kami, ia adalah DEBUG)
  • Mengikuti koma, kami menunjukkan semua pelengkap yang akan digunakan.
Untuk mengkonfigurasi nod pengelogan yang lebih khusus, anda akan menggunakan entri seperti ini:

log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
di mana log4j.logger.digunakan untuk merujuk nod tertentu. Dalam kes kita, com.github.romankh3.logginglecture. Sekarang mari kita bincangkan tentang mengkonfigurasi penambah 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 bahawa adalah mungkin untuk menetapkan tahap tertentu di mana penambah akan mula berfungsi. Berikut ialah contoh perkara yang sebenarnya berlaku: andaikan mesej dengan tahap INFO diterima oleh nod pengelogan dan dihantar kepada penambah yang diberikan kepadanya. Jika ambang penambah ditetapkan kepada WARN, maka ia menerima entri log tetapi tidak melakukan apa-apa dengannya. Seterusnya, kita perlu memutuskan susun atur yang akan digunakan oleh mesej. Saya menggunakan PatternLayout dalam contoh, tetapi terdapat banyak pilihan lain. Kami tidak akan membincangkannya dalam artikel ini. Contoh mengkonfigurasi penambah 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 boleh mengkonfigurasi fail khusus yang mana entri log akan ditulis, seperti yang dapat dilihat dari baris ini:

log4j.appender.FILE.File=./target/logging/logging.log
Entri ditulis pada logging.logfail. Untuk mengelakkan masalah dengan saiz fail, anda boleh mengkonfigurasi maksimum, yang dalam kes ini ialah 1MB. MaxBackupIndexmenunjukkan berapa banyak fail log tersebut akan ada. Jika kita perlu membuat lebih banyak fail daripada ini, maka fail pertama akan dipadamkan. Untuk melihat contoh sebenar di mana pengelogan dikonfigurasikan, anda boleh pergi ke repositori awam di GitHub.

Mengukuhkan apa yang telah kita bincangkan

Cuba sendiri untuk melakukan semua yang telah kami terangkan:
  • Buat projek anda sendiri seperti contoh kami di atas.
  • Jika anda tahu cara menggunakan Maven, gunakannya. Jika tidak, baca tutorial ini , yang menerangkan cara menyambungkan perpustakaan.

Secara ringkasnya

  1. Kami bercakap tentang penyelesaian pembalakan yang wujud di Jawa.
  2. Hampir semua perpustakaan pembalakan yang terkenal ditulis oleh seorang :D
  3. Kami belajar perkara yang patut dan tidak patut dilog.
  4. Kami mengetahui tahap log.
  5. Kami telah diperkenalkan dengan nod pembalakan.
  6. Kami melihat apa itu appender dan untuk apa ia.
  7. Kami mencipta fail log4j.proteties langkah demi langkah.

Bahan tambahan

  1. CodeGym: Pelajaran Logger
  2. Mingguan Geekly: pengelogan Java. Hai dunia
  3. Pengekodan Seram: Masalah Dengan Pembalakan
  4. YouTube: Memahami Java Logging Hell - Asasnya. Java Logging Hell & Cara untuk menjauhinya
  5. Log4j: Lampiran
  6. Log4j: Reka letak
Lihat juga artikel saya yang lain:
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION