-
Notifications
You must be signed in to change notification settings - Fork 41
Breaking changes
Mykhailo Shevchuk edited this page Jun 6, 2026
·
20 revisions
v9 is a ground-up rewrite of the sink in F#, with a public API that stays idiomatic from C#. See Upgrading from v8 to v9 for a step-by-step guide.
- Targets
net8.0,net9.0,net10.0. Droppednetstandard2.0,net5.0,net6.0,net7.0(all EOL) - Requires Serilog 4.3.1+ (uses Serilog's native batching)
-
FSharp.Coreis now a transitive dependency
-
batchPostingLimit→batchSizeLimit - The
levellabel is now controlled byhandleLogLevelAsLabel(defaulttrue); in v8 the label was added automatically and could not be turned off - Removed
reservedPropertyRenamingStrategy(andIReservedPropertyRenamingStrategy) - Removed
useInternalTimestamp - Removed
leavePropertiesIntact -
queueLimitis now bounded by default (50 000) instead of unbounded
-
Fatalis now rendered asfatal(wascritical) - update dashboards/alerts - Properties promoted via
propertiesAsLabelsare now kept in the log body as well - Reserved body keys (
Message,MessageTemplate,Exception,TraceId,SpanId) are collision-prefixed with_ - Delivery uses Serilog native batching: failed batches are retried with exponential backoff up to
retryTimeLimit(default 10 min), then dropped; emission is fully async (no dispose deadlock) - The
uriis validated at logger-configuration time (throwsArgumentException) - The
tenantis also validated at logger-configuration time, now against Loki's documented tenant ID rules: alphanumerics plus!-_.*'(), at most 150 bytes, and not.or..(throwsArgumentException). v8 used a slightly different rule set - it rejected..anywhere in the value (now only the exact values./..are rejected, per the docs) and had no length cap
- Removed
ILokiHttpClient/BaseLokiHttpClient/LokiHttpClient/LokiGzipHttpClient - Inject a standard
HttpClient(httpClient) orHttpMessageHandler(httpMessageHandler) instead; gzip is now aDelegatingHandler- see Custom HttpClient
-
TraceId/SpanIdcorrelation viatraceIdMode/spanIdMode(to the body or structured metadata) - see Trace and span enrichment - Structured metadata: per-line, non-indexed key/value pairs via
propertiesAsStructuredMetadata- see Structured metadata - Pluggable exception serialization via
ILokiExceptionFormatter- see Custom exception formatting
-
LokiJsonTextFormatteris used as a default text formatter. Removed propertyoutputTemplate - Removed interface
ILabelAwareTextFormatter - Redesigned approach of mapping properties to labels: removed
filtrationModeandfiltrationLabels, addedpropertiesAsLabels - Properties, mapped to the labels won't be passed to the text formatter
- Redesigned behavior of log level data (
levellabel): removedcreateLevelLabel - Added
IReservedPropertyRenamingStrategyandreservedPropertyRenamingStrategyconfiguration property
More detailed description and reasons behind this changes are described here
- Now
levellabel is not created by default
To keep previous behavior set createLevelLabel to true at sink configuration
.WriteTo.GrafanaLoki(
"http://localhost:3100",
createLevelLabel: true) {
"Name": "GrafanaLoki",
"Args": {
"uri": "http://localhost:3100",
"createLevelLabel": true
}
}- Deprecated dependency
Serilog.Sinks.Http - Replaced
IHttpClientwithILokiHttpClientMigration guide: You will have to migrate your code if you've implemented your own version ofILokiHttpClient. The signature of methodILokiHttpClient.PostAsync(before upgradeIHttpClient.PostAsynchas changed from Task PostAsync(string, HttpContent) to Task PostAsync(string, Stream).
Before upgrade:
public class CustomLokiHttpClient : IHttpClient
{
// Code removed for brevity...
public async Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
{
// Here you probably have some code updating the content,
// and then you send the request
return await httpClient.PostAsync(requestUri, content)
}
}After update:
public class CustomLokiHttpClient : ILokiHttpClient
{
// Code removed for brevity...
public async Task<HttpResponseMessage> PostAsync(string requestUri, Stream contentStream)
{
using var content = new StreamContent(contentStream);
// Here you probably have some code updating the content,
// and then you send the request
return await httpClient.PostAsync(requestUri, content)
}
}- Removed
DurableGrafanaLokiUsingTimeRolledBuffersandDurableGrafanaLokiUsingFileSizeRolledBuffers
- Replaced
excludedLabelswithfiltrationModeandfiltrationLabels