I use log4net for diagnostic logging in my applications, that is, if log4net doesn't work, the application runs fine anyway. I have a separate Audit Trail log that will block the application if the audit trail fails.
I want to include Audit Trail messages in my log4net logs, but I have a conundrum: I want the AuditTrail messages to be output with the highest priority (Critical like), but I don't want the audit trail messages to be represented as fatal errors.
They should be emitted with an INFO level, given they are not critical errors, but simply mandatory messages.
I was looking into the internals of log4net and I stumbled upon the protected Logger.Forcedlog
method:
/// <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);
}
I can call this method via reflection and bypass any level check, but I'm feeling very guilty.
Are there any "cleaner" alternatives?
You can set up a named logger, e.g. AuditLog
, with or without an explicit configuration in the log4net
settings.
By default this logger will inherit the log level from the root logger or a configured one.
Just after where you apply the log4net
configuration, you configure/overrule that specific logger with the (minimal) log level you need.
You apply the configuration, e.g. from a file.
var repository = log4net.LogManager.GetRepository(Assembly.GetExecutingAssembly());
log4net.Config.XmlConfigurator.Configure(repository, new FileInfo("log4net.config"));
Immediately after the above configuration, you change the log level of the AuditLog
logger programmatically, e.g. to Info
.
var auditLog = repository.GetLogger("AuditLog") as Logger;
auditLog.Level = log4net.Core.Level.Info;
Anywhere in your application when you log via this AuditLog
logger, its programmatically set level will be considered. The below call to log an informational message will pass as it fulfills the Info
log level that has been set.
var auditLog = LogManager.GetLogger("AuditLog");
auditLog.Info("Hello audit trail log!");
An example.
Given the configuration below, where the log level is Off
, the AuditLog
logger will still log to the configured FileAppender
.
Any other loggers will not, because of the Off
setting.
<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>