1

I'm working on a legacy .NET Framework console application. (No ASP.NET or .NET Core logging frameworks are involved).

The VS solution contains the console application project, and also a separate class library project which the console application depends on.

I have the following Serilog-related NuGet packages installed in the two C# projects:

Console application assembly

  • Serilog 2.10.0
  • Serilog.Enrichers.Demystifier 1.0.1
  • Serilog.Sinks.Console 4.0.0
  • Serilog.Sinks.File 5.0.0
  • Various dependencies of the above

Library assembly

  • Serilog 2.10.0
  • Direct dependencies of Serilog

I am configuring the global static logger at the top of my console application like so:

    static void Main(String[] args)
    {
        // Configure Serilog static logger
        Log.Logger = new LoggerConfiguration()
            .Enrich.WithDemystifiedStackTraces()
            .WriteTo.Console(LogEventLevel.Information)
            .WriteTo.File("app-.log", 
                rollingInterval: RollingInterval.Day, 
                retainedFileCountLimit: 7, 
                restrictedToMinimumLevel: LogEventLevel.Debug
            )
            .CreateLogger();

Calls to Log.Information(), Log.Warning(), Log.Error() etc work fine as long as I'm calling them from the context of the console application assembly.

But when the console app calls into methods that are defined in the library assembly, calling Log.Information() and friends has no visible effect. The expected log messages don't show up in the Console or File sinks.

Once the library method returns, back to the Console assembly, the Log static methods work once again.

What's going on here? Why does the global static Log.Logger seem to have different configuration or behaviour when in the scope of the library code? The documentation gave me the impression that I only needed to set Log.Logger once, and then I would be able to use the static methods like Log.Information() from anywhere. Am I supposed to be passing my configured logger explicitly across the assembly boundary, or somehow disambiguating between multiple global Log.Logger instances?

Hydrargyrum
  • 3,378
  • 4
  • 27
  • 41
  • This shouldn't happen in normal conditions. [Log.Logger is a static property](https://github.com/serilog/serilog/blob/v2.10.0/src/Serilog/Log.cs#L43-L53) that is shared across the same AppDomain. It looks like you might have something else going on in your project/environment. If you can put a reproducible example on GitHub we might be able to help further. – C. Augusto Proiete Aug 25 '21 at 16:17
  • Are you really using Microsoft's .NET Framework, or something custom like ScriptHookVDotNet or similar? If it's the latter, it's possible your runtime is managing the static context differently. [ScriptHookVDotNet is known to do that](https://stackoverflow.com/a/65366432/211672). – C. Augusto Proiete Aug 25 '21 at 16:35

1 Answers1

0

Well, that's embarrassing. I messed around with changing the target .NET Framework version of the console app and class library and various other experiments. But it turns out that the actual cause was that my log messages in the class library coincidentally happened to be of LogEventLevel.Debug or LogEventLevel.Verbose log level, while the log messages in the calling console application were LogEventLevel.Information or above. I got distracted by the fact that the calls were in different assemblies without noticing the different levels in each context.

Although I had configured the File sink with Minimum LogEventLevel set to LogEventLevel.Debug, it wasn't catching any log messages, because new LoggerConfiguration objects have an implicit default minimum log level of Information. I had never overridden that implicit default because I hadn't noticed its description on the "Serilog Configuration Basics" doc page. That meant the log events from the class library were getting filtered out before the sinks ever got a chance to see them.

The solution was to add .MinimumLevel.Debug() (or .MinimumLevel.Verbose()) to the LoggerConfiguration:

        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .Enrich.WithDemystifiedStackTraces()
            .WriteTo.Debug(LogEventLevel.Debug)
            .WriteTo.Console(settingsConsoleLogMinimumLevel)
            .WriteTo.File("tadloader-.log", 
                rollingInterval: RollingInterval.Day, 
                retainedFileCountLimit: settings.LogFileCount, 
                restrictedToMinimumLevel: settingsLogFileMinimumLevel
            )
            .CreateLogger();
Hydrargyrum
  • 3,378
  • 4
  • 27
  • 41