ASP.NET Core logging with Serilog - c#

I am trying to understand why my application does not log the same number of informations when executed from visual studio and/or under IIS.
This is my startup code (constructor) related to logging:
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration( Configuration )
.CreateLogger();
and then in Configure method
public void Configure( IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory ) {
loggerFactory.AddSerilog();
}
here finally you can find an extract of the appsettings.json configuration file
"Serilog": {
"Using": [ "Serilog.Sinks.RollingFile" ],
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"Microsoft": "Error",
"Microsoft.AspNetCore.Identity": "Debug",
"IdentityServer4": "Verbose",
"IdentityModel": "Verbose",
"System": "Warning",
"Serilog": "Verbose"
}
},
"WriteTo": [
{
"Name": "RollingFile",
"Args": {
"pathFormat": "AppLogs/logger-{Date}.log",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}",
"fileSizeLimitBytes": 16384
}
},
{
"Name": "LiterateConsole"
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": {
"Application": "Sample"
}
},
The log file is created but the information inside the file is not the same as the ones I can see in the console output.
What does I am missing?

Related

NLog 5 ignores Logging.LogLevel.Default option

I'm trying to configure NLog for a .NET 6 console app using the following appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
}
},
"NLog": {
"targets": {
"console": {
"type": "Console",
"layout": "${longdate} ${pad:padding=5:inner=${uppercase:${level}}} ${message}${onexception:inner=${newline}${exception:format=ToString}}"
}
},
"rules": [
{
"logger": "*",
"writeTo": "console",
"minLevel": "Trace"
}
]
}
}
Host.CreateDefaultBuilder(args)
.ConfigureLogging((context, logging) =>
{
var configuration = context.Configuration.GetSection("NLog");
if (!configuration.Exists())
return;
LogManager.Configuration = new NLogLoggingConfiguration(configuration);
logging.ClearProviders();
logging.AddNLog();
})
.ConfigureServices(services =>
{
services.AddHostedService<MyHostedService>();
})
.Build()
.Run();
The following code of the MyHostedService works as expected with NLog.Extensions.Logging 1.7.5 - only messages at the Information level and higher are displayed in the console.
private readonly ILogger<MyHostedService> _logger;
public MyHostedService(ILogger<MyHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogTrace("Test");
_logger.LogDebug("Test");
_logger.LogInformation("Test");
_logger.LogWarning("Test");
_logger.LogError("Test");
_logger.LogCritical("Test");
return Task.CompletedTask;
}
But if 5.2.0 is installed then it outputs all messages. What am I doing wrong? Does NLog.Extensions.Logging 5.2.0 package require additional settings to consider Logging.LogLevel.Default configuration option value?
NLog v5 includes several breaking changes where one is NLog.Extensions.Logging without any filter
You can do this:
"NLog": {
"targets": {
"console": {
"type": "Console",
"layout": "${longdate} ${pad:padding=5:inner=${uppercase:${level}}} ${message}${onexception:inner=${newline}${exception:format=ToString}}"
}
},
"rules": [
{
"logger": "*",
"finalMinLevel": "Info"
},
{
"logger": "Microsoft*",
"finalMinLevel": "Warn"
},
{
"logger": "*",
"writeTo": "console",
"minLevel": "Trace"
}
]
}
Or you can do this:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
},
"NLog": {
"RemoveLoggerFactoryFilter": false
}
},
"NLog": {
"targets": {
"console": {
"type": "Console"
}
},
"rules": [
{
"logger": "*",
"writeTo": "console",
"minLevel": "Trace"
}
]
}
}
See also: https://github.com/NLog/NLog.Extensions.Logging/wiki/NLog-configuration-with-appsettings.json

Serilog configuration read depending on the Environment variable in Worker service in .Net 5

