Trying to understand the log4net filtering. After reading the docs some aspects are still elusive to me.
For example I have this config file:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="..\Logs\CurrentLog" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10000" />
<staticLogFileName value="true" />
<filter type="log4net.Filter.LevelRangeFilter">
<acceptOnMatch value="true" />
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date [%thread] %-22.22c{1} - %m%n" />
</layout>
</appender>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
<file value="log-file.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<header value="Service Logging -- Start" />
<footer value="Service Logging -- End" />
<conversionPattern value="%date [%thread] %-5level %logger [%ndc]
<%property{auth}> - %message%newline" />
</layout>
</appender>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
<applicationName value="WindowsService1.exe" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger
[%property{NDC}] - %message%newline" />
</layout>
</appender>
<!-- Set the default logging level and add the active appenders -->
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="RollingFileAppender" />
</root>
<!-- Specify the level for specific categories (“namespace.class”)-->
<logger name="WindowsService1.MyMonitor">
<level value="WARN" />
<appender-ref ref="EventLogAppender" />
</logger>
</log4net>
My expectations were:
- The RollingFileAppender has a range of [INFO:FATAL] The Root has a Level of DEBUG so it would let DEBUG and "greater" pass. Which means all of RollingFileAppender's range would go through.
- The LogFileAppender has no range specified so it would use Root's of DEBUG or greater.
- And the EventLogAppender would only send event messages of WARN or greater to the Windows Event System - and - they would only be messages from the class "WindowsService1.MyMonitor".
However it appears that all the messaging gets filtered to the WARN level! Including my rolling log files and the log file "log-file.txt"
This seems like it should be simple - don't know why I'm so confused by it. Hope someone can enlighten me. Please feel free to use crayons and pictures because I think I need them. Thanks.
UPDATE
In my Program.cs I have:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4Net.config", Watch = true)]
And in each class where logging is done:
private static readonly ILog log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
UPDATE 2
At a different computer now. Had to recreate everything and used log4net debugging to assist.
But still can't get the desired output.
Basically want the WARN and above messages to go to one file and the Event logger. And those messages would be a subset of all the INFO and above messages. The INFO and above messages - superset - would go into the rolling appender and overwrite themselves eventually. But the warnings and errors would always be maintained.
So here is a rework of all the files for a simple service. If I set WARN on the appender-ref ref=EventLogAppender
then all the INFOs are suppressed.
Program.cs
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4Net.config", Watch = true)]
// Ref: http://www.c-sharpcorner.com/UploadFile/naresh.avari/develop-and-install-a-windows-service-in-C-Sharp/
//
// use 'sc' to install/delete the service
// run 'sc' as administrator
// sc create "MySillyService" binpath= "C:\whatever\something.exe"
// sc delete "MySillyService"
namespace SimpleService1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
}
Service1.cs
namespace SimpleService1
{
public partial class Service1 : ServiceBase
{
private static readonly ILog log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Timer timer1;
private int counter = 0;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer1 = new Timer();
timer1.Interval = 4000;
timer1.Elapsed += new ElapsedEventHandler(timer1_Tick);
timer1.Enabled = true;
log.Info("my service is started");
}
private void timer1_Tick(object sender, ElapsedEventArgs e)
{
counter++;
if (counter%2 == 0)
{
log.Info(String.Format("Counter({0:D}) is now even", counter));
}
else
{
log.Error(String.Format("Counter({0:D}) is now even", counter));
}
}
protected override void OnStop()
{
timer1.Enabled = false;
log.Info("my service was stopped");
}
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add
name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="C:\tmp\log4net.txt" />
</listeners>
</trace>
</system.diagnostics>
</configuration>
Log4net.config
<?xml version="1.0" encoding="utf-8" ?>
<!--
Ref: http://mitch-wheat.blogspot.com/2007/04/log4net-net-logging-tool.html
I keep this config file in a separate directory and copy it with a
post-build event:
copy /Y $(SolutionDir)Logger\Log4Net.config $(TargetDir)Log4Net.config
-->
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="..\Logs\CurrentLog" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10000" />
<staticLogFileName value="true" />
<filter type="log4net.Filter.LevelRangeFilter">
<acceptOnMatch value="true" />
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date [%thread] %-22.22c{1} - %m%n" />
</layout>
</appender>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
<file value="log-file.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<header value="Service Logging -- Start - " />
<footer value="Service Logging -- End - " />
<conversionPattern value="%date [%thread] %-5level %logger [%ndc]
<%property{auth}> - %message%newline" />
</layout>
</appender>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
<applicationName value="Service1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger
[%property{NDC}] - %message%newline" />
</layout>
</appender>
<!-- Set the default logging level and add the active appenders -->
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="RollingFileAppender" />
</root>
<!-- Specify the level for specific categories (�namespace.class�)-->
<logger name="SimpleService1.Service1">
<level value="WARN" />
<appender-ref ref="EventLogAppender" />
</logger>
</log4net>
Thanks for your help
Finally figured out the nuances to get this working as desired. Here's the config for anyone interested.
-Skippy