Question

I am using NLog for logging purpose.

My code is as follows:

<?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">

  <!-- make sure to set 'Copy To Output Directory' option for this file -->
  <!-- go to http://nlog-project.org/wiki/Configuration_file for more information -->

  <targets>
    <target
      name="logfile"
      xsi:type="File"
      layout="${message}"
      fileName="${basedir}../Data/debugLog1.txt"
      archiveAboveSize ="5000000"
      maxArchiveFiles="2"/>
  </targets>

  <rules>
    <logger name="*" minlevel="Trace" writeTo="logfile" />
  </rules>
</nlog>

I am logging data in debugLog1.txt. Now, from another location in the project, I also want to log data, but this data is of another type so I want to make a debugLog2.txt and log data to it. How can I modify my code above to do so?

Était-ce utile?

La solution

I think you need to define another logger.

<logger name="SpecialLogger" minlevel="Trace" writeTo="logfile2" />

To log to it:

var logger = LogManager.GetLogger("SpecialLogger");

Autres conseils

If you want a separate file to log information from another part of your program, you can add a logger and another target.

For example, if you have a program that is completing two different tasks and you want to log those tasks separately, you could do the following

<targets>
  <target
    name="task1File"
    xsi:type="File"
    layout="${message}"
    fileName="${basedir}../Data/debugLog1.txt"
    archiveAboveSize ="5000000"
    maxArchiveFiles="2"/>
  <target
    name="task2File"
    xsi:type="File"
    layout="${message}"
    fileName="${basedir}../Data/debugLog2.txt"
    archiveAboveSize ="5000000"
    maxArchiveFiles="2"/>
</targets>

<rules>
  <logger name="task1Logger" minlevel="Trace" writeTo="task1File" />
  <logger name="task2Logger" minlevel="Trace" writeTo="task2File" />
</rules>

Then, in your program, access them with:

var task1Logger = NLog.LogManager.GetLogger("task1Logger")
var task2Logger = NLog.LogManager.GetLogger("task2Logger")

I had the similar situation where I had to generate random log files for special cases and here is what I created.

I called below code to get three files created.

Caller

    var log1 = NLogAdapter.CreateCustomLogger("CustomLog1");
    var log2 = NLogAdapter.CreateCustomLogger("CustomLog2");
    var log3 = NLogAdapter.CreateCustomLogger("CustomLog3");
    log1.Error("Error1");
    log2.Error("Error2");
    log3.Error("Error3");

Results:

enter image description here

NOTE: THIS APPROACH RESOLVES THE ISSUE of "same error logs written into multiple files". Every instance created by these methods will be completely isolated from other instances with no cross writing of log entries.

Source code:

        /// <summary>
    /// Create Custom Logger using parameters passed.
    /// </summary>
    /// <param name="name">Name of file.</param>
    /// <param name="LogEntryLayout">Give "" if you want just message. If omited will switch to full log paramaters.</param>
    /// <param name="logFileLayout">Filename only. No extension or file paths accepted.</param>
    /// <param name="absoluteFilePath">If you want to save the log file to different path thatn application default log path, specify the path here.</param>
    /// <returns>New instance of NLog logger completly isolated from default instance if any</returns>
    public static Logger CreateCustomLogger(string name = "CustomLog",
        string LogEntryLayout = "${ date:format=dd.MM.yyyy HH\\:mm\\:ss.fff} thread[${threadid}] ${logger} (${level:uppercase=true}): ${message}. ${exception:format=ToString}",
        string logFileLayout = "logs/{0}.${{shortdate}}.log",
        string absoluteFilePath = "")
    {
        var factory = new LogFactory();
        var target = new FileTarget();
        target.Name = name;
        if (absoluteFilePath == "")
            target.FileName = string.Format(logFileLayout, name);
        else
            target.FileName = string.Format(absoluteFilePath + "//" +logFileLayout, name);
        if (LogEntryLayout == "") //if user specifes "" then use default layout.
            target.Layout = "${message}. ${exception:format=ToString}";
        else
            target.Layout = LogEntryLayout;
        var defaultconfig = LogManager.Configuration;
        var config = new LoggingConfiguration();
        config.AddTarget(name, target);

        var ruleInfo = new LoggingRule("*", NLog.LogLevel.Trace, target);

        config.LoggingRules.Add(ruleInfo);

        factory.Configuration = config;

        return factory.GetCurrentClassLogger();
    }

    /// <summary>
    /// Create Custom Logger using a seperate configuration file.
    /// </summary>
    /// <param name="name">Name of file.</param>
    /// <returns>New instance of NLog logger completly isolated from default instance if any</returns>
    public static Logger CreateCustomLoggerFromConfig(string configname)
    {
        var factory = new LogFactory(new XmlLoggingConfiguration(configname));
        return factory.GetCurrentClassLogger();
    }

