简体   繁体   中英

Creating method to return Serilog LoggerConfiguration (Asp.Net Core 2.0)

I was initially using one log file for Serilog, which I accomplished by doing this

var slc = new SerilogSubLoggerConfiguration();   
configuration.GetSection("Serilog:SubLogger").Bind(slc);

and then configuring the SubLogger in the Main method of Program.cs

 Log.Logger = new LoggerConfiguration()
            .ReadFrom.Configuration(configuration)
            .WriteTo.Logger(logger => logger.Filter.
                ByIncludingOnly(lvl => lvl.Level == slc.Level).WriteTo.RollingFile(slc..PathFormat))
            .CreateLogger();

I have moved to using three separate logs now defined in the appsettings file. This creates the class, with one property, a list of Serilog configurations

 public class SerilogSubLoggerConfigurations
{
    public List<SerilogSubLoggerConfiguration> SubLoggers { get; set; }
}

var slcs = configuration.GetSection("Serilog").Get<SerilogSubLoggerConfigurations>();

Now that I have my list of SubLogger configs, I need to create the logger, and add all these sub loggers. Each SubLogger will need its own

.WriteTo.Logger(logger => logger.Filter.
                ByIncludingOnly(lvl => lvl.Level == slc.Level).WriteTo.RollingFile(slc..PathFormat))

line in the Log.Logger call, therefore I need to iterate over the SubLoggers. My intention was to write a method to do so.

public static LoggerConfiguration GetLoggerConfiguration(IConfiguration config, SerilogSubLoggerConfigurations slcs)
    {
        var lc = new LoggerConfiguration();
        lc.ReadFrom.Configuration(config);

        foreach (var cfg in slcs.SubLoggers)
        {
            lc.WriteTo.Logger(logger => logger.Filter
                                       .ByIncludingOnly(lvl => lvl.Level == cfg.Level).WriteTo
                                       .RollingFile(cfg.PathFormat));
        }

        lc.CreateLogger();
        return lc;
    }

and then just use this in the Main method

Log.Logger = GetLoggerConfiguration(configuration, slcs);

But this errs,

Cannot implicitly convert type 'Serilog.LoggerConfiguration' to 'Serilog.ILogger'

I tried changing the method to an ILogger and returning an ILogger, but ILogger doesn't contain the WriteTo and ReadFrom methods, so that was a no go. I tried casting the returned LoggerConfiguration to an ILogger, but that didn't work either and a number of other iterations that also failed.

There must be a way to accomplish this. Any help appreciated.

Update:

 public static int Main(string[] args)
    {
        var currentEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{currentEnv}.json", optional: true)
            .AddEnvironmentVariables()
            .Build();

        var slcs = configuration.GetSection("Serilog").Get<SerilogSubLoggerConfigurations>();
        Log.Logger = BuildLogger(configuration, slcs);
        Log.Information(Appname != null ? $"{Appname}{LogDelimeter}Logger created." : "Logger created.");

        try
        {
            Log.Information(Appname != null ? $"{Appname}{LogDelimeter}Starting web host" : "Starting web host.");
            BuildWebHost(args).Run();
            return 0;
        }
        catch (Exception ex)
        {
            Log.Fatal(ex,
                Appname != null
                    ? $"{Appname}{LogDelimeter}Web Host terminated unexpectedly"
                    : "Web Host terminated unexpectedly");
            return 1;
        }
        finally
        {

            Log.Information(Appname != null ? $"{Appname}{LogDelimeter}Flushing log and closing it." : "Flushing log and closing it.");
            Log.CloseAndFlush();
        }
    }

I tried changing the method to an ILogger and returning an ILogger, but ILogger doesn't contain the WriteTo and ReadFrom methods, so that was a no go.

The sequence of Serilog bootstraping is following:

  1. You create an instance of Serilog.LoggerConfiguration object and setup it with either code calls ( WriteTo.RollingFile() ) or from config files ( ReadFrom.Configuration() ).
  2. Then after Serilog configuration is built, you create a logger with LoggerConfiguration.CreateLogger() call.

So before you finished loading configuration you can't log any messages (you don't have Logger instance yet). But after you built a logger there is no point to call WriteTo or ReadFrom methods since logger is already built and changes to source configuration will not affect anything.

So you could change your GetLoggerConfiguration() method as:

public static Serilog.ILogger BuildLogger(IConfiguration config, SerilogSubLoggerConfigurations slcs)
{
    var lc = new LoggerConfiguration();
    lc.ReadFrom.Configuration(config);

    foreach (var cfg in slcs.SubLoggers)
    {
        lc.WriteTo.Logger(logger => logger.Filter
            .ByIncludingOnly(lvl => lvl.Level == cfg.Level).WriteTo
            .RollingFile(cfg.PathFormat));
    }

    //  Apply any additional changes to lc configuration here

    //  Finally build a logger
    return lc.CreateLogger();
}

static void Main(string[] args)
{
    //  ...
    var logger = BuildLogger(configuration, subLoggerConfigurations);

    //  No any changes could be made to logging configuration at this point.
    //  Just log what you need.

    logger.Information("Test info message");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM