davidfowl/TodoApi

Serilog is better when the settings are via config sources

Closed this issue ยท 10 comments

๐Ÿ‘‹๐Ÿป G'day @davidfowl

So now that Serilog has been merged (ref: #49) I was hoping you might consider another Serilog PR which now removes any hardcoding of serilog settings and instead replacing them with the settings being defined via configuration sources.

Serilog has it's own special Serilog Configuration nuget which it then knows how to define some serilog settings via .NET configuration (file/env vars/etc):

image

The obvious example here is via the appsettings.json, given a specific "section". This extends to env vars so it works really nicely with Azure App Services or Docker Containers.

Can even use "Secrets" if you really need to -> think, API/License keys fr for the logging sink which is in the cloud.

Why do this?

This means anyone can easily change/setup their "sinks" and/or their logging "levels" at any time, without requiring any new build/deploys. For example, something weird is going on, you could just edit the azure app settings "env vars"/configuration settings and mod the logging level for a specific class or just in general (i.e. all logging is now Debug, not Info) .. etc.

Would you be interested in this?

I don't see how you can add new sinks at runtime without also adding a nuget package for that sink (maybe you meant, configure existing sinks?). As for changing log levels at runtime, that's important.

I don't think it's runtime? The app will need to be restarted manually or via (I think) an OptionsSnapshot or IOptionsMonitor ? (reloadable configuration?)

Adding/Changing sinks dynamically I wouldn't want to be in this application. Configuring existing sinks via config is good.

kewl! that would be fine via the official Serilog Configuration nuget.

So you're happy for a PR to come, enabling this option? (no I haven't done anything yet -> just touching base first, etc).

Just so I understand, isn't this what's happening here?

Ah yes! that's correct actually. That's what I was going to do.

<Reads the code .... >

but wait .. i feel like the current setup is incomplete.

see this code here:

image

this looks like it's a poor persons way of using configuration but then having to still hardcode the code based on some config values.

What happens if I want to send the logs to DataDog or any of the other provided sinks? If I wish to now send the data to DDog or Splunk or whatever, I need to hardcode. With the config file method, I can set everything up via the configuration source. The biggest "catch" is that the relevant nuget file needs to be in the bin. (I've never tried manually putting a nuget to a bin, post deployment).

Here's some code to explain:

  • remove this
if (serilogOptions.UseConsole)
{
    // https://github.com/serilog/serilog-sinks-async
    loggerConfiguration.WriteTo.Async(writeTo =>
    writeTo.Console(outputTemplate: serilogOptions.LogTemplate));
}

then add this to appsettings.json :

image

  1. This is any "not-default" sinks that you want to use. It's basically the namespace of the nuget package that isn't in the default Serilog nuget. This is where you would add DataDog, Splunk, etc.. if that's where u want to send data to.
  2. This is a customizable way to determine what to "enrich" each log, with. It's identical to:

image

.. except, this way, you can change the enrichment if your want .. versus .. having it hardcoded for every log. Sure, you might say "I want the log-context" value in each log message. But I personally really like picking one (hardcoding) or the other (configuration source) as the one place to define all of this. I just feel like, having this defined in a configuration source gives you more options later on. Say, test environment is playing up ... you can play with the enrichment values here to get more data, if needed.

  1. Just another key/value that is added with each log message. Or should I say, each log message is "enriched" with this key/value. You have this hardcoded.
  2. Console sink: pretty simple. No customization required. Just -> log to the console, please.
  3. Seq sink: this is a bit more complicated but it's where the seq settings will go. Usually it's a form of the sink's "constructor". Can also support arrays in here. Nick Blum has done a great job here, IMO.

and of course, you can keep adding more sinks in here - as required. And different environments (dev/test/prod) could of course have different sinks and/or different log levels, etc.

I hope this makes any sense, at all ๐Ÿ˜Š

What happens if I want to send the logs to DataDog or any of the other provided sinks? If I wish to now send the data to DDog or Splunk or whatever, I need to hardcode. With the config file method, I can set everything up via the configuration source. The biggest "catch" is that the relevant nuget file needs to be in the bin. (I've never tried manually putting a nuget to a bin, post deployment).

That seems logical to me. Add the nuget package, choose to configure it in code or via config. Adding sinks dynamically isn't something that makes sense IMO.

I think it makes sense to move some things to config but not all of them. For example, I need to be able to detect when a URL is configured so that I can dynamically enable one of those sinks (elastic search for e.g.). Does the configuration model support branches (if statements etc)?

Today I can pass in the application name from the hosting environment but when using config, I need to duplicate that name. There are tradeoffs. Also, I can set breakpoints in code ๐Ÿ˜„.

That said, send me a PR and we can go back and forth until we meet somewhere in the middle.

Added draft PR #62 . Not sure if you get notifications for draft PR's.

I've decided to swap out serilog in favor of the otel logging pipeline.

okay - i have more to learn, it seems! looking forward to seeing what/why/etc :) kewl!