Skip to content

Commit c08dda9

Browse files
committed
Log objects with whitespace prop names as DictionaryValue
1 parent 525b98f commit c08dda9

File tree

2 files changed

+115
-94
lines changed

2 files changed

+115
-94
lines changed

src/Destructurama.JsonNet/JsonNet/JsonNetDestructuringPolicy.cs

Lines changed: 67 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,58 +20,77 @@
2020

2121
namespace Destructurama.JsonNet
2222
{
23-
internal class JsonNetDestructuringPolicy : IDestructuringPolicy
24-
{
25-
public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
26-
{
27-
switch (value)
28-
{
29-
case JObject jo:
30-
result = Destructure(jo, propertyValueFactory);
31-
return true;
32-
case JArray ja:
33-
result = Destructure(ja, propertyValueFactory);
34-
return true;
35-
case JValue jv:
36-
result = Destructure(jv, propertyValueFactory);
37-
return true;
38-
}
23+
internal class JsonNetDestructuringPolicy : IDestructuringPolicy
24+
{
25+
public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
26+
{
27+
switch (value)
28+
{
29+
case JObject jo:
30+
result = Destructure(jo, propertyValueFactory);
31+
return true;
32+
case JArray ja:
33+
result = Destructure(ja, propertyValueFactory);
34+
return true;
35+
case JValue jv:
36+
result = Destructure(jv, propertyValueFactory);
37+
return true;
38+
}
3939

40-
result = null;
41-
return false;
42-
}
40+
result = null;
41+
return false;
42+
}
4343

44-
LogEventPropertyValue Destructure(JValue jv, ILogEventPropertyValueFactory propertyValueFactory)
45-
{
46-
return propertyValueFactory.CreatePropertyValue(jv.Value, true);
47-
}
44+
private static LogEventPropertyValue Destructure(JValue jv, ILogEventPropertyValueFactory propertyValueFactory)
45+
{
46+
return propertyValueFactory.CreatePropertyValue(jv.Value, true);
47+
}
4848

49-
// ReSharper disable once ParameterTypeCanBeEnumerable.Local
50-
LogEventPropertyValue Destructure(JArray ja, ILogEventPropertyValueFactory propertyValueFactory)
51-
{
52-
var elems = ja.Select(t => propertyValueFactory.CreatePropertyValue(t, true));
53-
return new SequenceValue(elems);
54-
}
49+
private static LogEventPropertyValue Destructure(JArray ja, ILogEventPropertyValueFactory propertyValueFactory)
50+
{
51+
var elems = ja.Select(t => propertyValueFactory.CreatePropertyValue(t, true));
52+
return new SequenceValue(elems);
53+
}
5554

56-
LogEventPropertyValue Destructure(JObject jo, ILogEventPropertyValueFactory propertyValueFactory)
57-
{
58-
string typeTag = null;
59-
var props = new List<LogEventProperty>(jo.Count);
60-
foreach (var prop in jo.Properties())
61-
{
62-
if (prop.Name == "$type")
63-
{
64-
if (prop.Value is JValue typeVal && typeVal.Value is string)
65-
{
66-
typeTag = (string)typeVal.Value;
67-
continue;
68-
}
69-
}
55+
private static LogEventPropertyValue Destructure(JObject jo, ILogEventPropertyValueFactory propertyValueFactory)
56+
{
57+
return jo.Properties().All(prop => LogEventProperty.IsValidName(prop.Name)) ?
58+
DestructureToStructureValue(jo, propertyValueFactory) :
59+
DestructureToDictionaryValue(jo, propertyValueFactory);
60+
}
7061

71-
props.Add(new LogEventProperty(prop.Name, propertyValueFactory.CreatePropertyValue(prop.Value, true)));
72-
}
62+
private static LogEventPropertyValue DestructureToStructureValue(JObject jo, ILogEventPropertyValueFactory propertyValueFactory)
63+
{
64+
string typeTag = null;
65+
var props = new List<LogEventProperty>(jo.Count);
7366

74-
return new StructureValue(props, typeTag);
75-
}
76-
}
67+
foreach (var prop in jo.Properties())
68+
{
69+
if (prop.Name == "$type")
70+
{
71+
if (prop.Value is JValue typeVal && typeVal.Value is string)
72+
{
73+
typeTag = (string)typeVal.Value;
74+
continue;
75+
}
76+
}
77+
78+
props.Add(new LogEventProperty(prop.Name, propertyValueFactory.CreatePropertyValue(prop.Value, true)));
79+
}
80+
81+
return new StructureValue(props, typeTag);
82+
}
83+
84+
private static LogEventPropertyValue DestructureToDictionaryValue(JObject jo, ILogEventPropertyValueFactory propertyValueFactory)
85+
{
86+
var elements = jo.Properties().Select(
87+
prop =>
88+
new KeyValuePair<ScalarValue, LogEventPropertyValue>(
89+
new ScalarValue(prop.Name),
90+
propertyValueFactory.CreatePropertyValue(prop.Value, true)
91+
)
92+
);
93+
return new DictionaryValue(elements);
94+
}
95+
}
7796
}

