Use current class name as name for log folder in log4net - c#

I've created a scheduler project (console application with quartz.net) that contains several classes (jobs) that will be executed recurrently. I'm using log4Net to create the log files and right now every job is appending it's messages to the same file called scheduler/Scheduler.Info.txt. I would like to have a differente folder for each scheduler job.
what I have now is every job appending on
scheduler/scheduler/scheduler.Info.txt
what I want is:
scheduler/SomeJob1/SomeJobJob1.Info.txt
scheduler/SomeJob2/SomeJobJob2.Info.txt
scheduler/SomeJob3/SomeJobJob3.Info.txt
So, the pattern is
scheduler/{CLASS NAME}/{CLASS NAME}.Info.txt
My current configuration for log4net:
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="SchedulerLogFileInfoAppender" />
</root>
<appender name="SchedulerLogFileInfoAppender" type="log4net.Appender.RollingFileAppender" >
<param name="File" value="c:\Scheduler\Scheduler.Info.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="%d{dd/MM/yy HH:mm:ss} - %p - %logger - %m%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMax value="INFO" />
</filter>
</appender>
</log4net>
And this is one of the jobs logging a message:
public class SomeJob1: IJob
{
private static readonly ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
...
private void DoStuff()
{
logger.Info("THIS IS A MESSAGE");
...
}
}

Related

Log4net is not writing anything in log files

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.

log4net is not logging to log file or console (external log4net.config file)

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.

C# Log4Net Writing To Both Appenders

I am using C# to write an in house application and we've been trying to figure out a resolution to this issue for a couple of days now. We're using Log4Net v1.2.15.0 compiling against .Net v4.5.2. I have two rolling file appenders, EventsLogger and SitrepLogger which are both set to write to the network. I have confirmed that this does work as intended however when I call one appender (doesn't matter which) to write out, it writes to both EventsLogger and SitrepLogger files. Here is the relevant data from my app.config
<log4net>
<appender name="EventsLogger" type="log4net.Appender.RollingFileAppender">
<file name="File" value="\\TS-WXLF41\Project\Ambushed\${USERNAME}\EventsLog" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="1MB" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<param name="StaticLogFileName" value="false"/>
<param name="RollingStyle" value="Date"/>
<param name="DatePattern" value="_MM-dd-yy.\tx\t" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline%newline%date{HH:mm:ss tt} %message" />
</layout>
</appender>
<appender name="SitrepLogger" type="log4net.Appender.RollingFileAppender">
<file name="File" value="\\TS-WXLF41\Project\Ambushed\${USERNAME}\logs\sitrep" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="1MB" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<param name="StaticLogFileName" value="false"/>
<param name="RollingStyle" value="Date"/>
<param name="DatePattern" value="_MM-dd-yy.\tx\t"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline%newline%date{HH:mm:ss tt} %message" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="EventsLogger" />
<appender-ref ref="SitrepLogger" />
</root>
</log4net>
In my Program's entry point constructor I call log4net.Config.XmlConfigurator.Configure(); which I am pretty sure is working as intended. I do not call Configure anywhere else in the code except from there. In the members are of my entry point class I call private static readonly log4net.ILog logger = log4net.LogManager.GetLogger("SitrepLogger"); to fetch the logger that I need for my Program (entry point) class. In my other classes I use the EventsLogger so I call private static readonly log4net.ILog eventslogger = log4net.LogManager.GetLogger("EventsLogger"); in the members are of those classes. I do not call GetLogger more than once per class and I am sure I invoking the correct appender by calling eventslogger.Info()
This used to work fine (using multiple appenders to write to different files) for us but we've made many many changes since then, which we have tried reverting to with no success. No errors, no warnings and no messages on compilation. Thank you for everything in advance! :)
You are confusing appenders and loggers. Your application is creating loggers "SitrepLogger" and "EventsLogger". These both inherit the configuration of the root logger, and write to appenders with the same names "SitrepLogger" and "EventsLogger".
Try the following configuration, which I think will give you what you want:
<log4net>
<appender name="EventsAppender" ... >
...
</appender>
<appender name="SitrepAppender" ... >
...
</appender>
<root>
<level value="ALL" />
</root>
<logger name="EventsLogger" additivity="False">
<appender-ref ref="EventsAppender" />
</logger>
<logger name="SitrepLogger" additivity="False">
<appender-ref ref="SitrepAppender" />
</logger>
</log4net>