I have different configurations for Serilog based on the Environment variable. And they are written in the appsettings.json and appsetting.Development.json. My problem is when configuring logger it does not read from the appsettings.Development.json even in Development mode.
I've tried to configure it like this,
.ConfigureAppConfiguration((w, c) =>
{
var env = w.HostingEnvironment;
if (env.EnvironmentName == "Development")
{
c.AddCustomJsonFile($"appsettings.{env.EnvironmentName}.json");
}
else
{
c.AddCustomJsonFile($"appsettings.json");
}
})
.ConfigureServices((hostContext, services) =>
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(hostContext.Configuration)
.CreateLogger();
}).UseSerilog();
And my appsettings.json is like this,
"Serilog": {
"MinimumLevel": {
"Defult": "Information",
"Override": {
"Micorsoft": "Warning",
"System": "Information"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "Seq",
"Args": {
"serverUrl": "http://localhost:5341/"
}
}
]
And in appsetting.Development.json,
"Serilog": {
"MinimumLevel": {
"Defult": "Debug",
"Override": {
"Micorsoft": "Warning",
"System": "Information"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "Seq",
"Args": {
"serverUrl": "http://localhost:5341/"
}
}
]
I've tested it with other services where it uses the correct appsettings based on the environment variable, Just Serilog is having problems with this. Does anybody know how to solve this?
Thanks in advance.

How do I configure serilog-sinks-slack in appsettings.json

I am trying to configure serilog on my asp.net core application and I can set it up using the startup configuration, but I cannot do it on appsettings.json.
When I do:
I am using this sink:
https://github.com/mgibas/serilog-sinks-slack
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
Logger log = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Slack(new SlackSinkOptions()
{
WebHookUrl = "https://hooks.slack.com/services/xxx/yyy/zzz",
CustomChannel = "#myuser"
}).CreateLogger();
loggerFactory.AddSerilog(log);
It works fine and I can see the messages in my slack channel.
Then I try to bring it in my app settings so I change it to this:
Logger log = new LoggerConfiguration()
.MinimumLevel.Verbose()
.ReadFrom.Configuration(Configuration)
.CreateLogger();
and with the appconfig:
{
"Serilog": {
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "Slack",
"SlackSinkOptions":
{
"WebHookUrl": "https://hooks.slack.com/services/xxx/yyy/zzz",
"CustomChannel": "#myuser"
}
}
]
},
"AllowedHosts": "*"
}
But it doesn't write anything in slack. I've also tried:
{
"Serilog": {
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "Slack",
"WebHookUrl": "https://hooks.slack.com/services/xxx/yyy/zzz",
"CustomChannel": "#myuser"
}
]
},
"AllowedHosts": "*"
}
Any clue what is worng with my config/setup?
Ah! I should have used Args instead of Options as Hugo mentioned in the comments
{
"Serilog": {
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "Slack",
"Args":
{
"WebHookUrl": "https://hooks.slack.com/services/xxx/yyy/zzz",
"CustomChannel": "#myuser"
}
}
]
},
"AllowedHosts": "*"
}

Serilog not writing to File (.net core 2.2)

