来自静态类的 ASP.NET Core Web API 日志记录

Posted

技术标签:

【中文标题】来自静态类的 ASP.NET Core Web API 日志记录【英文标题】:ASP.NET Core Web API Logging from a Static Class 【发布时间】:2018-07-18 11:19:43 【问题描述】:

我在我的控制器上使用依赖注入记录得很好,现在我需要记录一些来自静态类的东西。

如何静态类记录?

我不能使用依赖注入,因为它是静态的,而且我不能只将现有的记录器对象传递给静态类,因为它会在日志文件中使用错误的类名。

换句话说,我如何从我的静态类中的 loggerfactory 获取一个记录器?

我遇到了一个类似的问题,他们指出了一篇关于静态类中的 loggerfactory 的文章,但这实际上不起作用,因为我无法从中获取新的记录器,因为它不接受静态类作为参数:

“静态类型不能用作类型参数”

【问题讨论】:

你有没有想过这个问题?我想从扩展方法登录。 解决方案在这里@illug 相关:***.com/q/50712720/11635 【参考方案1】:

我在 Startup 类中添加了 ILoggerFactory 的静态成员,因此它可以在其他类中使用。

public class Startup

    internal static ILoggerFactory LogFactory  get; set; 
    …

    public void Configure(…, ILoggerFactory logFactory)
    
        …
        LogFactory = logFactory;
    

然后在静态类中使用。

static class YourClass

    private static ILogger<YourClass> Logger = Startup.LogFactory.CreateLogger<YourClass>();
…

但是,当 CreateLogger 抛出异常时,这段代码会导致 TypeInitializationException,所以你应该尝试做得更好。 [1]

【讨论】:

【参考方案2】:

我发现这个问题的答案很有用,但我记得我已经安装了 Serilog。我可以使用 Serilog 的默认实现,而不是实现自定义静态实例。

它带有多个不错的日志记录功能和多个重载版本。 这里有两个例子:

using Serilog;
...
    Log.Error(myException, "my message");
    Log.Warning("My message", myValue);

Serilog.Log 是一个静态实例,在 Program.cs 或 Startup.cs 中配置后即可使用。

【讨论】:

如果您不需要使用关注点分离原则,您可以在需要时轻松替换日志框架。 是的,如果想在自定义记录器中使用 Serilog,可以让自定义记录器基本上成为 Serilog 的包装器:) 如 OP 所要求的,要绑定到调用类, 可以实现类似 factorymethod 的方法,其类型参数为 @Adrian 所描述的。 您是在编写具体的代码,而不是编写接口。未来的读者,只要“注意”这种情况。【参考方案3】:

您可以将静态LoggerFactory 实例与以下扩展方法一起使用,该方法接受Type 类型的常规参数,而不是泛型类型参数: CreateLogger(ILoggerFactory, Type)

loggerFactory.CreateLogger(typeof(T)) 而不是 loggerFactory.CreateLogger&lt;T&gt;()

【讨论】:

您的意思是“a static LoggerFactory instance”吗?除非您设置一个,否则没有可用的静态 LoggerFactory 实例。【参考方案4】:

解决方案是在启动时初始化的实用程序静态类中对 LoggerFactory 进行静态引用:

/// <summary>
    /// Shared logger
    /// </summary>
    internal static class ApplicationLogging
    
        internal static ILoggerFactory LoggerFactory  get; set; // = new LoggerFactory();
        internal static ILogger CreateLogger<T>() => LoggerFactory.CreateLogger<T>();        
        internal static ILogger CreateLogger(string categoryName) => LoggerFactory.CreateLogger(categoryName);

    

您在 Startup.cs 上初始化的内容:

 public Startup(ILogger<Startup> logger, ILoggerFactory logFactory, IHostingEnvironment hostingEnvironment)
        
            _log = logger;
            _hostingEnvironment = hostingEnvironment;
            Util.ApplicationLogging.LoggerFactory = logFactory;//<===HERE

        

然后您可以构建一个记录器以从您的静态类中使用,如下所示:

internal static class CoreJobSweeper
    
        private static ILogger log = Util.ApplicationLogging.CreateLogger("CoreJobSweeper");

【讨论】:

完美!然而,值得添加一个强类型 CreateLogger 的示例,特别是对于我们复制/粘贴爱好者来说只是寻找快速解决问题的方法:) 即 private static ILogger log = Util.ApplicationLogging.CreateLogger();跨度> 这不再像github.com/aspnet/Announcements/issues/353 中的公告那样起作用。注入 ILogger 和 ILoggerFactory 不起作用。 “新的 ApplicationInsightsLoggerProvider 可以在应用程序启动管道的早期捕获日志。尽管 ApplicationInsightsLoggerProvider 在 Application Insights 中自动启用(从版本 2.7.1 开始),但直到管道后期才设置检测密钥。所以,只会捕获来自控制器/其他类的日志..." 解决方法是将 ILogger logger, ILoggerFactory logFactory 移到 Configure() 建议:将返回类型更改为 ILogger :内部静态 ILogger CreateLogger() => LoggerFactory.CreateLogger();用法:私有静态 ILogger log = Util.ApplicationLogging.CreateLogger();否则显式强制转换是强制性的 但是如果静态类在 project/dll 中,而启动时没有对服务器项目的引用呢?【参考方案5】:

首先,我同意NightOwl888 的回答。

但作为一种选择(将其视为一种解决方法),您可以通过方法参数注入 ILogger 依赖项 => 因此将调用此静态方法的类应该负责提供 ILogger 的正确实现。

static class YourClass

    public static void DoSomething(ILogger logger)
    
         // do something
         // call log.Log();
    

【讨论】:

Nightowl 根本没有回答这个问题,而是发表了一个不受欢迎的演讲,我在我的问题中专门讨论了你的建议以及为什么我不能这样做。 为了能够在任何地方记录,您必须在数万行代码中强制要求对每个方法/对象的记录器依赖。这对我来说听起来是个可怕的主意。在这种情况下,静态工厂是更明智的选择。

以上是关于来自静态类的 ASP.NET Core Web API 日志记录的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core——从静态类访问配置

ASP.NET Core Web API使用静态swagger.json文件

如果参数名称等于属性名称,则来自查询的 ASP.NET Core Web API 复杂类型绑定不起作用

使用静态基类方案让 ASP.NET Core 实现遵循 HATEOAS Restful Web API

ASP.NET Core使用静态文件目录游览与MIME类型管理

如何在 ASP.NET Core 中构建轻量级服务