1

I have a web application in MVC that uses NLog and Quartz to run some jobs.
I need to save the logs of the jobs in a different file, but I cannot find a way to do this, since I have just one LogManager to the application.
Tried to use other targets, but no success.
Does anyone knows how to do it?
Below is what I'm using today:

var config = new NLog.Config.LoggingConfiguration();
var logfile = new NLog.Targets.FileTarget("logfile") { FileName = ArquivoLog, Name="logfile", CreateDirs = true, Layout = FormatoLog, ArchiveEvery = NLog.Targets.FileArchivePeriod.Day, ArchiveNumbering = NLog.Targets.ArchiveNumberingMode.DateAndSequence, MaxArchiveFiles = 31, WriteFooterOnArchivingOnly = true, KeepFileOpen = true, OpenFileCacheTimeout = 30 };
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile);
NLog.LogManager.Configuration = config;
Rodrigo Souza
  • 147
  • 1
  • 1
  • 10
  • https://stackoverflow.com/questions/20352325/logging-in-multiple-files-using-nlog – Steve Nov 29 '18 at 12:43
  • If you know the jobs during development you could just use multiple logger targets. If not, you could use tags in the file name (called [layout renderers](https://github.com/nlog/NLog/wiki/Configuration-file#layouts-and-layout-renderers)). You could use a different logger per job and use `"${logger}.txt"` as a filename. – Panagiotis Kanavos Nov 29 '18 at 12:50

2 Answers2

2

To do it via the NLog.config file see the answer of Andrew Tarasenko. If you want to do it in code, have you tried the following?

var config = new NLog.Config.LoggingConfiguration();

var logfile = new NLog.Targets.FileTarget("logfile1") { FileName = ArquivoLog, Name="logfile1", CreateDirs = true, Layout = FormatoLog, ArchiveEvery = NLog.Targets.FileArchivePeriod.Day, ArchiveNumbering = NLog.Targets.ArchiveNumberingMode.DateAndSequence, MaxArchiveFiles = 31, WriteFooterOnArchivingOnly = true, KeepFileOpen = true, OpenFileCacheTimeout = 30 };
var logfile2 = new NLog.Targets.FileTarget("logfile2") { FileName = ArquivoLog, /* Name="NotReallyNeeded as it is already passed in constructor" */, CreateDirs = true, Layout = FormatoLog, ArchiveEvery = NLog.Targets.FileArchivePeriod.Day, ArchiveNumbering = NLog.Targets.ArchiveNumberingMode.DateAndSequence, MaxArchiveFiles = 31, WriteFooterOnArchivingOnly = true, KeepFileOpen = true, OpenFileCacheTimeout = 30 };

config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile1, "Job1");
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile2, "Job2");

NLog.LogManager.Configuration = config;

And then in you jobs you should create a logger like this

var loggerInJob1 = NLog.LogManager.GetLogger("Job1");
var loggerInJob2 = NLog.LogManager.GetLogger("Job2");

See NLog documentation for the loggerNamePattern property which I've added.

This way the log of each job is saved to a different logfile.
Personally I would go for a NLog.config way. That way it's easier to add new targets (for new jobs) without recompiling your code.
But don't know if it's possible in your solution.

ArieKanarie
  • 944
  • 1
  • 15
  • 29
0

If the number of jobs is not known in advance and the requirement is one log file per job, it is possible to update the NLog configuration programmatically at the start of each job.

At the start of the job, create a new NLog target.

var target = new NLog.Targets.FileTarget()
{
    FileName = $"Arquivo{jobNumber}.Log",
    Name = $"logfile{jobNumber}",
    Layout = "${logger} ${longdate} ${level} ${message}",
    //add settings are required
};

Then get the existing NLog configuration, add the target and add a rule for the target.

var config = NLog.LogManager.Configuration;
config.AddTarget(target);
config.AddRuleForAllLevels(target, loggerName);

Finally call ReconfigExistingLoggers. (see ReconfigExistingLoggers, this answer and this forum entry)

NLog.LogManager.ReconfigExistingLoggers();

The jobs are in all likelihood concurrent, so a locking mechanism is required.

The code above will append to an existing configuration, even when there is a Nlog.config file present.

Here is a full sample.

using NLog;
using System.Threading;
using System.Threading.Tasks;
using NLog.Config;

namespace ConsoleApplication2
{
class Program
{
    private static readonly object LoggerSynchronization = new object();

    static void Main(string[] args)
    {
        //create some jobs
        int numberOfJobs = 5;
        for (int i = 0; i < numberOfJobs; i++)
        {
            var jobNumber = i;
            Task.Run(() => RunJob(jobNumber));
        }

        Thread.Sleep(1000); //wait till done
    }

    private static void RunJob(int jobNumber)
    {
        var logger = SetupLog(jobNumber);

        logger.Info($"Running job {jobNumber}.");

        //do stuff here ...

    }

    private static Logger SetupLog(int jobNumber)
    {
        var loggerName = $"Job{jobNumber}";

        //create a custom target per job
        var target = new NLog.Targets.FileTarget()
        {
            FileName = $"Arquivo{jobNumber}.Log",
            Name = $"logfile{jobNumber}",
            Layout = "${logger} ${longdate} ${level} ${message}",
        };

        //add the target to the configuration
        lock (LoggerSynchronization) //avoid concurrency issues between the jobs
        {
            //check if configuration exists
            if (NLog.LogManager.Configuration == null)
            {
                NLog.LogManager.Configuration = new LoggingConfiguration();
            }

            var config = NLog.LogManager.Configuration;
            config.AddTarget(target);
            config.AddRuleForAllLevels(target, loggerName);

            NLog.LogManager.ReconfigExistingLoggers();
        }
        return NLog.LogManager.GetLogger(loggerName);
    }
}
}

And sample NLog.config

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      throwExceptions="false">

  <targets>
    <target name="console" xsi:type="ColoredConsole" layout="${logger} ${longdate} ${level} ${message}" />
  </targets>


  <rules>
    <logger name="*" writeTo="console" minlevel="Info" />
  </rules>
</nlog>

Sample output

enter image description here

robor
  • 2,969
  • 2
  • 31
  • 48