2

I am writing a NLog file for an application. One of the requirements needed is that the user should be able to select the file size and the log level. The log level can be selected from a drop down menu. I was thinking that I can have a place holder for file size and log level. How can I go about doing this? Currently, I've done this:

<target name="logfile" xsi:type="File" FileName=".\logs\${shortdate}.log" 
        archiveFileName=".\logs\archive\${shortdate}.log"
        maxArchiveFiles="60" archiveEvery="Day" archiveAboveSize="###MaxSize###"
        layout="${longdate}|${level:uppercase=true}|${callsite}|${message}|${exception:format=toString}"/>
    <rules>
<logger name="*" minlevel="Trace" writeTo="logfile" />

I have two questions regarding this:

  1. How can I make it so that the log level can be selected on a choice?
  2. Do I need to make different target for each log level?
jamesnet214
  • 1,044
  • 13
  • 21
  • Is this In-App or is this going to be a "Log-Configurator" that will be run outside the Application process and "simply" changes the logging config file? Are user choices meant to be "temporary" (e.g. until App is restarted) or persistent? – Fildor May 17 '21 at 11:38
  • @Fildor The drop down menu and being able to select the file size will be added in the app. In here, I will have place holders which will then be replaced by whatever the size or log level is selected. So this whole will be In-App. The user choices are permanent. – Scripter9700 May 17 '21 at 11:42
  • Ok, if it's in-app I'd start by changing the NLog config programmatically. (Be inspired by https://stackoverflow.com/questions/10302561/reconfigure-nlog-loggingconfiguration-filters-programmatically) and https://github.com/NLog/NLog/wiki/Configure-from-code#update-config-in-code – Fildor May 17 '21 at 11:44
  • ^^ as shown in the latter, I'd probably save the user choices in the app settings and re-apply every time the config is reloaded. – Fildor May 17 '21 at 11:51

2 Answers2

3

Building upon Combine nlog.config and config from code

Please note that combining the config file (nlog.config) and changing it in code, the reload of nlog.config could undo your changes. If you combine both, then reapply the changes on the reload event. E.g.

// On start of your program
UpdateConfig();

LogManager.ConfigurationReloaded += (sender, e) =>
{
    //Re apply if config reloaded
    UpdateConfig();
};

Where UpdateConfig is

public void UpdateConfig()
{
    var configuration = LogManager.Configuration;
    var fileTarget = configuration.FindTargetByName<FileTarget>("myTargetName");
    fileTarget.FileName = "${basedir}/file.log";
    LogManager.Configuration = configuration; //apply
}

and then, I'd tweak this to

public void UpdateConfig()
{
    var configuration = LogManager.Configuration;

    // Get User-Defined LogLevel and FileSize from App Settings
    // Set NLog LogLevel and FileSize

    LogManager.Configuration = configuration; //apply
}

while in the handler for the Log-Config-Dialog, I'd write Level and FileSize to App Settings, then call UpdateConfig.

Make sure to either ship with defaults set for those app settings or handle the settings not been set, yet.

Fildor
  • 14,510
  • 4
  • 35
  • 67
3

Semi Dynamic Routing Rules

NLog 4.6.7 makes it easy to change the LogLevel on-the-fly:

<nlog>
   <variable name="myLevel" value="Trace" />
    <rules>
      <logger name="*" minlevel="${var:myLevel}" writeTo="logfile" />
    </rules>
</nlog>

And then change it from runtime like this:

LogManager.Configuration.Variables["myLevel"] = "Debug";
LogManager.ReconfigExistingLoggers();

https://github.com/NLog/NLog/wiki/Filtering-log-messages#semi-dynamic-routing-rules

Rewrite and reload NLog.config

But it sounds like you should just perform a search and replace in the NLog.config-file, and then perform an explicit reload:

<nlog>
    <variable name="myLevel" value="Trace" />
    <variable name="mySize" value="42" />
    <targets>
        <target name="logfile" xsi:type="File"
              fileName=".\logs\${shortdate}.log" 
              archiveAboveSize="${mySize}" />
    </targets>
    <rules>
      <logger name="*" minlevel="${var:myLevel}" writeTo="logfile" />
    </rules>
</nlog>

After the file-rewrite/update (that changes the two variables) then explicit reload is done like this:

NLog.LogManager.Configuration = NLog.LogManager.Configuration?.Reload();

Alternative to explicit reload would be to use <nlog autoReload="true"> (Then NLog will detect changes to NLog.config-file and reload automatically).

Rewrite and reload NLog.user.config

If you feel excited and like advanced stuff, then you could also make use of include-files, and have a default NLog.config that includes NLog.user.config:

<nlog autoreload="true">
    <variable name="myLevel" value="Trace" />
    <variable name="mySize" value="42" />
    <include file="NLog.user.config" ignoreErrors="true" />  <!-- Can override variables -->
    <targets>
        <target name="logfile" xsi:type="File"
              fileName=".\logs\${shortdate}.log" 
              archiveAboveSize="${mySize}" />
    </targets>
    <rules>
      <logger name="*" minlevel="${var:myLevel}" writeTo="logfile" />
    </rules>
</nlog>

See also: https://github.com/NLog/NLog/wiki/XML-config-include-Example

Rolf Kristensen
  • 17,785
  • 1
  • 51
  • 70