test/Destructurama.JsonNet.Tests/JsonNetTypesDestructuringTests.cs

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,50 +8,52 @@
88

99
namespace Destructurama.JsonNet.Tests
1010
{
11-
class HasName
12-
{
13-
public string Name { get; set; }
14-
}
15-
16-
public class JsonNetTypesDestructuringTests
17-
{
18-
[Fact]
19-
public void AttributesAreConsultedWhenDestructuring()
20-
{
21-
LogEvent evt = null;
22-
23-
var log = new LoggerConfiguration()
24-
.Destructure.JsonNetTypes()
25-
.WriteTo.Sink(new DelegatingSink(e => evt = e))
26-
.CreateLogger();
27-
28-
var test = new
29-
{
30-
HN = new HasName { Name = "Some name" },
31-
Arr = new[] { 1, 2, 3 },
32-
S = "Some string",
33-
D = new Dictionary<int, string> { { 1, "One" }, { 2, "Two" } },
34-
E = (object)null
35-
};
36-
37-
var ser = JsonConvert.SerializeObject(test, new JsonSerializerSettings
38-
{
39-
TypeNameHandling = TypeNameHandling.Auto
40-
});
41-
var dyn = JsonConvert.DeserializeObject<dynamic>(ser);
42-
43-
log.Information("Here is {@Dyn}", dyn);
44-
45-
var sv = (StructureValue)evt.Properties["Dyn"];
46-
var props = sv.Properties.ToDictionary(p => p.Name, p => p.Value);
47-
48-
Assert.IsType<StructureValue>(props["HN"]);
49-
Assert.IsType<SequenceValue>(props["Arr"]);
50-
Assert.IsType<string>(props["S"].LiteralValue());
51-
Assert.Null(props["E"].LiteralValue());
52-
53-
// Not currently handled correctly - will serialize as a structure
54-
// Assert.IsInstanceOf<DictionaryValue>(props["D"]);
55-
}
56-
}
11+
class HasName
12+
{
13+
public string Name { get; set; }
14+
}
15+
16+
public class JsonNetTypesDestructuringTests
17+
{
18+
[Fact]
19+
public void AttributesAreConsultedWhenDestructuring()
20+
{
21+
LogEvent evt = null;
22+
23+
var log = new LoggerConfiguration()
24+
.Destructure.JsonNetTypes()
25+
.WriteTo.Sink(new DelegatingSink(e => evt = e))
26+
.CreateLogger();
27+
28+
var test = new
29+
{
30+
HN = new HasName { Name = "Some name" },
31+
Arr = new[] { 1, 2, 3 },
32+
S = "Some string",
33+
D = new Dictionary<int, string> { { 1, "One" }, { 2, "Two" } },
34+
E = (object)null,
35+
ESPN = JsonConvert.DeserializeObject("{\"\":\"Empty string property name\"}"),
36+
WSPN = JsonConvert.DeserializeObject("{\"\r\n\":\"Whitespace property name\"}")
37+
};
38+
39+
var ser = JsonConvert.SerializeObject(test, new JsonSerializerSettings
40+
{
41+
TypeNameHandling = TypeNameHandling.Auto
42+
});
43+
var dyn = JsonConvert.DeserializeObject<dynamic>(ser);
44+
45+
log.Information("Here is {@Dyn}", dyn);
46+
47+
var sv = (StructureValue)evt.Properties["Dyn"];
48+
var props = sv.Properties.ToDictionary(p => p.Name, p => p.Value);
49+
50+
Assert.IsType<StructureValue>(props["HN"]);
51+
Assert.IsType<SequenceValue>(props["Arr"]);
52+
Assert.IsType<string>(props["S"].LiteralValue());
53+
Assert.IsType<StructureValue>(props["D"]);
54+
Assert.Null(props["E"].LiteralValue());
55+
Assert.IsType<DictionaryValue>(props["ESPN"]);
56+
Assert.IsType<DictionaryValue>(props["WSPN"]);
57+
}
58+
}
5759
}

0 commit comments

Comments
 (0)