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.
I'm trying to use Serilog to log to the Log Analytics workspace from an app service, but nothing is being logged there from any of my controllers (which are taking ILogger using DI).
Is there something obvious I'm missing? The workspace shows no custom logs, and the calls to the API return everything they are expected to return.
public class Program
{
public static void Main(string[] args)
{
// The initial "bootstrap" logger is able to log errors during start-up. It's completely replaced by the
// logger configured in `UseSerilog()` below, once configuration and dependency-injection have both been
// set up successfully.
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateBootstrapLogger();
Log.Information("Starting up!");
try
{
CreateHostBuilder(args).Build().Run();
Log.Information("Stopped cleanly");
return;
}
catch (Exception ex)
{
Log.Fatal(ex, "An unhandled exception occured during bootstrapping");
return;
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Controllers
services.AddControllers().AddNewtonsoftJson();
// Web
services.AddWebRegistry(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
// Write streamlined request completion events, instead of the more verbose ones from the framework.
// To use the default framework request logging instead, remove this line and set the "Microsoft"
// level in appsettings.json to "Information".
app.UseSerilogRequestLogging();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
{
"Serilog": {
"Using": [ "Serilog.Sinks.AzureAnalytics" ],
"MinimumLevel": "Debug",
"Override": {
"System": "Information",
"Microsoft": "Information",
"Microsoft.AspNetCore.Authentication": "Information",
"Microsoft.AspNetCore.SignalR": "Debug",
"Microsoft.AspNetCore.Http.Connections": "Debug"
},
"WriteTo": [
{
"Name": "AzureAnalytics",
"Args": {
"logName": "devlog",
"authenticationId": "secret",
"workspaceId": "secret"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithThreadName", "WithEventType" ]
},
I think you're missing the package to sink logs from Serilog to Log Analytics:
Add the following packages:
Serilog.AspNetCore
Serilog.Sinks.AzureAnalytics
then:
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.AzureAnalytics(workspaceId: "WORKSPACE ID",
authenticationId: "PRIMARY KEY")
.CreateLogger();
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog();
var logger = new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).Enrich.FromLogContext()
.CreateLogger();
builder.Logging.ClearProviders();
builder.Logging.AddSerilog(logger);
This is my config file
"Serilog": {
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.AzureAnalytics" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"SerilogTest": "Debug",
"Microsoft.AspNetCore": "Warning",
"Microsoft": "Warning"
}
},
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "../logs/webapi-.log",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3} {Username} {Message:lj}{Exception}{NewLine}"
}
},
{
"Name": "AzureAnalytics",
"Args": {
"logName": "mycustomtablename",
"authenticationId": "xxxxxxx",
"workspaceId": "xxxxxx",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3} {Username} {Message:lj}{Exception}{NewLine}"
}
}
]
}
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.
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
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?