I'm developing a Windows Service application with C#, .NET Framework 4.7 and log4net 2.08.
My problem is that log4net is not logging anything. It only creates the files and nothing else.
This is my configuration file (app.config):
<log4net>
<appender type="log4net.Appender.RollingFileAppender" name="ERPErrorAppender">
<file value="D:\MyCompany\Logs\ERP_Service.Error.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value=".yyyyMMdd.lo\g" />
<maximumFileSize value="5MB" />
<maxSizeRollBackups value="-1" />
<countDirection value="1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %-5level [%thread] %logger - %message%newline%exception" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="WARN" />
<levelMax value="ERROR" />
</filter>
</appender>
<appender type="log4net.Appender.RollingFileAppender" name="ERPDebugAppender">
<file value="D:\MyCompany\Logs\ERP_Service.Debug.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value=".yyyyMMdd.lo\g" />
<maximumFileSize value="5MB" />
<maxSizeRollBackups value="-1" />
<countDirection value="1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %-5level [%thread] %logger - %message%newline%exception" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="INFO" />
</filter>
</appender>
<logger name="ERPService_Error">
<level value="ERROR" />
<appender-ref ref="ERPErrorAppender" />
</logger>
<logger name="ERPService_Debug">
<level value="DEBUG" />
<appender-ref ref="ERPDebugAppender" />
</logger>
</log4net>
And the contents in Program.cs:
static class Program
{
private static readonly log4net.ILog log =
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
And the contents in my ServiceBase class:
public partial class ERPWindowsService : ServiceBase
{
private static readonly ILog _log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
And when I catch an exception in my ServiceBase class:
catch (Exception ex)
{
_log.Error(ex);
this.Stop();
}
And when I Stop the service (I do the same on OnStart):
protected override void OnStop()
{
_log.Debug("OnStop");
// Stop timer and dispose it.
if (_timer != null)
{
try
{
_timer.Stop();
_timer.Dispose();
}
catch (Exception ex)
{
_log.Error(ex);
}
}
}
Why it is not writing anything on files?
I have restarted the service and the log files remain empty.
You mention that the log files get created, this means that the configuration has been loaded successfully.
Since you haven't configured a root logger (which is valid to do so), but only named loggers, you must make sure that the configured names match with the ones given to the ILog instances.
This is where it goes wrong.
Your ILog instances get named via the type returned from the line below.
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)
This will be the FullName of the Type, including its namespace.
For class Program this will be YourNamespace.Program.
For class ERPWindowsService this will be YourNamespace.ERPWindowsService.
You must use these full names in the Log4net configuration.
<logger name="YourNamespace.ERPWindowsService">
<level value="DEBUG" />
<appender-ref ref="ERPDebugAppender" />
</logger>
Because there is no root logger configured, an explicit one must be configured for each ILog instance; here for class Program.
<logger name="YourNamespace.Program">
<!-- .... -->
</logger>
Alternatively, you can assign explicit names to your ILog instances, eg.:
log4net.ILog log = log4net.LogManager.GetLogger("ERPService_Error");
to match with your current Log4net configuration.
<logger name="ERPService_Error">
j.v. in your comments is correct. Make sure that if you are configuring the logger in your AssemblyInfo.cs file, that it points to the correct xml configuration file (in your case app.config).
Alternatively you can call
log4net.Config.XmlConfigurator.Configure();
Or one of its overloads from within your program.cs file.
This thread might provide some more explanation.
Related
I have an application that is using Anotar.Log4Net for logging. I cannot strip out the Anotar.Log4Net as other team members are using it. I would like to add my own logging file. I added an additional file appender to my app.config called BGDEV. I reviewed the post here to see how other's are accomplishing the task of having two file appenders. The desired behavior below is for each logger to log to it's own file. Everything is logging to MainLog.txt. Is this because there is something wrong with the app.config settings or because I have the anotar library installed?
<log4net>
<appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
<file value="MainLog.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="5"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline%exception"/>
</layout>
</appender>
<appender name="BGDEV" type="log4net.Appender.RollingFileAppender">
<file value="BG_Log.txt" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<datePattern value="yyyyMMdd" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true"/>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="FileAppender"/>
</root>
<logger additivity="false" name="BGDev">
<level value="INFO"/>
<appender-ref ref="BGDev" />
</logger>
In code I create a logger and use it. Is there something wrong with my config file or is this becaise I am using
private static readonly ILog otherLog = LogManager.GetLogger("BGDEV");
otherLog.Info("TEST OTHER LOG");
You have a couple of issues with naming in your code and config. Names are case sensitive - you're defining a logger named BGDev, but you call GetLogger("BGDEV"), since no logger named BGDEV exists, it falls back to the root logger.
Your logger named BGDev also references an appender named BGDev, however again, no such appender exists, since you are defining it with an all-uppercase name BGDEV.
Finally, your BGDev logger needs to have a <layout>...</layout> section, or it won't be able to format log messages.
If you fix these issues, it should work as you expect.
I created a a file called log4net.config in my project and added the following configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="console" />
<appender-ref ref="RollingFileAppender" />
</root>
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %logger - %message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="${LOCALAPPDATA}\MyApp\LogFile.log" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5level [%d{yyyy-MM-dd hh:mm:ss}] [%thread] (Line:%line) %M: - %m%n" />
</layout>
</appender>
</log4net>
</configuration>
After that, I added the line below to my AssemblyInfo.cs file:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
In the application, I have the following static class:
public static class Logger
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static void LogInfo(string msg)
{
log.Info(msg);
}
public static void LogDebug(string msg)
{
log.Debug(msg);
}
public static void LogWarn(string msg, Exception e)
{
log.Warn(msg, e);
}
public static void LogError(string msg, Exception e)
{
log.Error(msg, e);
}
}
Then I'm trying to log somewhere in the application in another class using Logger.LogDebug("Error logger working.");
However, I can't see any log file being created or written to it. What am I doing wrong?
UPDATE:
I also added the following in my app.config file but I see nothing at all on my Output console...
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
If you have the log4net configuration in a log4net logging configuration file, you do not have to add the configuration of the web.config (configuration tag and sections). Just add the log4net tags:
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="console" />
<appender-ref ref="RollingFileAppender" />
</root>
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %logger - %message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="${LOCALAPPDATA}\MyApp\LogFile.log" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5level [%d{yyyy-MM-dd hh:mm:ss}] [%thread] (Line:%line) %M: - %m%n" />
</layout>
</appender>
</log4net>
I could not reproduce your mistake. Configure log4net in AssemblyInfo works fine. maybe the problem in configuration. let me show you another implementation
private static readonly ILog log = LogManager.GetLogger("myLogger");
private static string configFile = "log4net.config";
static Logger()
{
XmlConfigurator.Configure(new FileInfo(configFile));
}
log4net.config:
<log4net>
<logger name="myLogger">
<level value="ALL" />
<appender-ref ref="console" />
<appender-ref ref="RollingFileAppender" />
</logger>
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %logger - %message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="${LOCALAPPDATA}\MyApp\LogFile.log" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5level [%d{yyyy-MM-dd hh:mm:ss}] [%thread] (Line:%line) %M: - %m%n" />
</layout>
</appender>
</log4net>
Managed to find out the issue thanks to stuartd's comment. My problem was, my full solution had 2 projects. I had only configured one project (which is not the start-up project) for log4net.
My original log4net configuration did not have any mistake. I simply added log4net reference to my start up project and added log4net configuration to that project as well and it started logging.
Many thanks to everyone who tested my config.
I am using the following app.config settings for multiple log files. The following are my app.config settings. But when I use "LogFileAppender" settings to write log to a file, it also writing the logs to the Console
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<File value="C:\File1.log" />
<AppendToFile value="true" />
<rollongStyle value="Composite" />
<maximumFileSize value="200MB" />
<layout type="log4net.Layout.PatternLayout">
<ConversionPattern value="%date %messge%newline"/>
</layout>
</appender>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<File value="C:\File2.log" />
<AppendToFile value="true" />
<rollongStyle value="Date" />
<maximumFileSize value="100MB" />
<layout type="log4net.Layout.PatternLayout">
<ConversionPattern value="%date %messge%newline"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<acceptOnMatch value="true" />
<levelMin value="INFO" />
</filter>
<filter type="log4net.Filter.LevelRangeFilter">
<acceptOnMatch value="true" />
<levelMin value="FATAL" />
</filter>
</appender>
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value ="ERROR"/>
<foreColor value ="Red"/>
</mapping>
<mapping>
<level value ="WARN"/>
<foreColor value ="Yellow"/>
</mapping>
<layout type="log4net.Layout.PatternLayout">
<ConversionPattern value="%date %messge%newline"/>
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="RollingFile" />
<appender-ref ref="ColoredConsoleAppender" />
</root>
</log4net>
In the C# code, I am using the below method calls.
private static readonly log4net.ILog ilogger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
log4net.Config.XmlConfigurator.Configure();
Question:
How can I restrict the Console logging while using the LogFileAppender using the above app.config file?
Add a ForwardingAppender in your configuration between the root logger and the ColoredConsoleAppender, so that you get this configuration
root -> LogFileAppender
root -> RollingFile
root -> ForwardingAppender -> ColoredConsoleAppender
Then in your ForwardingAppender add a filter that will only let pass events that do not originate from the application you don't want; a LoggerMatchFilter would be a good idea since you can exclude loggers originating from the namespace of the desired application.
I found the solution by modifying the app.config as following.
<logger name = "FileLogger" additivity="false">
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
</logger>
<root>
<level value="ALL"/>
<appender-ref ref="RollingFile"/>
<appender-ref ref="RollingFileAppender" />
<appender-ref ref="ColoredConsoleAppender" />
</root>
In the C# code, call the LogFileAppender explicitly as below
private static readonly log4net.ILog ilogger = log4net.LogManager.GetLogger("FileLogger");
I have two log files written from my application, which have multiple assemblies in the following manner:
Assembly1 log -> MainLog.log
Assembly2 log -> MainLog.log
Assembly3 log -> MainLog.log
Assembly4 log -> MainLog.log
Assembly5 log -> SubLog.log
Assembly6 log -> SubLog.log
The log files get written correctly, but the problem here is, the SubLog entries get written into the MainLog file as well. I don't want this kind of logging duplication to happen. This is my log4net configuration.
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Logs//MainLog.txt" />
<appendToFile value="true" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="100KB" />
<rollingStyle value="Size" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%M %date [%thread] %-5level %logger [%ndc] - %message %C, %F, %l, %L %M %newline" />
</layout>
</appender>
<appender name="NewForEveryRun" type="log4net.Appender.FileAppender">
<file type="log4net.Util.PatternString" value="Logs//SubLog-%processid.txt"/>
<appendToFile value="true" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<logger name="Assembly5">
<level value="DEBUG"/>
<appender-ref ref="NewForEveryRun"/>
</logger>
<logger name="Assembly6">
<level value="DEBUG"/>
<appender-ref ref="NewForEveryRun"/>
</logger>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>
For Assembly5 and Assembly6, I've specified the appender NewForEveryRun. In addition to this, I've kept the root, so that the rest of the assemblies are logged according to configuration specified in the RollingLogFileAppender appender. I guess, the root element is logging all the assemblies by default, even if I mention different logger for other assemblies. Is there any way to block the logging of Assembly5 and Assembly6 from root?
Got it! The loggers should look like this:
<logger name="Assembly5" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="NewForEveryRun"/>
</logger>
<logger name="Assembly6" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="NewForEveryRun"/>
</logger>
Setting additivity as false is the solution. No more duplicate logging :)
I have the following in my web.config:
<log4net>
<appender name="mainLog"
type="log4net.Appender.FileAppender">
<file value="Log/Log.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="linqLog"
type="log4net.Appender.FileAppender">
<file value="Log/Log.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline" />
</layout>
</appender>
<logger name="MainLogger">
<level value="ALL" />
<appender-ref ref="mainLog" />
</logger>
<logger name="LinqLogger">
<level value="ALL" />
<appender-ref ref="linqLog" />
</logger>
</log4net>
The first appender called "mainLog" is working. But the second one called "linqLog" is not. If I comment out "mainLog", then "linqLog" works.
In my Global.asax file I have the following:
protected void Application_Start(object sender, EventArgs e)
{
XmlConfigurator.Configure();
}
Here is how I am calling them:
public static void LogMessage(string message, string loggerName)
{
ILog log = LogManager.GetLogger(loggerName);
log.Info(string.Format(message));
}
LogMessage("My test message for MainLogger", "MainLogger");
LogMessage("My test message for LinqLogger", "LinqLogger");
Any ideas what I've done wrong?
Two file appenders cannot log to the same file, unless you specify a lockingModel
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
See http://logging.apache.org/log4net/release/config-examples.html
Log4net does support two appenders writing to the same file, but you need to set the locking model to "MinimalLock".
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />