Skip to content

JsonLayout - Protect against cyclic object graphs when DottedRecursion#6084

Merged
snakefoot merged 1 commit intoNLog:devfrom
snakefoot:jsonlayout_cyclic
Jan 31, 2026
Merged

JsonLayout - Protect against cyclic object graphs when DottedRecursion#6084
snakefoot merged 1 commit intoNLog:devfrom
snakefoot:jsonlayout_cyclic

Conversation

@snakefoot
Copy link
Contributor

Followup to #5999 to complete #5991

@snakefoot snakefoot added enhancement Improvement on existing feature json / json-layout labels Jan 31, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 31, 2026

Walkthrough

Removed the comparer parameter from SingleItemScopedInsert to use ReferenceEqualityComparer.Default; added dotted-recursion flattening in JsonLayout with new traversal and cycle-tracking helpers; updated call-sites, ObjectReflectionCache decision logic, and tests (renamed Recursive → RecursiveCollection, added RecursiveProperty, new flattening test).

Changes

Cohort / File(s) Summary
Core change
src/NLog/Internal/SingleItemOptimizedHashSet.cs
Removed IEqualityComparer<T> parameter from SingleItemScopedInsert constructor; constructor and internal usages now use ReferenceEqualityComparer.Default.
Json layout flattening
src/NLog/Layouts/JSON/JsonLayout.cs
Added dotted-recursion support: PropertyValueSupportsDottedRecursion, AppendFlattenedPropertyValue, FlattenObjectProperties; depth-aware traversal and cycle avoidance using SingleItemOptimizedHashSet.
Reflection decision logic
src/NLog/Internal/ObjectReflectionCache.cs
Introduced CheckForObjectProperties and ConvertSimpleToString; adjusted when objects are enumerated vs treated as simple/string values and excluded several reflection-sensitive types.
Call-site updates
src/NLog/Layouts/XML/XmlElementBase.cs, src/NLog/MessageTemplates/ValueFormatter.cs, src/NLog/Targets/DefaultJsonSerializer.cs
Removed local _referenceEqualsComparer fields and updated SingleItemScopedInsert calls to the new three-argument overload (omitting comparer).
Tests
tests/NLog.UnitTests/Layouts/JsonLayoutTests.cs
Renamed BadObject.RecursiveRecursiveCollection, added RecursiveProperty, adjusted expectations, and added DottedRecursion_BadObject_Flattens test verifying flattening behavior.

Sequence Diagram

sequenceDiagram
    participant JsonLayout as JsonLayout (Renderer)
    participant Eligibility as PropertyValueSupportsDottedRecursion
    participant Flattener as AppendFlattenedPropertyValue
    participant Tracker as SingleItemOptimizedHashSet (Tracker)
    participant Walker as FlattenObjectProperties

    JsonLayout->>Eligibility: Check DottedRecursion & value eligibility
    alt flattenable
        JsonLayout->>Flattener: Request flattened append
        Flattener->>Tracker: Start scoped insert (prevent cycles)
        Flattener->>Walker: Traverse object properties (with startDepth)
        Walker->>Tracker: Add nested objects to tracking set
        Walker->>Walker: Recurse and collect flattened property pairs
        Walker->>Tracker: Remove objects from tracking (end scope)
        Walker-->>Flattener: Return flattened properties
        Flattener-->>JsonLayout: Emit flattened JSON properties
    else not flattenable
        JsonLayout->>JsonLayout: Use AppendJsonPropertyValue / AppendPropertyValueInternal
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibble code and twitch my nose,
I swap comparers, tidy rows.
I flatten nests of JSON light,
I skip the loops that cause a fright.
Small hops, new paths — the output's right!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main changes: adding DottedRecursion support with cyclic object graph protection in JsonLayout, which matches the core objective across multiple modified files.
Description check ✅ Passed The description references related issues (#5999, #5991) and frames this as a followup, which is related to the changeset even if minimal in detail.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/NLog/Layouts/JSON/JsonLayout.cs`:
- Around line 541-556: The loop in FlattenObjectProperties uses
SingleItemOptimizedHashSet<object>.SingleItemScopedInsert with
forceHashSet=false which can leave the first inserted item in objectsInPath
across sibling iterations; change the scoped insert to force a HashSet so the
disposed scope always removes the item and prevents leaking first child state —
update the using(...) around SingleItemScopedInsert(objectPropertyValue, ref
objectsInPath, false) to pass true for the forceHashSet parameter (or otherwise
ensure a HashSet-backed scoped insert) so objectsInPath is correctly restored
after each FlattenObjectProperties call.

@snakefoot snakefoot force-pushed the jsonlayout_cyclic branch 4 times, most recently from 1c735f7 to 609825c Compare January 31, 2026 14:30
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/NLog/Layouts/JSON/JsonLayout.cs`:
- Around line 545-548: The flattening loop in JsonLayout.cs currently skips
properties when objectPropertyValue is null, causing null-valued properties to
be lost even if ExcludeEmptyProperties is false; update the logic around
objectPropertyValue and objectProperty.Name so only empty names are skipped and
null values are passed into AppendJsonPropertyValue (so AppendJsonPropertyValue
and the ExcludeEmptyProperties handling decide whether to emit or skip the
property), preserving nulls in flattened output; refer to the variables
objectPropertyValue, objectProperty.Name and the method AppendJsonPropertyValue
when making the change.

@sonarqubecloud
Copy link

@snakefoot snakefoot merged commit 63bdb65 into NLog:dev Jan 31, 2026
5 of 6 checks passed
@snakefoot snakefoot added this to the 6.1.0 milestone Jan 31, 2026
@snakefoot snakefoot changed the title JsonLayout - DottedRecursion protect against cyclic object graphs JsonLayout - Protect against cyclic object graphs when DottedRecursion Jan 31, 2026
@snakefoot snakefoot linked an issue Feb 1, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvement on existing feature json / json-layout size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JsonLayout IncludeEventProperties with DottedRecursion = true

1 participant