Serilog not getting application events, only coded logger events - c#

I set up my application to use Serilog as the logging mechanism. And I do in fact get log files and can view them on Seq. Initially I was getting the application events logged, but for some reason I am no longer getting them. See the images below.
In the first image I am getting application events. Later, when doing the same testing operations, I am NOT getting the application events any more, only the coded events in the files (i.e. _logger.LogWarning("Warning");)
I set up Serilog in Main method.
public static int Main(string[] args)
{
var currentEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{currentEnv}.json", optional: true)
.AddEnvironmentVariables()
.Build();
//Configure logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
Log.Information("Logger created");
try
{
Log.Information("Starting web host");
BuildWebHost(args).Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Web Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
My Serilog settings
"Serilog": {
"Using": [
"Serilog.Sinks.RollingFile",
"Serilog.Sinks.Async",
"Serilog.Sinks.ApplicationInsights",
"Serilog.Sinks.Console",
"Serilog.Sinks.Seq"
],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "RollingFile",
"Args": { "pathFormat": "C:/Logs/Serilog/log-{Date}.log" }
},
{
"Name": "Seq",
"Args": { "serverUrl": "http://localhost:5341" }
}
]
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": {
"Application": "WebTemplate"
}
}
Before I move on to making Serilog more functional, I would like to sort out why I am not getting application events any longer.

I expect this is down to the following section in your Serilog settings:
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning"
}
}
Nicholas Blumhardt's blog post goes into detail about how the Override setting works:
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.
This quote seems to apply directly to your situation, whereby you are asking Serilog to filter out any events that belong to the Microsoft.* namespace and are lower than a severity of Warning.
The messages you show in your first screenshot are coming from either MVC or Entity Framework, which live in the Microsoft.* namespace and will be logging at a lower severity than warning.

It looks like you are missing UseSerilog() in BuildWebHost():
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseSerilog() // <- Add this line
.UseStartup<Startup>()
.Build();
This assumes you have the Serilog.AspNetCore NuGet package installed.

Related

How to switch between Serilog and another logger in .Net Core through configuration?

I need to be able to switch between Serilog and another logger, MyLog. Currently I am switching by comment/uncomment code as the following:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
//// === to switch between Serilog and MyLogger comment/uncomment code below ===
//.UseSerilog((hostContext, loggerConfig) =>
// loggerConfig.ReadFrom.Configuration(hostContext.Configuration));
.ConfigureLogging((hostBuilderContext, logging) =>
{
logging.AddMyLogger(options =>
{
hostBuilderContext.Configuration.GetSection(MyLoggerOptions.LogOptions).Bind(options);
});
});
}
This works, but I prefer to make it controlled by a appsettings.json setting, say, Logger. So here is my appsettings.json file:
{
"Logger": "Serilog", // Use Serilog or MyLog
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Grpc": "Information",
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Information"
},
"MyLog": {
"Options": {
"FolderPath": "logs",
"FilePath": "Svr_{date}.log"
},
"LogLevel": {
"Default": "Information",
"Microsoft": "Error",
"Microsoft.Hosting.Lifetime": "Error"
}
}
},
"Serilog": {
"MinimumLevel": "Verbose",
"Override": {
"Microsoft.AspNetCore": "Warning"
},
"WriteTo": [
{
"Name": "Console "
},
{
"Name": "File",
"Args": {
"path": "Logs\\Serilog_Server-.log",
"formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
"rollingInterval": "Day"
}
}
]
}
}
and here is the code where I try to set log depending on the Loger setting:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging((hostBuilderContext, logging) =>
{
string loger = hostBuilderContext.Configuration.GetValue<String>("Logger");
if (loger == "MyLog")
{
logging.AddMyLogger(options =>
{
hostBuilderContext.Configuration.GetSection(MyLoggerOptions.LogOptions).Bind(options);
});
}
else if (loger == "Serilog")
{
logging.AddSerilog(); // here is the problem. Serilog doesn't write.
}
});
The problem of this code is the Serilog (MyLog is fine) - it doesn't write at all. My guess is that, since I don't have a way to pass in the configuration object, it might not get configured properly. But how do I fix it? or is there a better way to do this?
UPDATE
Tried what Camilo suggested as the following with an error. How do I get the configuration object from here?

Serilog not logging to Sentry levels different than Error

