unable to get log4net working with .net windows service

42,415

Solution 1

By Design Log4Net is

fail-stop, we mean that log4net will not throw unexpected exceptions at run-time potentially causing your application to crash

So it is very difficult to figure out what is causing the issue .

How do I enable log4net internal debugging?

FROM FAQ - http://logging.apache.org/log4net/release/faq.html

  • Internal debugging can also be enabled by setting a value in the application's configuration file (not the log4net configuration file, unless the log4net config data is embedded in the application's config file). The log4net.Internal.Debug application setting must be set to the value true. For example:
<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
            <appSettings>
                <add key="log4net.Internal.Debug" value="true"/>
            </appSettings> 
</configuration>

This setting is read immediately on startup an will cause all internal debugging messages to be emitted.

  • . To enable log4net's internal debug programmatically you need to set the log4net.Util.LogLog.InternalDebugging property to true. Obviously the sooner this is set the more debug will be produced.

So here is a custom class i created for log4Net - because config file was very confusing I created this helper class

  • you can initiate as many appender you need across the applications so if one dll call other dll both can initiate appenders and both appends will work.
  • also you can close the appender and ( as in case of file appender) then send it as a email
Log4NetFileHelper log = new Log4NetFileHelper();
        log.Init(); //Initialize
        log.AddConsoleLogging(); //Add Console Logging
        log.AddFileLogging(Path.Combine(AssemblyDirectory, "BatchConsole.log")); 
        log.AddFileLogging(Path.Combine(AssemblyDirectory,"BatchConsole_error.log"),log4net.Core.Level.Error); 

Do set this Property to True log4net.Util.LogLog.InternalDebugging=true;

public class Log4NetFileHelper
{
    private string  DEFAULT_LOG_FILENAME=string.Format("application_log_{0}.log",DateTime.Now.ToString("yyyyMMMdd_hhmm"));
    Logger root;
    public Log4NetFileHelper()
    {

    }

    public virtual void Init()
    {
        root = ((Hierarchy)LogManager.GetRepository()).Root;
        //root.AddAppender(GetConsoleAppender());
        //root.AddAppender(GetFileAppender(sFileName));
        root.Repository.Configured = true;
    }

    #region Public Helper Methods
    #region Console Logging
    public virtual void AddConsoleLogging()
    {
        ConsoleAppender C = GetConsoleAppender();
        AddConsoleLogging(C);
    }

    public virtual void AddConsoleLogging(ConsoleAppender C)
    {
        root.AddAppender(C);
    }
    #endregion

    #region File Logging
    public virtual FileAppender AddFileLogging()
    {
        return AddFileLogging(DEFAULT_LOG_FILENAME);
    }

    public virtual FileAppender AddFileLogging(string sFileFullPath)
    {
        return AddFileLogging(sFileFullPath, log4net.Core.Level.All);
    }

    public virtual FileAppender AddFileLogging(string sFileFullPath, log4net.Core.Level threshold)
    {
        return AddFileLogging(sFileFullPath, threshold,true);  
    }

    public virtual FileAppender AddFileLogging(string sFileFullPath, log4net.Core.Level threshold, bool bAppendfile)
    {
        FileAppender appender = GetFileAppender(sFileFullPath, threshold , bAppendfile);
        root.AddAppender(appender);
        return appender;
    }

    public virtual SmtpAppender AddSMTPLogging(string smtpHost, string From, string To, string CC, string subject, log4net.Core.Level threshhold)
    {
        SmtpAppender appender = GetSMTPAppender(smtpHost, From, To, CC, subject, threshhold);
         root.AddAppender(appender);
         return appender;
    }

    #endregion


    public log4net.Appender.IAppender GetLogAppender(string AppenderName)
    {
        AppenderCollection ac = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root.Appenders;

        foreach(log4net.Appender.IAppender appender in ac){
            if (appender.Name == AppenderName)
            {
                return appender;
            }
        }

        return null;
    }

