1
votes

I'm using the latest NLog v3.1 and have a question on how to set logging level at runtime. I have just one target and logger in my NLog.config file. The logger name = "*" and the minlevel = "Info". I have the following code in a module to declare the logger along with a function GetLoggingLevel which I can pass in the logger name to retrieve it's level. However, how may I set the logging level? Currently I'm having to open the NLog.config XML and modify the minlevel in the XML. Since I have autoReload = "true", it takes affect - but was hoping there was a way to set this using an NLog method/property.

Imports System.Xml
Imports NLog

Module modLogging

Private m_Log As Logger

Public ReadOnly Property Log As Logger
    Get
        If (m_Log Is Nothing) Then
            m_Log = LogManager.GetCurrentClassLogger
        End If
        Return m_Log
    End Get
End Property

Public Sub LogShutdown()
    LogManager.Shutdown()
End Sub

Public Function GetLoggingLevel(ByVal loggerName) As String
    Dim level As String = String.Empty

    If (LogManager.GetLogger(loggerName).IsInfoEnabled) Then
        level = "Info"
    ElseIf (LogManager.GetLogger(loggerName).IsErrorEnabled) Then
        level = "Error"
    ElseIf (LogManager.GetLogger(loggerName).IsDebugEnabled) Then
        level = "Debug"
    End If

    Return (level)
End Function

With this I can easily call Log.Info("some text") or Log.Error("some error"), etc. in my project. I can obtain the current level and show this to the user, but I want the user to be able to change the logging level to either Debug, Info, Error, etc. but I cannot figure out how to set the minlevel in the config file at runtime without loading & modifying the config XML directly. Any help would be appreciated.

Kindest Regards

3

3 Answers

3
votes

You can access the LogManager.Configuration.LoggingRules and enable or disable logging for a certain level. For instance, using a small project with a NLog config as :

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>    
    <target name="consoleDetailed" 
            xsi:type="Console" 
            layout="${message}"/>
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="consoleDetailed" />
  </rules>
</nlog>  

and a console app like

Sub Main()

    Dim log As Logger = LogManager.GetCurrentClassLogger

    log.Debug("debug message")
    log.Info("info message")

    For Each rule As LoggingRule In LogManager.Configuration.LoggingRules
        rule.DisableLoggingForLevel(LogLevel.Debug)
    Next

    LogManager.ReconfigExistingLoggers()

    log.Debug("debug message") REM This line will not be logged
    log.Info("info message")

    Console.ReadLine()

End Sub
0
votes

You need to implement ILoggerProvider to return your own custom logger. The logger you create can implement ILogger. You will need to duplicate your nlog configuration file and change the min and max level to allow all log levels. This will be overriden in a class that you will use only for these special requests that need different logging.

VB:

Public NotInheritable Class CustomLevelNLogProvider
    Inherits ILoggerProvider

    Private ReadOnly factory As NLog.LogFactory

    ' pass a separate nlog config path that has logging enabled all the way to trace level, you will override it down below in the LogWrapper class
    Public Sub New(ByVal customNlogConfigPath As String)
        factory = NLog.Web.NLogBuilder.ConfigureNLog(customNlogConfigPath)
    End Sub

    Public Function CreateLogger(ByVal categoryName As String) As ILogger
        Dim logger = factory.GetLogger(categoryName)
        Return New CustomLevelLogger(logger)
    End Function
End Class

Public NotInheritable Class CustomLevelLogger
    Inherits ILogger

    Private ReadOnly innerLogger As ILogger
    Private ReadOnly minLevel As LogLevel
    Private ReadOnly maxLevel As LogLevel

    Public Sub New(ByVal innerLogger As ILogger)
        Me.innerLogger = innerLogger
    End Sub

    ' call this method on each request that needs a temporary log level
    Public Sub SetLogLevels(ByVal minLevel As LogLevel, ByVal maxLevel As LogLevel)
        Me.minLevel = minLevel
        Me.maxLevel = maxLevel
    End Sub

    ' implement the ILogger interface, making sure to use minLevel and maxLevel properly, forward calls on to innerLogger if level matches
}
End Class

C#:

public sealed class CustomLevelNLogProvider : ILoggerProvider
{
    private readonly NLog.LogFactory factory;

    // pass a separate nlog config path that has logging enabled all the way to trace level, you will override it down below in the LogWrapper class
    public CustomLevelNLogProvider(string customNlogConfigPath)
    {
        factory = NLog.Web.NLogBuilder.ConfigureNLog(customNlogConfigPath);
    }

    ' call this method on each request that needs a temporary log level
    public ILogger CreateLogger(string categoryName)
    {
        var logger = factory.GetLogger(categoryName);
        return new CustomLevelLogger(logger);
    }
}

public sealed class CustomLevelLogger : ILogger
{
    private readonly ILogger innerLogger;
    private readonly LogLevel minLevel;
    private readonly LogLevel maxLevel;

    public CustomLevelLogger(ILogger innerLogger)
    {
        this.innerLogger = innerLogger;
    }

    // call this method on each request that needs a temporary log level
    public void SetLogLevels(LogLevel minLevel, LogLevel maxLevel)
    {
        this.minLevel = minLevel;
        this.maxLevel = maxLevel;
    }

    // implement the ILogger interface, making sure to use minLevel and maxLevel properly, forward calls on to innerLogger if level matches
}
0
votes

NLog ver. 4.6.7 enables you to do this:

<nlog>
   <variable name="myLevel" value="Warn" />
    <rules>
      <logger minLevel="${var:myLevel}" />
    </rules>
</nlog>

Then you can execute this code, and it will dynamically update the logging rule:

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

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