Serilog ignoring LogLevel from Microsoft.Extension.Logging - c#

I am using NET5 ASP.NET MVC application. Application is using Serilog.AspNetCore 3.4.0 for logging
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Error"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.Console"],
"WriteTo": [
{
"Name": "Console"
}
]
}
}
Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.ConfigureLogging((hostingContext, logging) =>
{
logging.ClearProviders();
})
.UseSerilog((hostingContext, logging) =>
{
logging.ReadFrom.Configuration(hostingContext.Configuration);
});
});
I have also tried
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.ConfigureLogging((hostingContext, logging) =>
{
logging.ClearProviders();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(hostingContext.Configuration)
.CreateLogger();
logging.AddSerilog();
});
});
Issue
My expectation is no Information log will be shown in Console since default LogLevel is Error.
However, that is not working. In console I see every request is getting logged including Information
Throughout my application I am using Microsoft.Extensions.Logging.ILogger<MyClassName> to log information. All those statements are actually logging Info even if the LogLevel is Error.
Looks like Serilog ignoring LogLevel from Microsoft.Extensions.Logging.
Note that, I can set serilog's restrictedToMinimumLevel property to Error and that stops logging information. However I think serilog should obey the LogLevel from Microsoft.Extension.Logging

Use MinimumLevel property:
"Logging": {
"MinimumLevel": {
"Default": "Error"
}
}
Also it supports overrides for categories:
"Logging": {
"MinimumLevel": {
"Default": "Error",
"Override": {
"System": "Information",
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore": "Debug"
}
}
}

If you check the project's Github page it advises to actually remove the standard "Logging" section in appsettings.json :-(
I think this is bad since it actually breaks the compatibility with Microsoft.Extensions.Logging framework (you can't anymore change the actual log provider (Log4Net, NLog, Serilog) without changing the appsettings.json).

If you use Serilog.Extensions.Logging and AddSerilog() on ILoggingBuilder, you'll get what you're expecting.
However, IHostBuilder.UseSerilog() (provided by Serilog.Extensions.Hosting, via Serilog.AspNetCore) is almost always a better choice, hence that's what all the Serilog docs show.
Although it seems more "integrated" to use the default configuration section this way, what you're getting behind the scenes is actually two different logging frameworks running at the same time, e.g. in the AddSerilog() case (or in the default NLog configuration):
ILogger<T> -->
MEL (routing, configuration, levels, filters) -->
Serilog (routing, configuration, levels, filters)
Logging is supposed to be very predictable/reliable and lightweight. Having two logging frameworks running at the same time erodes this and creates problems where the levels and filters specified for one framework don't match the other. (E.g. Debug and trace logs not printed when using Nlog and ILoggerFactory in .NetCore console app).
In the UseSerilog() case, (and when NLog's ReplaceLoggerFactory option is specified - mentioned in a comment on the SO thread above), you get:
ILogger<T> -->
Serilog (routing, configuration, levels, filters)
You give up support for the default "Logging" configuration section, but in exchange, you get rid of a whole logging framework at runtime, and all of your Serilog (or NLog) configuration just works, with the Microsoft.Extensions.Logging ILogger<T> available to your application code and the framework.

Related

What's the proper way to configure Serilog in a .NET Core 6.0 Razor page application?

I'm trying to configure Serilog to work with a .NET 6 Razor page web application. I've tried following the aspnetcore directions here and applicationinsights here. Nothing I try seems to work. I see my enricher being hit but nothing is written to application insights.
The program.cs files looks like this:
using AppInsightsSerilogCustomDimensions;
using Microsoft.ApplicationInsights.Extensibility;
using Serilog;
Log.Logger = new LoggerConfiguration()
.Enrich.With<SystemInfoEnricher>()
.WriteTo.ApplicationInsights(TelemetryConfiguration.Active, TelemetryConverter.Traces)
.CreateBootstrapLogger();
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.With<SystemInfoEnricher>()
.WriteTo.ApplicationInsights(TelemetryConfiguration.Active, TelemetryConverter.Traces));
// Error: No service for type 'Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration' has been registered.
//builder.Host.UseSerilog((context, services, configuration) => configuration
// .ReadFrom.Configuration(context.Configuration)
// .ReadFrom.Services(services)
// .Enrich.With<SystemInfoEnricher>()
// .WriteTo.ApplicationInsights(services.GetRequiredService<TelemetryConfiguration>(), TelemetryConverter.Traces));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
I've configured my appsettings.json file according to the Microsoft docs here, but threw in an InstrumentationKey as well just in case that would help.
{
"ApplicationInsights": {
"InstrumentationKey": "--I put the key here--",
"ConnectionString": "---I put a connection string here---"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Information"
}
},
"AllowedHosts": "*"
}
I've been banging my head against this for 3 hours now and it just doesn't work. I've been able to configure application insight WITHOUT Serilog in the application and it logged to the Application Insights resource, but I just can't get it to work WITH Serilog.
I suspect it has something to do with the instrumentation key not being read since I see error No service for type 'Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration' when I uncomment the code in program.cs.
Any help would be appreciated.
Your Instrumentation key is not configured properly.
Refer the below workaround
Make sure you have below Nuget packages installed are updated
Serilog.Settings.Configuration
Serilog.AspNetCore
Serilog.Sinks.ApplicationInsights
Microsoft.ApplicationInsights.AspNetCore
Program.cs
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
.WriteTo.ApplicationInsights(TelemetryConfiguration.Active, TelemetryConverter.Traces)
);
Output :
References taken from :
Serilog.AspNetCore