    public void CloseAppender(string AppenderName)
    {
        log4net.Appender.IAppender appender = GetLogAppender(AppenderName);
        CloseAppender(appender);
    }

    private void CloseAppender(log4net.Appender.IAppender appender)
    {
        appender.Close();
    }

    #endregion

    #region Private Methods

    private SmtpAppender GetSMTPAppender(string smtpHost, string From, string To, string CC, string subject, log4net.Core.Level threshhold)
    {
        SmtpAppender lAppender = new SmtpAppender();
        lAppender.Cc = CC;
        lAppender.To = To;
        lAppender.From = From;
        lAppender.SmtpHost = smtpHost;
        lAppender.Subject = subject;
        lAppender.BufferSize = 512;
        lAppender.Lossy = false;
        lAppender.Layout = new
        log4net.Layout.PatternLayout("%date{dd-MM-yyyy HH:mm:ss,fff} %5level [%2thread] %message (%logger{1}:%line)%n");
        lAppender.Threshold = threshhold;
        lAppender.ActivateOptions();
        return lAppender;
    }

    private ConsoleAppender GetConsoleAppender()
    {
        ConsoleAppender lAppender = new ConsoleAppender();
        lAppender.Name = "Console";
        lAppender.Layout = new 
        log4net.Layout.PatternLayout(" %message %n");
        lAppender.Threshold = log4net.Core.Level.All;
        lAppender.ActivateOptions();
        return lAppender;
    } 
    /// <summary>
    /// DETAILED Logging 
    /// log4net.Layout.PatternLayout("%date{dd-MM-yyyy HH:mm:ss,fff} %5level [%2thread] %message (%logger{1}:%line)%n");
    ///  
    /// </summary>
    /// <param name="sFileName"></param>
    /// <param name="threshhold"></param>
    /// <returns></returns>
    private FileAppender GetFileAppender(string sFileName , log4net.Core.Level threshhold ,bool bFileAppend)
    {
        FileAppender lAppender = new FileAppender();
        lAppender.Name = sFileName;
        lAppender.AppendToFile = bFileAppend;
        lAppender.File = sFileName;
        lAppender.Layout = new 
        log4net.Layout.PatternLayout("%date{dd-MM-yyyy HH:mm:ss,fff} %5level [%2thread] %message (%logger{1}:%line)%n");
        lAppender.Threshold = threshhold;
        lAppender.ActivateOptions();
        return lAppender;
    }

    //private FileAppender GetFileAppender(string sFileName)
    //{
    //    return GetFileAppender(sFileName, log4net.Core.Level.All,true);
    //}

    #endregion

    private void  ConfigureLog(string sFileName)
    {


    }
}

Solution 2

Please note that when the process is run as Windows Service, Environment.CurrentDirectory will be "C:\Windows\system32"

So if you put the log4net configuration file (log4net.config) next to your *.exe, you can use the following code to configure log4net.

var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
XmlConfigurator.Configure(new FileInfo(Path.Combine(assemblyFolder, "log4net.config")));

Solution 3

Here is the config that works for me.

AssemblyInfo.cs

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4net.config", Watch = true)]

Log4net.Config

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender,log4net">
            <param name="File" value="C:\TEMP\Logs.txt"/>
            <lockingModel type="log4net.Appender.FileAppender+MinimalLock,log4net" />
            <appendToFile value="true" />
            <rollingStyle value="Size" />
            <maxSizeRollBackups value="2" />
            <maximumFileSize value="1MB" />
            <staticLogFileName value="true" />
        <layout type="log4net.Layout.PatternLayout,log4net">
            <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
        </layout>
    </appender>
    <root>
         <level value="ALL" />
         <appender-ref ref="LogFileAppender" />
    </root>
</log4net>

C# Code

private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(typeof(class_name));

I have this setup in C# Class library project and all other project uses this project reference to log the exceptions.

