Sesuai dokumentasi NLog:
Sebagian besar aplikasi akan menggunakan satu pencatat per kelas, di mana nama pencatat sama dengan nama kelas.
Ini adalah cara yang sama seperti log4net beroperasi. Mengapa ini praktik yang baik?
Sesuai dokumentasi NLog:
Sebagian besar aplikasi akan menggunakan satu pencatat per kelas, di mana nama pencatat sama dengan nama kelas.
Ini adalah cara yang sama seperti log4net beroperasi. Mengapa ini praktik yang baik?
Jawaban:
Dengan log4net, menggunakan satu pencatat per kelas membuatnya mudah untuk menangkap sumber pesan log (mis. Kelas yang menulis ke log). Jika Anda tidak memiliki satu pencatat per kelas, tetapi memiliki satu pencatat untuk seluruh aplikasi, Anda perlu menggunakan lebih banyak trik refleksi untuk mengetahui dari mana pesan log tersebut berasal.
Bandingkan berikut ini:
using System.Reflection;
private static readonly ILog _logger =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public void SomeMethod()
{
_logger.DebugFormat("File not found: {0}", _filename);
}
Logger.DebugFormat("File not found: {0}", _filename); // Logger determines caller
-- or --
Logger.DebugFormat(this, "File not found: {0}", _filename); // Pass in the caller
Menggunakan contoh kedua, Logger perlu membuat pelacakan tumpukan untuk melihat siapa yang memanggilnya atau kode Anda harus selalu diteruskan ke pemanggil. Dengan gaya logger-per-class, Anda masih melakukan ini, tetapi Anda dapat melakukannya sekali per kelas, bukan sekali per panggilan dan menghilangkan masalah kinerja yang serius.
Keuntungan menggunakan "logger per file" di NLog: Anda memiliki kemungkinan untuk mengelola / memfilter log dengan namespace dan nama kelas. Contoh:
<logger name="A.NameSpace.MyClass" minlevel="Debug" writeTo="ImportantLogs" />
<logger name="A.NameSpace.MyOtherClass" minlevel="Trace" writeTo="ImportantLogs" />
<logger name="StupidLibrary.*" minlevel="Error" writeTo="StupidLibraryLogs" />
<!-- Hide other messages from StupidLibrary -->
<logger name="StupidLibrary.*" final="true" />
<!-- Log all but hidden messages -->
<logger name="*" writeTo="AllLogs" />
NLogger memiliki potongan kode yang sangat berguna untuk melakukan ini. The nlogger
potongan akan membuat kode berikut:
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
Jadi hanya sedikit penekanan tombol dan Anda memiliki logger per kelas. Ini akan menggunakan namespace dan nama kelas sebagai nama logger. Untuk menyetel nama yang berbeda ke logger kelas Anda, Anda dapat menggunakan ini:
private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");
Dan, seperti yang dikatakan @JeremyWiebe, Anda tidak perlu menggunakan trik untuk mendapatkan nama kelas yang mencoba memasukkan pesan: Nama logger (biasanya nama kelas) dapat dengan mudah masuk ke file (atau target lain) dengan menggunakan ${logger}
in layout.
Saya dapat melihat beberapa alasan untuk pilihan ini.
Dalam banyak kasus, nama kelas memberikan nama yang bagus untuk logger. Saat memindai file log, Anda dapat melihat pesan log dan mengaitkannya secara langsung dengan sebaris kode.
Contoh yang bagus di mana ini bukan pendekatan terbaik, adalah log SQL Hibernate. Ada logger bersama bernama "Hibernate.SQL" atau semacamnya, di mana sejumlah kelas yang berbeda menulis SQL mentah ke kategori logger tunggal.
Dari sudut pandang pengembangan, paling mudah jika Anda tidak perlu membuat objek logger setiap saat. Di sisi lain, jika Anda tidak melakukannya, tetapi Anda membuatnya secara dinamis menggunakan refleksi, itu akan memperlambat kinerja. Untuk mengatasi ini, Anda dapat menggunakan kode berikut yang membuat logger secara dinamis secara asinkron:
using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinForms
{
class log
{
public static async void Log(int severity, string message)
{
await Task.Run(() => LogIt(severity, message));
}
private static void LogIt(int severity, string message)
{
StackTrace st = new StackTrace();
StackFrame x = st.GetFrame(2); //the third one goes back to the original caller
Type t = x.GetMethod().DeclaringType;
Logger theLogger = LogManager.GetLogger(t.FullName);
//https://github.com/NLog/NLog/wiki/Log-levels
string[] levels = { "Off", "Trace", "Debug", "Info", "Warn", "Error", "Fatal" };
int level = Math.Min(levels.Length, severity);
theLogger.Log(LogLevel.FromOrdinal(level), message);
}
}
}
Dua alasan segera muncul di benak:
Mungkin karena Anda ingin dapat membuat log metode yang hanya terlihat oleh kelas tanpa merusak enkapsulasi, hal ini juga memudahkan penggunaan kelas dalam aplikasi lain tanpa merusak fungsionalitas logging.
Jika Anda menggunakan NLOG Anda dapat menentukan situs panggilan di konfigurasi, ini akan mencatat nama kelas dan metode di mana pernyataan pencatatan berada.
<property name="CallSite" value="${callsite}" />
Anda kemudian dapat menggunakan konstanta untuk nama logger Anda atau nama rakitan.
Penafian: Saya tidak tahu bagaimana NLOG mengumpulkan informasi ini, dugaan saya akan menjadi refleksi jadi Anda mungkin perlu mempertimbangkan kinerjanya. Ada beberapa masalah dengan metode Async jika Anda tidak menggunakan NLOG v4.4 atau yang lebih baru.