-
Notifications
You must be signed in to change notification settings - Fork 1.4k
MessageLayoutRenderer - Handle Exception ToString can throw with AOT #5992
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds a safe exception-rendering helper in MessageLayoutRenderer that wraps Exception.ToString() with a try/catch and falls back to type/message plus recursive inner-exception rendering; also reorders two assignments in ExceptionLayoutRenderer.AppendToString's try block. No public API changes. Changes
Sequence Diagram(s)sequenceDiagram
participant Renderer as MessageLayoutRenderer
participant Helper as AppendExceptionToString
participant Ex as Exception
participant Log as InternalLogger
Renderer->>Helper: AppendExceptionToString(builder, ex)
alt ex.ToString() succeeds
Helper->>Ex: ex.ToString()
Ex-->>Helper: renderedString
Helper-->>Renderer: append renderedString
else ex.ToString() throws
Helper->>Ex: ex.ToString()
Ex--x Helper: throws
Helper->>Log: Warn("Exception.ToString() failed", ex)
Helper-->>Renderer: append "ExceptionType: message"
opt inner exception present
Helper->>Helper: AppendExceptionToString(builder, innerException)
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the 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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/NLog/LayoutRenderers/MessageLayoutRenderer.cs (2)
95-103: Robust exception rendering path — good. One edge-case to verify.
If the message is empty (e.g., Raw with ""),ExceptionSeparatoris still appended, producing a leading separator. Confirm this matches prior behavior; if not, gate the separator on whether this renderer appended any message content.Possible tweak (requires capturing start length earlier in Append):
protected override void Append(StringBuilder builder, LogEventInfo logEvent) { + int startLen = builder.Length; @@ - if (!exceptionOnly) - builder.Append(ExceptionSeparator); + if (!exceptionOnly && builder.Length > startLen) + builder.Append(ExceptionSeparator); AppendExceptionToString(builder, primaryException); }
105-126: Fallback should include all AggregateException inners; trim allocations.
WhenToString()throws on anAggregateExceptionwith multiple inners, onlyInnerExceptionis rendered. IterateInnerExceptionsin the fallback and avoid interpolation to reduce temps.Apply within the catch:
- catch (Exception ex) - { - InternalLogger.Warn(ex, "Message-LayoutRenderer Could not output ToString for Exception: {0}", exception.GetType()); - builder.Append($"{exception.GetType()}: {exceptionMessage}"); - if (innerException != null) - { - builder.AppendLine(); - AppendExceptionToString(builder, innerException); - } - } + catch (Exception ex) + { + InternalLogger.Warn(ex, "Message-LayoutRenderer failed to call ToString() on {0}", exception.GetType()); + var typeName = exception.GetType().FullName ?? exception.GetType().Name; + builder.Append(typeName); + if (!string.IsNullOrEmpty(exceptionMessage)) + { + builder.Append(": "); + builder.Append(exceptionMessage); + } + + if (exception is AggregateException agg && agg.InnerExceptions?.Count > 0) + { + foreach (var ie in agg.InnerExceptions) + { + builder.AppendLine(); + AppendExceptionToString(builder, ie); + } + } + else if (innerException != null) + { + builder.AppendLine(); + AppendExceptionToString(builder, innerException); + } + }Also consider a simple recursion cap (e.g., max depth 16) to prevent pathological cycles.
Would you like a small unit test that defines an Exception whose
ToString()throws and asserts the fallback (including multipleAggregateExceptioninners)?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/NLog/LayoutRenderers/MessageLayoutRenderer.cs(2 hunks)
🔇 Additional comments (1)
src/NLog/LayoutRenderers/MessageLayoutRenderer.cs (1)
38-38: LGTM: InternalLogger import is appropriate.
Enables safe fallback logging inside the new exception renderer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/NLog/LayoutRenderers/ExceptionLayoutRenderer.cs (1)
441-446: Avoid losing the fallback Message when InnerException getter throwsReordering means if
ex.InnerExceptionthrows beforeexceptionMessageis captured, the fallback becomesType:with an empty message. CapturingMessagefirst preserves more signal in that failure mode.Apply minimal swap:
- innerException = ex.InnerException; - exceptionMessage = ex.Message; + exceptionMessage = ex.Message; + innerException = ex.InnerException;Alternative (more robust): capture both properties in separate try/catch blocks before calling
ToString()so either getter failing doesn’t hide the other.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/NLog/LayoutRenderers/ExceptionLayoutRenderer.cs(1 hunks)src/NLog/LayoutRenderers/MessageLayoutRenderer.cs(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/NLog/LayoutRenderers/MessageLayoutRenderer.cs
|


Followup to #5741