Search code examples
log4netnlogcommon.logging

Logging to multiple folders


I have a windows service that accepts web requests to trigger a long running async task. I want each of the task to output the logs to different directories (the name of which is determined by the request id and user who triggered the job). Inside each directory, I have multiple log files.

I am using Common.Logging and log4net. However I'm having to reset the log4net configuration in order to change the directory (as given below), and this does not work well if a task is triggered while another is still running. The logs of both tasks are changing to the latest directory created.

 protected ILog CreateLoggerInstance(string loggerName, string logFolder)
    {
        logFolder += "/";
        // This is a hack to avoid creation of a folder called (null), because of limitation in log4net. 
        // More details: https://github.com/net-commons/common-logging/issues/81
        log4net.GlobalContext.Properties["LogsDirectory"] = logFolder;

        this.LogInstance = LogManager.GetLogger(loggerName);
        this.LogInstance.GlobalVariablesContext.Set("LogsDirectory", logFolder);
        LogManager.Reset();
        this.LogInstance = LogManager.GetLogger(loggerName);

        this.LogFolder = logFolder;
        return this.LogInstance;
    }

Is there a way to set the log only for a specific logger? Or can I avoid Reset() somehow? Also, this particular piece of code is the only place where I'm referring to log4net. So I am okay moving to NLog if I can create multiple folders for each log set.

Edit: I've found this functionality in NLog - https://github.com/NLog/NLog/wiki/Configure-component-logging

But it does not look like Common.Logging supports it.


Solution

  • The solution is pretty simple in NLog,

    Just use the requestId and user in the fileName attribute.

    <targets>
        <target name="file" xsi:type="File"
            layout="${longdate} ${logger} ${message}" 
            fileName="${basedir}/${var:requestid}_${var:user}.log" />
    </targets>
    
    <rules>
        <logger name="*" minlevel="Debug" writeTo="file" />
    </rules>
    

    You could set the requestid & username in the various contexts: the global variables, GDC / MDC etc. See https://github.com/NLog/NLog/wiki/Gdc-layout-renderer