Skip to content

Commit 69c15e5

Browse files
committed
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 #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.
1 parent f9a2d2c commit 69c15e5

File tree

3 files changed

+74
-19
lines changed

3 files changed

+74
-19
lines changed

src/core/Akka.TestKit/EventFilter/Internal/EventFilterBase.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,26 @@ protected virtual void OnEventMatched(LogEvent logEvent)
8787
/// <returns>TBD</returns>
8888
protected bool InternalDoMatch(string src, object? msg)
8989
{
90+
// Check source matcher first (fast path)
91+
if (!_sourceMatcher.IsMatch(src))
92+
return false;
93+
94+
// For semantic logging support, try matching against both the formatted message
95+
// and the unformatted template pattern
96+
if (msg is LogMessage logMessage)
97+
{
98+
// Try matching against the template pattern first (e.g., "User {UserId} logged in")
99+
if (_messageMatcher.IsMatch(logMessage.Format))
100+
return true;
101+
102+
// Fall back to matching the formatted message (e.g., "User 12345 logged in")
103+
var formattedMsg = logMessage.ToString() ?? "null";
104+
return _messageMatcher.IsMatch(formattedMsg);
105+
}
106+
107+
// Non-semantic logging or legacy messages
90108
var msgstr = msg == null ? "null" : msg.ToString() ?? "null";
91-
return _sourceMatcher.IsMatch(src) && _messageMatcher.IsMatch(msgstr);
109+
return _messageMatcher.IsMatch(msgstr);
92110
}
93111

94112
/// <summary>

src/core/Akka.Tests/Loggers/SemanticLoggingSpecs.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System;
99
using System.Collections.Generic;
1010
using System.Linq;
11+
using Akka.Configuration;
1112
using Akka.Event;
1213
using Akka.TestKit;
1314
using FluentAssertions;
@@ -17,6 +18,14 @@ namespace Akka.Tests.Loggers
1718
{
1819
public class SemanticLoggingSpecs : AkkaSpec
1920
{
21+
public SemanticLoggingSpecs() : base(ConfigurationFactory.ParseString(@"
22+
akka {
23+
loglevel = INFO
24+
stdout-loglevel = INFO
25+
}
26+
"))
27+
{
28+
}
2029
[Fact(DisplayName = "MessageTemplateParser should parse positional templates correctly")]
2130
public void MessageTemplateParser_should_parse_positional_templates()
2231
{
@@ -331,5 +340,45 @@ public void End_to_end_semantic_logging_should_work()
331340
// Message formatting
332341
logMessage.ToString().Should().Be("User 123 performed action Login");
333342
}
343+
344+
[Fact(DisplayName = "EventFilter should match semantic logging templates with named properties")]
345+
public void EventFilter_should_match_semantic_templates()
346+
{
347+
// This test demonstrates the issue from GitHub #7932
348+
// EventFilter should match against the template pattern, not just the formatted output
349+
350+
EventFilter.Info("OnCreateBet BetId:{BetId} created").ExpectOne(() =>
351+
{
352+
Log.Info("OnCreateBet BetId:{BetId} created", 12345);
353+
});
354+
}
355+
356+
[Fact(DisplayName = "EventFilter should match semantic logging templates with contains")]
357+
public void EventFilter_should_match_semantic_templates_with_contains()
358+
{
359+
EventFilter.Info(contains: "BetId:{BetId}").ExpectOne(() =>
360+
{
361+
Log.Info("OnCreateBet BetId:{BetId} created", 12345);
362+
});
363+
}
364+
365+
[Fact(DisplayName = "EventFilter should match semantic logging templates with partial pattern")]
366+
public void EventFilter_should_match_semantic_partial_pattern()
367+
{
368+
EventFilter.Info(start: "User {UserId}").ExpectOne(() =>
369+
{
370+
Log.Info("User {UserId} logged in from {IpAddress}", 123, "192.168.1.1");
371+
});
372+
}
373+
374+
[Fact(DisplayName = "EventFilter should still match formatted output when template doesn't match")]
375+
public void EventFilter_should_fallback_to_formatted_output()
376+
{
377+
// Should also be able to match against the actual formatted values
378+
EventFilter.Info(contains: "12345").ExpectOne(() =>
379+
{
380+
Log.Info("OnCreateBet BetId:{BetId} created", 12345);
381+
});
382+
}
334383
}
335384
}

src/core/Akka/Event/SemanticLogMessageFormatter.cs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,9 @@ public string Format(string format, IEnumerable<object> args)
7777
for (int i = 0; i < readOnlyList.Count; i++)
7878
argArray[i] = readOnlyList[i];
7979

80-
try
81-
{
82-
return string.Format(format, argArray);
83-
}
84-
catch (FormatException)
85-
{
86-
return $"{format} [{string.Join(", ", argArray)}]";
87-
}
80+
// For positional templates, use string.Format directly without catching FormatException
81+
// to maintain backward compatibility with DefaultLogMessageFormatter behavior
82+
return string.Format(format, argArray);
8883
}
8984
else
9085
{
@@ -110,16 +105,9 @@ public string Format(string format, IEnumerable<object> args)
110105

111106
if (isPositional2)
112107
{
113-
// Use standard string.Format for positional templates
114-
try
115-
{
116-
return string.Format(format, argArray);
117-
}
118-
catch (FormatException)
119-
{
120-
// If formatting fails, return the format string with args appended
121-
return $"{format} [{string.Join(", ", argArray)}]";
122-
}
108+
// For positional templates, use string.Format directly without catching FormatException
109+
// to maintain backward compatibility with DefaultLogMessageFormatter behavior
110+
return string.Format(format, argArray);
123111
}
124112
else
125113
{

0 commit comments

Comments
 (0)