I am setting up Serilog for a .NET 5 Worker Service, and running it locally. Everything was working as expected, then I changed the "DOTNET_ENIVORNMENT" environment variable in launchSettings.json from "Development" to "asdf" to test using appsettings.json config instead of appsettings.Development.json. Again everything worked as expected. But now that I have changed that environment variable back to "Development", Serilog is still using the settings from appsettings.json.
I set both appsettings files to be copied to output directory always.
<ItemGroup>
<Content Update="appsettings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
Here is my current launchSettings.json file.
{
"profiles": {
"MyMicroservice": {
"commandName": "Project",
"dotnetRunMessages": true,
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}
When I run the program Serilog only writes to one file, instead of 2 files and the console. However I am passing the WorkerSettings configuration to my Worker.cs class and it is getting the "TaskInterval" setting of 5 seconds from appsettings.Development.json. Why is Serilog not using config from appsettings.Development.json?
Below are my appsettings files and Program.cs file.
appsettings.Development.json - I setup Serilog settings to write to console and to 2 files. I also created a setting "TaskInterval" set to 5 seconds.
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Information",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "C:/temp/MyMicroservice/HealthCheck.txt",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}",
"rollingInterval": "Day"
}
}
],
"WriteTo:Async": {
"Name": "Async",
"Args": {
"configure": [
{
"Name": "File",
"Args": {
"path": "%TEMP%/MyMicroservice/HealthCheck.txt",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}",
"rollingInterval": "Day"
}
}
]
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
},
"WorkerSettings": {
"TaskInterval": 5000
}
}
appsettings.json - I setup Serilog settings to write to only 1 file. This time I set the "TaskInterval" setting to 10 seconds.
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Information",
"System": "Warning"
}
},
"WriteTo:Async": {
"Name": "Async",
"Args": {
"configure": [
{
"Name": "File",
"Args": {
"path": "%TEMP%/MyMicroservice/HealthCheck.txt",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}",
"rollingInterval": "Day"
}
}
]
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
},
"WorkerSettings": {
"TaskInterval": 10000
}
}
Program.cs
public static class Program
{
public static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
BuildConfig(builder);
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Build())
.CreateLogger();
try
{
Log.Information("Starting up {Service}.", nameof(MyMicroservice));
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "There was a problem starting {Service}.", nameof(MyMicroservice));
}
finally
{
Log.Information("Ending {Service}.", nameof(MyMicroservice));
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddOptions<WorkerSettings>().Bind(hostContext.Configuration.GetSection(nameof(WorkerSettings)));
//services.Configure<Settings>(hostContext.Configuration.GetSection(nameof(Settings)));
services.AddHostedService<Worker>();
})
.UseSerilog();
}
static void BuildConfig(IConfigurationBuilder builder)
{
builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"apsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production"}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
}
}
This works for me:
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var isDevelopment = environmentName == "Development";
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: isDevelopment)
.AddJsonFile($"appsettings.{environmentName}.json", true, isDevelopment)
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateBootstrapLogger();
CreateHostBuilder(args, configuration)
.Build()
.Run();
...
private static IHostBuilder CreateHostBuilder(string[] args, IConfiguration configuration) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((hostingContext, services, loggerConfiguration) =>
{
loggerConfiguration.ReadFrom.Configuration(configuration);
loggerConfiguration.ReadFrom.Services(services);
loggerConfiguration.Enrich.FromLogContext();
})
.Net6 : DOTNET_ENVIRONMENT
Package : Serilog.Settings.Configuration
var environmentName = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile($"appsettings.{environmentName}.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
Related
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'm logging events for all types (information, error, debug, etc.) in an asp.net core 3.1 project, but I need to separate logs files according to the LogLevel. errors.log file will store LogLevels such as Error, Fatal and Warning, and information.log will store LogLevels such as Information and Debug.
This is the configuration in appSettings.json file:
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"WriteTo": [
{
"Name": "Logger",
"Args": {
"configureLogger": {
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"expression": "(#Level = 'Error' or #Level = 'Fatal' or #Level = 'Warning')"
}
}
],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "Logs/errors_.log",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({SourceContext}) {Message}{NewLine}{Exception}",
"fileSizeLimitBytes": 1024000,
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
]
}
}
},
{
"Name": "Logger",
"Args": {
"configureLogger": {
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"expression": "(#Level = 'Information' or #Level = 'Debug')"
}
}
],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "Logs/information_.log",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({SourceContext}) {Message}{NewLine}{Exception}",
"fileSizeLimitBytes": 1024000,
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
]
}
}
}
],
"Enrich": [
"FromLogContext",
"WithMachineName"
],
"Properties": {
"Application": "SicotX"
}
This is the 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)
.AddJsonFile($"appsettings.{Environment.MachineName}.json", optional: true)
.AddEnvironmentVariables()
.Build();
public static void Main(string[] args)
{
var host = CreateHost(args);
// ======================================================================================================
// See configuration details in appsettings.json
// Verbose: Verbose is the noisiest level, rarely(if ever) enabled for a production app.
// Debug: Debug is used for internal system events that are not necessarily observable from the outside,
// but useful when determining how something happened.
// Information: Information events describe things happening in the system that correspond to its responsibilities
// and functions.Generally these are the observable actions the system can perform.
// Warning: When service is degraded, endangered, or may be behaving outside of its expected parameters, Warning level events are used.
// Error: When functionality is unavailable or expectations broken, an Error event is used.
// Fatal: The most critical level, Fatal events demand immediate attention.
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.CreateLogger();
try
{
Log.Logger.Information("Creating the web host ...");
host.Run();
Log.Logger.Information("Shutting down the web host ...");
}
catch (Exception e)
{
Log.Logger.Fatal(e, "A fatal error ocurred creating the web host.");
}
finally
{
Log.CloseAndFlush();
}
}
public static IHost CreateHost(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, config) =>
{
config.ClearProviders();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseSerilog()
.Build();
}
No matter if MinimunLevel/Default is "Information" or "Error", both files, information_.log and errors_.log files are created and logs are reported in both files. There's not separation of information type. Following is a part of the content of the information_log file as a sample to show that info logs and errors logs are mixed in the same file:
I log errors by using _logger.Error(...) and information by using _logger.Information(...).
How can I do to filter and log data according LogLevel in the corresponding file?.
Thanks
I've found the solution!
On one hand, I was missing the nuget package Serilog.Expressions that enables Filter args expressions.
On the other hand, latest versions of serilog use the expression #1 instead of #Level, so the filter should be like this:
"Args": {
"expression": "#l in ['Error', 'Fatal', 'Warning']"
}
Now, the type level of log is sent to the right type of file.
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