【问题标题】:How to use Microsoft.Extensions.Logging in a .NET Core 3.0 Worker Service如何在 .NET Core 3.0 Worker 服务中使用 Microsoft.Extensions.Logging
【发布时间】:2019-10-30 07:30:23
【问题描述】:

我开始了一个新的 Windows 服务项目,并决定使用 .NET Core 3.0 Worker Service 模板。此服务永远不会在云/网络项目中使用,但我可能希望在某个时候对其进行调整以在 Linux 上运行。

我非常熟悉使用 NLog 进行日志记录。在每个类中创建一个新的静态记录器对象的模型非常直观。我看到 Worker Service 已经嵌入了 Microsoft.Extensions.Logging 框架,以至于默认的 worker 有一个 ILogger<Worker> 直接传入。这对于“我的第一个服务”来说非常好,但是一个真正的长期运行的服务呢?很多类,每个都需要记录?

我为此模板找到的所有教程都涉及完成所有工作和登录 Worker 类的服务。由于历史原因,大多数日志记录文章只考虑 ASP.NET 核心,其中 DI 是优先考虑的。我还没有找到任何关于如何使用由多个长期存在的类组成的树构建应用程序的描述,每个类都有自己的 ILogger 对象要写入。

尽管我在这个项目中永远不需要 DI,但在我的代码库中采用它似乎是一个很好的标准,最初将它连接到 NLog 提供程序。我可以在我的Main 中获取IHostBuilder,然后添加一个静态函数以从其ILoggingBuilder 以类似于NLog 的方式创建记录器,但我不敢相信这是最好的方法。

这里有既定的最佳实践吗?它是否涉及从 Worker Service 模板中解开一些魔力?

【问题讨论】:

    标签: logging .net-core nlog .net-core-3.0


    【解决方案1】:

    NLog 在 .Net Core 中运行良好,无需依赖注入的任何帮助。你就像往常一样:

    private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
    
    private static void Main()
    {
        Logger.Info("Hello World");
    }
    

    但是 NLog 还可以使用 Microsoft 依赖注入与 Microsoft 扩展日志记录 (MEL) 集成。您只需注册NLog LoggingProvider,然后 MEL-ILogger 输入将被转发到 NLog。

    IHostBuilder.ConfigureLogging 中,可以调用AddNLog()(就像可以调用AddDebug()AddConsole() 用于内置MEL-LoggingProviders)

    您可以在 wiki 页面上找到一个简单的示例(如果需要,还可以找到指向 ASP.NET Core 的链接):

    https://github.com/NLog/NLog/wiki/Getting-started-with-.NET-Core-2---Console-application

    有些人不喜欢 MEL-ILogger 必须通过类构造函数注入,即使是简单的类(太杂乱)。相反,他们只是直接使用NLog.LogManager.GetCurrentClassLogger()

    【讨论】:

    • 听起来您在说,“不,MEL-ILogger 确实像您担心的那样笨重。桌面应用程序没有好方法。”如果是真的,我很感激你为我节省了进一步探索的时间!必须在一个地方创建所有记录器,然后将它们提供给每个构造函数,这对于复杂的应用程序来说实在是太麻烦了。更不用说反序列化这样的对象模型了。后续问题是如果我不想要,如何最好地从 Worker 项目中删除 MEL。
    • 依赖注入框架会自动将 ilogger 注入到构造函数中。 Microsoft 在他们的 NetCore 框架中使用 MEL-ILogger,因此如果想要他们的日志输出以进行故障排除,那么您应该保留它。但这听起来像是一个全新的问题。
    【解决方案2】:

    也许值得看看Seriloghttps://serilog.net/? Serilog 非常灵活,您可以添加各种接收器,例如:控制台、文件、elasticsearch、seq 等。而且您不必到处 DI。

    这就是我使用它打印到控制台的方式(std::out)。

    using System;
    using System.IO;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Serilog;
    namespace YourNamespace
    {
    public class Program
    {
        private static readonly string _applicationName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
        public static IConfiguration Configuration = new ConfigurationBuilder()
                  .SetBasePath(Directory.GetCurrentDirectory())
                  .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                  .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", reloadOnChange: true, optional: true)
                  .AddEnvironmentVariables()
                  .Build();
    
        public static int Main(string[] args)
        {
            // serilog
            Log.Logger = new LoggerConfiguration()
                            .ReadFrom.Configuration(Configuration)
                            .Enrich.FromLogContext()
                            .CreateLogger();
    
            try
            {
                if (string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")))
                    throw new Exception("Hosting environment variable not set");
    
                Log.Information($"Bootstrapping application: {_applicationName}");
                CreateWebHostBuilder(args).Build().Run();
                Log.Information($"Gracefully closing application: {_applicationName}");
                return 0; // returning a zero, indicates a successful shutdown.
            }
            catch (Exception e)
            {
                Log.Information($"Host {_applicationName} - terminated unexpectedly.", e);
                return 1; // returning a none-zero, indicates failure.
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseConfiguration(Configuration)
                .UseSerilog(); // overrides default logger
    }
    }
    

    您现在可以在程序中的任何位置使用它,例如控制器

    try 
    {
       Log.Information("Testing the logs..");
    }
    catch (Exception e)
    {      
       Log.Error("{@e}", e); // stack trace or other objects where {@e} is the object template.
       return BadRequest($"Rule violation: {e.Message}");
    }
    

    以及相应的配置(只写入控制台):

    "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*",
      "Serilog": {
        "MinimumLevel": {
          "Default": "Information",
          "Override": { // overrides default logger from MS
            "Microsoft": "Warning",
            "System": "Warning"
          }
        },  
        "WriteTo": [
          {
            "Name": "Console",
            "Args": {
              "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {SourceContext}>{NewLine}{Exception}"
            }
          }
        ]
      }
    

    还有 nugets:

        <PackageReference Include="Serilog" Version="2.9.0" />
        <PackageReference Include="Serilog.AspNetCore" Version="3.1.0" />
        <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
    

    如果您确实想要 DI 记录器,也许您应该看看 Autofac DI 框架? 希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-29
      • 2019-11-18
      • 1970-01-01
      • 2020-01-31
      • 1970-01-01
      • 2020-05-02
      相关资源
      最近更新 更多