Repository navigation
Make LogExceptionHandler log again - #389
Merged
Merged
Conversation
Since the move to Microsoft.Extensions.Logging the handler built the SpEL
text "#log.<Level>(<expr>, #e)" and evaluated it against an ILogger, which
has no such instance methods. The evaluation threw, the catch swallowed it
with a warning, and nothing was logged.
ActionExpressionText is now the message expression. HandleException
evaluates it against the call context and logs the result directly with
the constant "{Message}" template at LogLevel, in the LogName category,
attaching the exception from #e unless LogMessageOnly is set. A failing
expression still logs a warning through the handler's own logger and the
handler still returns "logged". The set-once guard is gone, the getter
returns the expression as assigned, and the "log" context variable is
assigned rather than added so several log handlers can share a context.
Adds LogExceptionHandlerTests (direct and through ExceptionHandlerAdvice)
and replaces the legacy #log.Fatal(...) action in an existing test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGkLQuAuUjvRjrU1AcTsmk
Signed-off-by: Marko Lahma <marko.lahma@gmail.com>
- BreakingChanges.txt item 10: LogExceptionHandler.ActionExpressionText is now the message expression only. - Fix the history note in the XML doc. - When the expression fails and starts with "#log.", warn that the form is no longer supported instead of the generic message. - Log the message outside the try, so a failing logging provider is not reported as an expression failure; test a null-valued expression. - ExceptionHandlerAspectIntegrationTests: assert exact message, level and category instead of substrings that the failure warning could satisfy, and use Assert.Throws instead of try/catch helpers that asserted nothing when no exception was thrown. This also exposed that ExecuteSpelAction never executed its action (unresolvable type name); it now uses T(type, assembly). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGkLQuAuUjvRjrU1AcTsmk Signed-off-by: Marko Lahma <marko.lahma@gmail.com>
…eption Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGkLQuAuUjvRjrU1AcTsmk Signed-off-by: Marko Lahma <marko.lahma@gmail.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LogExceptionHandler, thelogaction of the exception-handler advice, hasn't logged anything since logging moved to Microsoft.Extensions.Logging in 3.0.3 (fda46d9). PR #346 named this as a follow-up.The bug. The handler wrapped its expression as
#log.<Level>(<expression>[, #e])and evaluated it with#logbound to anILogger.ILoggerhas noInformation/Fatal/… instance methods, onlyLogXxxextension methods. So every evaluation threw, the catch reduced it to a warning, and the handler returned "logged" without writing anything.The fix.
ActionExpressionTextis the message expression.HandleExceptionevaluates it against the call context (#method,#args,#target,#e). It then callsILogger.Log(LogLevel, LogMessageOnly ? null : #e, "{Message}", message), so the template stays constant.LogName,LogLevel(default Trace) andLogMessageOnlykeep their meaning.#log.Fatal(...)expression gets a specific warning that says how to rewrite it.logentry in the call context is now assigned, not added. Before, a second log handler on the same call threwArgumentExceptionand replaced the user's exception.ActionExpressionTextis removed. It had frozen the first statement's expression, level andLogMessageOnlyon a shared keyed handler.BreakingChanges item 10.
#log.<Level>(...)wrapper.#log.Fatal('msg', #e)doesn't log. That form worked on 3.0.2 and earlier only by accident of nesting, and nothing has logged since 3.0.3. Migrate toActionExpressionText="'msg'"withLogLevel="Critical".#log, which we'd have to maintain.Tests.
LogExceptionHandlerTests, with 17 cases. They use a recording logger factory to check level, category, message text and whether the exception is attached. They also cover:LogLevelConverter;ExceptionHandlerAdvicewith the DSL, the constraint DSL, keyed handlers and handler lists.ExceptionHandlerAspectIntegrationTestsactually test something now. Before, they matched a substring anywhere in the log, so the failure warning satisfied them, and some asserted nothing if no exception was thrown. Six of them fail against the old source.ExecuteSpelActionnever ran its action, because the type name in its expression couldn't be resolved; it now usesT(type, assembly)and asserts the action ran.spring-revieweraccepted the change with follow-ups, and those follow-ups are in this PR.Known, not changed here.
ExceptionHandlerAdvicereuses one keyed handler instance (log, translate, wrap) for every statement that names it, and each statement overwrites its expressions. This was already the case before this PR.🤖 Generated with Claude Code
https://claude.ai/code/session_01LGkLQuAuUjvRjrU1AcTsmk