Please note that you could use layout renderers in the filename (even custom layout renderers) and so this will also make multiple files:

 <target
      name="logfile"
      xsi:type="File"
      layout="${message}"
      fileName="${basedir}../Data/${level}.txt" 
      ...
   />

In this example it's a log file for each loglevel (fatal, error, warn, info, debug, trace)

If you want to still be able to use the convenient GetCurrentClassLogger method, you can filter the log messages to go to the correct target by using the namespaces in your project as a filter.

Say you have namespaces which start with fooA and namespaces which start with fooB. Then your NLog.config file would look like this:

<targets>
   <target name="fooAlog" 
           xsi:type="File" 
           fileName="${basedir}/logs/fooA.log" />
   <target name="fooBlog" 
           xsi:type="File" 
           fileName="${basedir}/logs/fooB.log" />
</targets>

<rules>
    <logger name="fooA.*" minlevel="Trace" writeTo="fooAlog" />
    <logger name="fooB.*" minlevel="Trace" writeTo="fooBlog" />
</rules>

And in your code, you just add a logger in every class you want to log:

private static Logger logger = LogManager.GetCurrentClassLogger();

As long as your namespaces are consistent, the log messages will filter to the correct file and you get a nice little class tag in your log messages to tell you where the log event occurred.

Here is a more complex example for when you want to have a log file per thread (for background processes for example):

  1. Add this line at the beginning of the thread you want to log in a separate file:

    MappedDiagnosticsLogicalContext.Set("BackgroundProcess", true);
    
    public void StartRetryMechanism()
    {
        BackgroundTaskManager.Run(() =>
        {
            Start();
        });            
    }
    
    private void Start()
    {
            MappedDiagnosticsLogicalContext.Set("BackgroundProcess", true);
            ...
    }
    
  2. Then, in the NLog configuration, you can filter on the "BackgroundProcess" variable:

    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true">
      <targets>
        <target name="file" xsi:type="File" layout="${longdate} ${level} ${logger} ${threadid} ${message} ${exception:format=tostring}" fileName="${basedir}/logs/Application.log" keepFileOpen="false" encoding="iso-8859-2" archiveFileName="${basedir}/logs/Application_${shortdate}.{##}.log" archiveNumbering="Sequence" archiveEvery="Day" archiveAboveSize="10857600" maxArchiveFiles="3" />
      </targets>
      <targets>
        <target name="backgroundProcessFile" xsi:type="File" layout="${longdate} ${level} ${logger} ${threadid} ${message} ${exception:format=tostring}" fileName="${basedir}/logs/BackgroundProcess.log" keepFileOpen="false" encoding="iso-8859-2" archiveFileName="${basedir}/logs/BackgroundProcess_${shortdate}.{##}.log" archiveNumbering="Sequence" archiveEvery="Day" archiveAboveSize="10857600" maxArchiveFiles="3" />
      </targets>
      <rules>
        <logger name="*" minlevel="Trace" writeTo="backgroundProcessFile">
          <filters>
            <when condition="'${mdlc:item=BackgroundProcess}' != true" action="Ignore" />
          </filters>
        </logger>
        <logger name="*" minlevel="Trace" writeTo="file">
          <filters>
            <when condition="'${mdlc:item=BackgroundProcess}' == true" action="Ignore" />
          </filters>
        </logger>
      </rules>
    </nlog>
    
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top