I would like to log to different log files depending on the iformation.
The application log file should contain general information about the application or service behavior and exceptions.
Inside a service I would like to log to the application logfile and for stuff which is not suitable for the general logfile to a service logfile. An example for a service logfile could be the communication of a serial port.
I have a .net core application where I initialize the Log4Net Logger:
public void Configure(..., ILoggerFactory loggerFactory, ...)
{
...
loggerFactory.AddLog4Net();
...
}
My log4net.config for the application log looks like this:
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %logger - %message%newline" />
</layout>
</appender>
<appender name="file" type="log4net.Appender.RollingFileAppender">
<file value="logs/application.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="-yyyyMMdd" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="5MB" />
<preserveLogFileNameExtension value="true" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
</appender>
</log4net>
I use dependency injection to use the logger in services which are implemented in .net standard 2.0 projects. These projects have a reference to the Microsoft.Extensions.Logging.Abstractions nuget package. https://github.com/aspnet/Extensions/tree/master/src/Logging/Logging.Abstractions/src
Example Service
public void MyService(ILogger<MyService> logger)
{
logger.Log(LogLevel.Information, $"application log info");
// How to log to the service log file?
// logger.LogServiceLog(LogLevel.Information, $"service log info")
}
I know that i can configure log4net to log to different log files depending on the namespace. However I want to be able to use both log files.
Is there a way to achieve this with Microsoft.Extensions.Logging.Abstractions?
Can I log a scope to a different log file?
using (_logger.BeginScope("Service Scope"))
{
_logger.LogInformation("Service info");
}
Finally I found a solution which satisfies my needs. I will share it in case someone else wants to do the same.
As I alread supposed there is a possibility to achieve this with logging in a scope. The scope properties have to be set in order that they can be used to log to a different file.
For convenience I wrote an extension method:
private const string PropertyKey = "ServiceLogger";
private const string ValueSuffix = "ServiceLogger";
public static void ServiceLog<TCategoryName>(this ILogger<TCategoryName> logger, LogLevel level, string message)
{
using (logger.BeginScope(new[] { new KeyValuePair<string, object>(PropertyKey, $"{typeof(TCategoryName).Name}{ValueSuffix}") }))
{
logger.Log(level, message);
}
}
And now in the service I can use:
public void MyService(ILogger<MyService> logger)
{
// application log file
logger.Log(LogLevel.Information, $"application log info");
// service log file
logger.ServiceLog(LogLevel.Information, $"service log info");
}
In order that this works the log4net config has to be adjusted as I want to log to a different file if the key is set. Therfore I added a new appender whith a filter for Property Key=ServiceLogger and value=MyServiceServiceLogger.
Note if this logs should only be in one logfile we have to set an ignore filter on the general appender for the Property Key=ServiceLogger and value containing ServiceLogger.
Example config:
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="console" />
<appender-ref ref="app_logger" />
<appender-ref ref="service_myservice_logger" />
</root>
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%2thread] %-5level %.50logger - %message%newline" />
</layout>
</appender>
<appender name="app_logger" type="log4net.Appender.RollingFileAppender">
<file value="logs/application.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="-yyyyMMdd" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="5MB" />
<preserveLogFileNameExtension value="true" />
<staticLogFileName value="false" />
<filter type="log4net.Filter.PropertyFilter">
<key value="ServiceLogger" />
<regexToMatch value="ServiceLogger" />
<acceptOnMatch value="false" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%2thread] %-5level %.50logger - %message%newline" />
</layout>
</appender>
<appender name="service_myservice_logger" type="log4net.Appender.RollingFileAppender">
<file value="logs/my_service.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="-yyyyMMdd" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="5MB" />
<preserveLogFileNameExtension value="true" />
<staticLogFileName value="false" />
<filter type="log4net.Filter.PropertyFilter">
<Key value="ServiceLogger" />
<StringToMatch value="MyServiceServiceLogger" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%2thread] %-5level %.50logger - %message%newline" />
</layout>
</appender>
</log4net>