我们知道 NLog 4.6.7 添加了对使用 NLog 布局的支持,例如 ${gdc:globalLevel} 到 dynamically change level attributes at runtime。如果可能的话,更好的解决方案是升级您的 NLog。
更新:新解决方案
我在 4.5 版上试过这段代码,它工作正常。看来您不需要升级您的 NLog 版本。
在这种情况下,所有配置都以编程方式设置。您可以在标题中将所需级别发送为loglevel。如果您在标头中发送loglevel,它将被使用。否则,logLevel 将为Error。请参阅here。
注意:请使用using NLog;。你不需要using Microsoft.Extensions.Logging;
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly Logger _log = LogManager.GetCurrentClassLogger();
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
var requestLogLevel = Request.Headers.SingleOrDefault(x => x.Key == "loglevel");
LogLevel logLevel = LogLevel.Error;
switch (requestLogLevel.Value.ToString().ToLower())
{
case "trace":
logLevel = LogLevel.Trace;
break;
case "debug":
logLevel = LogLevel.Debug;
break;
case "info":
logLevel = LogLevel.Info;
break;
case "warn":
case "warning":
logLevel = LogLevel.Warn;
break;
case "error":
logLevel = LogLevel.Error;
break;
case "fatal":
logLevel = LogLevel.Fatal;
break;
}
var config = new NLog.Config.LoggingConfiguration();
var defaultMode = new NLog.Targets.FileTarget("defaultlog") { FileName = "log.txt" };
config.AddRule(logLevel, LogLevel.Fatal, defaultMode);
NLog.LogManager.Configuration = config;
_log.Trace("Some logs");
return new string[] { "value1", "value2" };
}
}
解决方案 1) 将 NLog 升级到 4.6.7 或更高版本:
var config = new NLog.Config.LoggingConfiguration();
// Targets where to log to: File and Console
var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "file.txt" };
var logconsole = new NLog.Targets.ConsoleTarget("logconsole");
// Rules for mapping loggers to targets
config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole);
config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile);
// Apply config
NLog.LogManager.Configuration = config;
解决方案 2) 以编程方式更改配置文件:
因为您的NLog 版本不支持自动更改配置,我们将以编程方式对其进行更改:
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly Logger _log = LogManager.GetCurrentClassLogger();
// Special Authorization needed
public bool ChangeToDebugMode()
{
try
{
XmlDocument doc = new XmlDocument();
doc.Load(AppDomain.CurrentDomain.BaseDirectory + "nlog.config");
XmlNode root = doc.DocumentElement;
XmlNode myNode = root["include"].Attributes["file"];
myNode.Value = "debugmode.config";
doc.Save(AppDomain.CurrentDomain.BaseDirectory + "nlog.config");
}
catch (Exception)
{
return false;
}
return true;
}
// Special Authorization needed
public bool RestToDefault()
{
try
{
XmlDocument doc = new XmlDocument();
doc.Load(AppDomain.CurrentDomain.BaseDirectory + "nlog.config");
XmlNode root = doc.DocumentElement;
XmlNode myNode = root["include"].Attributes["file"];
myNode.Value = "defaultmode.config";
doc.Save(AppDomain.CurrentDomain.BaseDirectory + "nlog.config");
}
catch (Exception)
{
return false;
}
return true;
}
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
_log.Trace("Some logs");
return new string[] { "value1", "value2" };
}
}
在这种情况下,您需要对配置文件进行一些更改。
您需要将autoReload=true 添加到配置中。现在,当任何配置更改时,NLog 会自动重新加载配置,您无需重新启动应用程序。你需要看看autoReload和includehere
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">
<include file="defaultmode.config" />
</nlog>
defaultmode.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">
<targets>
<target name="logfile" xsi:type="File" fileName="file.txt" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="logfile" />
</rules>
<!-- ... -->
</nlog>
debugmode.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">
<targets>
<target name="logfile" xsi:type="File" fileName="file.txt" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile" />
</rules>
<!-- ... -->
</nlog>
我制作了另外两个配置文件。 debugmode.config 和 defaultmode.config。默认情况下,nlog.config 文件中包含deafultmode.config。当ChangeToDebugMode被调用时,它变成debugmode.config,当RestToDefault被调用时,它变成defaultmode.config。我使用include 并将配置分成两个文件只是为了简单。
解决方案 3) 根据您的问题:
在这种情况下,我使用了您在问题中提供的代码。如果您在请求标头中发送日志级别,则将予以考虑。如果您不发送,它将使用您在配置中设置的默认值。因此,您无需在客户端更改您的应用程序。它工作正常。只需在调试时发送所需的日志级别即可。
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly Logger _log = LogManager.GetCurrentClassLogger();
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
var requestLogLevel = Request.Headers.SingleOrDefault(x => x.Key == "loglevel");
LogLevel logLevel = LogLevel.Error;
switch (requestLogLevel.Value.ToString().ToLower())
{
case "trace":
logLevel = LogLevel.Trace;
break;
case "debug":
logLevel = LogLevel.Debug;
break;
case "info":
logLevel = LogLevel.Info;
break;
case "warn":
case "warning":
logLevel = LogLevel.Warn;
break;
case "error":
logLevel = LogLevel.Error;
break;
case "fatal":
logLevel = LogLevel.Fatal;
break;
}
SetMinLogLevel(logLevel);
_log.Trace("Some logs.");
return new string[] { "value1", "value2" };
}
public static void SetMinLogLevel(LogLevel NewLogLevel)
{
foreach (var rule in LogManager.Configuration.LoggingRules)
{
rule.EnableLoggingForLevel(NewLogLevel);
}
//Call to update existing Loggers created with GetLogger() or
//GetCurrentClassLogger()
LogManager.ReconfigExistingLoggers();
}
}
问题是,这种情况每次都需要发送日志级别。
在这些屏幕截图中,您会看到如何在调试模式下发送日志级别。