We are writing a new logging functionality and injecting into our existing services.

Following is the way we do it:

1) Setup Serilog using UseSerilog() call in Program.cs

2) Setup Serilog config in appsettings.json to setup sinks for writing to Log file.

3) Wrote a Facade Custom Logger Class which does logging internally using Serilog global Log instance.

public class MyLogger<T> : IMyLogger<T>
public MyLogger()
    {
        _logger = Log.ForContext(typeof(T));
    }
public void LogInformation(Exception ex)
    {
        _logger.Information(ex.Message);
    }

4) Inject IMyLogger into all my existing services via DI

5) Register all services (Logger, Project related services) in ConfigureServices()

Everything works. But I want to set different log levels for different namespaces in my Application so that in Production I can simple set in config only 4-5 important Core Namespaces whose Logging Method calls (MyLogger.LogInformation()) will be sent to Log file.

Is something like below possible? Because MyLogger is the class thats logging. But If the call is from MyProject.CartManager Namespace, then it should automatically Log based on the config below in Example.

Please share your thoughts.

eg:

"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": {
  "Default": "Information",
  "Override": {
    "Microsoft": "Warning",
    "System": "Information",
    "MyProject.Inventory":  "Information"
    "MyProject.CartManager":  "Error"
  }
}
2

There are 2 answers

0
GPuri On

As you suggested in your configuration as well. It is possible to do so. Below is the sample configuration.

"serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": {
  "Default": "Information",
  "Override": {
    "Microsoft": "Warning",
    "Microsoft.Hosting.Lifetime": "Information"
  }
},
"WriteTo": [
  {
    "Name": "Console",
    "Args": {
      "formatter": "Serilog.Formatting.Elasticsearch.ElasticsearchJsonFormatter,Serilog.Formatting.Elasticsearch"
    }
  }
]}

MinimumLevel config section dictates what should be default and overrides for specific namespaces.

  1. Default log level is Information.
  2. Classes in Microsoft namespace except Microsoft.Hosting.Lifetime should have minimum log level as Warning

As side note I registered my Serilog as

webBuilder.UseSerilog((ctx, lc) => lc.ReadFrom.Configuration(ctx.Configuration));

And formatter part is Trivial in context of the question but if you want to use it I refered Serilog.Sinks.ElasticSearch as extra package to use it.

0
d_f On

Your IMyLogger seems to be excessive. Microsoft offers Microsoft.Extensions.Logging for the same purpose. So you can inject just ILogger<MyProject.Inventory.Foo> into your class and Serilog handles that with the Serilog.Extensions.Logging package. Beyond that your example must work as it is, meeting your expectations. Probably for your particular injections you used a wrong T(the implementation has no check over that).

Just started googling for almost the same: using MinimumLevel overrides for a few dedicated namespaces or contexts and first found this question with no answer, but the next was this great article.

The essentials:

The first argument of Override is a source context prefix, which is normally matched against the namespace-qualified type name of the class associated with the logger.

// Using Serilog:
var myLog = Log.ForContext<MyClass>();
myLog.Information("Hello!");
// -> SourceContext is "MyNamespace.MyClass"
//Using Microsoft.Extensions.Logging:
var myLog = loggerFactory.CreateLogger("MyNamespace.MyClass");
myLog.LogInformation("Hello!");
// -> SourceContext is "MyNamespace.MyClass"