Відповідно до документації NLog:
Більшість програм використовуватимуть по одному реєстратору на клас, де ім'я реєстратора збігається з ім'ям класу.
Це те саме, що працює log4net. Чому це хороша практика?
Відповідно до документації NLog:
Більшість програм використовуватимуть по одному реєстратору на клас, де ім'я реєстратора збігається з ім'ям класу.
Це те саме, що працює log4net. Чому це хороша практика?
Відповіді:
У log4net використання одного реєстратора на клас полегшує отримання джерела повідомлення журналу (тобто запис класу в журнал). Якщо у вас немає одного реєстратора на клас, але натомість у вас є один реєстратор для всієї програми, вам потрібно вдатися до додаткових хитрощів, щоб знати, звідки надходять повідомлення журналу.
Порівняйте наступне:
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
Використовуючи другий приклад, реєстратору потрібно буде побудувати трасування стека, щоб побачити, хто його викликає, або ваш код завжди повинен передавати абонента. Зі стилем реєстратора за класом ви все одно робите це, але ви можете робити це один раз для класу, а не один раз за дзвінок і усунути серйозну проблему з продуктивністю.
Перевага використання "реєстратора на файл" у NLog: у вас є можливість керувати / фільтрувати журнали за простором імен та іменем класу. Приклад:
<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 має дуже корисний фрагмент коду для цього. nlogger
Фрагмент коду створює наступний код:
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
Отже, лише кілька натискань клавіш, і у вас є реєстратор на клас. Він використовуватиме простір імен та ім'я класу як ім'я реєстратора. Щоб встановити інше ім'я для свого реєстратора класів, ви можете використовувати це:
private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");
І, як сказав @JeremyWiebe, вам не потрібно використовувати хитрощі, щоб отримати ім'я класу, який намагається записати повідомлення: Ім'я реєстратора (яке зазвичай є ім'ям класу) можна легко записати у файл (або іншої цілі) за допомогою ${logger}
в макеті.
Я бачу кілька причин такого вибору.
У більшості випадків назва класу забезпечує гарне ім'я для реєстратора. Під час сканування файлів журналу ви можете побачити повідомлення журналу та пов'язати його безпосередньо з рядком коду.
Хорошим прикладом, коли це не найкращий підхід, є журнали SQL Hibernate. Існує спільний реєстратор з назвою "Hibernate.SQL" або щось подібне, де кілька різних класів записують необроблений SQL в одну категорію реєстратора.
З точки зору розробки, найпростіше, якщо вам не доведеться створювати об'єкт реєстратора щоразу. З іншого боку, якщо ви цього не зробите, а скоріше динамічно створюєте його за допомогою відображення, це сповільнить продуктивність. Щоб вирішити цю проблему, ви можете використовувати такий код, який створює реєстратор динамічно асинхронно:
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);
}
}
}
Відразу з’являються дві причини:
Можливо, тому, що ви хочете мати можливість реєструвати методи, видимі лише для класу, не порушуючи інкапсуляцію, це також полегшує використання класу в іншій програмі, не порушуючи функціонування журналу.
Якщо ви використовуєте NLOG, ви можете вказати місце виклику в конфігурації, це запише ім'я класу та метод, де знаходився оператор журналювання.
<property name="CallSite" value="${callsite}" />
Потім ви можете використовувати константу для імені вашого журналу або імені збірки.
Застереження: я не знаю, як NLOG збирає цю інформацію, я думаю, це буде відображенням, тому вам, можливо, доведеться розглянути результативність. Якщо ви не використовуєте NLOG v4.4 або новішої версії, є кілька проблем із методами Async.