I want log to sentry.io Information log level using serilog.
In appsettings.json I made this config:
"Sentry": {
"Dsn": "url",
"MaxRequestBodySize": "Always",
"SendDefaultPii": true,
"IncludeActivityData": true,
"AttachStackTrace": true,
"Debug": true,
"DiagnosticLevel": "Info"
},
"Serilog": {
"Using": [
"Serilog.Sinks.Console"
],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Error",
"Microsoft.EntityFrameworkCore.Database.Command": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.SystemConsoleTheme::Literate, Serilog.Sinks.Console",
"outputTemplate": "[{Timestamp:HH:mm:ss} {Properties} {SourceContext} [{Level}] {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "Sentry",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.SystemConsoleTheme::Literate, Serilog.Sinks.Console",
"outputTemplate": "[{Timestamp:HH:mm:ss} {Properties} {SourceContext} [{Level}] {Message:lj}{NewLine}{Exception}"
}
}
],
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithThreadId",
"WithHtpContextData",
"WithExceptionDetails"
]
}
I registered serilog and sentry into my Program.cs class:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseSentry();
})
.UseSerilog((hostingContext, loggerConfig) => loggerConfig.ReadFrom.Configuration(hostingContext.Configuration));
In my class i make code like this:
using System.Threading.Tasks;
using Quartz;
using Serilog;
//
private readonly ILogger _logger;
public QueuedJob(ILogger logger)
{
_logger = logger;
}
public Task Execute(IJobExecutionContext context)
{
_logger.Information("Hello World!");
return Task.CompletedTask;
}
Why from this configuration in sentry.io portal i see only logs that i logged as Error level? Why i cant log into sentry.io Information level? All levels of logs are printed to my console but only Errors are printed into console and sentry.io
By default, the Sentry Serilog integration only sends events for log level Error or higher.
For Info logs, the SDK keeps a ring buffer so when an error happens all related logs are included with that event.
This can be configured though, you can send everything (Debug or higher for example): https://docs.sentry.io/platforms/dotnet/guides/serilog/#configuration
In fact, I use this exact setup on NuGet Trends to capture any Warning or higher as event, and include any Debug or higher as breadcrumb:
Here's the configuration:
https://github.com/dotnet/nuget-trends/blob/dac67d1bd4707a94063b843571127eb055a4cc4f/src/NuGetTrends.Scheduler/appsettings.Production.json#L33-L34

OrchardCore loading within Program.cs, is it possible?

All the examples of OrchardCore show embedding within the startup.cs file but is there a way to load it earlier within the Program.cs? I'm trying to setup a module for Serilog so I can just drop it into my projects but maybe this isn't even possible, I don't know.
I got an answer on OrchardCore's github repo found here
EDIT
Later I realized this didn't really answer my question but oh well. Leaving this answer here in case it fits someone's needs.
Here is the setup:
add a reference to OrchardCore.Logging.Serilog
add serilog configuration in appsettings.json
"Serilog": {
"MinimumLevel": {
"Default": "Warning",
"Override": {
"Default": "Warning",
"Microsoft": "Error",
"System": "Error"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"outputTemplate": "{Timestamp:HH:mm:ss}|{TenantName}|{RequestId}|{SourceContext}|{Level:u3}|{Message:lj}{NewLine}{Exception}",
"restrictedToMinimumLevel": "Information"
}
},
{
"Name": "RollingFile",
"Args": {
"pathFormat": "app_data/logs/orchard-log-{Date}.txt",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.ffff}|{TenantName}|{RequestId}|{SourceContext}|{Level:u3}|{Message:lj}{NewLine}{Exception}",
"restrictedToMinimumLevel": "Warning"
}
}
]
}
Modify program.cs to use Serilog
public static IWebHost BuildWebHost(string[] args)
=> WebHost.CreateDefaultBuilder(args)
.UseSerilogWeb()
.UseStartup<Startup>()
.Build();
Modify startup.cs to include TenantName in LogContext
using OrchardCore.Logging;
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseOrchardCore(c => c.UseSerilogTenantNameLoggingMiddleware());
}

appSetting.Development.json not injected during Debug on ASP.Net Core App

