Почему регистраторы рекомендуют использовать регистратор для каждого класса? - PullRequest
85 голосов
/ 29 июня 2010

Согласно документации NLog:

Большинство приложений будет использовать один регистратор на класс, где имя регистратора совпадает с именем класса.* Это так же, как работает log4net.Почему это хорошая практика?

Ответы [ 10 ]

57 голосов
/ 29 июня 2010

При использовании 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 должен был бы построить трассировку стека, чтобы увидеть, кто его вызывал, или ваш код всегда должен передавать вызывающему.Со стилем логгер для класса вы все равно делаете это, но вы можете делать это один раз для класса, а не один раз для вызова, и устранить серьезную проблему производительности.

15 голосов
/ 24 июля 2013

Преимущество использования «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} в макете.

5 голосов
/ 29 июня 2010

Я вижу несколько причин для этого выбора.

  • Вы всегда будете знать, откуда пришел конкретный оператор журнала, если вы включите имя регистратора в свой формат вывода журнала.
  • Вы можете контролировать, какие операторы журнала вы видите на мелком уровне, включив или выключив определенные регистраторы или установив их уровень.
4 голосов
/ 12 января 2016

В случае NLog также есть преимущество в производительности. Большинство пользователей будут использовать

Logger logger = LogManager.GetCurrentClassLogger()

Поиск текущего класса по трассировке стека требует некоторой (но не очень) производительности.

3 голосов
/ 29 июня 2010

В большинстве случаев имя класса обеспечивает хорошее имя для регистратора. При сканировании файлов журнала вы можете увидеть сообщение журнала и связать его непосредственно со строкой кода.

Хороший пример, где такой подход не самый лучший, - это журналы SQL Hibernate. Существует общий регистратор с именем «Hibernate.SQL» или что-то в этом роде, где несколько различных классов записывают необработанный SQL в одну категорию регистраторов.

2 голосов
/ 19 января 2016

С точки зрения разработки, проще всего, если вам не нужно каждый раз создавать объект регистратора. С другой стороны, если вы этого не сделаете, а создадите его динамически с помощью отражения, это снизит производительность. Чтобы решить эту проблему, вы можете использовать следующий код, который динамически асинхронно создает логгер:

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);

        }
    }
}
1 голос
/ 29 июня 2010

На ум сразу приходят две причины:

  1. Наличие отдельного журнала для каждого класса облегчает группирование всех сообщений / ошибок журнала, относящихся к данному классу.
  2. Наличиежурнал внутри класса позволяет вам регистрировать внутренние детали, которые могут быть недоступны за пределами класса (например, частное состояние, информация, касающаяся реализации класса и т. д.).
0 голосов
/ 24 октября 2017

Если вы используете NLOG, вы можете указать место вызова в конфигурации, при этом будет записано имя класса и метод, в котором находился оператор ведения журнала.

<property name="CallSite" value="${callsite}" />

Затем вы можете использовать константу для имени вашего регистратора или имени сборки.

Отказ от ответственности: я не знаю, как NLOG собирает эту информацию, я думаю, что это будет отражением, поэтому вам, возможно, придется рассмотреть производительность. Есть несколько проблем с асинхронными методами, если вы не используете NLOG v4.4 или новее.

0 голосов
/ 29 июня 2010

Упрощает настройку дополнений по пространству имен или классу.

0 голосов
/ 29 июня 2010

Возможно, потому что вы хотите иметь возможность регистрировать методы, которые видны только классу, не нарушая инкапсуляцию, это также упрощает использование класса в другом приложении без нарушения функциональности ведения журнала.

...