1

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.

Narayana
  • 2,654
  • 3
  • 32
  • 32
  • If you want to write to several locations at the same time, then you will need one file appender per location. The only other alternative is to use locking around logger creation, which would be detrimental to performance. – stuartd Aug 12 '16 at 11:25

1 Answers1

1

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

Julian
  • 33,915
  • 22
  • 119
  • 174
  • Brilliant, this worked. I was able to create logger with MDC, and then use Common.Logging everywhere. In just one file, I had to use NLog.MappedDiagnosticsContext. Quick question, MDC should work fine with TPL tasks right? My tests so far suggest that they work, but will there be issues with ThreadPool? – Narayana Aug 17 '16 at 10:13
  • 1
    for TPL (Tasks) you need the MDLC: https://github.com/NLog/NLog/wiki/MDLC-Layout-Renderer – Julian Aug 17 '16 at 11:01