-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Description
EventPipe is intended to maintain a current keyword and level filter for each EventSource based on the set of active tracing sessions. Whenever a new session starts or an existing session finishes these filters may need to be updated. Unforetunately the update on session end isn't correct and the keyword and level filters still include the session that is exiting. One of the ways the keyword and level filters are visible is through the EventSource.IsEnabled(level, keyword) API which returns incorrect results.
Reproduction Steps
- Compile and run this code:
using System.Diagnostics.Tracing;
namespace ConsoleApp63
{
internal class Program
{
static void Main(string[] args)
{
MyEventSource.Log.Info1("Hello, World!");
Console.ReadLine();
}
}
[EventSource(Name ="MyEventSource")]
public class MyEventSource : EventSource
{
public static MyEventSource Log = new MyEventSource();
[Event(1, Level = EventLevel.Informational)]
public void Info1(string message)
{
WriteEvent(1, message);
}
override protected void OnEventCommand(EventCommandEventArgs args)
{
Console.WriteLine($"IsEnabled(Level=Info,Keyword=2): {this.IsEnabled(EventLevel.Informational, (EventKeywords)0x2)}");
}
}
}-
In a 2nd console window start an EventPipe session by running:
dotnet-trace collect -n <app_name_here> --providers MyEventSource:1:Error -
In a 3rd console window start another EventPipe session by running:
dotnet-trace collect -n <app_name_here> --providers MyEventSource:2:Informational -
Hit enter in the 3rd console window to stop the Informational level session
-
Hit enter in the 2nd console window to stop the Error level session
Expected behavior
Each step 2-5 should print one line of this output:
IsEnabled(Level=Info,Keyword=2): False
IsEnabled(Level=Info,Keyword=2): True
IsEnabled(Level=Info,Keyword=2): False
IsEnabled(Level=Info,Keyword=2): False
Actual behavior
Each step 2-5 should print one line of this output:
IsEnabled(Level=Info,Keyword=2): False
IsEnabled(Level=Info,Keyword=2): True
IsEnabled(Level=Info,Keyword=2): True
IsEnabled(Level=Info,Keyword=2): False
Regression?
Unverified, but the issue probably extends back to when EventPipe was first added.
Known Workarounds
No response
Configuration
Windows x64 .NET 10 Preview but I expect it reproes on any config
Other information
I believe there are actually two separate bugs that cause this:
-
In the EventPipe source code when disabling a session the update calcuation for level and keyword should exclude the session being disabled but doesn't:
https://github.com/dotnet/runtime/blob/main/src/native/eventpipe/ep-config.c#L588 -
In the EventSource code when a session disables a provider the keyword and level aren't recalculated
runtime/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
Lines 2760 to 2791 in 767be2a
if (!commandArgs.enable) { // If we are disabling, maybe we can turn on 'quick checks' to filter // quickly. These are all just optimizations (since later checks will still filter) // There is a good chance EnabledForAnyListener are not as accurate as // they could be, go ahead and get a better estimate. foreach (int eventID in m_eventData.Keys) { bool isEnabledForAnyListener = false; for (EventDispatcher? dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next) { Debug.Assert(dispatcher.m_EventEnabled != null); if (dispatcher.m_EventEnabled[eventID]) { isEnabledForAnyListener = true; break; } } ref EventMetadata eventMeta = ref CollectionsMarshal.GetValueRefOrNullRef(m_eventData, eventID); eventMeta.EnabledForAnyListener = isEnabledForAnyListener; } // If no events are enabled, disable the global enabled bit. if (!AnyEventEnabled()) { m_level = 0; m_matchAnyKeyword = 0; m_eventSourceEnabled = false; } }