NLog: aturan dan filter

NLog: aturan dan filter


Di Konfirmasi, kami menggunakan perpustakaan NLog untuk masuk ke aplikasi .NET kami. Meskipun ada dokumentasi untuk pustaka ini, sulit bagi saya untuk memahami cara kerjanya. Pada artikel ini, saya akan mencoba menjelaskan bagaimana aturan dan filter diterapkan di NLog. Mari kita mulai.


Cara mengkonfigurasi NLog


Dan kita akan mulai dengan sedikit pengingat tentang apa yang bisa kita lakukan dengan konfigurasi NLog. Dalam kasus yang paling sederhana, konfigurasi ini adalah file XML (misalnya, NLog.config):


<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <targets> <target name="target1" xsi:type="ColoredConsole" layout="Access Log|${level:uppercase=true}|${logger}|${message}"> <highlight-row condition="true" foregroundColor="red"/> </target> <target name="target2" xsi:type="ColoredConsole" layout="Common Log|${level:uppercase=true}|${logger}|${message}"> <highlight-row condition="true" foregroundColor="green"/> </target> <target name="target3" xsi:type="ColoredConsole" layout="Yellow Log|${level:uppercase=true}|${logger}|${message}"> <highlight-row condition="true" foregroundColor="yellow"/> </target> </targets> <rules> <logger name="*" minlevel="Warn" writeTo="target1,target2,target3" /> </rules> </nlog> 

Anda dapat mengunduh file ini dengan satu baris kode:


 LogManager.Configuration = new XmlLoggingConfiguration("NLog.config"); 

Apa yang bisa kita lakukan dengannya? Kami dapat mengatur beberapa penerima pesan (target) dengan aturan:


 <rules> <logger name="*" minlevel="Warn" writeTo="target1,target2,target3" /> </rules> 

Kami dapat menentukan untuk level apa pencatatan aturan ini diterapkan:


 <rules> <logger name="*" minlevel="Warn" writeTo="target1" /> <logger name="*" levels="Debug,Warn,Info" writeTo="target2" /> </rules> 

Kami dapat menetapkan filter untuk setiap aturan:


 <rules> <logger name="*" minlevel="Info" writeTo="target1"> <filters defaultAction='Log'> <when condition="contains('${message}','Common')" action="Ignore" /> </filters> </logger> </rules> 

Dan akhirnya, kita dapat mendefinisikan aturan bertingkat:


 <rules> <logger name="*" minlevel="Info" writeTo="target1"> <logger name="*" minlevel="Warn" writeTo="target2" /> </logger> </rules> 

Saatnya untuk mencari tahu cara kerjanya.


Membuat konfigurasi logger


Saat Anda meminta instance logger,


 var commonLogger = LogManager.GetLogger("Common"); 

NLog mengambil yang sudah ada dari cache atau membuat yang baru (lihat di sini ). Dalam kasus terakhir, konfigurasi juga dibuat untuk logger dengan nama yang diberikan. Mari kita lihat proses pembuatannya.


Singkatnya, konfigurasi logger adalah rantai penerima yang terpisah dan filter yang sesuai untuk setiap tingkat logging ( Trace , Debug , Info , Warn , Error , Fatal ) (lihat di sini ). Sekarang saya akan menunjukkan kepada Anda bagaimana rantai ini dibangun.


Metode utama yang bertanggung jawab untuk membuat rantai ini adalah GetTargetByLevelForLogger dari kelas LogFactory . Beginilah cara kerjanya. Semua aturan yang ditentukan dalam konfigurasi NLog dipilih secara bergantian. Pertama, ia memeriksa untuk melihat apakah nama aturan cocok dengan nama logger. Nama aturan dapat berisi wildcard, seperti yang kami gunakan untuk objek sistem file:


  • * - urutan karakter yang sewenang-wenang
  • ? - setiap karakter tunggal

Dengan demikian, nama aturan ' * ' cocok dengan nama logger apa pun, dan ' Common* ' cocok dengan semua logger yang namanya dimulai dengan ' Common '.


Jika nama aturan tidak cocok dengan nama logger, maka aturan ini dibuang dengan semua aturan yang tertanam di dalamnya. Jika tidak, metode GetTargetsByLevelForLogger mendapatkan semua level logging yang aturan ini diaktifkan. Untuk setiap level seperti itu, NLog menambahkan semua penerima pesan yang ditentukan dalam aturan ke rantai penerima yang sesuai bersama dengan filter untuk aturan ini.


Ada fitur penting lainnya dalam membangun rantai penerima. Jika aturan saat ini ditandai sebagai final dan namanya cocok dengan nama logger, maka NLog menyelesaikan konstruksi rantai untuk semua level logging termasuk untuk aturan ini. Ini berarti bahwa baik aturan bertingkat maupun aturan berikutnya tidak menambahkan apa pun ke rantai penerima ini. Penciptaan mereka sepenuhnya selesai dan mereka tidak akan berubah. Oleh karena itu tidak masuk akal untuk menulis sesuatu seperti ini:


 <rules> <logger name="*" minlevel="Info" writeTo="target1" final="true"> <logger name="*" minlevel="Warn" writeTo="target2" /> </logger> </rules> 