Two different FileAppender writing same logs message in two log files

I am getting a problem, when I configured two appenders and try to write a log message to one of the apender this also write the same message to another appenders file. Below is the configuration section,
<log4net>
<root>
<level value="INFO" />
<appender-ref ref="ErrorLog" />
<appender-ref ref="PayWinSrvLog" />
</root>
<appender name="ErrorLog" type="log4net.Appender.FileAppender">
<param name="File" value="E:\Webhome\FimFolders\BankWinserviceService\Error_Log.txt" />
<param name="AppendToFile" value="true" />
<maxSizeRollBackups value="0" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<maximumFileSize value="2MB" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c %m%n" />
</layout>
</appender>
<appender name="PayWinSrvLog" type="log4net.Appender.FileAppender">
<param name="File" value="E:\Webhome\FimFolders\BankWinserviceService\PayWinSrv_Log.txt" />
<param name="AppendToFile" value="true" />
<maxSizeRollBackups value="0" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<maximumFileSize value="2MB" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c %m%n" />
</layout>
</appender>
and this is the only code I am using in Start method of my windows service project.
protected override void Start()
{
ErrorLog = LogManager.GetLogger("ErrorLog");
PayWinSrvLog = LogManager.GetLogger("PayWinSrvLog");
XmlConfigurator.Configure();
ErrorLog.Error("Error Message."); // this also get printed in PayWinSrv_Log.txt
}
I also include the line
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
excuse me for my English.
You're getting confused with Appenders and Loggers. A log itself can have multiple appenders (e.g. you could have an SmtpAppender and a FileAppender for an error log, but you may want a separate FileAppender for normal messages). Since you only configure the root logger, using <root>..., then that is the only log that is ever returned using LogManager.GetLogger, which in your configuration has both FileAppenders.
To configure multiple, separate logs, use <logger tags, and then specify the appenders for each log:
<logger name="ErrorLog">
<level value="INFO" />
<appender-ref ref="ErrorLog" />
</logger>
<logger name="PayWinSrvLog">
<level value="INFO" />
<appender-ref ref="PayWinSrvLog" />
</logger>

I would like to create two log files - one with "DEBUG" another with "INFO" logs only

I have here this log4net config:
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="D:\logfolder\logfile.txt" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="20MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
</layout>
</appender>
</log4net>
This is working well, but I would like to create another logfile with only "INFO" input. Is it possible to log in two different files, without changing anything in my C# code, just changing the config file?
Or lets just make the question simple: What do I have to add exactly to my config file?
And also, I have another issue: if I choose "INFO" instead of "DEBUG", I get INFO + ERROR logs. can I change this somehow, not to get ERROR logs, just INFO? Thank you.
You can configure second appender with filter specified, and add it to your root logger.
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="AnotherLogFileAppender" />
</root>
<appender name="LogFileAppender"
type="log4net.Appender.RollingFileAppender">
...
</appender>
<appender name="AnotherLogFileAppender"
type="log4net.Appender.RollingFileAppender">
<param name="File" value="D:\logfolder\anotherlogfile.txt" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="20MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern"
value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="INFO"/>
<param name="LevelMax" value="INFO"/>
</filter>
</appender>
</log4net>
Also consider to use new style of log4net configuration, rather than old one with param tags:
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="AnotherLogFileAppender" />
</root>
<appender name="LogFileAppender"
type="log4net.Appender.RollingFileAppender">
<file value="D:\logfolder\logfile.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="20MB"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n"/>
</layout>
</appender>
<appender name="AnotherLogFileAppender"
type="log4net.Appender.RollingFileAppender">
<file value="D:\logfolder\anotherlogfile.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="20MB"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n"/>
</layout>
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="INFO"/>
</filter>
</appender>
</log4net>

Categories