Trouble getting Serilog to read appsettings.json settings

I have the following code in my console application.
// Build configuration
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(ApplicationInfo.DataPath)
.AddJsonFile("appsettings.json", false, false)
.Build();
// Configure Serilog
string logFormat = "[{Timestamp:yyyy-MM-dd hh:mm:ss tt}][{Level:u3}] {Message:lj}{NewLine}{Exception}";
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.WriteTo.Console(LogEventLevel.Verbose, logFormat)
.WriteTo.File(ApplicationInfo.GetDataFileName("log"), LogEventLevel.Verbose, logFormat)
.CreateLogger();
AppHost = Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureServices((context, services) =>
{
services.AddDbContext<TTApplicationDbContext>(options =>
{
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
});
services.Configure<EmailSettings>(configuration.GetSection("EmailSettings"));
services.Configure<SftpSettings>(configuration.GetSection("FtpSettings"));
})
.Build();
This seems to be working. However, when I add the following section to my appsettings.json file, I do not get any of the verbose logging from within the framework. All I get is the logging that I specifically log in my application.
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Information",
"System": "Information"
}
}
}
As best I can tell, Serilog is ignoring these settings. How can I change that?
Update:
If I change the Default value to Debug in appsettings.json, that does in fact control whether or not my own calls to LogDebug() show up. But I don't understand why none of Microsoft's logging shows up. Wouldn't Microsoft's code use whatever logger is configured?
While configuring a DotNet Core App, I had the same problem. I found that if I added the Nuget Package serilog-extensions-hosting, it will also start outputting the framework messages to the logs.
https://github.com/serilog/serilog-extensions-hosting
I hope this helps

Serilog not loading configuration?

