From adfcb19d2c8b4dc954e807d17a1f76da29804ff4 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 26 Aug 2026 16:28:04 +1000 Subject: [PATCH 1/4] Avoid accidental data trunctation when outputting JSON through Serilog. Assisted-by: Claude:claude-opus-5 --- src/SeqCli/Output/OutputFormat.cs | 4 ++++ test/SeqCli.EndToEnd/Data/trace-tree.clef | 4 ++++ test/SeqCli.EndToEnd/Mcp/McpTraceTestCase.cs | 2 +- test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs | 12 ++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/SeqCli/Output/OutputFormat.cs b/src/SeqCli/Output/OutputFormat.cs index 2cd46d09..64a5703f 100644 --- a/src/SeqCli/Output/OutputFormat.cs +++ b/src/SeqCli/Output/OutputFormat.cs @@ -170,6 +170,8 @@ public void WriteEntity(Entity entity) var writer = new LoggerConfiguration() .Destructure.With() + // The default limit truncates deeply-nested documents, such as trace trees. + .Destructure.ToMaximumDepth(10000) .Enrich.With() .WriteTo.Console(TextFormatters.Plain(TemplateTheme, "{@m}" + Environment.NewLine)) .CreateLogger(); @@ -200,6 +202,8 @@ public void WriteObject(object value) var writer = new LoggerConfiguration() .Destructure.With() + // The default limit truncates deeply-nested documents, such as trace trees. + .Destructure.ToMaximumDepth(10000) .Enrich.With() .WriteTo.Console(TextFormatters.Plain(TemplateTheme, "{@m}" + Environment.NewLine)) .CreateLogger(); diff --git a/test/SeqCli.EndToEnd/Data/trace-tree.clef b/test/SeqCli.EndToEnd/Data/trace-tree.clef index 465817fa..2f00a000 100644 --- a/test/SeqCli.EndToEnd/Data/trace-tree.clef +++ b/test/SeqCli.EndToEnd/Data/trace-tree.clef @@ -4,3 +4,7 @@ {"@t":"2023-12-20T00:50:00.2Z","@l":"Warning","@tr":"7d4dedcc73b18e449e0e4ea08cbe346d","@sp":"2222222222222222","@mt":"{RowCount} rows retrieved","RowCount":42,"@x":"System.TimeoutException: The query timeout was reached"} {"@t":"2023-12-20T00:50:00.9Z","@st":"2023-12-20T00:50:00.5Z","@tr":"7d4dedcc73b18e449e0e4ea08cbe346d","@sp":"4444444444444444","@ps":"1111111111111111","@m":"Render response"} {"@t":"2023-12-20T00:50:00.95Z","@tr":"7d4dedcc73b18e449e0e4ea08cbe346d","@sp":"9999999999999999","@m":"Orphan log"} +{"@t":"2023-12-20T00:50:00.85Z","@st":"2023-12-20T00:50:00.55Z","@tr":"7d4dedcc73b18e449e0e4ea08cbe346d","@sp":"5555555555555555","@ps":"4444444444444444","@m":"Serialize model"} +{"@t":"2023-12-20T00:50:00.8Z","@st":"2023-12-20T00:50:00.6Z","@tr":"7d4dedcc73b18e449e0e4ea08cbe346d","@sp":"6666666666666666","@ps":"5555555555555555","@m":"Serialize order"} +{"@t":"2023-12-20T00:50:00.75Z","@st":"2023-12-20T00:50:00.65Z","@tr":"7d4dedcc73b18e449e0e4ea08cbe346d","@sp":"7777777777777777","@ps":"6666666666666666","@m":"Format currency"} +{"@t":"2023-12-20T00:50:00.72Z","@st":"2023-12-20T00:50:00.7Z","@tr":"7d4dedcc73b18e449e0e4ea08cbe346d","@sp":"8888888888888888","@ps":"7777777777777777","@m":"Lookup locale"} diff --git a/test/SeqCli.EndToEnd/Mcp/McpTraceTestCase.cs b/test/SeqCli.EndToEnd/Mcp/McpTraceTestCase.cs index c81c4882..9c7b8d81 100644 --- a/test/SeqCli.EndToEnd/Mcp/McpTraceTestCase.cs +++ b/test/SeqCli.EndToEnd/Mcp/McpTraceTestCase.cs @@ -33,7 +33,7 @@ protected override async Task ExecuteAsync(SeqConnection connection, ILogger log }); var text = AssertTextResult(loaded); - Assert.Contains("Loaded 4 span(s)", text); + Assert.Contains("Loaded 8 span(s)", text); var document = AssertStructuredObjectResult(loaded); Assert.Equal(TraceId, document.GetProperty("traceId").GetString()); diff --git a/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs b/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs index 34707ef3..3fd970c7 100644 --- a/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs +++ b/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs @@ -100,6 +100,18 @@ public Task ExecuteAsync( ["SELECT * FROM orders", "42 rows retrieved"], ((JArray)query["children"]!).Select(c => (string)c["message"]!).ToArray()); + // Deeply-nested spans must survive JSON serialization; the tree is six spans deep here. + var node = root; + foreach (var message in new[] { "Render response", "Serialize model", "Serialize order", "Format currency", "Lookup locale" }) + { + var children = node["children"] as JArray; + Assert.True(children != null, $"Expected children under `{(string?)node["message"]}` in: {runner.LastRunProcess!.Output}"); + node = (JObject)children!.Single(c => (string?)c["message"] == message); + } + + Assert.Equal("8888888888888888", (string?)node["spanId"]); + Assert.Null(node["children"]); + var orphan = (JObject)Assert.Single((JArray)document["orphans"]!); Assert.Equal("log", (string?)orphan["type"]); Assert.Equal("Orphan log", (string?)orphan["message"]); From 64300d14b5cb2c7137fa42c0be8eb97d590e8f0c Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 26 Aug 2026 16:32:38 +1000 Subject: [PATCH 2/4] Tidy up test --- test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs b/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs index 3fd970c7..5a241dbd 100644 --- a/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs +++ b/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs @@ -100,13 +100,11 @@ public Task ExecuteAsync( ["SELECT * FROM orders", "42 rows retrieved"], ((JArray)query["children"]!).Select(c => (string)c["message"]!).ToArray()); - // Deeply-nested spans must survive JSON serialization; the tree is six spans deep here. var node = root; - foreach (var message in new[] { "Render response", "Serialize model", "Serialize order", "Format currency", "Lookup locale" }) + foreach (var message in ["Render response", "Serialize model", "Serialize order", "Format currency", "Lookup locale"]) { - var children = node["children"] as JArray; - Assert.True(children != null, $"Expected children under `{(string?)node["message"]}` in: {runner.LastRunProcess!.Output}"); - node = (JObject)children!.Single(c => (string?)c["message"] == message); + var children = Assert.IsType(node["children"]); + node = (JObject)children.Single(c => (string?)c["message"] == message); } Assert.Equal("8888888888888888", (string?)node["spanId"]); From 6ac4531668b77789d6bbff91b5d6b71202baf535 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 26 Aug 2026 16:34:51 +1000 Subject: [PATCH 3/4] Drop a comment --- src/SeqCli/Output/OutputFormat.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/SeqCli/Output/OutputFormat.cs b/src/SeqCli/Output/OutputFormat.cs index 64a5703f..7b9c5ea7 100644 --- a/src/SeqCli/Output/OutputFormat.cs +++ b/src/SeqCli/Output/OutputFormat.cs @@ -170,7 +170,6 @@ public void WriteEntity(Entity entity) var writer = new LoggerConfiguration() .Destructure.With() - // The default limit truncates deeply-nested documents, such as trace trees. .Destructure.ToMaximumDepth(10000) .Enrich.With() .WriteTo.Console(TextFormatters.Plain(TemplateTheme, "{@m}" + Environment.NewLine)) @@ -202,7 +201,6 @@ public void WriteObject(object value) var writer = new LoggerConfiguration() .Destructure.With() - // The default limit truncates deeply-nested documents, such as trace trees. .Destructure.ToMaximumDepth(10000) .Enrich.With() .WriteTo.Console(TextFormatters.Plain(TemplateTheme, "{@m}" + Environment.NewLine)) From 4b64c34ff2e972f5b21b420e201af1e003659ee6 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 26 Aug 2026 16:37:29 +1000 Subject: [PATCH 4/4] More test tidiying --- test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs b/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs index 5a241dbd..e85c24fa 100644 --- a/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs +++ b/test/SeqCli.EndToEnd/Traces/TraceShowTestCase.cs @@ -101,10 +101,10 @@ public Task ExecuteAsync( ((JArray)query["children"]!).Select(c => (string)c["message"]!).ToArray()); var node = root; - foreach (var message in ["Render response", "Serialize model", "Serialize order", "Format currency", "Lookup locale"]) + foreach (var message in new[] {"Render response", "Serialize model", "Serialize order", "Format currency", "Lookup locale"}) { var children = Assert.IsType(node["children"]); - node = (JObject)children.Single(c => (string?)c["message"] == message); + node = Assert.IsType(Assert.Single(children, c => (string?)c["message"] == message)); } Assert.Equal("8888888888888888", (string?)node["spanId"]);