可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I created a consumer/job that I will have running as a process on linux written in C#.
The process will:
- Read a message from RabbitMQ
- Make changes to the database
- Log any errors
All the documentation on nlog about .net core are on aspnet core. When I try to get an ILogger
implementation, it returns null.
Here is an except of wiring and usage:
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"); [...] }
Do not be confused with the environment variable ASPNETCORE_ENVIRONMENT
; it is used solely to determine which appsettings.json
to use.
I've based my code on this issue report.
Finally, these are the packages I currently have installed.
<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>
回答1:
Complete minimalistic example of NLog usage in a .NET Core console app (based on NLog.Extensions.Logging repository):
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");
References:
<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>
回答2:
In DotNet Core 2 you can use the start up class now and clean up the code a bit to look more like the web one.
And as a bonus a way to start your app inside the DI container using ConsoleApp
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(); }
Startup.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.AddSingleton(new LoggerFactory() .AddNLog() .ConfigureNLog("nlog.config") ); services.AddLogging(); services.AddTransient<ConsoleApp>(); } }
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; } }
回答3:
My solution is to use an adapter pattern that uses Console.Writeline, until a more sane version of NLog becomes available.
using System; public static class Log { public static void Write(string message) { Console.WriteLine($"{DateTime.Now}: {message}"); } }