Different Minimum Level Logs Serilog - c#

Is there a way to differentiate what level is logged between the different loggers for Serilog? I want to be able to log MinimumLevel Debug to the console output but only Warning and above to my file output. I am using ASP.NET Core 2.1 and this is what the appsetting.json currently looks like:
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "RollingFile",
"IsJson": true,
"Args": {
"pathFormat": "C:\\Logs\\Log-{Hour}.json",
"formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog"
}
},
{
"Name": "Console"
}
]
},
Is it something like another parameter under "Args"? I've tried "minimumnLevel" in this location but it did not work.

The setting you're looking for is restrictedToMinimumLevel. This GitHub issue shows some examples of this, but for your example, you just need to add restrictedToMinimumLevel to your Args for RollingFile:
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "RollingFile",
"IsJson": true,
"Args": {
"pathFormat": "C:\\Logs\\Log-{Hour}.json",
"formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
"restrictedToMinimumLevel": "Warning"
}
},
{
"Name": "Console"
}
]
},

Working from the answers above, this is how I set it up in code as opposed to config
LoggerConfiguration GetConfig()
=> new LoggerConfiguration()
.WriteTo.Seq(serverUrl: "http://localhost:5341", restrictedToMinimumLevel: LogEventLevel.Debug)
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Error);
var logger = GetConfig().CreateLogger();
builder.RegisterInstance(logger).As<ILogger>();
After I did this, it worked for log level Information and above. Debug didn't work. This post explained why.
I had to set a 'global' minimum level like this.
LoggerConfiguration GetConfig()
=> new LoggerConfiguration()
.WriteTo.Seq(serverUrl: "http://localhost:5341", restrictedToMinimumLevel: LogEventLevel.Debug)
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Error)
.MinimumLevel.Verbose();

In your configuration you have one Serilog logger, but you have 2 sinks. One of your sinks is RollingFile and the other is Console.
You can override (but only raise) the minimum logging level per sink, The argument is called restrictedToMinimumLevel.
Since you want to raise the minimum logging level from your logger's default Debug to Warning in your file sink, in your appsettings.json file, it would look like this:
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "RollingFile",
"IsJson": true,
"Args": {
"pathFormat": "C:\\Logs\\Log-{Hour}.json",
"formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
"restrictedToMinimumLevel": "Warning"
}
},
{
"Name": "Console"
}
]
},

Related

C# Serilog - ApplicationInsights - ASP.NET Core 6 - Own Exception logging with ILogger

How can i set ApplicationInsights to send Ilogger _logger messages.
Now i see every log at Console and in files, but in azure i don't see my own Logs.
I tried a lot of things and maybe the information is here:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-monitoring
But i don't find it. :(
Thanks for helping.
In Program.cs:
var _logger = new LoggerConfiguration().CreateBootstrapLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((context, services, loggerConfiguration) => loggerConfiguration
.ReadFrom
.Configuration(builder.Configuration)
.Enrich
.FromLogContext());
Bootstrap.ConfigureServices(builder.Services, builder.Configuration, builder.Environment);
var app = builder.Build();
Bootstrap.ConfigureWebApp(app);
app.Run();
In appsettings.json:
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
"Serilog.Sinks.File",
"Serilog.Sinks.ApplicationInsights"
],
"MinimumLevel": {
"Default": "Debug"
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"Path": "../Logs/MyLog-.json",
"RollingInterval": "Day",
"formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog"
}
},
{
"Name": "File",
"Args": {
"Path": "../Logs/MyLog-.log",
"RollingInterval": "Day",
//"OutputTemplate": "[({Component}|{MachineName}|{ThreadId}) {Timestamp:G} [{Level:u3}]{Message:lj}{NewLine}{Exception} ]"
}
},
{
"Name": "ApplicationInsights",
"Args": {
"ConnectionString": "[MyCONNECTIONSTRING]",
"telemetryConverter": "Serilog.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
}
}
]
},

Serilog Filtering not working in appsettings.json

