diff --git a/src/Serilog.Sinks.Loki.Example/LogLabelProvider.cs b/src/Serilog.Sinks.Loki.Example/LogLabelProvider.cs index 358d38c..9d95284 100644 --- a/src/Serilog.Sinks.Loki.Example/LogLabelProvider.cs +++ b/src/Serilog.Sinks.Loki.Example/LogLabelProvider.cs @@ -13,5 +13,10 @@ public IList GetLabels() new LokiLabel("namespace", "prod") }; } + + public IList PropertiesAsLabels { get; set; } = new List + { + "MyPropertyName" + }; } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Loki/Labels/DefaultLogLabelProvider.cs b/src/Serilog.Sinks.Loki/Labels/DefaultLogLabelProvider.cs new file mode 100644 index 0000000..8b7e1cd --- /dev/null +++ b/src/Serilog.Sinks.Loki/Labels/DefaultLogLabelProvider.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Serilog.Sinks.Loki.Labels +{ + class DefaultLogLabelProvider : ILogLabelProvider + { + public IList GetLabels() + { + return new List(); + } + + public IList PropertiesAsLabels { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/src/Serilog.Sinks.Loki/Labels/ILogLabelProvider.cs b/src/Serilog.Sinks.Loki/Labels/ILogLabelProvider.cs index ad5535e..62cbbd6 100644 --- a/src/Serilog.Sinks.Loki/Labels/ILogLabelProvider.cs +++ b/src/Serilog.Sinks.Loki/Labels/ILogLabelProvider.cs @@ -5,5 +5,6 @@ namespace Serilog.Sinks.Loki.Labels public interface ILogLabelProvider { IList GetLabels(); + IList PropertiesAsLabels { get; set; } } } \ No newline at end of file diff --git a/src/Serilog.Sinks.Loki/LokiBatchFormatter.cs b/src/Serilog.Sinks.Loki/LokiBatchFormatter.cs index 1a1e4a4..f61eae3 100644 --- a/src/Serilog.Sinks.Loki/LokiBatchFormatter.cs +++ b/src/Serilog.Sinks.Loki/LokiBatchFormatter.cs @@ -14,15 +14,17 @@ namespace Serilog.Sinks.Loki internal class LokiBatchFormatter : IBatchFormatter { private readonly IList _globalLabels; + private readonly IList _propertiesAsLabels; public LokiBatchFormatter() { _globalLabels = new List(); } - public LokiBatchFormatter(IList globalLabels) + public LokiBatchFormatter(ILogLabelProvider logLabelProvider) { - _globalLabels = globalLabels; + _globalLabels = logLabelProvider.GetLabels(); + _propertiesAsLabels = logLabelProvider.PropertiesAsLabels; } public void Format(IEnumerable logEvents, ITextFormatter formatter, TextWriter output) @@ -46,14 +48,6 @@ public void Format(IEnumerable logEvents, ITextFormatter formatter, Te foreach (LokiLabel globalLabel in _globalLabels) stream.Labels.Add(new LokiLabel(globalLabel.Key, globalLabel.Value)); - foreach (KeyValuePair property in logEvent.Properties) - // Some enrichers pass strings with quotes surrounding the values inside the string, - // which results in redundant quotes after serialization and a "bad request" response. - // To avoid this, remove all quotes from the value. - // We also remove any \r\n newlines and replace with \n new lines to prevent "bad request" responses - // We also remove backslashes and replace with forward slashes, Loki doesn't like those either - stream.Labels.Add(new LokiLabel(property.Key, property.Value.ToString().Replace("\"", "").Replace("\r\n", "\n").Replace("\\", "/"))); - var time = logEvent.Timestamp.ToString("o"); var sb = new StringBuilder(); @@ -69,6 +63,24 @@ public void Format(IEnumerable logEvents, ITextFormatter formatter, Te } } + foreach (KeyValuePair property in logEvent.Properties) + { + // Some enrichers pass strings with quotes surrounding the values inside the string, + // which results in redundant quotes after serialization and a "bad request" response. + // To avoid this, remove all quotes from the value. + // We also remove any \r\n newlines and replace with \n new lines to prevent "bad request" responses + // We also remove backslashes and replace with forward slashes, Loki doesn't like those either + var propertyValue = property.Value.ToString().Replace("\"", "").Replace("\r\n", "\n").Replace("\\", "/"); + if (_propertiesAsLabels.Contains(property.Key, StringComparer.OrdinalIgnoreCase)) + { + stream.Labels.Add(new LokiLabel(property.Key, propertyValue)); + } + else + { + sb.Append($" {property.Key}={propertyValue}"); + } + } + // Loki doesn't like \r\n for new line, and we can't guarantee the message doesn't have any // in it, so we replace \r\n with \n on the final message // We also flip backslashes to forward slashes, Loki doesn't like those either. diff --git a/src/Serilog.Sinks.Loki/LokiSinkExtensions.cs b/src/Serilog.Sinks.Loki/LokiSinkExtensions.cs index cee9953..08f3b60 100644 --- a/src/Serilog.Sinks.Loki/LokiSinkExtensions.cs +++ b/src/Serilog.Sinks.Loki/LokiSinkExtensions.cs @@ -11,7 +11,7 @@ public static LoggerConfiguration LokiHttp(this LoggerSinkConfiguration sinkConf private static LoggerConfiguration LokiHttpImpl(this LoggerSinkConfiguration sinkConfiguration, LokiCredentials credentials, ILogLabelProvider logLabelProvider, IHttpClient httpClient) { - var formatter = logLabelProvider != null ? new LokiBatchFormatter(logLabelProvider.GetLabels()) : new LokiBatchFormatter(); + var formatter = new LokiBatchFormatter(logLabelProvider ?? new DefaultLogLabelProvider()); var client = httpClient ?? new DefaultLokiHttpClient(); if (client is LokiHttpClient c) diff --git a/test/Serilog.Sinks.Loki.Tests/Infrastructure/TestLabelProvider.cs b/test/Serilog.Sinks.Loki.Tests/Infrastructure/TestLabelProvider.cs index 052de86..532aef6 100644 --- a/test/Serilog.Sinks.Loki.Tests/Infrastructure/TestLabelProvider.cs +++ b/test/Serilog.Sinks.Loki.Tests/Infrastructure/TestLabelProvider.cs @@ -12,5 +12,7 @@ public IList GetLabels() new LokiLabel("app", "tests") }; } + + public IList PropertiesAsLabels { get; set; } = new List(); } } \ No newline at end of file