I have the following in my appSetting.json;
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"MailServiceSettings": {
"SmtpServer": "<server>",
"ToAddresses": [
"email#domain.com",
"email2#domain.com"
],
"UserName": "username",
"Password": "password"
}
}
and in appSettings.Development.json i have a subtle change;
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"MailServiceSettings": {
"SmtpServer": "<server>",
"ToAddresses": [
"development#domain.com"
],
"UserName": "username",
"Password": "password"
}
}
This is so I can text the mail sender settings in my localhost without bombarding the live mailbox.
However, when I run in debug the settings from appSettings.json are being injected insted of the appSettings.Development.json.
My Program.cs is using the default WebHostBuilder;
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args)
.Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
}
and setup the DI as following in my StartUp.cs;
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.Configure<MailServiceSettings>(Configuration.GetSection("MailServiceSettings"));
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
Then when I debug and break on the configuration I can see that the appSettings.Development.json have been read (as I can drill down into the Configuration sections when debugging I can see they are added as an additional entry, and I believe WebHost.CreateDefaultbuilder adds the env.EnvironmentName files by default).
However, when I then instantiate an controller method;
public ContactController(IOptions<MailServiceSettings> mailSettings, IHostingEnvironment hostingEnvironment)
{
_mailSettings = mailSettings;
_hostingEnvironment = hostingEnvironment;
}
I am finding that the 2x email address from the appSettings.json are injected instead of the appSettings.Development.json
I have also checked env.IsDevelopment() at runtime and this is returning true.
Can anyone tell me what I am doing wrong here?
I'm having trouble tracking down and official source for this, but essentially the issue is that IConfiguration is basically a dictionary and the keys and values from configuration sources are flattened into that. In other words, at the end of the day, what you're actually getting is something like the following in pseudo-code:
["MailServiceSettings:ToAddresses[0]"] = "email#domain.com"
["MailServiceSettings:ToAddresses[1]"] = "email2#domain.com"
Then, when your appsettings.Development.json config comes in:
["MailServiceSettings:ToAddresses[0]"] = "development#domain.com"
In other words, you still have two items in the config. The only way around this is to have settings like this only in your environment-specific config. If you remove this from appsettings.json entirely and then do:
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"MailServiceSettings": {
"SmtpServer": "<server>",
"UserName": "username",
"Password": "password"
}
}
appsettings.Development.json
{
"MailServiceSettings": {
"ToAddresses": [
"development#domain.com"
]
}
}
appsettings.Production.json
{
"MailServiceSettings": {
"ToAddresses": [
"email#domain.com",
"email2#domain.com"
]
}
}
Then, you'll correctly only have the one address in development and the two in production.

asp.net core - Set Serilog.Exceptions from appsettings.json

I need to use Serilog.Exceptions package to catch exceptions.
Serilog is read from appsettings.json
{
"Serilog": {
"Using": [
"Serilog.Sinks.RollingFile",
"Serilog.Sinks.Seq"
],
"WriteTo": [
{
"Name": "RollingFile",
"Args": {
"restrictedToMinimumLevel": "Debug",
"pathFormat": "myPath\\log-{Date}.log"
}
},
{
"Name": "RollingFile",
"Args": {
"restrictedToMinimumLevel": "Error",
"pathFormat": "myPath\\error-{Date}.log"
}
},
{
"Name": "Seq",
"Args": {
"serverUrl": "myUrl",
"apiKey": "myApiKey"
}
}
],
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithThreadId"
],
"Properties": {
"Application": "myApplicationName"
}
}
}
And in my startup.cs
var logger = new LoggerConfiguration()
.Enrich.WithExceptionDetails()
.ReadFrom.Configuration(Configuration)
.CreateLogger();
Log.Logger = logger;
But it doesn't work. Do I need to add some other properties in appsettings.json for Serilog.Exceptions package? Or is the appsettings.json configure correctly? What am I doing wrong?
Thanks
The following is how I setup Serilog in ASP.NET Core 2.1. You can take it as checklist and see what you have missed.
Install packages from Nuget: Serilog.AspNetCore, Serilog.Exceptions, Serilog.Settings.Configuration and other sinks you want to use.
Setup Serilog in your main program:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog((hostingContext, loggerConfiguration) =>
loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
);
}
Put WithExceptionDetails in your Serilog section in appsettings.json:
{
"Serilog": {
...
"Enrich": [
"FromLogContext",
"WithExceptionDetails"
],
...
}
}

Categories