I just got started with Serilog. I started out a very simple configuration, but I can't confirm it's loaded...maybe I am not looking into the right place?
appsettings (snippet):
"Serilog": {
"Using": [ "Serilog", "Serilog.Sinks.Console", "Serilog.Sinks.EventLog" ],
"MinimumLevel": {
"Default": "Debug"
}
program.cs
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(
(hostingContext, config) =>
configureConfiguration(hostingContext, config))
.UseSerilog(
(hostingContext, config) =>
configureSeriLog(hostingContext, config));
// local function
void configureSeriLog(HostBuilderContext cntxt, LoggerConfiguration builder)
{
builder.ReadFrom
.Configuration(cntxt.Configuration);
}
I set a breakpoint at the ReadFrom.Configuration() call. After the call is made, I look at the non-Public members _minimumLevel under the builder variable and it says Information. Am I looking at the wrong spot or the configuration wasn't loaded. Thanks a million!
To diagnose issues, you can try using the SelfLog
Serilog.Debugging.SelfLog.Enable(x => Debug.WriteLine(x));
Debugging and Diagnostics
When Serilog is not behaving as you expect, this may be caused by an
internal exception or configuration issue. Here are a couple of ways
to sort things out.
...

ASP.NET Core ILogger does not log to Trace unless a debugger is attached

I am having a weird situation where I cannot receive any Trace from ASP.NET Core ILogger<T> unless a debugger is attached (even if I am running in Debug configuration). First let me explain:
I need to write logs to files by date, and I previously wrote a simple custom TraceListener for that, so I think I can reuse it without writing new Log Provider:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddTraceSource("IISLogCleaner");
// I added below line to make sure I am not missing anything
logging.SetMinimumLevel(LogLevel.Trace);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
In Startup.ConfigureServices(), I add the listener:
var listener = new DailyTraceListener(folder);
Trace.Listeners.Add(listener);
Now for the logging background task:
ILogger<CleanupTask> logger;
public CleanupTask(ILogger<CleanupTask> logger)
{
this.logger = logger;
}
// ...
async Task<int> WorkAsync(CancellationToken token)
{
System.Diagnostics.Debug.WriteLine("Start Working");
this.logger.LogInformation("Start working");
await Task.Delay(1000);
this.logger.LogInformation("Work finished");
return await Task.FromResult(10000);
}
Here's the problem: with debugger attached, all the logs are written to log file. However, when I choose to Run without Debugging, even in Debug configuration, no file is created, no content is written, until I added the Debug.WriteLine calls, now only these lines get logged, but all the logger.LogInformation() are not recorded.
The Output window however, receive all the messages:
To be safe, I have deleted the appsettings.Development.json file and only appsettings.json remains. Here is the Log content:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
Ages later, I know but I believe you are hitting this:
ASP.Net Core Logging and DebugView.exe
I spent 3 hours on this one today and feel your paint
TL;DR: Debugger.IsAttached is checked within Microsoft.Extensions.Logging.Debug.

What does MinimumLevel and Override mean in appsettings.json logging context?

I am looking at the appsettings.json from Serilog sample project, which has the following snippet:
"MinimumLevel": {
"Default": "Debug",
"Override": {
"System": "Information",
"Microsoft": "Information"
}
}
In this context, what is the purpose of Override? The System and Microsoft entries don't have a parent setting in the MinimumLevel node, so what is it overriding?
Unless I am completely misunderstanding the purpose of Override.
By default, you're saying any log entry that is severity "Debug" or higher should be sent to your sink(s) (console, file, etc).
This is similar behavior to Microsoft's document on logging:
For example, logging configuration is commonly provided by the Logging section of app settings files. The following example shows the contents of a typical appsettings.Development.json file:
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
"Console": {
"IncludeScopes": true
}
}
}
[...]
The LogLevel property under Logging specifies the minimum level to log for selected categories. In the example, System and Microsoft categories log at Information level, and all others log at Debug level.
The override section is for changing that minimum log level for types of a given namespace. In your example that means that a log from a System.* or Microsoft.* namespace must be Information or higher to be shown.
Normally you'd want to see Debug log entries for your code, but a higher level (like Information or Warning) for "not your code", like Microsoft and System.
Instead of putting this configuration in a configuation file you could also use code:
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog((ctx, cfg) =>
{
cfg.ReadFrom.Configuration(ctx.Configuration)
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information);
})
.Build();
Code from kimsereyblog.blogspot.com
Their explanation for the process is:
From the example we saw that we can configure a default minimum level of logging .MinimumLevel.Debug(). We can also override that default for certain namespaces, for example here we set the minimum level of logging for Microsoft namespace to Information. This will prevent ASP.NET Core to log all debug logs while keeping our own debug logs.
Another explanation, from nblumhardt.com:
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.
...
The effect of the configuration above, then, is to generate events only at or above the Warning level when the logger is owned by a type in a Microsoft.* namespace.

Categories