ILogger
The sample application, here, lets you understand how to integrate Serilog with Microsoft ILogger
, including scoped context (for both Serilog and Microsoft console loggers)
In case of distributed systems, if you need to track logs for a particular request across the systems, it will be very challenging to find the exact logs associated with that particular request. This allows you to add any unique identifier so that you can track the log message across the systems. Another good example of application would be, tracking logs across distributed transaction across database systems.
ILogger
(with or without Serilog integration) in a .NET Core application?ILogger
onlyNuget package required (version depends on SDK framework, preferably the latest one): Microsoft.Extensions.Logging
In Program.cs
, add the console logger under ConfigureLogging
extension method as below
.ConfigureLogging((builderContext, loggingBuilder) =>
{
loggingBuilder.AddConfiguration(builderContext.Configuration.GetSection("Logging"));
loggingBuilder.AddConsole((options) =>
{
options.IncludeScopes = Convert.ToBoolean(builderContext.Configuration["Logging:IncludeScopes"]);
});
})
Startup.cs
, under ConfigureServices
method, add the below code to inject LoggerFactory
into the service collectionservices.AddLogging();
appsettings.json
, which sets the log levels and scopes as needed (In Microsoft Logging, Scoping will be enabled only if Logging:IncludeScopes
is true)"Logging": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Information",
"System": "Warning",
"Microsoft": "Warning",
"Pivotal": "Warning",
"Steeltoe": "Warning"
}
}
ScopedLoggingMiddleware.cs
in the sample applicationusing (logger.BeginScope($"CorrelationID:{CorrelationID}"))
{
await next(context);
}
ILogger<T>
in any of the classes that requires logging, and add logging statements as necessary, refer to ValuesController.cs
in the sample application for the exact implementation. Sample code snippet below.private readonly ILogger<ValuesController> logger;
public ValuesController(ILogger<ValuesController> logger)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
logger.LogInformation("Log something here......");
return new string[] { "value1", "value2" };
}
CorrelationID
is the property we set as unique identifier for a requestinfo: Scoped.logging.Serilog.Controllers.ValuesController[0]
=> ConnectionId:0HLFTAFDRCVND => RequestId:0HLFTAFDRCVND:00000001 RequestPath:/api/values/12 => CorrelationID:c00d1372-6b4f-402b-9666-0f93894a261e => Scoped.logging.Controllers.ValuesController.Get (Scoped.logging)
Returning values '12' that was received
ILogger
integrated with Serilog (Using Microsoft.Logger.BeginScope()
)<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.2-dev-00777" />
<PackageReference Include="Serilog.Settings.Configuration" Version="2.6.1" />
Program.cs
, make sure you use the DefaultWebHostBuilder
or add configuration providers under ConfigureAppConfiguration
extension method as below.ConfigureAppConfiguration((builderContext, config) =>
{
config.SetBasePath(builderContext.HostingEnvironment.ContentRootPath)
.AddJsonFile($"appsettings.json", optional: false, reloadOnChange: false)
.AddEnvironmentVariables();
})
Startup.cs
, under the constructor, add the below code to create the Serilog logger, based on the configuration provided in appsettings.json
. Serilog.Settings.Configuration
package enables the logger creator based on a given configurationLog.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
Startup.cs
, under ConfigureServices
method, add the below code to inject LoggerFactory
with Serilog as logging provider into the service collectionservices.AddLogging((builder) =>
{
builder.AddSerilog(dispose: true);
});
Add the below section in appsettings.json
, which sets the log levels and other configurations as below. Here you can setup your own output template with your own custom properties, which need to part of scoped logging for a particular request. In this sample, I have used CorrelationID
as my custom property.
MinimumLevel:Default
- default log level
MinimumLevel:Override
- overrides on default log level
WriteTo:Name
- you are injecting Console logger (from Serilog.Sinks.Console
package to enable console logging)
WriteTo:Args:outputTemplate
- your own logging template, please note the way I setup CorrelationID
here, you can add any more as needed
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Pivotal": "Warning",
"Steeltoe": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss}|{Level} => CorrelationID:{CorrelationID} => RequestId:{RequestId} => RequestPath:{RequestPath} => {SourceContext}{NewLine} {Message}{NewLine}{Exception}"
}
}
]
,
"Enrich": [
"FromLogContext"
]
}
ScopedLoggingMiddleware.cs
in the sample applicationvar loggerState = new Dictionary<string, object>>
{
["CorrelationID"] = "your unique id value here"
//Add any number of properties to be logged under a single scope
};
using (logger.BeginScope<Dictionary<string, object>>(loggerState))
{
await next(context);
}
Startup.cs
, under Configure
method, add the below code to use the middleware you created, at the very beginning of the request pipelineapp.UseMiddleware<ScopedLoggingMiddleware>();
ILogger<T>
in any of the classes that requires logging, and add logging statements as necessary, refer to ValuesController.cs
in the sample application for the exact implementation. Sample code snippet below.private readonly ILogger<ValuesController> logger;
public ValuesController(ILogger<ValuesController> logger)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
logger.LogInformation("Log something here......");
return new string[] { "value1", "value2" };
}
CorrelationID
is the property we set as unique identifier for a request2018-08-08 13:24:55|Information => CorrelationID:c00d1372-6b4f-402b-9666-0f93894a261e =>
RequestId:0HLFTAFDRCVND:00000001 => RequestPath:/api/values/12 =>
Scoped.logging.Serilog.Controllers.ValuesController
ILogger
integrated with Serilog (Using Serilog.LogContext.PushProperty()
enrichment)This method will be useful if you are using any custom ILogger
interface other than Microsoft ILogger
Nuget package required (preferably the latest one)
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.2-dev-00777" />
<PackageReference Include="Serilog.Settings.Configuration" Version="2.6.1" />
Program.cs
, make sure you use the DefaultWebHostBuilder
or add configuration providers under ConfigureAppConfiguration
extension method as below.ConfigureAppConfiguration((builderContext, config) =>
{
config.SetBasePath(builderContext.HostingEnvironment.ContentRootPath)
.AddJsonFile($"appsettings.json", optional: false, reloadOnChange: false)
.AddEnvironmentVariables();
})
Startup.cs
, under the constructor, add the below code to create the Serilog logger, based on the configuration provided in appsettings.json
. Serilog.Settings.Configuration
package enables the logger creator based on a given configurationLog.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
Startup.cs
, under ConfigureServices
method, add the below code to inject LoggerFactory
with Serilog as logging provider into the service collectionservices.AddLogging((builder) =>
{
builder.AddSerilog(dispose: true);
});
Add the below section in appsettings.json
, which sets the log levels and other configurations as below. Here you can setup your own output template with your own custom properties, which need to part of scoped logging for a particular request. In this sample, I have used CorrelationID
as my custom property.
MinimumLevel:Default
- default log level
MinimumLevel:Override
- overrides on default log level
WriteTo:Name
- you are injecting Console logger (from Serilog.Sinks.Console
package to enable console logging)
WriteTo:Args:outputTemplate
- your own logging template, please note the way I setup CorrelationID
here, you can add any more as needed
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Pivotal": "Warning",
"Steeltoe": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss}|{Level} => CorrelationID:{CorrelationID} => RequestId:{RequestId} => RequestPath:{RequestPath} => {SourceContext}{NewLine} {Message}{NewLine}{Exception}"
}
}
]
,
"Enrich": [
"FromLogContext"
]
}
LogContext.PushProperty()
enricher as below, under the invoke operation, for complete details, please refer to ScopedSerilogSpecificLoggingMiddleware.cs
in the sample application. Nest as many as usings for additional propertiesusing(LogContext.PushProperty("CorrelationID", correlationId, true))
{
await next.Invoke(context);
}
Startup.cs
, under Configure
method, add the below code to use the middleware you created, at the very beginning of the request pipelineapp.UseMiddleware<ScopedSerilogSpecificLoggingMiddleware>();
ILogger<T>
in any of the classes that requires logging, and add logging statements as necessary, refer to ValuesController.cs
in the sample application for the exact implementation. Sample code snippet below.private readonly ILogger<ValuesController> logger;
public ValuesController(ILogger<ValuesController> logger)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
logger.LogInformation("Log something here......");
return new string[] { "value1", "value2" };
}
CorrelationID
is the property we set as unique identifier for a request2018-08-08 13:24:55|Information => CorrelationID:c00d1372-6b4f-402b-9666-0f93894a261e =>
RequestId:0HLFTAFDRCVND:00000001 => RequestPath:/api/values/12 =>
Scoped.logging.Serilog.Controllers.ValuesController
<PackageReference Include="Serilog.Filters.Expressions" Version="2.0.0" />
appsettings.json
, add configuration section as below. For more details on filtering, please refer to Serilog Filters Expressions. Refer to the sample for exact implementation"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "Contains(@Message, '*log to filter out*')"
}
}
]