强制 Log4Net 输出特定事件

Force Log4Net to output specific events

我在我的应用程序中使用 log4net 进行诊断日志记录,也就是说,如果 log4net 不起作用,应用程序仍然可以正常运行。 我有一个单独的审计跟踪日志,如果审计跟踪失败,它将阻止应用程序。

我想在我的 log4net 日志中包含 Audit Trail 消息,但我有一个难题:我希望 AuditTrail 消息以最高优先级(Critical 类)输出,但我不想要审计跟踪消息表示为致命错误。
它们应该以 INFO 级别发出,因为它们不是严重错误,而只是强制性消息。

我正在研究 log4net 的内部结构,偶然发现了受保护的 Logger.Forcedlog 方法:

/// <summary>
/// Creates a new logging event and logs the event without further checks.
/// </summary>
/// <param name="logEvent">The event being logged.</param>
/// <remarks>
/// <para>
/// Delivers the logging event to the attached appenders.
/// </para>
/// </remarks>
protected virtual void ForcedLog(LoggingEvent logEvent)
{
  logEvent.EnsureRepository((ILoggerRepository) this.Hierarchy);
  this.CallAppenders(logEvent);
}

我可以通过反射调用此方法并绕过任何级别检查,但我感到非常内疚。

是否有任何“更清洁”的替代品?

您可以设置命名记录器,例如AuditLog,在 log4net 设置中有或没有显式配置。
默认情况下,此记录器将从根记录器或配置的记录器继承日志级别。

在您应用 log4net 配置之后,您 configure/overrule 具有您需要的(最低)日志级别的特定记录器。

您应用配置,例如来自文件。

var repository = log4net.LogManager.GetRepository(Assembly.GetExecutingAssembly());
log4net.Config.XmlConfigurator.Configure(repository, new FileInfo("log4net.config"));

在上述配置之后,您可以立即以编程方式更改 AuditLog 记录器的日志级别,例如至 Info.

var auditLog = repository.GetLogger("AuditLog") as Logger;
auditLog.Level = log4net.Core.Level.Info;

当您通过此 AuditLog 记录器登录时,您应用程序中的任何地方都会考虑其编程设置的级别。以下记录信息性消息的调用将通过,因为它满足已设置的 Info 日志级别。

var auditLog = LogManager.GetLogger("AuditLog");
auditLog.Info("Hello audit trail log!");

一个例子。
鉴于下面的配置,日志级别为 OffAuditLog 记录器仍将记录到配置的 FileAppender.
由于 Off 设置,任何其他记录器都不会。

<log4net>
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
        <file value="log-file.txt" />
        <appendToFile value="true" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger %message%newline" />
        </layout>
    </appender>
    <root>
        <level value="Off" />
        <appender-ref ref="FileAppender" />
    </root>
</log4net>

感谢@pfx 的想法,最终对我有用的实际上是声明自定义日志级别。
鉴于这不完全是我的要求,我奖励 pfx 的答案,但我在这里报告我的解决方案以防它可以帮助其他人:

// declares a custom Log4Net Level named Audit with the same priority of Fatal errors
private static readonly Level AuditTrailLevel = new Level(Level.Fatal.Value, "AUDIT");

// to be used as:
_log.Logger.Log(null, AuditTrailLevel, message, exception);

甜蜜而简单!