Tidak ada pesan yang akan mencapai target2 . Tetapi dimungkinkan untuk menulis sesuatu seperti ini:


 <rules> <logger name="*" minlevel="Warn" writeTo="target1" final="true"> <logger name="*" minlevel="Info" writeTo="target2" /> </logger> </rules> 

Karena aturan eksternal tidak diaktifkan untuk tingkat Info , rantai penerima untuk tingkat ini tidak akan berakhir pada aturan eksternal. Oleh karena itu, semua pesan dengan tingkat Info akan masuk ke target2 .


Setelah semua penerima dari aturan ini ditambahkan ke rantai yang sesuai, metode ini secara rekursif memproses semua aturan yang bersarang dari aturan saat ini sesuai dengan algoritma yang sama. Ini terjadi terlepas dari level logging yang diaktifkan untuk aturan induk.


Secara total, konfigurasi untuk logger sudah siap. Ini berisi rantai penerima dengan filter untuk setiap tingkat logging yang memungkinkan:


Rantai Penerima


Saatnya untuk melihat bagaimana konfigurasi ini digunakan.


Menggunakan konfigurasi logger


Mari kita mulai dengan hal-hal sederhana. Kelas Logger memiliki metode IsEnabled dan properti IsXXXEnabled terkait ( IsDebugEnabled , IsInfoEnabled , ...). Bagaimana cara kerjanya? Bahkan, mereka hanya memeriksa apakah rantai penerima untuk tingkat logging tertentu mengandung setidaknya satu tautan (lihat di sini ). Ini berarti bahwa filter tidak pernah memengaruhi nilai properti ini.


Selanjutnya, izinkan saya menjelaskan apa yang terjadi ketika Anda mencoba mengamankan pesan. Seperti yang mungkin sudah Anda duga, pencatat mengambil rantai penerima untuk tingkat pencatatan pesan ini. Kemudian ia mulai memproses mata rantai rantai ini satu demi satu. Untuk setiap tautan, logger memutuskan apakah akan menulis pesan ke penerima yang ditentukan dalam tautan, dan apakah akan melanjutkan memproses rantai setelah itu. Keputusan ini dibuat menggunakan filter. Biarkan saya menunjukkan kepada Anda bagaimana filter bekerja di NLog.


Begini cara filter dikonfigurasikan:


 <rules> <logger name="*" minlevel="Info" writeTo="target1"> <filters defaultAction='Log'> <when condition="contains('${message}','Common')" action="Ignore" /> </filters> </logger> </rules> 

Biasanya filter berisi beberapa kondisi Boolean. Di sini Anda dapat memutuskan apakah filter mengembalikan true atau false untuk setiap pesan. Tapi ini tidak benar. Hasil pekerjaan mereka adalah nilai dari tipe FilterResult . Jika kondisi filter mengembalikan true , maka hasil filter menjadi nilai yang ditentukan dalam atribut action (dalam contoh kami, ini adalah Ignore ). Jika kondisi kembali false , maka hasil filter akan menjadi Neutral . Ini berarti bahwa filter tidak ingin memutuskan apa yang harus dilakukan dengan pesan tersebut.


Anda dapat melihat bagaimana rantai penerima diproses di sini . Untuk setiap penerima, hasil dari filter yang sesuai dalam metode GetFilterResult . Itu sama dengan hasil dari filter pertama yang mengembalikan bukan Neutral . Ini berarti bahwa jika beberapa filter mengembalikan nilai selain Neutral , semua filter berikutnya tidak dijalankan.


Tetapi apa yang terjadi jika semua filter mengembalikan Neutral ? Dalam hal ini, nilai default akan digunakan. Nilai ini diatur menggunakan atribut defaultAction dari elemen filters untuk aturan. Menurut Anda apa nilai default untuk defaultAction ? Anda benar jika Anda berpikir ini adalah Neutral . Artinya, seluruh rantai filter dapat mengembalikan Neutral sebagai hasilnya. Dalam hal ini, NLog berperilaku sama dengan menerima Log . Pesan akan ditulis ke penerima (lihat di sini ).


Seperti yang mungkin sudah Anda duga, jika filter mengembalikan Ignore atau IgnoreFinal , pesan tidak akan ditulis ke penerima. Jika hasil filter adalah Log atau LogFinal , pesan akan direkam. Tapi apa perbedaan antara Ignore dan IgnoreFinal dan antara Log atau LogFinal ? Sederhana saja. Dalam kasus IgnoreFinal dan LogFinal NLog berhenti memproses rantai penerima dan tidak menulis apa pun ke penerima yang terdapat dalam tautan selanjutnya.


Kesimpulan


Menganalisis kode NLog membantu saya memahami cara kerja aturan dan filter. Semoga artikel ini bermanfaat bagi Anda. Semoga beruntung

Source: https://habr.com/ru/post/id450728/


All Articles