Serilog és az ILogger Scope
Nemrég megkérdezték tőlem, mi történik, ha egy ILogger scope-ot használunk Seriloggal, hogyan jeleníthető meg a scope információ a naplóbejegyzésekben, akár MS SQL Szerverbe történő naplózáskor. Nézzük meg, hogyan működik ez a gyakorlatban.
A korábbi naplózási példából indulok ki, ahol egy egyszerű ASP.NET Core Web API projektben Serilogot használtunk naplózásra. Ehhez adtam hozzá scope-okat (rögtön kettőt), hogy azonnal lássuk, milyen hatása van az egymásba ágyazott hatóköröknek.
app.MapGet("/weatherforecast", (ILogger<Program> logger) =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
using IDisposable? loggerScope = logger.BeginScope("WeatherForecastScope");
logger.LogDebug("First log message");
using IDisposable? innerLoggerScope = logger.BeginScope("InnerWeatherForecastScope");
logger.LogInformation("Loaded weather forecast count: {count}", forecast.Length);
return forecast;
})
.WithName("GetWeatherForecast");
Console kimenet
Először nézzük meg a konzol kimenetet. Ehhez szükség van egy módosításra a Serilog konfigurációban, hogy megjelenítse a scope információt a naplóbejegyzésekben:
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Scope} - {Message}{NewLine}{Exception}"
}
},
]
A konzol kimenetben látható, hogy a scope információ megjelenik a naplóbejegyzésekben. Az első log üzenet csak a “WeatherForecastScope” scope-ot tartalmazza, míg a második log üzenet mindkét scope-ot (“WeatherForecastScope” és “InnerWeatherForecastScope”) megjeleníti.

Adatbázis kimenet
Külön beállítás nélkül a scope információ a Properties sql oszlopben található meg. Mutatom is, hogyan néz ki:
<properties>
<!-- ... -->
<property key='Scope'>
<sequence>
<item>WeatherForecastScope</item>
</sequence>
</property>
<!-- ... -->
</properties>
<properties>
<!-- ... -->
<property key='Scope'>
<sequence>
<item>WeatherForecastScope</item>
<item>InnerWeatherForecastScope</item>
</sequence>
</property>
<!-- ... -->
</properties>
Ez nehezen szűrhető és olvasható, de a korábbi példámban megmutattam hogyan lehet JSON formátumban is tárolni a Serilog által naplózott adatokat. Ilyenkor ebbe a mezőbe is bekerül a Scope információ, ami egy JSON tömbként jelenik meg.
{
"TimeStamp": "2026-02-15T18:51:25.0577241",
"Level": "Information",
"Message": "Loaded weather forecast count: 5",
"MessageTemplate": "Loaded weather forecast count: {count}",
"Properties": {
"count": 5,
"SourceContext": "Program",
"RequestId": "0HNJCNB84BNEC:00000003",
"RequestPath": "/weatherforecast",
"ConnectionId": "0HNJCNB84BNEC",
"Scope": [
"WeatherForecastScope",
"InnerWeatherForecastScope"
]
}
}
Természetesen a Scope információt külön oszlopban is tárolhatjuk, ehhez szükséges egy új oszlop hozzáadása a Log táblához.
ALTER TABLE dbo.Logs
ADD Scope nvarchar(MAX) NULL
Ezután a Serilog konfigurációban meg kell adni, hogy a Scope információ külön oszlopba kerüljön. Ehhez az additionalColumns beállításban helyezzük el az alábbi konfigurációt.
{
"ColumnName": "Scope",
"DataType": "nvarchar",
"DataLength": -1
}
A beállítás után a Scope információ külön oszlopban jelenik meg az adatbázisban, ami könnyebben szűrhető és olvasható.

[
"WeatherForecastScope",
"InnerWeatherForecastScope"
]
A teljes konfiguráció
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
"Serilog.Sinks.MSSqlServer"
],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft.AspNetCore": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Scope} - {Message}{NewLine}{Exception}"
}
},
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "LogDbConnectionString",
"sinkOptionsSection": {
"tableName": "Logs"
},
"columnOptionsSection": {
"addStandardColumns": [
"LogEvent"
],
"additionalColumns": [
{
"ColumnName": "RequestId",
"DataType": "nvarchar",
"DataLength": 36
},
{
"ColumnName": "Scope",
"DataType": "nvarchar",
"DataLength": -1
}
]
}
}
}
]
}
Kulcs-érték és egyéb típusok
Amennyiben a BeginScope paraméter Dictionary<string, object>, IEnumerable<KeyValuePair<string, object>>, ValueTuple<string, object>, vagy ITuple (ha támogatott és két tulajdonságot tartalmaz, ahol az első string) típusú, akkor nem jön létre Scope tulajdonság (üres értéket látunk majd). Ilyenkor a szöveges kulccsal kerül be a Properties gyűjteménybe és az objektum lesz az érték. Bármilyen más típus esetén a paramétert a Serilog a saját PropertyValueConverter osztálya segítségével alakítja át és az így kapott érték kerül a Scope mezőbe.
Módosítsuk az egyik BeginScope hívást
using IDisposable? loggerScope = logger.BeginScope(new Dictionary<string, object> {
{ "ExampleKey1",new ExampleRecord("Joe",22)},
{ "ExampleKey2","Value2"}
});
public sealed record ExampleRecord(string name, int age);
Ebben az esetben az alábbi Log event lesz látható az adatbázisban:
{
"TimeStamp": "2026-02-21T12:17:17.0714813",
"Level": "Debug",
"Message": "First log message",
"MessageTemplate": "First log message",
"Properties": {
"SourceContext": "Program",
"ExampleKey1": "ExampleRecord { name = Joe, age = 22 }",
"ExampleKey2": "Value2",
"RequestId": "0HNJH62EB061D:00000008",
"RequestPath": "/weatherforecast",
"ConnectionId": "0HNJH62EB061D"
}
}
Innentől kezdve, ha külön szeretnénk látni bármelyiket csak vegyük fel az additionalColumns gyűjteménybe vagy akár az outputTemplate-be és kész.