Serilog.Sinks.Loki.YetAnother
1.3.4-v1-0003-0000
dotnet add package Serilog.Sinks.Loki.YetAnother --version 1.3.4-v1-0003-0000
NuGet\Install-Package Serilog.Sinks.Loki.YetAnother -Version 1.3.4-v1-0003-0000
<PackageReference Include="Serilog.Sinks.Loki.YetAnother" Version="1.3.4-v1-0003-0000" />
paket add Serilog.Sinks.Loki.YetAnother --version 1.3.4-v1-0003-0000
#r "nuget: Serilog.Sinks.Loki.YetAnother, 1.3.4-v1-0003-0000"
// Install Serilog.Sinks.Loki.YetAnother as a Cake Addin #addin nuget:?package=Serilog.Sinks.Loki.YetAnother&version=1.3.4-v1-0003-0000&prerelease // Install Serilog.Sinks.Loki.YetAnother as a Cake Tool #tool nuget:?package=Serilog.Sinks.Loki.YetAnother&version=1.3.4-v1-0003-0000&prerelease
Serilog.Sinks.Loki.YetAnother
I know there are already a few Serilog Loki sinks out there, why another one?
Widly used loki sinks are good and work as expected. But if app produces a lot of logs, in the future this might allocate a lot of objects.
This sink is designed to use less memory and allocate less objects.
The main idea is to use Utf8JsonWriter
to write logs directly to the stream.
Moreover, to decrease GC pressure, and memory allocation, it uses custom TextWriter, that writes message directly to the ut8 stream, instead of usual way - StringWriter.
This approach allows to decrease number of allocations and its avg size, and decrease number of GC cycles as well.
As the result, you can send more logs with less drawbacks.
Example
Log.Logger = new LoggerConfiguration()
.WriteTo.Loki(new LokiSinkConfigurations()
{
Credentials = new LokiCredentials("< login here >", "< password here >"),
Url = new Uri("< uri to loki server here >"),
HandleLogLevelAsLabel = true, // adds Serilog.Events.LogEvent.Level as label (default is true)
PropertiesAsLabels = ["userId"], // adds Serilog.Events.LogEvent.Properties as labels (default is empty)
Labels = //global labels, will be added to each loki log message (default is empty)
[
new LokiLabel("app", "loki"),
]
},
batchSizeLimit: 1000, //The maximum number of events to include in a single batch (default is 1000)
period: TimeSpan.FromMilliseconds(2000), // period between sending batches to loki (default is 2000ms)
queueLimit: 100000, //Maximum number of events to hold in the sink's internal queue, or null for an unbounded queue
httpClient: null) // custom HttpClient instance, (can be used to set proxy, compression etc)
.CreateLogger();
Using Serilog.Settings.Configurations
appsettings.json
{
"Serilog": {
"Using": [ "Serilog.Sinks.Loki" ],
"WriteTo": [
{
"Name": "Loki",
"Args": {
"configurations": {
"Url": "https://logs-prod42.grafana.net",
"Labels": [
{
"key": "app",
"value": "myapp"
}
],
"Credentials": {
"Password": "password",
"Username": "username"
},
"PropertiesAsLabels": [
"app",
"environment"
],
"HandleLogLevelAsLabel": false,
"EnrichTraceId": true,
"EnrichSpanId": true
},
"batchSizeLimit": 999
}
}
]
}
}
Program.cs
using Microsoft.Extensions.Configuration;
using Serilog;
var builder = new ConfigurationBuilder()
.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json"))
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder)
.CreateLogger();
Benchmarks
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3)
Intel Core i5-14600K, 1 CPU, 20 logical and 14 physical cores
.NET SDK 8.0.101
[Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2
ShortRun : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2
Job=ShortRun InvocationCount=1 IterationCount=3
LaunchCount=1 UnrollFactor=1 WarmupCount=3
Method | Mean | Error | StdDev | Ratio | RatioSD | Completed Work Items | Lock Contentions | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|---|
Default | 150.9 ms | 138.60 ms | 7.60 ms | 1.00 | 0.00 | 6.0000 | 1.0000 | 5.23 MB | 1.00 |
Optimized | 157.4 ms | 96.08 ms | 5.27 ms | 1.05 | 0.08 | 11.0000 | 1.0000 | 1.18 MB | 0.23 |
Allocations are decreased by 4.4 times compared to Serilog.Sinks.Grafana.Loki
package, that is great!
However, this banchmarking does not properly handle these cases, so execution time results may not be accurate.
Inspiration and Credits
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Serilog (>= 3.1.1)
- Serilog.Sinks.PeriodicBatching (>= 3.1.0)
-
net8.0
- Serilog (>= 3.1.1)
- Serilog.Sinks.PeriodicBatching (>= 3.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.3.4-v1-0003-0000 | 111 | 4/28/2024 |
1.2.9 | 1,041 | 2/8/2024 |
1.2.4 | 111 | 2/8/2024 |
1.1.4 | 145 | 1/20/2024 |