Last active
March 16, 2021 21:57
-
-
Save rasmuskl/5b0eab54aa56edbfec57c35c5fa100ab to your computer and use it in GitHub Desktop.
Json.NET JsonConverters for deserializing Serilog's LogEvents.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Linq; | |
using Serilog.Events; | |
using Serilog.Parsing; | |
namespace MyNamespace | |
{ | |
public class LogEventJsonConverter : JsonConverter | |
{ | |
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |
{ | |
JObject jObject = JObject.Load(reader); | |
DateTimeOffset timestamp = serializer.Deserialize<DateTimeOffset>(jObject["Timestamp"].CreateReader()); | |
LogEventLevel level = serializer.Deserialize<LogEventLevel>(jObject["Level"].CreateReader()); | |
Exception exception = serializer.Deserialize<Exception>(jObject["Exception"].CreateReader()); | |
string messageTemplateText = jObject["MessageTemplate"]["Text"].Value<string>(); | |
MessageTemplateParser messageTemplateParser = new MessageTemplateParser(); | |
MessageTemplate messageTemplate = messageTemplateParser.Parse(messageTemplateText); | |
Dictionary<string, LogEventPropertyValue> logEventPropertyValues = serializer.Deserialize<Dictionary<string, LogEventPropertyValue>>(jObject["Properties"].CreateReader()); | |
return new LogEvent(timestamp, level, exception, messageTemplate, logEventPropertyValues.Select(x => new LogEventProperty(x.Key, x.Value))); | |
} | |
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |
{ | |
throw new NotImplementedException(); | |
} | |
public override bool CanConvert(Type objectType) | |
{ | |
return typeof(LogEvent).IsAssignableFrom(objectType); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Newtonsoft.Json; | |
using NUnit.Framework; | |
using Serilog.Events; | |
using Serilog.Parsing; | |
namespace MyNamespace | |
{ | |
[TestFixture] | |
public class LogEventJsonConverterTests | |
{ | |
[Test] | |
public void Roundtrip_Timestamp() | |
{ | |
DateTimeOffset timestamp = DateTimeOffset.Now; | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(timestamp, LogEventLevel.Fatal, null, new MessageTemplateParser().Parse("Test"), new LogEventProperty[0])); | |
Assert.AreEqual(timestamp, logEvent.Timestamp); | |
} | |
[Test] | |
public void Roundtrip_Level() | |
{ | |
var level = LogEventLevel.Fatal; | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(DateTimeOffset.Now, level, null, new MessageTemplateParser().Parse("Test"), new LogEventProperty[0])); | |
Assert.AreEqual(level, logEvent.Level); | |
} | |
[Test] | |
public void Roundtrip_MessageTemplate_Simple() | |
{ | |
MessageTemplate messageTemplate = new MessageTemplateParser().Parse("Test"); | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(DateTimeOffset.Now, LogEventLevel.Fatal, null, messageTemplate, new LogEventProperty[0])); | |
Assert.AreEqual(messageTemplate.Text, logEvent.MessageTemplate.Text); | |
} | |
[Test] | |
public void Roundtrip_MessageTemplate_Properties() | |
{ | |
MessageTemplate messageTemplate = new MessageTemplateParser().Parse("Test {key} and {value}"); | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(DateTimeOffset.Now, LogEventLevel.Fatal, null, messageTemplate, new LogEventProperty[0])); | |
Assert.AreEqual(messageTemplate.Text, logEvent.MessageTemplate.Text); | |
Assert.AreEqual(2, messageTemplate.Tokens.OfType<TextToken>().Count()); | |
Assert.AreEqual(2, messageTemplate.Tokens.OfType<PropertyToken>().Count()); | |
} | |
[Test] | |
public void Roundtrip_LogEventProperties_Scalar() | |
{ | |
var logEventProperties = new List<LogEventProperty>(); | |
logEventProperties.Add(new LogEventProperty("scalar", new ScalarValue(42))); | |
logEventProperties.Add(new LogEventProperty("dict", new DictionaryValue(new List<KeyValuePair<ScalarValue, LogEventPropertyValue>> { new KeyValuePair<ScalarValue, LogEventPropertyValue>(new ScalarValue(42), new ScalarValue(43)) }))); | |
logEventProperties.Add(new LogEventProperty("struct", new StructureValue(new[] { new LogEventProperty("struct-1", new ScalarValue(5)) }))); | |
logEventProperties.Add(new LogEventProperty("seq", new SequenceValue(new[] { new ScalarValue(37) }))); | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(DateTimeOffset.Now, LogEventLevel.Debug, null, new MessageTemplateParser().Parse("Test"), logEventProperties)); | |
LogEventPropertyValue value; | |
Assert.IsTrue(logEvent.Properties.TryGetValue("scalar", out value)); | |
Assert.IsAssignableFrom<ScalarValue>(value); | |
Assert.AreEqual(42, ((ScalarValue)value).Value); | |
} | |
[Test] | |
public void Roundtrip_LogEventProperties_Dictionary() | |
{ | |
var logEventProperties = new List<LogEventProperty>(); | |
logEventProperties.Add(new LogEventProperty("dict", new DictionaryValue(new List<KeyValuePair<ScalarValue, LogEventPropertyValue>> { new KeyValuePair<ScalarValue, LogEventPropertyValue>(new ScalarValue(92), new ScalarValue("value")) }))); | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(DateTimeOffset.Now, LogEventLevel.Debug, null, new MessageTemplateParser().Parse("Test"), logEventProperties)); | |
LogEventPropertyValue value; | |
Assert.IsTrue(logEvent.Properties.TryGetValue("dict", out value)); | |
Assert.IsAssignableFrom<DictionaryValue>(value); | |
Assert.AreEqual("92", ((DictionaryValue)value).Elements.Keys.First().Value); | |
Assert.AreEqual("value", ((DictionaryValue)value).Elements.Values.OfType<ScalarValue>().First().Value); | |
} | |
[Test] | |
public void Roundtrip_LogEventProperties_Structure() | |
{ | |
var logEventProperties = new List<LogEventProperty>(); | |
logEventProperties.Add(new LogEventProperty("struct", new StructureValue(new[] { new LogEventProperty("struct-1", new ScalarValue(5)) }, "typeTag"))); | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(DateTimeOffset.Now, LogEventLevel.Debug, null, new MessageTemplateParser().Parse("Test"), logEventProperties)); | |
LogEventPropertyValue value; | |
Assert.IsTrue(logEvent.Properties.TryGetValue("struct", out value)); | |
Assert.IsAssignableFrom<StructureValue>(value); | |
var structureValue = (StructureValue)value; | |
Assert.AreEqual("typeTag", structureValue.TypeTag); | |
LogEventProperty logEventProperty = structureValue.Properties.First(); | |
Assert.AreEqual("struct-1", logEventProperty.Name); | |
Assert.AreEqual(5, ((ScalarValue)logEventProperty.Value).Value); | |
} | |
[Test] | |
public void Roundtrip_LogEventProperties_Structure_NoTypeTag() | |
{ | |
var logEventProperties = new List<LogEventProperty>(); | |
logEventProperties.Add(new LogEventProperty("struct", new StructureValue(new[] { new LogEventProperty("struct-1", new ScalarValue(5)) }))); | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(DateTimeOffset.Now, LogEventLevel.Debug, null, new MessageTemplateParser().Parse("Test"), logEventProperties)); | |
LogEventPropertyValue value; | |
Assert.IsTrue(logEvent.Properties.TryGetValue("struct", out value)); | |
Assert.IsAssignableFrom<StructureValue>(value); | |
var structureValue = (StructureValue)value; | |
LogEventProperty logEventProperty = structureValue.Properties.First(); | |
Assert.AreEqual("struct-1", logEventProperty.Name); | |
Assert.AreEqual(5, ((ScalarValue)logEventProperty.Value).Value); | |
} | |
[Test] | |
public void Roundtrip_LogEventProperties_Sequence() | |
{ | |
var logEventProperties = new List<LogEventProperty>(); | |
logEventProperties.Add(new LogEventProperty("seq", new SequenceValue(new[] { new ScalarValue(37) }))); | |
LogEvent logEvent = RoundtripLogEvent(new LogEvent(DateTimeOffset.Now, LogEventLevel.Debug, null, new MessageTemplateParser().Parse("Test"), logEventProperties)); | |
LogEventPropertyValue value; | |
Assert.IsTrue(logEvent.Properties.TryGetValue("seq", out value)); | |
Assert.IsAssignableFrom<SequenceValue>(value); | |
Assert.AreEqual(37, ((SequenceValue)value).Elements.OfType<ScalarValue>().First().Value); | |
} | |
private LogEvent RoundtripLogEvent(LogEvent logEvent) | |
{ | |
string json = JsonConvert.SerializeObject(logEvent); | |
return JsonConvert.DeserializeObject<LogEvent>(json, new LogEventJsonConverter(), new LogEventPropertyValueConverter()); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Linq; | |
using Serilog.Events; | |
namespace MyNamespace | |
{ | |
public class LogEventPropertyValueConverter : JsonConverter | |
{ | |
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |
{ | |
JObject jObject = JObject.Load(reader); | |
if (FieldExists("Elements", jObject) && jObject["Elements"] is JArray) | |
{ | |
var logEventPropertyValues = serializer.Deserialize<LogEventPropertyValue[]>(jObject["Elements"].CreateReader()); | |
return new SequenceValue(logEventPropertyValues); | |
} | |
if (FieldExists("Elements", jObject) && jObject["Elements"] is JObject) | |
{ | |
var dictionary = serializer.Deserialize<Dictionary<string, LogEventPropertyValue>>(jObject["Elements"].CreateReader()); | |
return new DictionaryValue(dictionary.Select(x => new KeyValuePair<ScalarValue, LogEventPropertyValue>(new ScalarValue(x.Key), x.Value))); | |
} | |
if (FieldExists("Value", jObject)) | |
{ | |
return new ScalarValue(serializer.Deserialize(jObject["Value"].CreateReader())); | |
} | |
if (FieldExists("Properties", jObject)) | |
{ | |
var logEventProperties = serializer.Deserialize<LogEventProperty[]>(jObject["Properties"].CreateReader()); | |
var typeTag = serializer.Deserialize<string>(jObject["TypeTag"].CreateReader()); | |
return new StructureValue(logEventProperties, typeTag); | |
} | |
throw new NotSupportedException("Unknown LogEventPropertyValue: " + jObject); | |
} | |
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |
{ | |
throw new NotImplementedException(); | |
} | |
public override bool CanConvert(Type objectType) | |
{ | |
return typeof(LogEventPropertyValue).IsAssignableFrom(objectType); | |
} | |
private bool FieldExists(string fieldName, JObject jObject) | |
{ | |
return jObject[fieldName] != null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment