public void DistinctHashesAreComputed() { var h1 = EventIdHash.Compute("Template 1"); var h2 = EventIdHash.Compute("Template 2"); Assert.NotEqual(h1, h2); }
public void HashingIsConsistent() { var h1 = EventIdHash.Compute("Template 1"); var h2 = EventIdHash.Compute("Template 1"); Assert.Equal(h1, h2); }
public void AMinimalEventIsValidJson() { var jobject = AssertValidJson(log => log.Information("One {Property}", 42)); JToken m; Assert.True(jobject.TryGetValue("@m", out m)); Assert.Equal("One 42", m.ToObject <string>()); JToken i; Assert.True(jobject.TryGetValue("@i", out i)); Assert.Equal(EventIdHash.Compute("One {Property}").ToString("x8"), i.ToObject <string>()); }
/// <summary> /// Format the log event into the output. /// </summary> /// <param name="logEvent">The event to format.</param> /// <param name="output">The output.</param> /// <param name="valueFormatter">A value formatter for <see cref="LogEventPropertyValue"/>s on the event.</param> public void FormatEvent(LogEvent logEvent, TextWriter originalOutput, JsonValueFormatter valueFormatter) { if (logEvent == null) { throw new ArgumentNullException(nameof(logEvent)); } if (originalOutput == null) { throw new ArgumentNullException(nameof(originalOutput)); } if (valueFormatter == null) { throw new ArgumentNullException(nameof(valueFormatter)); } // wrap the originally text writer in one that can count the number of characters written var output = new CountingTextWriter(originalOutput); /* * 'timestamp', 'message', 'severity' and 'exception' are well-known * properties that Stackdriver will use to display and analyse your * logs correctly. */ // TIMESTAMP output.Write("{\"timestamp\":\""); output.Write(logEvent.Timestamp.UtcDateTime.ToString("O")); // MESSAGE output.Write("\",\"message\":"); var message = logEvent.MessageTemplate.Render(logEvent.Properties); JsonValueFormatter.WriteQuotedJsonString(message, output); // FINGERPRINT output.Write(",\"fingerprint\":\""); var id = EventIdHash.Compute(logEvent.MessageTemplate.Text); output.Write(id.ToString("x8")); output.Write('"'); // SEVERITY // https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity output.Write(",\"severity\":\""); var severity = StackDriverLogLevel.GetSeverity(logEvent.Level); output.Write(severity); output.Write('\"'); // EXCEPTION if (logEvent.Exception != null) { output.Write(",\"exception\":"); JsonValueFormatter.WriteQuotedJsonString(logEvent.Exception.ToString(), output); } // Serilog Message Template if (_includeMessageTemplate) { // Capitalized to match default Serilog JsonFormatter output.Write(",\"MessageTemplate\":"); JsonValueFormatter.WriteQuotedJsonString(logEvent.MessageTemplate.Text, output); } // Custom Properties passed in by code logging foreach (var property in logEvent.Properties) { var name = property.Key; if (name.Length > 0 && name[0] == '@') { // Escape first '@' by doubling name = '@' + name; } WriteKeyValue(output, valueFormatter, name, property.Value); } output.Write('}'); output.WriteLine(); // finish the log line // if we have blown the limit of a single stackdriver line (which means that error reporting won't parse // it correctly for instance) - then log that fact out too so we can adjust the logging and fix the problem if (_checkForPayloadLimit && (output.CharacterCount * 4) >= STACKDRIVER_ENTRY_LIMIT_BYTES) { string text = "An attempt was made to write a log event to stackdriver that exceeds StackDriver Entry length limit - check logs for partially parsed entry just prior to this and fix at source"; var tooLongLogEvent = new LogEvent( logEvent.Timestamp, LogEventLevel.Fatal, null, new MessageTemplate(text, new MessageTemplateToken[] { new TextToken(text) }), // this is actually what gets rendered new List <LogEventProperty>() ); FormatEvent(tooLongLogEvent, output, valueFormatter); } }
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { logEvent.AddOrUpdateProperty(new LogEventProperty("EventId", new ScalarValue(EventIdHash.Compute(logEvent.MessageTemplate.Text)))); }
/// <summary> /// Format the log event into the output. /// </summary> /// <param name="logEvent">The event to format.</param> /// <param name="output">The output.</param> /// <param name="valueFormatter">A value formatter for <see cref="LogEventPropertyValue"/>s on the event.</param> public static void FormatEvent(LogEvent logEvent, TextWriter output, JsonValueFormatter valueFormatter) { if (logEvent == null) { throw new ArgumentNullException(nameof(logEvent)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } if (valueFormatter == null) { throw new ArgumentNullException(nameof(valueFormatter)); } /* * 'timestamp', 'message', 'severity' and 'exception' are well-known * properties that Stackdriver will use to display and analyse your * logs correctly. */ output.Write("{\"timestamp\":\""); output.Write(logEvent.Timestamp.UtcDateTime.ToString("O")); output.Write("\",\"message\":"); var message = logEvent.MessageTemplate.Render(logEvent.Properties); JsonValueFormatter.WriteQuotedJsonString(message, output); output.Write(",\"fingerprint\":\""); var id = EventIdHash.Compute(logEvent.MessageTemplate.Text); output.Write(id.ToString("x8")); output.Write('"'); // Log severity as understood by Stackdriver: // https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity output.Write(",\"severity\":\""); switch (logEvent.Level) { case LogEventLevel.Debug: case LogEventLevel.Verbose: // Stackdriver doesn't have a Verbose level output.Write("DEBUG"); break; case LogEventLevel.Warning: output.Write("WARNING"); break; case LogEventLevel.Error: output.Write("ERROR"); break; case LogEventLevel.Fatal: output.Write("CRITICAL"); break; case LogEventLevel.Information: output.Write("INFO"); break; default: output.Write("DEFAULT"); break; } output.Write('\"'); if (logEvent.Exception != null) { output.Write(",\"exception\":"); JsonValueFormatter.WriteQuotedJsonString(logEvent.Exception.ToString(), output); } foreach (var property in logEvent.Properties) { var name = property.Key; if (name.Length > 0 && name[0] == '@') { // Escape first '@' by doubling name = '@' + name; } output.Write(','); JsonValueFormatter.WriteQuotedJsonString(name, output); output.Write(':'); valueFormatter.Format(property.Value, output); } output.Write('}'); }