动态设置每个记录器实例的 Nlog 日志级别 ASP.Net Core 2.x

2024-02-02

客观的:动态选择我想要详细日志记录的 HTTP 请求(不同的日志级别)。

Overview:我有一个正在运行的 ASP.Net core 2.1 Web 服务器,一旦投入生产,如果我需要调试问题,我希望能够更改日志级别。我已经找到了如何全局更改日志级别 https://stackoverflow.com/questions/10302561/reconfiguring-nlog-programmatically;但是,更改日志级别是持久的...也就是说,每次调用我的控制器后都不会重置。

    [HttpGet]
    public async Task<IEnumerable<string>> Get()
    {
        this.Logger.LogTrace("This should NOT get logged");
        SetMinLogLevel(LogLevel.Trace);
        this.Logger.LogTrace("This should be logged");

        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();
    }

我希望请求者能够在其 HTTP 请求(标头或 cookie)中设置一个标志,以便对每个请求进行更详细的日志记录。这样我就不会用请求者的详细日志淹没我的日志。

Question:如何动态设置每个记录器实例的日志级别? (我相信这是正确的措辞)

我目前使用 NLog 包 4.5。


我们知道 NLog 4.6.7 添加了对使用 NLog Layout 的支持,例如${gdc:globalLevel} to 在运行时动态更改级别属性 https://github.com/nlog/NLog/wiki/Configure-from-code。更好的解决方案是如果可能的话升级您的 NLog。

更新:新解决方案 我在 4.5 版本上尝试了这段代码,效果很好。看来你不需要升级你的NLog版本。在这种情况下,所有配置均以编程方式设置。您可以在标题中发送您想要的级别:loglevel。如果您发送loglevel在标题中,它将被使用。否则,logLevel 将为Error. See here https://github.com/NLog/NLog/wiki/Tutorial#configure-nlog-targets-for-output, 请。

注意:只需使用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 and include here https://github.com/nlog/NLog/wiki/Configure-from-code

nlog配置文件

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

默认模式配置

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

调试模式配置

<?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 and defaultmode.config。默认情况下nlog.config file, 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();
    }
}

The problem is, this situation needs to send the log level every time. In these screenshots, you see how to send log level in debugging mode. The Postman result

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态设置每个记录器实例的 Nlog 日志级别 ASP.Net Core 2.x 的相关文章

  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • 对类 static constexpr 结构的未定义引用,g++ 与 clang

    这是我的代码 a cp p struct int2 int x y struct Foo static constexpr int bar1 1 static constexpr int2 bar2 1 2 int foo1 return
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • C++ 中的 include 和 using 命名空间

    用于使用cout 我需要指定两者 include
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