5

How can I separate my normal logging/auditing from my security logging/auditing? The Windows Event Log makes this distinction with Application Events and Security Events.

If I could create a custom LogLevel, e.g. LogLevel.AuditSuccess or LogLevel.AuditFailure, then I could set my config file rules to equal these and output those events. For example,

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

Then I could just use 1 table, record the "Level" in a column, and be able to search and sort my data using this column info. (I don't think we can create a custom LogLevel.)

One workaround that I come up with is to use 2 loggers per class--with each logger being saved to a different target. However, this seems like overkill, especially if I need to add additional similar target types.

<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");
    ...
}

With this, I could create two database targets--each with a different table--and then create 1 rule for each destination target.

Any suggestions?

4

2 回答 2

6

这可能不是您所追求的,但请耐心等待...

您可以包装 NLog 以便您可以使用自己的“记录器”进行记录。查看Common.Logging for .NETSLF以获取有关如何包装 NLog 的示例(它们是完整的日志记录抽象,因此它们比您所追求的更复杂,但您可能会得到一些好主意)。另请参阅此处(如果您认为您可能对简单地包装或子类化 NLog Logger 感兴趣,可能应该首先查看此处)以获取如何正确包装(或子类化)NLog 的示例(请注意,关键是传递您的类型将记录器包装/子类化为 NLog 的 Log 方法)。

所以,你可能有这样的东西(缩写):

//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.Whatever

然后你可以“打开” Security 或 Security.Audit 或. .Failure(不确定最后一个是否有效)。

希望这可以帮助。

于 2010-10-07T22:12:15.767 回答
3

难道你不能在你的类中使用两个不同命名的记录器,输出到同一个目标,并使用${logger} 布局渲染器作为字段值吗?

老实说,如果这些事件在应用程序域中如此重要,那么通过日志框架记录它们可能是错误的做法。也许它应该是您的应用程序中更明确建模的概念。当然,如果您需要将事件数据存储在与其他日志消息相同的位置,您可能没有这个选择。

否则,我倾向于远离自定义日志级别,因为它们从未真正证明值得添加它们的麻烦。

于 2010-10-07T22:23:49.087 回答