Пользовательский NLog LogLevels или несколько регистраторов на класс?

Как я могу отделить мой normal логирование / аудит из моей системы безопасности логирование / аудит? Журнал событий Windows делает это различие с событиями приложений и событиями безопасности.

Если бы я мог создать пользовательский LogLevel, например, LogLevel.AuditSuccess или LogLevel.AuditFailure, то я мог бы установить правила моего файла конфигурации равными этим и вывести эти события. Например,

<logger name="*" levels="AuditSuccess,AuditFailure" writeTo="target1"/>
<logger name="*" levels="DEBUG,INFO" writeTo="target1"/>

Тогда я мог бы просто использовать 1 таблицу, записать "Уровень" в столбце и иметь возможность искать и сортировать мои данные, используя эту информацию столбца. (Я не думаю, что мы можем создать собственный LogLevel.)

Один из обходных путей, который я придумала, - это использование 2-х регистраторов на класс - при этом каждый регистратор сохраняется в другой цели. Тем не менее, это кажется излишним, особенно если мне нужно добавить дополнительные похожие типы целей.

<logger name="myNamespace.*" levels="INFO,ERROR" writeTo="target1"/>
<logger name="mySecurityLogger" levels="INFO,ERROR" writeTo="target2"/>

public class MyClass {
    private static Logger _logger = LogManager.GetCurrentClassLogger();
    private statac Logger _loggerSecurity = LogManager.GetLogger("mySecurityLogger");
    ...
}

При этом я мог бы создать две цели базы данных - каждая с отдельной таблицей - и затем создать 1 правило для каждой цели назначения.

Какие-либо предложения?

2 ответа

Это может быть не то, что вы после, но потерпите меня...

Вы можете обернуть NLog так, чтобы вы могли войти с помощью своих собственных "регистраторов". Посмотрите на Common.Logging для.NET или SLF, чтобы найти примеры того, как обернуть NLog (они являются полными абстракциями журналирования, поэтому они более сложны, чем то, что вам нужно, но вы можете найти некоторые хорошие идеи). Также см. Здесь (вероятно, следует посмотреть здесь в первую очередь, если вы считаете, что вас может заинтересовать просто обертывание или создание подкласса NLog Logger), чтобы найти примеры того, как правильно обернуть (или создать подкласс) NLog (обратите внимание, что ключ заключается в передаче типа вашего завернутый / вложенный регистратор в метод журнала NLog).

Итак, вы можете иметь что-то вроде этого (сокращенно):

//Wrapped logger that you could create once in a class and use to log both 
//"normal" messages and "audit" messages.  NLog log level is determined by the 
//logger configuration for the class.
public class MyLogger
{
  private Logger logger; //NLog logger

  public MyLogger(string name)
  {
    logger = LogManager.GetLogger(name);
  }

  public void Info(string message)
  {
    if (!logger.IsInfoEnabled) return;

    Write(LogLevel.Info, LogLevel.Info.ToString(), message);
  }

  public void AuditSuccess(string message)
  { 
    if (!logger.IsInfoEnabled) return;

    Write(LogLevel.Info, "AuditSuccess", message);
  }

  private void Write(LogLevel level, string customLevel, string message)
  {
    LogEventInfo le = new LogEventInfo(level, logger.Name, message);
    le.Context["CustomLogLevel"] = customLevel;
    logger.Log(typeof(MyLogger), le);
  }
}

Это даст вам методы ведения журнала, соответствующие вашим пользовательским уровням. Это также даст вам возможность вывести пользовательский столбец, содержащий ваш "пользовательский уровень" ( с использованием средства визуализации контекста событие-контекст). Это не дает вам возможность включать или выключать вход в систему на уровне "AuditSuccess". Он все еще должен контролироваться встроенными уровнями.

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

//Wrapped logger that you could create once in a class and use to log both "normal"
//and "audit" messages.  NLog log level for each type of message is controllable
//separately since the logger wrapper actually wraps two logger.
public class MyLogger
{
  private Logger logger; //NLog logger
  private Logger auditLogger;

  public MyLogger(string name)
  {
    logger = LogManager.GetLogger(name);
    auditLogger = LogManager.GetLogger("AuditLogger");
  }

  public void Info(string message)
  {
    if (!logger.IsInfoEnabled) return;

    Write(logger, LogLevel.Info, LogLevel.Info.ToString(), messsage);
  }

  public void AuditSuccess(string message)
  { 
    if (!auditLogger.IsInfoEnabled) return;

    Write(auditLogger, LogLevel.Info, "AuditSuccess", message);
  }

  private void Write(Logger log, LogLevel level, string customLevel, string message)
  {
    LogEventInfo le = new LogEventInfo(level, log.Name, message);
    le.Context["CustomLogLevel"] = customLevel;
    log.Log(typeof(MyLogger), le);
  }
}

Вы по-прежнему будете иметь те же ограничения, что перечислены выше, но вы можете по крайней мере контролировать ведение журнала "аудит / безопасность" отдельно от "обычного" ведения журнала.

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

Безопасность Security.Audit Security.Audit.Success Security.Audit.Failure Security.Login Security.Login.Success Security.Login.Failure Health Health.Heartbeat Health.Wh независимо

Тогда вы можете "включить" Security или Security.Audit или . Неудача (не уверен, что последний работает или нет).

Надеюсь это поможет.

Не могли бы вы использовать два регистратора с разными именами в своем классе, вывести их на одну и ту же цель и использовать средство рендеринга макета ${logger} в качестве значения поля?

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

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

Другие вопросы по тегам