Solution 4

After checking and recheck... :-)

All you need is to call XmlConfigurator.Configure(); before you create the logger (only once).

Glad to help you,

Ofir

Solution 5

If you will make a different configuration file and put log4net related things in it, then you will need to use [assembly: log4net.Config.XmlConfigurator(ConfigFile = @"...\log4net.config", Watch = true)] inside AssemblyInfo.cs instead of just

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

Otherwise, you have to put <log4net> ... </log4net> part of the configuration inside your App.config

Share:
42,415
Null Reference
Author by

Null Reference

N.A

Updated on April 29, 2020

Comments

  • Null Reference
    Null Reference about 4 years

    I have a windows service with an app.config and a log4net.config.

    app.config:

      <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
      </configSections>
      <log4net configSource="log4net.config" />
    

    log4net.config:

    <log4net>
      <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
        <param name="File" value="D:\Projects\Integration\Interface Module\bin\Logs\MyFirstLogger.log"/>
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <appendToFile value="true" />
        <rollingStyle value="Size" />
        <maxSizeRollBackups value="2" />
        <maximumFileSize value="1MB" />
        <staticLogFileName value="true" />
        <layout type="log4net.Layout.PatternLayout">
          <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
        </layout>
      </appender>
    
      <root>
        <level value="ALL" />
        <appender-ref ref="LogFileAppender" />
      </root>
    </log4net>
    

    I have added this in AssemblyInfo.cs too:

    [assembly: log4net.Config.XmlConfigurator(Watch = true)]
    

    And in one of my classes, I have:

    private readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
    

    and

    _log.Info(content);
    

    I have given all users full permissions to my Logs folder.

    My bin folder (which the service is running from) has both my app.config and log4net.config.

    But no logging file got generated. What settings did I miss?

    Updated on 4-March-2014

    If you are using a separate config file like I did (log4net.config), do remember to set the Copy to output directory setting to Copy always in the Solution Explorer

  • Null Reference
    Null Reference about 11 years
    I did it in my AssemblyInfo.cs [assembly: log4net.Config.XmlConfigurator(Watch = true)]
  • sgmoore
    sgmoore about 11 years
    I think you either need to call XmlConfigurator.Configure() or else change your assemblyInfo.cs to use [assembly: log4net.Config.XmlConfigurator(Watch = true, ConfigFile="log4net.config")]
  • Null Reference
    Null Reference about 11 years
    ConfigFile = @"...\log4net.config" <- this must be the full directory? Or do I just put exactly "...\log4net.config"
  • Alpay
    Alpay about 11 years
    It must be the full path of the log4net.config. if it is located in your C:\temp for example, you should enter C:\temp\log4net.config I am not sure it accepts relative paths, it worths giving it a try
  • Ofir
    Ofir about 11 years
    It does not work for me in the AssemblyInfo.cs file. Please call 'XmlConfigurator.Configure();' before 'GetLogger'. Let me know if it still doesn't work.
  • Alpay
    Alpay about 11 years
    This article explains the usage clearly. I hope it helps
  • realnero
    realnero over 10 years
    in my case issue appeared to be with FileAppender. I've replaced it RollingFileAppender and it worked fine. Nothing helped before.
  • Hernaldo Gonzalez
    Hernaldo Gonzalez about 8 years
    Only y change GetLogger(System.Reflection.MethodBase.GetCurrentMethod().De‌​claringType); and work perfect thanks man!
  • N8allan
    N8allan almost 7 years
    This was it for me. Also note that for the same reason you probably don't want to use relative paths in your logging file names, as they'll end up under windows\system32, if permissions even allow writing at all.
  • andrew pate
    andrew pate over 4 years
    Good answer. Worked for me too.
  • sox with Monica
    sox with Monica about 2 years
    it is imperative to make a logging call as early as possible during the application start-up This made me waste an entire day of work looking for bugs in two identically configured projects, one working and one not