pm4net / serilog-enrichers-callerinfo

A simple Serilog enricher to add information about the calling method.
Apache License 2.0
10 stars 2 forks source link

How do I configure WithCallerInfo via appsettings.json? #1

Closed lscorcia closed 1 year ago

lscorcia commented 1 year ago

Hi, I'm trying to configure WithCallerInfo via appsettings.json (Serilog.Settings.Configuration). If I configure it via code everything works fine. I have verified that my appsettings.json is actually parsed and used to configure Serilog by manipulating the log template.

This is my configuration:

{
  "AllowedHosts": "*",
  "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.Debug" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "{Level:u} {Timestamp:yyyy-MM-dd HH:mm:ss.fff} {MachineName} {ThreadId} {SourceContext} {Method} {Message:lj}{NewLine}{Exception}"
        }
      },
      {
        "Name": "Debug",
        "Args": {
          "outputTemplate": "{Level:u} {Timestamp:yyyy-MM-dd HH:mm:ss.fff} {MachineName} {ThreadId} {SourceContext} {Method} {Message:lj}{NewLine}{Exception}"
        }
      }
    ],
    "Enrich": [
      "FromLogContext",
      "WithMachineName",
      "WithThreadId",
      {
        "Name": "WithCallerInfo",
        "Args": {
          "includeFileInfo": "false",
          "assemblyPrefix": "MyAssembly.",
          "prefix": ""
        }
      }
    ],
    "Properties": {
      "Application": "MyApp"
    }
  }
}

Using the SelfLog I noticed that the prefix attribute must be present in the config even if it is optional in code, otherwise the Enricher is not found by Serilog.Settings.Configuration. However it seems no make no difference, the method name is never present in the logs. Any idea?

EDIT: The plot thickens. If I change the assemblyPrefix to "" then it prints "Enrich" as the Method name (as expected). But if I change it to MyAssembly in the json file then nothing is printed. If I configure it using .Enrich.WithCallerInfo(false, "MyAssembly") it works fine.

johannesmols commented 1 year ago

Hi, first of all thank you for using it! I admittedly only tested it via code, so I'm not sure what is wrong either, your config looks correct. I'm currently on vacation and can't test, but will try to do it once I'm back! In the meantime you're welcome to try and clone the project and see if you can find the issue.

lscorcia commented 1 year ago

Thanks for your quick answer! I debugged the code and found the culprit:

https://github.com/pm4net/serilog-enrichers-callerinfo/blob/3d136031310a1e47ee8fa7e816885652127082d9/Serilog.Enrichers.CallerInfo/EnricherConfiguration.cs#L41

When the configuration is read from a JSON file, the calling assembly is Serilog.Settings.Configuration, which does not reference any useful assembly. I also think there's an issue here:

https://github.com/pm4net/serilog-enrichers-callerinfo/blob/3d136031310a1e47ee8fa7e816885652127082d9/Serilog.Enrichers.CallerInfo/EnricherConfiguration.cs#L63

If the starting assembly does not respect the filter it is added anyway. I think it should be guarded by if (filter(asm.GetName())). However this just means that no actual assembly is ever considered, so I changed this line:

https://github.com/pm4net/serilog-enrichers-callerinfo/blob/3d136031310a1e47ee8fa7e816885652127082d9/Serilog.Enrichers.CallerInfo/EnricherConfiguration.cs#L56

to:

var stack = new Stack<Assembly>(AppDomain.CurrentDomain.GetAssemblies());

This makes it work, but it assumes that the assemblies have already been loaded at the time of log initialization. This may not always be the case. In the end probably there's going to be some additional configuration parameter to specify the starting assembly, or maybe even ditch the "filter by assembly" rule and filter by namespace/type instead. I really don't know if there's a one-size-fits-all approach to this issue.

johannesmols commented 1 year ago

Of course. Thank you for the detailed report, appreciate it. They are good suggestions and I will consider them once I'm back. You're of course very welcome to make a PR with a solution that you see fit (I agree that the filter may not be necessary, so an additional switch to toggle it might be useful as you say it can't be optional if configured via JSON). Otherwise I'll probably look at implementing a solution when I have the time.

johannesmols commented 1 year ago

Hi @lscorcia, sorry for taking so long. I have now looked at it and added another optional parameter "startingAssembly" to be used via appsettings to define the starting assembly, instead of calling Assembly.GetCallingAssembly() (which is still possible if the parameter isn't provided, to be used via code configuration). I hope that solves your issue.

I also added the filter for the starting assembly as you kindly pointed out, thank you for that.

And lastly, I didn't have any issue when not providing the prefix parameter in the appsettings, it was set to the empty string just fine. Let me know if this still isn't working for you after the update.

The changes are now available in 1.0.2.