'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