将NLog集成到.NET Core控制台应用程序中

22

我创建了一个使用C#编写并将作为Linux进程运行的消费者/作业。

该进程将:

  1. 从RabbitMQ读取消息
  2. 对数据库进行更改
  3. 记录任何错误

NLog关于.NET Core的所有文档都是关于ASP.NET Core的。当我尝试获取ILogger实现时,它返回null。

以下是连接和用法摘录:

static void ConfigureServices()
{
    string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

    var builder = new ConfigurationBuilder()
         .SetBasePath(Path.Combine(AppContext.BaseDirectory))
         .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
         .AddJsonFile($"appsettings.{environment}.json", optional: true);

    var services = new ServiceCollection();

    Configuration = builder.Build();

    [...]

    services.AddLogging();

    ServiceProvider = services.BuildServiceProvider();

    var loggerFactory = ServiceProvider.GetService<ILoggerFactory>();
    loggerFactory.AddNLog();
}

static void Main(string[] args)
{
    ConfigureServices();
    
    var logger = ServiceProvider.GetService<NLog.ILogger>();

    logger.Debug("Logging");

    [...]
}

不要将环境变量ASPNETCORE_ENVIRONMENT与其混淆;它仅用于确定要使用哪个appsettings.json

我基于这个问题报告编写了我的代码。

最后,这些是我当前已安装的软件包。

<ItemGroup>
  <PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.2" />
  <PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.2" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="1.1.2" />
  <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
  <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
  <PackageReference Include="NLog" Version="5.0.0-beta09" />
  <PackageReference Include="NLog.Extensions.Logging" Version="1.0.0-rtm-beta5" />
  <PackageReference Include="Npgsql" Version="3.2.4.1" />
  <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="1.1.0" />
</ItemGroup>

请使用 Microsoft.Extensions.Logging.ILogger 替代 NLog.ILogger - Ilya Chumakov
@IlyaChumakov 这样做会不会只给我提供 msft 日志记录器,并将所有日志路由通过 msft 日志记录? - Matt R
实际上,我刚刚测试了一下,logger 仍然是 null。 - Matt R
我的错误,我是指 ILogger<T> - Ilya Chumakov
你会收到一个通用的 MSFT 日志记录器。总的来说,这很好,因为你的代码不依赖于具体的日志记录器实现。你可以随时附加和替换它。 - Ilya Chumakov
3个回答

27

这是一个基于NLog.Extensions.Logging库的.NET Core 1控制台应用程序中NLog的完整极简示例:

var services = new ServiceCollection();
services.AddLogging();
var provider = services.BuildServiceProvider();

var factory = provider.GetService<ILoggerFactory>();
factory.AddNLog();
factory.ConfigureNLog("nlog.config");

var logger = provider.GetService<ILogger<Program>>();
logger.LogCritical("hello nlog");

参考文献:

    <ItemGroup>
        <PackageReference Include="NLog.Extensions.Logging" Version="1.0.0-rtm-beta5" />
        <PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.2" />
        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
        <PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
    </ItemGroup>

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"
      internalLogFile="internal-nlog.txt">

  <variable name="Layout"
            value="${longdate}|${level:uppercase=true}|${logger}|${message}"/>

  <!-- the targets to write to -->
  <targets>
    <!-- write logs to file -->
    <target xsi:type="File" 
            name="allfile" 
            fileName="nlog-all-${shortdate}.log"
            layout="${Layout}" />

    <!-- write to the void aka just remove -->
    <target xsi:type="Null" name="blackhole" />
  </targets>

  <!-- rules to map from logger name to target -->
  <rules>
    <!--All logs, including from Microsoft-->
    <logger name="*" minlevel="Trace" writeTo="allfile" />

    <!--Skip Microsoft logs and so log only own logs-->
    <logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
  </rules>
</nlog>

14

在DotNet Core 2中,您现在可以使用启动类来清理代码,使其看起来更像Web应用程序。

作为奖励,还有一种使用ConsoleApp在DI容器内启动应用程序的方式。

Program.cs

static void Main(string[] args)
{
    IServiceCollection services = new ServiceCollection();

    Startup startup = new Startup();
    startup.ConfigureServices(services);

    IServiceProvider serviceProvider = services.BuildServiceProvider();

    // entry to run app
    serviceProvider.GetService<ConsoleApp>().Run();
}

启动.cs

public class Startup
{
    IConfigurationRoot Configuration { get; }

    public Startup()
    {
        var builder = new ConfigurationBuilder()
          .SetBasePath(Directory.GetCurrentDirectory())
          .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

        Configuration = builder.Build();
    }


    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IConfigurationRoot>(Configuration);

        services.AddSingleton<IMyConfiguration, MyConfiguration>();

        services.AddLogging(loggingBuilder => {
           loggingBuilder.AddNLog("nlog.config");
        });

        services.AddTransient<ConsoleApp>();
    }
}

控制台应用程序.cs

public class ConsoleApp
{
    private readonly ILogger<ConsoleApp> _logger;
    private readonly IMyConfiguration _config;

    public ConsoleApp(IMyConfiguration configurationRoot, ILogger<ConsoleApp> logger)
    {
        _logger = logger;
        _config = configurationRoot;
    }


    public void Run()
    {
        var test = _config.YourItem;

        _logger.LogCritical(test);

        System.Console.ReadKey();
    }
}

Configuration.cs

public class MyConfiguration : IMyConfiguration
{

    IConfigurationRoot _configurationRoot;
    public MyConfiguration(IConfigurationRoot configurationRoot)
    {
        _configurationRoot = configurationRoot;
    }

    public string YourItem => _configurationRoot["YourItem"];
}


public interface IMyConfiguration
{
    string YourItem { get; }
}

-9
我的解决方案是使用适配器模式,它使用Console.Writeline,直到更合理的NLog版本可用为止。
using System;
public static class Log
{
    public static void Write(string message)
    {
        Console.WriteLine($"{DateTime.Now}: {message}");
    }
}

2
通过使用Microsoft.Extensions.Logging,您可以获得结构化日志记录的支持。并且能够执行动态过滤并将日志接收器/目标替换为您喜欢的选择。如果您只想要控制台日志记录,则无需选择任何日志记录框架。 - Rolf Kristensen
这是适配器模式吗?看起来不像。我的意思是,如果您至少尝试了 Singleton 模式,那么也许我会点赞。这只是一个违反 SOLID 原则的静态“全局”变量。但当然,随你便。 - Piotr Kula

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接