I am writing a web service that is using Serilog. I was having problems getting files to write out (but console logging worked). I noticed that the setup changed when .net core 2.0 came out based on this and this pages' explanation.
However, now, I can't see any logging (perhaps in the past the default M$ loggers were actually what I was seeing).
Here's how program.cs is set up:
public class Program
{
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.AddUserSecrets<Startup>()
.Build();
public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration.GetSection("Serilog"))
.CreateLogger();
try
{
Log.Information("Starting webhost...");
BuildWebHost(args).Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseConfiguration(Configuration)
.UseSerilog()
.Build();
}
My appsettings.json has this section in the root:
"Serilog": {
"Using" : ["Serilog.Sinks.Console", "Serilog.Sinks.File"],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
},
"Enrich" : ["FromLogContext"],
"WriteTo": [
{"Name": "Console" },
{"Name": "Debug" },
{"Name": "File", "Args": {"path": "%LogDir%\\sampleapp\\log-{Date}.txt", "rollingInterval": "Day", "shared": true } }
]
},
"Properties": {
"Application": "sampleapp"
}
},
Note that %LogDir% is an environment variable on my machine and resolves fine in other applications. The path is already created and the Logs folder has full RW permissions for the credentials this app uses.
I call logging like so...
private readonly ILogger<PartnerController> _logger;
private readonly IPartnerDao _partnerDao;
public PartnerController(ILogger<PartnerController> logger, IPartnerDao partnerDao)
{
_logger = logger;
_partnerDao = partnerDao;
}
[HttpGet]
[Route("{titleCode}")]
public async Task<IActionResult> Get(string titleCode)
{
_logger.LogInformation("Test logging");
}
Yet, somehow nothing shows in the ASP.NET Core Web Server window and not file is created on my machine when running the service.
Am I missing something obvious?
Turns out I had copied some of the JSON from documentation incorrectly. It's hard to tell but in the original question I actually had Enrich, WriteTo, and Properties sections embedded within the MinimumLevel section.
Obviously this prevented Serilog from correctly knowing which Sinks to write to.
Here's my corrected settings JSON:
"Serilog": {
"Using": ["Serilog.Sinks.Console", "Serilog.Sinks.File"],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": ["FromLogContext"],
"WriteTo": [
{ "Name": "Console" },
{ "Name": "Debug" },
{
"Name": "File",
"Args": {
"path": "%LogDir%\\sampleapp\\log-.txt",
"rollingInterval": "Day",
"shared": true
}
}
],
"Properties": {
"Application": "sampleapp"
}
},
Note that I also removed the {Date} from the filename. Apparently it'll tack that on if you set the rolling interval to day....
appsettings.Development.json overwrite settings in appsettings.json
I repeat again, configuration in appsettings.Development.json will take precedence over appsettings.json. I know that sounds obvious but I bet someone could overlook this in the future just like I did.
I spent nearly an hour scratching my head why no log was being written to the file, only to notice later I had only Console sink in my appsettings.Development.json (effectively removing my File sink in appsettings.json duh!).
Here is a sample of a proper configuration (modify according to your needs):
ASP.NET Core 3.1
Program.cs
using Microsoft.AspNetCore.Hosting;
using Serilog;
using System;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog.Core;
namespace My.App
{
public class Program
{
private static bool IsDevelopment =>
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true)
.AddEnvironmentVariables()
.Build();
public static Logger Logger { get; } = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext()
.CreateLogger();
public static int Main(string[] args)
{
Log.Logger = Logger;
try
{
Log.Information("Starting...");
var host = CreateHostBuilder(args).Build();
host.Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
.UseSerilog()
.UseServiceProviderFactory(
new AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>();
});
return host;
}
}
}
ASP.NET Core 2.2
Program.cs
public class Program
{
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddEnvironmentVariables()
.Build();
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext()
.CreateLogger();
try
{
Log.Information("Starting...");
CreateWebHostBuilder(args).Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHost CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog()
.Build();
}
appsettings.json
{
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
}
}
appsettings.Development.json
{
"Serilog": {
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "Console"
},
{
"Name": "Debug"
},
{
"Name": "DiagnosticTrace"
},
{
"Name": "File",
"Args": {
"path": "/home/log/api-log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"buffered": true
}
}
]
}
}
]
}
}
appsettings.Production.json
{
"Serilog": {
"MinimumLevel": {
"Default": "Information"
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "ApplicationInsights",
"Args": {
"restrictedToMinimumLevel": "Information",
"telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
}
},
{
"Name": "Email",
"Args": {
"EmailConnectionInfo": {
"EmailSubject": "PRODUCTION error logs",
"FromEmail": "xxxxxxx",
"ToEmail": "xxxxxxx",
"MailServer": "xxxx",
"NetworkCredentials": {
"username": "xxxxxx",
"password": "xxxxxx",
"domain": "xxxxx"
},
"Port": 25
},
"restrictedToMinimumLevel": "Error"
}
},
{
"Name": "File",
"Args": {
"path": "/home/log/api-log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 15,
"buffered": true
}
}
]
}
}
]
}
}
Here's my corrected settings JSON:
In Startup class:
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config)
.Enrich.With<EventTypeEnricher>()
.CreateLogger();
In appsettings.json
{
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
"Serilog.Sinks.Seq",
"Serilog.Sinks.Async",
"Serilog.Sinks.File",
"Serilog.Sinks.Debug"
],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [
"FromLogContext",
"WithMachineName"
],
"Properties": {
"ApplicationName": "AppSim Crawler"
},
"WriteTo": [
{
"Name": "Seq",
"Args": {
"serverUrl": "http://localhost:5341",
"apiKey": "none"
}
},
{
"Name": "Debug",
"Args": {
"outputTemplate": "{Timestamp:dd-MM-yyyy HH:mm:ss.fff} [{EventType:x8} {Level:u3}] <s:[{SourceContext}]> <method:[{FileName} > {MemberName}]>{NewLine}at {FilePath}:{LineNumber}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
}
},
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"outputTemplate": "{Timestamp:dd-MM-yyyy HH:mm:ss.fff} [{EventType:x8} {Level:u3}] <c:[%COMPUTERNAME%]> <s:[{SourceContext}]> <method:[{FileName} > {MemberName}]>{NewLine}at {FilePath}:{LineNumber}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
}
}
]
}
},
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "File",
"Args": {
"path": "C:/appsim/logs/appSimCrawler.log",
"outputTemplate": "{Timestamp:dd-MM-yyyy HH:mm:ss.fff} [{EventType:x8} {Level:u3}] <s:[{SourceContext}]> <method:[{FileName} > {MemberName}]>{NewLine}at {FilePath}:{LineNumber}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
"rollingInterval": "Day",
"retainedFileCountLimit": 30,
"shared": true,
"rollOnFileSizeLimit": true
}
}
]
}
}
]
}
}
For me, serilog did not write to log file because I was missing one of the many nuget packages (Serilog.Sinks.Async). So besides making sure that your config in appsettings.json is correct - and that you are using the right file for dev vs prod, also:
I recommend looking at the documentation, or tutorial, again and make sure you add every nuget package that it says in the instructions.

