Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overriding Default Settings #26

Closed
RehanSaeed opened this issue Sep 30, 2016 · 6 comments
Closed

Overriding Default Settings #26

RehanSaeed opened this issue Sep 30, 2016 · 6 comments

Comments

@RehanSaeed
Copy link

I would like to provide some sensible defaults before relying on configuration to override settings e.g.

  • Using Environment.UserInteractive to turn on console logging.
  • Using The AssemblyProductAttribute to provide a Source property.
  • Providing a default file path for the file logger.

How can I provide these defaults and use configuration to override them, rather than replace them entirely?

var drive = DriveInfo
    .GetDrives()
    .Where(x => x.DriveType == DriveType.Fixed)
    .Any(x => string.Equals(x.Name, @"D:\", StringComparison.Ordinal)) ? "D" : "C";
var source = GetProduct();
var environment = configuration["Serilog:Properties:Environment"];
var country = configuration["Serilog:Properties:Country"];

Log.Logger = new LoggerConfiguration()
    .Enrich.WithEnvironmentUserName()
    .Enrich.WithMachineName()
    .Enrich.WithProcessId()
    .Enrich.WithThreadId()
    .Enrich.WithExceptionDetails()
    .Enrich.WithProperty("Source", source)
    .Enrich.WithRequestId(httpContextAccessor)
    .WriteToIfTrue(CanLogToConsole(hostingEnvironment), x => x.ColoredConsole())
    .WriteTo.RollingFile(
        new JsonFormatter(renderMessage: true),
        $@"{drive}:\Logs\{source}-{environment}-{country}-{{Date}}.log",
        fileSizeLimitBytes: null,
        retainedFileCountLimit: null)
    .ReadFrom.Configuration(configuration)
    .CreateLogger();

private static bool CanLogToConsole(IHostingEnvironment hostingEnvironment)
{
#if NET461
    return Environment.UserInteractive;
#else
    return hostingEnvironment.IsDevelopment();
#endif
}

private static string GetProduct()
{
    return Assembly
        .GetEntryAssembly()
        .GetCustomAttributes(typeof(AssemblyProductAttribute))
        .OfType<AssemblyProductAttribute>()
        .Select(x => x.Product)
        .FirstOrDefault();
}

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Properties": {
      "Country": "UK",
      "Environment": "Development"
    }
  }
}
@nblumhardt
Copy link
Member

Interesting ticket, thanks for the example.

I'm not sure there will be a simpler solution than just doing everything programmatically - the range of possible configurations is pretty vast.

One thing you might explore is doing the overriding via the configuration subsystem itself; e.g. create an in-memory configuration source with the defaults, and add it to the ConfigurationBuilder before adding the JSON file. The configuration subsystem does last-in-wins overriding, IIRC.

@RehanSaeed
Copy link
Author

I was hoping that ReadFrom.Configuration settings would layer on-top of the settings I specified using the fluent interface on LoggerConfiguration and not just throw everything away and rebuild it. The issue is that my config will get quite large and given a microservice architecture, will have to get copied in a few locations with few differences between them.

Your idea for in-memory config is a reasonable workaround. Perhaps serilog-settings-configuration could make this easier by providing a static object to do this. Something like this:

Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(
        new DefaultConfiguration()
        {
            MinimumLevel = LogEventLevel.Debug,
            Properties["Environment"] = "Development",
            ...
        })
    .ReadFrom.Configuration(configurationRoot)
    .CreateLogger();

@skomis-mm
Copy link
Contributor

Could not reproduce this. That's strange.. As far as I know ReadFrom.XXX(...) cannot rebuild what was aready specified by LoggerConfiguration because it's API can only add things except MinimumLevel which is overridable. So in example above .ReadFrom.Configuration(configurationRoot) essentially (should) translates to:

    .WriteTo.RollingFile(...)

    .MinimumLevel.ControlledBy(new LoggingLevelSwitch(LogEventLevel.Debug))
    .MinimumLevel.Override("Microsoft", new LoggingLevelSwitch(LogEventLevel.Warning))
    .MinimumLevel.Override("System", new LoggingLevelSwitch(LogEventLevel.Warning))
    .Enrich.WithProperty("Country", "UK")
    .Enrich.WithProperty("Environment", "Development")

    .CreateLogger();

@tsimbalar
Copy link
Member

@RehanSaeed would issue serilog/serilog#1038 help ? feedback would be welcome :)

@forrestab
Copy link

forrestab commented Jun 17, 2019

I recently found myself needing something similar to this in regards to sharing configuration via a separate library. After following the various links here and in other issues I found the serilog-settings-combined repository, but it looks like development stopped quite some time ago.

As @nblumhardt suggested, I also tried creating a custom configuration provider, but ran into an issue where arguments for the Oracle sink were not being passed correctly for sink initialization. I was unable to determine why from appsettings.json everything worked fine, but the same values via my custom provider did not.

Anyway, just wanted to see if anyone else had any ideas for sharing configuration across multiple solutions.

Edit
I was able to move my shared configuration into a class library using this method. Essentially I created a custom in memory file provider and faked a json file using this technique.

@skomis-mm
Copy link
Contributor

Closing this in favor of serilog-settings-combined as discussion about mixing with Serilogs fluent API code configuration is outside of the scope of this project which relies solely on Microsoft.Extensions.Configuration and its layering design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants