dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.47k stars 4.76k forks source link

Event Tracing for TransactionScope does not work. #109101

Open Camios opened 1 month ago

Camios commented 1 month ago

Description

I am unable to enable the EventSource with the Name "System.Transactions.TransactionsEventSource" (defined TransactionsEtwProvider) because it incorrectly defines two event Ids with the same value (11).

This means no events get sent to any listener.

Reproduction Steps

NET 8.0.403 System.Transactions file version 8.0.1024.46610

Repro

  1. In an EventListener, enable the eventSource called "System.Transactions.TransactionsEventSource"
  2. In main program, create a TransactionScope

Minimal code for repro follows. Put a break point on the call to EnableEvents in TransactionScopeEventListener and step into the System.Diagnostics.Tracing.EventSource code and put a breakpoint on DoCommand method and note it throws.

Event Listener

using System.Collections.Concurrent;
using System.Diagnostics.Tracing;

namespace Proto.Transactions;
public class TransactionScopeEventListener : EventListener
{
    private const string EventSourceName = "System.Transactions.TransactionsEventSource";
    public ConcurrentQueue<EventInfo> Events { get; } = new();

    public TransactionScopeEventListener()
    {
        EventSourceCreated += OnEventSourceCreated;
        EventWritten += OnEventWritten;
    }

    private void OnEventWritten(object? sender, EventWrittenEventArgs e)
    {
        if (e.EventSource.Name == EventSourceName)
        {
            Events.Append(new EventInfo(e.EventId, e.EventName, e.Level, e.PayloadNames?.ToArray() ?? Array.Empty<string>()));
        }
    }

    private void OnEventSourceCreated(object? sender, EventSourceCreatedEventArgs e)
    {
        if (e.EventSource?.Name == EventSourceName)
        {
            EnableEvents(e.EventSource, EventLevel.LogAlways);
        }
    }
}

Program

using System.Transactions;

namespace Proto.Transactions;

internal class Program
{
    static void Main(string[] args)
    {
        using var listener = new TransactionScopeEventListener();
        using (TransactionScope scope = new TransactionScope())
        {
            ...
        }
        ...
    }
}

Expected behavior

A MethodEntered event is logged and exists in the listener's Events collection.

Actual behavior

A MethodEntered event isn't logged because the EventSource isn't enabled.

The EventSource wasn't enabled because of an error when trying to enable the "System.Transactions.TransactionsEventSource" defined by the TransactionsEtwProvider class.

The ArgumentException message is "Event MethodEnterTraceLtm has ID 11 which is already in use."

Am I doing something wrong or is it a blatant mistake for TransactionsEtwProvider to have two event Ids the same (looks like the second one should have been 51 if it was following the sequence)? Specifically: private const int METHOD_ENTER_LTM_EVENTID = 11; private const int TRANSACTION_CREATED_OLETX_EVENTID = 11;

https://source.dot.net/#System.Transactions.Local/System/Transactions/TransactionsEtwProvider.cs,09968f86241d7c4d

Exception details

System.ArgumentException
  HResult=0x80070057
  Message=Event MethodEnterTraceLtm has ID 11 which is already in use.
  Source=System.Private.CoreLib
  StackTrace:
   at System.Diagnostics.Tracing.ManifestBuilder.ManifestError(String msg, Boolean runtimeCritical) in /_/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs:line 5601
   at System.Diagnostics.Tracing.EventSource.DebugCheckEvent(Dictionary`2& eventsByName, EventMetadata[] eventData, MethodInfo method, EventAttribute eventAttribute, ManifestBuilder manifest, EventManifestOptions options) in /_/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs:line 3600
   at System.Diagnostics.Tracing.EventSource.CreateManifestAndDescriptors(Type eventSourceType, String eventSourceDllName, EventSource source, EventManifestOptions flags) in /_/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs:line 3330
   at System.Diagnostics.Tracing.EventSource.EnsureDescriptorsInitialized() in /_/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs:line 2830
   at System.Diagnostics.Tracing.EventSource.DoCommand(EventCommandEventArgs commandArgs) in /_/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs:line 2624

  This exception was originally thrown at this call stack:
    System.Diagnostics.Tracing.ManifestBuilder.ManifestError(string, bool) in EventSource.cs
    System.Diagnostics.Tracing.EventSource.DebugCheckEvent(ref System.Collections.Generic.Dictionary<string, string>, System.Diagnostics.Tracing.EventSource.EventMetadata[], System.Reflection.MethodInfo, System.Diagnostics.Tracing.EventAttribute, System.Diagnostics.Tracing.ManifestBuilder, System.Diagnostics.Tracing.EventManifestOptions) in EventSource.cs
    System.Diagnostics.Tracing.EventSource.CreateManifestAndDescriptors(System.Type, string, System.Diagnostics.Tracing.EventSource, System.Diagnostics.Tracing.EventManifestOptions) in EventSource.cs
    System.Diagnostics.Tracing.EventSource.EnsureDescriptorsInitialized() in EventSource.cs
    System.Diagnostics.Tracing.EventSource.DoCommand(System.Diagnostics.Tracing.EventCommandEventArgs) in EventSource.cs

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

dotnet-policy-service[bot] commented 1 month ago

Tagging subscribers to this area: @tarekgh, @tommcdon, @pjanotti See info in area-owners.md if you want to be subscribed.

martincostello commented 1 month ago

Looks like a typo to me too, as the one after is 52.

dotnet-policy-service[bot] commented 1 month ago

Tagging subscribers to this area: @roji, @ajcvickers See info in area-owners.md if you want to be subscribed.

Camios commented 1 month ago

https://github.com/dotnet/runtime/pull/109138 Never done a pull request to this repo before.