'How to init, inject and use a Logger in a abp.io Console application
starting from the Console Application Startup Template, I'd like to register, configure and use a Logger (Microsoft, Serilog or any other; I don't mind) and FluentScheduler.
This is the code I changed from the initial template, but it did not work: Logger is always set to NullLogger :-(
class Program {
static async Task Main(string[] args) {
await CreateHostBuilder(args).RunConsoleAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(build => {
build.AddJsonFile("appsettings.secrets.json", optional: true);
})
.ConfigureServices((hostContext, services) => {
// === TRY CFG LOGGER HERE - start
services.AddLogging(cfg => {
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(path: "appsettings.json", optional: false, reloadOnChange: true)
.Build();
cfg.AddConfiguration(configuration);
});
// === TRY CFG LOGGER HERE - end
services.AddHostedService<ConsoleTestAppHostedService>();
});
}
public class ConsoleTestAppHostedService : IHostedService {
// ... see https://docs.abp.io/en/abp/latest/Startup-Templates/Console
}
public abstract class AbstractAbpJob : IJob, ITransientDependency {
public ILogger Logger { get; set; } // <=== it not injected
public AbstractAbpJob() {
Logger = NullLogger<AbstractAbpJob>.Instance;
}
public abstract void Execute();
}
Please, help.
Solution 1:[1]
Add code.
...
application.Services.AddSingleton<ILoggerFactory>(
(Func<IServiceProvider, ILoggerFactory>)(services => new SerilogLoggerFactory(Log.Logger)));
Solution 2:[2]
Thanks to all your messages and thanks to the suggestions of @ma-huwei. I finally arrived to a code that works:
class Program {
static async Task Main(string[] args) {
// Its important that logging is default initialized as early
// as possible, so that errors that might prevent your app from
// starting are logged
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
// CreateBootstrapLogger() sets up Serilog so that the initial
// logger configuration (which writes only to Console),
// can be swapped out later in the initialization process,
// once the hosting infrastructure is available.
.CreateBootstrapLogger();
Log.Information($"Starting up...");
try {
await CreateHostBuilder(args).RunConsoleAsync();
}
finally {
Log.Information("=== Program terminated ===");
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingCtx, build) => {
build.AddJsonFile("appsettings.json", optional: true);
build.AddJsonFile(path: "appsettings.secrets.json", optional: true, reloadOnChange: true);
})
.ConfigureServices(services => {
// this is the (let's say) "new" 'console main'
services.AddHostedService<ProgramAppHostedService>();
})
.UseSerilog((context, loggerConfig) => {
loggerConfig.ReadFrom.Configuration(context.Configuration);
});
}
And this is the invoked ProgramAppHostedService:
/// <summary>
/// This is the new '.NET main' activated by Program.Main.
/// The advantage here is that DI, logging, etc. are now available
/// </summary>
public class ProgramAppHostedService : IHostedService {
private readonly IHostApplicationLifetime _appLifetime;
private readonly IConfiguration _configuration;
private readonly ILogger<ProgramAppHostedService> _logger;
private byte[] _appsettingsHash = new byte[20];
private static object _initLock = new object();
public ProgramAppHostedService(
IHostApplicationLifetime appLifetime,
IConfiguration configuration,
ILogger<ProgramAppHostedService> logger) {
_appLifetime = appLifetime;
_configuration = configuration;
_logger = logger;
}
/// <summary>
/// Gracefully shutdown the application
/// </summary>
public Task StopAsync(CancellationToken cancellationToken) {
_logger.LogInformation("Application host stopped");
return Task.CompletedTask;
}
/// <summary>
/// This the Apb.io main. It is automatically invoked by the .NET framework IHost system.
/// </summary>
public async Task StartAsync(CancellationToken cancellationToken) {
try {
using (var abpApplication = await AbpApplicationFactory.CreateAsync<ProgramAppModule>(options => {
options.Services.ReplaceConfiguration(_configuration);
options.UseAutofac(); //Autofac integration
// this is important to ensure correct logger injectio cfg
options.Services.AddLogging(c => c.AddSerilog());
})) {
_logger.LogInformation("Application initialize...");
await abpApplication.InitializeAsync();
_logger.LogInformation("Application initialized");
try {
// Resolve a service and use it
var helloWorldService = abpApplication.ServiceProvider.GetService<HelloWorldService>();
await helloWorldService.SayHello();
}
finally {
await abpApplication.ShutdownAsync();
}
}
}
finally {
_appLifetime.StopApplication();
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | ma huwei |
| Solution 2 | Gianpiero |
