Согласно документации 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
Используя второй пример, Logger должен будет построить трассировку стека, чтобы узнать, кто ее вызывается, или ваш код всегда должен проходить в вызывающем. С помощью стиля logger-per-class вы все равно это делаете, но вы можете делать это один раз за класс, а не один раз за звонок, и устранять серьезную проблему с производительностью.
Преимущество использования "logger per file" в 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}
в макете.
Я вижу несколько причин для этого выбора.
В большинстве случаев имя класса предоставляет хорошее имя для регистратора. При сканировании файлов журнала вы можете увидеть сообщение журнала и связать его напрямую с линией кода.
Хорошим примером, где это не лучший подход, является журнал Hibernate SQL. Существует общий логгер с именем "Hibernate.SQL" или что-то в этом роде, где несколько разных классов записывают исходный SQL-код в одну категорию регистратора.
Две причины немедленно spring:
Вероятно, потому что вы хотите иметь возможность регистрировать методы, которые видны только классу, не нарушая инкапсуляцию, это также упрощает использование класса в другом приложении без нарушения функций ведения журнала.
Легко настраивать приложения по пространству имен или классу.
В случае NLog также есть преимущество в производительности. Большинство пользователей будут использовать
Logger logger = LogManager.GetCurrentClassLogger()
Поиск текущего класса из трассировки стека требует некоторой (но не очень высокой) производительности.
С точки зрения разработки это проще всего, если вам не нужно создавать объект журнала каждый раз. С другой стороны, если вы этого не сделаете, но вы создаете его динамически с помощью отражения, это замедлит работу. Чтобы решить эту проблему, вы можете использовать следующий код, который динамически создает асинхронный журнал:
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, вы можете указать callsite в config, это будет записывать имя и метод класса, в которых был указан оператор ведения журнала.
<property name="CallSite" value="${callsite}" />
Затем вы можете использовать константу для имени вашего журнала или имени сборки.
Отказ от ответственности: я не знаю, как NLOG собирает эту информацию, моя догадка будет отражением, поэтому вам может потребоваться рассмотреть производительность. Есть несколько проблем с методами Async, если вы не используете NLOG v4.4 или новее.