|
| 1 | +# EventPipe EventSource Dispatch Issue - Investigation Results |
| 2 | + |
| 3 | +## Issue Summary |
| 4 | +The original issue reported that EventSource events from EventPipe files were not being dispatched properly when using `TraceEventDispatcher.GetDispatcherFromFileName()` directly, while they worked correctly when using `TraceLog.Events.GetSource()`. |
| 5 | + |
| 6 | +## Investigation Findings |
| 7 | + |
| 8 | +### Root Cause |
| 9 | +The issue was caused by the lack of a specialized parser to handle EventPipe-specific event templates. When EventPipe files were read using `TraceEventDispatcher.GetDispatcherFromFileName()`, the created `EventPipeEventSource` would: |
| 10 | + |
| 11 | +1. Parse metadata from the EventPipe file and create `DynamicTraceEventData` templates |
| 12 | +2. Store these templates in an internal `_metadataTemplates` dictionary |
| 13 | +3. But these templates were not being registered with the TraceEventSource's template lookup table |
| 14 | + |
| 15 | +When events were dispatched: |
| 16 | +- The `Lookup` method couldn't find the template in the table |
| 17 | +- It would call unhandled event handlers |
| 18 | +- But there was no handler that knew how to retrieve templates from EventPipeEventSource's metadata cache |
| 19 | + |
| 20 | +### The Fix |
| 21 | +The fix was implemented through the introduction of `EventPipeTraceEventParser` (commit 338bf0507753a9e7b261469fde800b681b0ac9ac): |
| 22 | + |
| 23 | +1. **EventPipeTraceEventParser** - A new parser class was created that: |
| 24 | + - Extends `ExternalTraceEventParser` to automatically register as an unhandled event handler |
| 25 | + - Implements `TryLookup` to retrieve templates from `EventPipeEventSource._metadataTemplates` |
| 26 | + - Integrates with the DynamicTraceEventParser's event definition system |
| 27 | + |
| 28 | +2. **DynamicTraceEventParser Integration** - The DynamicTraceEventParser was updated to: |
| 29 | + - Create an `EventPipeTraceEventParser` instance (line 53) |
| 30 | + - Hook up the parser's `NewEventDefinition` callback to its own `OnNewEventDefintion` method (line 54) |
| 31 | + - This ensures that when EventPipe templates are discovered, they're properly registered |
| 32 | + |
| 33 | +### How It Works |
| 34 | +When an unknown EventSource event is encountered in an EventPipe file: |
| 35 | + |
| 36 | +1. `EventPipeEventSource.DispatchEvent` is called |
| 37 | +2. `Lookup` doesn't find the event in the template table, returns unhandled |
| 38 | +3. The unhandled event handlers are called in order: |
| 39 | + - `RegisteredTraceEventParser.TryLookup` - checks if it's a registered system event |
| 40 | + - `EventPipeTraceEventParser.TryLookup` - retrieves the template from EventPipeEventSource's metadata cache |
| 41 | +4. The template is registered via `OnNewEventDefintion` |
| 42 | +5. Subsequent events of the same type are dispatched directly |
| 43 | + |
| 44 | +## Test Results |
| 45 | + |
| 46 | +### Test Created |
| 47 | +A comprehensive test was added to `EventPipeParsing.cs` called `EventSourceEventsDispatchedUsingGetDispatcherFromFileName` that: |
| 48 | +- Creates a synthetic EventPipe file with EventSource-like events |
| 49 | +- Tests both `TraceEventDispatcher.GetDispatcherFromFileName()` and `TraceLog.Events.GetSource()` |
| 50 | +- Verifies both methods see the same events |
| 51 | + |
| 52 | +### Test Output |
| 53 | +``` |
| 54 | +Events from Dispatcher: 4 |
| 55 | +Event names: AppStarted, ProcessingItem, ProcessingItem, AppStopped |
| 56 | +Events from TraceLog: 4 |
| 57 | +Event names: AppStarted, ProcessingItem, ProcessingItem, AppStopped |
| 58 | +``` |
| 59 | + |
| 60 | +**Result: PASSED** ✅ |
| 61 | + |
| 62 | +Both methods now correctly dispatch all EventSource events from EventPipe files. |
| 63 | + |
| 64 | +## Conclusion |
| 65 | + |
| 66 | +The issue has been **FIXED** by the addition of `EventPipeTraceEventParser` and its integration with `DynamicTraceEventParser`. The test confirms that EventSource events are now properly dispatched when using `TraceEventDispatcher.GetDispatcherFromFileName()` on EventPipe files. |
| 67 | + |
| 68 | +## Code Locations |
| 69 | + |
| 70 | +- **Fix Implementation**: `src/TraceEvent/EventPipe/EventPipeTraceEventParser.cs` |
| 71 | +- **Integration Point**: `src/TraceEvent/DynamicTraceEventParser.cs` (lines 52-54) |
| 72 | +- **Metadata Storage**: `src/TraceEvent/EventPipe/EventPipeEventSource.cs` (CacheMetadata, TryGetTemplateFromMetadata) |
| 73 | +- **Test Validation**: `src/TraceEvent/TraceEvent.Tests/Parsing/EventPipeParsing.cs` (EventSourceEventsDispatchedUsingGetDispatcherFromFileName) |
| 74 | + |
| 75 | +## References |
| 76 | + |
| 77 | +- Original Issue: EventSource Events from EventPipe Aren't Dispatched Properly using EventPipeEventSource Directly |
| 78 | +- Fix Commit: 338bf0507753a9e7b261469fde800b681b0ac9ac - "Implement A Thread Time View for Universal Traces (#2320)" |
| 79 | +- Related CoreCLR PR: https://github.com/dotnet/coreclr/pull/16645 |
0 commit comments