Serilog ASP.NET Core appsettings config for syslog

I am trying to configure Serilog using the appsettings.json config file in an ASP.NET Core web application. I have managed to get the RollingFile config section to work, but I am also trying to send log information to another online log tool (e.g. logentries or papertrail)
I have the following Nuget packages installed:
Serilog.AspNetCore
Serilog.Settings.Configuration
Serilog.Sinks.Async
Serilog.Sinks.RollingFile
Serilog.Sinks.SyslogMessages
I have then put the following configuration in my appsettings.json file:
"Serilog": {
"Using": [ "Serilog.Sinks.Async", "Serilog.Sinks.Syslog", "Serilog.Sinks.RollingFile" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Error"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "RollingFile",
"Args": {
"outputTemplate": "[{Timestamp:MMM dd HH:mm:ss}] {Level:u3} {Message:lj} <s:{SourceContext}>{NewLine}{Exception}",
"pathFormat": "C:\\LogFiles\\Application\\{Date}.log",
"fileSizeLimitBytes": 5000000,
"retainedFileCountLimit": null
}
},
{
"Name": "Syslog",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} <s:{SourceContext}>{NewLine}{Exception}",
"host": "logs.papertrailapp.com",
"port": 12345,
"format": "RFC5424",
"secureProtocols": "SecureProtocols.None",
"appName": "Application",
"facility": "Local7"
}
}
]
}
}
]
}
My C# code to set the logger is:
public static void Main(string[] args)
{
var currentEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{currentEnv}.json", true)
.AddEnvironmentVariables()
.Build();
Log.Logger =
new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
try
{
Log.Information("Starting web host");
CreateWebHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
Log.Fatal(exception, "Host terminated unexpectedly");
throw;
}
finally
{
Log.CloseAndFlush();
}
}
Am I missing something from the Syslog config block?
When configuring Serilog using the IConfiguration approach, the Name value is not necessarily the name of the sink itself. For Serilog.Sinks.RollingFile, it is simply RollingFile, but for Serilog.Sinks.Syslog, you actually have three options:
UdpSyslog
TcpSyslog
LocalSyslog
I find the best way to discover these options is to look at the docs for the code-based configuration. e.g. for Serilog.Sinks.Syslog, the examples are:
.WriteTo.UdpSyslog
.WriteTo.TcpSyslog
.WriteTo.LocalSyslog

Categories

Resources