I implemented Serilogger and put the configuration in the Program.cs and it worked great. I'm trying to move the configuration to appsettings.json and its writing to the logs but I can't get the filters to work now. I know its reading the config because I can change the minimum log level and I see the result in the logs.
I've been reading and rereading the Serilog pages in Github, especially the configuration page
Here is the code that worked in Program.cs
try
{
Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));
var levelSwitch = new LoggingLevelSwitch();
levelSwitch.MinimumLevel = LogEventLevel.Warning;
return new LoggerConfiguration()
.ReadFrom.Configuration(config, "Serilog");
.MinimumLevel.ControlledBy(levelSwitch)
.Enrich.FromLogContext()
.WriteTo.Debug()
.WriteTo.Logger(l => l
.Filter.ByExcluding("source = 'application'")
.WriteTo.File("Logs\\log-.txt", rollingInterval: RollingInterval.Day))
.WriteTo.Logger(l => l
.Filter.ByIncludingOnly("source='customer'")
.WriteTo.MSSqlServer(
connectionString:
"Server=(localdb)\\Infinity;Database=Infinity;Trusted_Connection=True;MultipleActiveResultSets=True;",
sqlSinkOptions));
}
Here is the new appsettings file
{
"Serilog": {
"Using": [ "Serilog.Enrichers.FromLogContext" ],
"MinimumLevel": "Warning",
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=(localdb)\\Infinity;Database=Infinity;Trusted_Connection=True;MultipleActiveResultSets=True;",
"tableName": "Log",
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"expression": "source = 'customer'"
}
}
]
}
},
{
"Name": "File",
"Args": {
"path": "Logs\\log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "source = 'customer'"
}
}
]
}
}
],
"Enrich": [ "FromLogContext" ]
},
Update: I figured out the custom property that I'm filtering on is not getting inserted into the logger object any longer. I think that has something to do with the "enricher"? But its not the source of the filter problem, because the "IncludeOnly" filter shouldn't write anything if the property isn't there, correct?
Here is a snippet from the method where I'm using PushProperty to insert the property and value. Since I haven't touched this code, I assume the problem is still in the app settings.
public void LogError(LogDestination destination, LogLevel level, string msg)
{
if (destination == LogDestination.Customer)
{
using (LogContext.PushProperty("source", "customer")) {
switch (level)
{
case LogLevel.Debug:
_logger.LogInformation(msg);
break;
I've also tried adding the .Enrich back into the LoggerConfiguration with no difference.
return new LoggerConfiguration()
.ReadFrom.Configuration(config, "Serilog")
.Enrich.FromLogContext();
Update I added a global filter at the top-level. I tried an Include Only and Exclude and both work as expected. I can't figure out why the sink filters aren't working.
{
"Serilog": {
"Using": [ "Serilog.Expressions", "Serilog.Sinks.File", "Serilog.Sinks.MSSqlServer" ],
"MinimumLevel": "Warning",
"Filter": [
{
"Name": "ByExluding",
"Args": {
"expression": "source = 'customer'"
}
}
],
I have tried using Filters instead of Filter in Appsettings file, it's working for me. But didn't see any documentation around it.
{
"Serilog": {
"Using": [ "Serilog.Expressions", "Serilog.Sinks.File", "Serilog.Sinks.MSSqlServer" ],
"MinimumLevel": "Warning",
"Filters": [
{
"Name": "ByExluding",
"Args": {
"expression": "source = 'customer'"
}
}
],

Is there a way to set Serilog formatter variables via appsettings.json?

I have the following appsettings.json configuration:
{
"Serilog": {
"Using": [],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [ "FromLogContext", "WithMachineName" ],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "C:\\Logs\\log.json",
"formatter": "Serilog.Formatting.Elasticsearch.ElasticsearchJsonFormatter, Serilog.Formatting.Elasticsearch"
}
}
]
}
}
What I am trying to configure in the above appsettings.json file would be represented in C# as something like this:
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.WriteTo.File(new ElasticsearchJsonFormatter(inlineFields:true, renderMessageTemplate: false), #"C:\logs\log.json")
.CreateLogger();
I need to set "inlineFields" equal to true and "renderMessageTemplate" equal to false as overrides in my appsettings.json file on the ElasticsearchJsonFormatter instance. Is there a way to do that in the appsettings.json file so that I can keep my configuration out of C#?
I asked this question on GitHub: https://github.com/serilog/serilog-sinks-file/issues/138
No way :(
They added this feature in Serilog.Settings.Configuration -v 3.3.0-dev-00291.
Serilog__WriteTo__Console__Name=Console
Serilog__WriteTo__Console__Args__formatter__type="Serilog.Templates.ExpressionTemplate, Serilog.Expressions"
Serilog__WriteTo__Console__Args__formatter__template="[{#t:HH:mm:ss} {#l:u3} {Coalesce(SourceContext, '<none>')}] {#m}\n{#x}"
[22:38:40 INF My.Foo.FooClient] HELLO WORLD
links
https://www.nuget.org/packages/Serilog.Settings.Configuration/3.3.0-dev-00291
https://github.com/serilog/serilog-settings-configuration/pull/281

How to config `Serilog` to write to the application directory with the cofig file?

I'm using Serilog on a .net core.
I want to config the log path to the application directory.
I see there's an extension https://github.com/serilog/serilog-settings-configuration that enable Serilog to read from Configuration.
In the example , the path is configured as "%TEMP%\\Logs\\serilog-configuration-sample.txt".
How can I set it to the working directory?
I've searched on so, and know that it can be done by code, but it seems there's no one asking how to do this by the config file, i.e. appsettings.json.
Current configuration:
{
"Serilog": {
"Using": [
"Serilog.Sinks.File"
],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "File",
"Args": { "path": "Logs\\serilog-configuration-sample.txt" }
}
],
"Enrich": [ "FromLogContext", "WithMachineName" ],
"Destructure": [
],
"Properties": {
}
},
"AllowedHosts": "*"
}
I want the log path to be set to the working directory.
But currently it's in "C:\Program Files\IIS Express".
Configuring path like Logs/log.txt will write log files under logs folder in working directory
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "Logs/log.txt"
}
}
Also you can check this answer for another option
You can add a "RollingFile" wich can write to a local path file. In this example I'm writing in a File inside of the root of my project as it shows bellow.
{
"Name": "RollingFile",
"Args": {
"pathFormat": ".\\Logs\\logs.txt",
"fileSizeLimitBytes": 1048576
}
},
Also the full json on appsettings.json end up like this (in case you need a full example)
...
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"System": "Debug",
"Microsoft": "Debug"
}
},
"WriteTo": [
{
"Name": "ApplicationInsightsEvents",
"Args": {
"instrumentationKey": "xxxxxxxxxx"
}
},
{
"Name": "RollingFile",
"Args": {
"pathFormat": ".\\Logs\\logs.txt",
"fileSizeLimitBytes": 1048576
}
},
{ "Name": "Console" },
{
"Name": "EventLog",
"Args": {
"source": "API NAME",
"logName": "CustomLog",
"restrictedToMinimumLevel": "Warning"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": {
"Application": "API NAME"
}
}
...

Filter Serilog logs to different sinks depending on context source?

I have a .NET Core 2.0 application in which I successfully use Serilog for logging. Now, I would like to log some database performance statistics to a separate sink (they are not for debugging, which basically is the purpose of all other logging in the application, so I would like to keep them separate) and figured this could be accomplished by creating the DB statistics logger with Log.ForContext<MyClass>().
I do not know how I am supposed to configure Serilog using my appsettings.json to log my "debug logs" to one sink and my DB statistics log to another? I am hoping it is possible to do something like:
"Serilog": {
"WriteTo": [
{
"Name": "RollingFile",
"pathFormat": "logs/Log-{Date}.log",
"Filter": {
"ByExcluding": "FromSource(MyClass)"
}
},
{
"Name": "RollingFile",
"pathFormat": "logs/DBStat-{Date}.log",
"Filter": {
"ByIncludingOnly": "FromSource(MyClass)"
}
}
]
}
The "Filter" parts of the configuration is pure guesswork on my part. Is this possible using my configuration filer or do I need to do this in code in my Startup.cs file?
EDIT: I have got it working using the C# API but would still like to figure it out using JSON config:
Log.Logger = new LoggerConfiguration()
.WriteTo.Logger(lc => lc
.Filter.ByExcluding(Matching.FromSource<MyClass>())
.WriteTo.LiterateConsole())
.WriteTo.Logger(lc => lc
.Filter.ByExcluding(Matching.FromSource<MyClass>())
.WriteTo.RollingFile("logs/DebugLog-{Date}.log"))
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(Matching.FromSource<MyClass>())
.WriteTo.RollingFile("logs/DBStats-{Date}.log", outputTemplate: "{Message}{NewLine}"))
.CreateLogger();
I completed this work today, and thought that I'd provide a proper answer since it took me quite a few posts, issues and other pages to work through to get this sorted out.
It's useful to have all the logs, but I also wanted to log only my API code separately, and omit the Microsoft. namespace logs. The JSON config to do that looks like this:
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/system.log",
... //other unrelated file config
}
},
{
"Name": "Logger",
"Args": {
"configureLogger": {
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/api.log",
... //other unrelated file config
}
}
],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.')"
}
}
]
}
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
... //Destructure and other config
}
The top-level WriteTo is the first simple, global, sink. All log events write to this. If you add a Filter section on the same level as this, it will affect all configured WriteTo elements.
Then I configure another WriteTo as a Logger (not File), but the Args for this looks different and has a configureLogger element which serves the same purpose as Serilog on the top level, that is to say, it is the top level of the sub-logger. This means that you can easily split out the config for this into a separate file and add it additionally in the config builder (see bottom).
From here, this sub-logger works the same way: You can configure multiple WriteTos, and the Filter element on this level will affect only this sub-logger.
Simply add more "Name": "Logger" elements to the top level WriteTo section and setup filters for each one separately.
Note
It is also important to note that, even though you are doing all this in config and not referencing a single bit of the Serilog.Filters.Expressions package in your code, you still have to add the NuGet reference to that package. It doesn't work without the package reference.
About splitting the config:
If I have to add more loggers, I would definitely split out the different loggers into separate files for clarity, e.g.
appsettings.json:
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": "Error",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/system.log",
...
}
},
{
"Name": "Logger",
"Args": {
"configureLogger": {} // leave this empty
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
...
apilogger.json:
{
"Serilog:WriteTo:1:Args:configureLogger": { //notice this key
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/api_separateFile.log",
...
}
}
],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.')"
}
}
]
}
}
And then adjust my IWebHost builder to include the additional config:
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("apilogger.json", optional: false, reloadOnChange: false);
})
.UseStartup<Startup>();
This way it is easier to understand, read and maintain.
I had to do a similar thing, but in code, not JSON. Using a logger as a sink, as described at the bottom of https://github.com/serilog/serilog/wiki/Configuration-Basics did the trick.
In my case I wanted to log everything to a file and to the console, except that messages from a specific source should go only to the file:
private static bool SourceContextEquals(LogEvent logEvent, Type sourceContext)
=> logEvent.Properties.GetValueOrDefault("SourceContext") is ScalarValue sv && sv.Value?.ToString() == sourceContext.FullName;
private static ILogger CreateLogger() =>
new LoggerConfiguration()
.WriteTo.File("mylog.log")
.WriteTo.Logger(lc =>
lc.Filter.ByExcluding(le => SourceContextEquals(le, typeof(TypeThatShouldLogOnlyToFile)))
.WriteTo.Console()
)
.CreateLogger();
Writing only entityframework log to a file is done below but we need to install Serilog.Filters.Expressions nuget package
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"WriteTo": [
{
"Name": "Logger",
"Args": {
"configureLogger": {
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.EntityFrameworkCore')"
}
}
],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "C:\\LOGS\\TestService_EF_.json",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
]
}
}
}
]
}

Categories