private void GenerateEntry( LokiLogEvent lokiLogEvent, ITextFormatter formatter, LokiStream stream) { var buffer = new StringWriter(new StringBuilder(DefaultWriteBufferCapacity)); var logEvent = lokiLogEvent.LogEvent; var timestamp = logEvent.Timestamp; if (_useInternalTimestamp) { logEvent.AddPropertyIfAbsent( new LogEventProperty("Timestamp", new ScalarValue(timestamp))); timestamp = lokiLogEvent.InternalTimestamp; } formatter.Format(logEvent, buffer); stream.AddEntry(timestamp, buffer.ToString().TrimEnd('\r', '\n')); }
private (Dictionary <string, string> Labels, LokiLogEvent LokiLogEvent) GenerateLabels(LokiLogEvent lokiLogEvent) { var labels = _globalLabels.ToDictionary(label => label.Key, label => label.Value); var properties = lokiLogEvent.Properties; var(propertiesAsLabels, remainingProperties) = properties.Partition(kvp => _propertiesAsLabels.Contains(kvp.Key)); foreach (var property in propertiesAsLabels) { var key = property.Key; // If a message template is a composite format string that contains indexed placeholders ({0}, {1} etc), // Serilog turns these placeholders into event properties keyed by numeric strings. // Loki doesn't accept such strings as label keys. Prefix these numeric strings with "param" // to turn them into valid label keys and at the same time denote them as ordinal parameters. if (char.IsDigit(key[0])) { key = $"param{key}"; } // Some enrichers generates extra quotes and it breaks the payload var value = property.Value.ToString().Replace("\"", string.Empty); if (labels.ContainsKey(key)) { SelfLog.WriteLine( "Labels already contains key {0}, added from global labels. Property value ({1}) with the same key is ignored", key, value); continue; } labels.Add(key, value); } return(labels, lokiLogEvent.CopyWithProperties(remainingProperties)); }