Backport: Add native semantic logging support with property extraction#7955
Merged
Aaronontheweb merged 1 commit intoakkadotnet:v1.5from Dec 2, 2025
Merged
Conversation
…kkadotnet#7933) * feat: Add native semantic logging support to Akka.NET core Implements semantic/structured logging with support for both positional ({0}) and named ({PropertyName}) message templates, enabling structured property extraction for external logging frameworks. Key Features: - MessageTemplateParser with ThreadStatic LRU cache for template parsing - LogMessage enhanced with PropertyNames and GetProperties() APIs - SemanticLogMessageFormatter for Serilog-style template formatting - LogEventExtensions helper methods for easy property extraction - StandardOutLogger updated to display semantic properties - Zero new dependencies - pure BCL implementation - Full backward compatibility maintained Performance Optimizations: - ThreadStatic caching avoids lock contention - Lazy property evaluation (zero cost if not used) - FrozenDictionary on .NET 8+ for optimal read performance - LRU eviction prevents unbounded cache growth Testing: - 25 new unit tests covering template parsing, property extraction, and formatting - All 79 existing logger tests pass (full backward compatibility) - Tests validate positional templates, named templates, edge cases, and caching This enables external logger plugins (Serilog, NLog, MEL) to easily extract structured properties using logEvent.TryGetProperties() for integration with their native structured logging capabilities. Addresses akkadotnet#7932 * perf: optimize semantic logging memory allocations (75% reduction) Implemented Priority 1 performance optimizations to reduce GC pressure in semantic logging operations. Changes: - LogMessage.GetProperties(): Avoid ToArray() when Parameters() returns IReadOnlyList<object> (LogValues<T> structs), saving ~200-300 bytes - SemanticLogMessageFormatter.Format(): Check args type before conversion, use IReadOnlyList directly for named templates, only convert to array when required by string.Format(), saving ~500-800 bytes - SemanticLoggingBenchmarks: Add comprehensive benchmark suite (34 benchmarks) and fix GlobalSetup to include GetProperties benchmarks Performance Results: - Full E2E pipeline: 1592B → 400B (75% reduction) 🎯 - Format 3 params: 1248B → 680B (45% reduction) - GetProperties access: 526ns → 1.7ns (99.7% faster) - Template cache hits: 70ns → 47ns (33% faster) - E2E semantic logging: 1.34μs → 284ns (79% faster) All 79 unit tests passing. Benchmarks confirm optimizations maintain correctness while achieving target allocation reductions. Addresses akkadotnet#7932 * Enable SemanticLogMessageFormatter as default logger formatter Changed the default logger formatter from DefaultLogMessageFormatter to SemanticLogMessageFormatter to enable semantic logging support by default. This allows both positional {0} and named {PropertyName} templates to work out of the box. Changes: - Updated akka.conf to use SemanticLogMessageFormatter as default - Added special case handling in Settings.cs for SemanticLogMessageFormatter singleton instance All 62 existing logger tests pass, confirming backward compatibility with positional templates while enabling new semantic logging capabilities. * feat: Add EventFilter support for semantic logging templates Enables EventFilter to match against semantic logging templates in unit tests, resolving the core issue from GitHub akkadotnet#7932 where EventFilter.Info("BetId:{BetId}") would fail to match log messages using named property syntax. Changes: - Modified EventFilterBase.InternalDoMatch to check LogMessage.Format template before falling back to formatted output - Allows matching against both template patterns ("{UserId}") and formatted values ("12345") - Added comprehensive tests for EventFilter with semantic templates (exact match, contains, starts with) - Removed FormatException catching for positional templates to maintain backward compatibility with DefaultLogMessageFormatter All 66 logger tests pass, including 4 new EventFilter semantic logging tests and existing backward compatibility tests. * test: Add semantic logging integration tests for log filtering Added 8 comprehensive tests verifying that log filtering works correctly with semantic logging templates. Tests cover: - Filtering by formatted message content with named properties - Filtering by property values (e.g., {AlertLevel} = "CRITICAL") - Multiple properties in single log message - Positional templates with filtering (backward compatibility) - Source filtering combined with semantic logging - Format specifiers in templates (e.g., {Amount:N2}) - Messages that should pass through filters All 25 log filter tests pass (17 existing + 8 new), confirming semantic logging integrates seamlessly with the log filtering system introduced in v1.5.21. * fix: Update ConfigurationSpec to expect SemanticLogMessageFormatter as default Updated the configuration validation test to expect SemanticLogMessageFormatter instead of DefaultLogMessageFormatter as the default logger formatter, matching the change made in commit f9a2d2c. All 4 configuration tests pass. * fix: enable nullable reference types in LogEventExtensions - Added #nullable enable directive - Marked 'properties' out parameter as nullable in TryGetProperties - Ensures proper null safety for the semantic logging API * test: Add semantic logging edge cases verification test - Added ShouldHandleSemanticLogEdgeCases test to DefaultLogFormatSpec - Tests named properties, positional properties, mixed types, null values, special characters, booleans, dates, and formatting alignment - Reuses existing sanitization methods from DefaultLogFormatSpec - Verifies semantic logging formatter output for various edge cases * Update API Approval list * Add new edge case unit tests (failing) * docs: Add Message Templates spec reference to SemanticLogMessageFormatter - Added link to https://messagetemplates.org/ specification - Documented supported syntax (named/positional properties, format specifiers, alignment, escaped braces) - Documented unsupported syntax (destructuring operators, empty property names) * fix: Correct escaped brace handling in semantic logging per Message Templates spec Parser fixes: - Removed incorrect }} check after placeholder closing brace - Parser now correctly extracts {UserId} from "{UserId}}" and "{{{UserId}}}" Formatter fixes: - Rewrote FormatNamedTemplate to handle }} in literal text correctly - Added UnescapeBraces helper for templates with no placeholders - "Use {{ and }}" now correctly produces "Use { and }" Test updates: - Updated {:N2} test to document as invalid per Message Templates spec - Invalid templates have "garbage in, garbage out" behavior (not crashing) Fixes edge cases reported in commit 1c58a6b. All 34 semantic logging tests now pass. * fix: Use culture-independent format specifiers in verify test The ShouldHandleSemanticLogEdgeCases verify test was failing on CI due to locale differences: - {Amount:C} produces $123.45 on US locale but ¤123.45 on invariant - DateTime.ToString() produces different formats per locale Changed to culture-independent formats: - Use ${Amount:F2} (literal $ + fixed-point number) instead of {Amount:C} - Use {JoinDate:yyyy-MM-dd} (ISO 8601) for dates * test: Add escaped brace benchmarks and .NET Framework verified file - Added benchmark category for escaped brace handling to track performance of edge case fixes - Added .Net.verified.txt baseline for .NET Framework 4.8 CI runs * Add unit tests * fix: Implement alignment specifiers and null ToString() handling in SemanticLogMessageFormatter - Add support for alignment specifiers in named templates per Message Templates spec - Parse {Name,alignment:format} syntax correctly - Apply PadLeft() for positive alignment (right-align) - Apply PadRight() for negative alignment (left-align) - Fix null handling when ToString() returns null - Check ToString() result before attempting format operations - Return "null" string instead of empty string for null ToString() results - Handles both plain and formatted property cases - Fix test bug: missing '>' character in alignment test format string These changes ensure the semantic logging formatter correctly implements the Message Templates specification for alignment and handles defensive edge cases. --------- Co-authored-by: Gregorius Soedharmo <arkatufus@yahoo.com>
This was referenced Dec 11, 2025
This was referenced Jan 7, 2026
This was referenced Feb 20, 2026
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.
Cherry-pick of #7933 from dev to v1.5
Summary
Backports semantic logging support to v1.5 release branch.
This adds native semantic logging support with property extraction, allowing structured logging with named placeholders (e.g.,
Log.Info("User {UserId} logged in", userId)).Original PR: #7933