Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing')
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/ActivityTracker.cs663
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs263
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterPayload.cs130
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/DiagnosticCounter.cs168
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventActivityOptions.cs41
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventCounter.cs202
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventDescriptor.cs145
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs1353
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs6204
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSourceException.cs52
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/FrameworkEventSource.cs161
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IEventProvider.cs44
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IncrementingEventCounter.cs94
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IncrementingPollingCounter.cs96
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/PollingCounter.cs86
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/StubEnvironment.cs376
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ArrayTypeInfo.cs66
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs129
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSetItem.cs23
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs368
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EmptyStruct.cs17
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EnumHelper.cs31
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs68
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventDataAttribute.cs148
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldAttribute.cs78
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldFormat.cs130
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventIgnoreAttribute.cs27
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs150
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs314
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceOptions.cs107
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs230
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs95
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs126
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyAnalysis.cs41
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs272
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleEventTypes.cs40
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs299
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs693
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs125
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataType.cs351
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs890
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTraits.cs30
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs243
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs381
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs179
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs104
-rw-r--r--netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/Winmeta.cs185
47 files changed, 0 insertions, 16018 deletions
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/ActivityTracker.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/ActivityTracker.cs
deleted file mode 100644
index 07c2112878f..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/ActivityTracker.cs
+++ /dev/null
@@ -1,663 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#else
-using System.Threading.Tasks;
-#endif
-using System.Threading;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Tracks activities. This is meant to be a singleton (accessed by the ActivityTracer.Instance static property)
- ///
- /// Logically this is simply holds the m_current variable that holds the async local that holds the current ActivityInfo
- /// An ActivityInfo is represents a activity (which knows its creator and thus knows its path).
- ///
- /// Most of the magic is in the async local (it gets copied to new tasks)
- ///
- /// On every start event call OnStart
- ///
- /// Guid activityID;
- /// Guid relatedActivityID;
- /// if (OnStart(activityName, out activityID, out relatedActivityID, ForceStop, options))
- /// // Log Start event with activityID and relatedActivityID
- ///
- /// On every stop event call OnStop
- ///
- /// Guid activityID;
- /// if (OnStop(activityName, ref activityID ForceStop))
- /// // Stop event with activityID
- ///
- /// On any normal event log the event with activityTracker.CurrentActivityId
- /// </summary>
- internal class ActivityTracker
- {
- /// <summary>
- /// Called on work item begins. The activity name = providerName + activityName without 'Start' suffix.
- /// It updates CurrentActivityId to track.
- ///
- /// It returns true if the Start should be logged, otherwise (if it is illegal recursion) it return false.
- ///
- /// The start event should use as its activity ID the CurrentActivityId AFTER calling this routine and its
- /// RelatedActivityID the CurrentActivityId BEFORE calling this routine (the creator).
- ///
- /// If activity tracing is not on, then activityId and relatedActivityId are not set
- /// </summary>
- public void OnStart(string providerName, string activityName, int task, ref Guid activityId, ref Guid relatedActivityId, EventActivityOptions options, bool useTplSource = true)
- {
- if (m_current == null) // We are not enabled
- {
- // We used to rely on the TPL provider turning us on, but that has the disadvantage that you don't get Start-Stop tracking
- // until you use Tasks for the first time (which you may never do). Thus we change it to pull rather tan push for whether
- // we are enabled.
- if (m_checkedForEnable)
- return;
- m_checkedForEnable = true;
- if (useTplSource && TplEventSource.Log.IsEnabled(EventLevel.Informational, TplEventSource.Keywords.TasksFlowActivityIds))
- Enable();
- if (m_current == null)
- return;
- }
-
- Debug.Assert((options & EventActivityOptions.Disable) == 0);
-
- ActivityInfo? currentActivity = m_current.Value;
- string fullActivityName = NormalizeActivityName(providerName, activityName, task);
-
- TplEventSource? log = useTplSource ? TplEventSource.Log : null;
- bool tplDebug = log != null && log.Debug;
- if (tplDebug)
- {
- log!.DebugFacilityMessage("OnStartEnter", fullActivityName);
- log!.DebugFacilityMessage("OnStartEnterActivityState", ActivityInfo.LiveActivities(currentActivity));
- }
-
- if (currentActivity != null)
- {
- // Stop activity tracking if we reached the maximum allowed depth
- if (currentActivity.m_level >= MAX_ACTIVITY_DEPTH)
- {
- activityId = Guid.Empty;
- relatedActivityId = Guid.Empty;
- if (tplDebug)
- log!.DebugFacilityMessage("OnStartRET", "Fail");
- return;
- }
- // Check for recursion, and force-stop any activities if the activity already started.
- if ((options & EventActivityOptions.Recursive) == 0)
- {
- ActivityInfo? existingActivity = FindActiveActivity(fullActivityName, currentActivity);
- if (existingActivity != null)
- {
- OnStop(providerName, activityName, task, ref activityId);
- currentActivity = m_current.Value;
- }
- }
- }
-
- // Get a unique ID for this activity.
- long id;
- if (currentActivity == null)
- id = Interlocked.Increment(ref m_nextId);
- else
- id = Interlocked.Increment(ref currentActivity.m_lastChildID);
-
- // The previous ID is my 'causer' and becomes my related activity ID
- relatedActivityId = EventSource.CurrentThreadActivityId;
-
- // Add to the list of started but not stopped activities.
- ActivityInfo newActivity = new ActivityInfo(fullActivityName, id, currentActivity, relatedActivityId, options);
- m_current.Value = newActivity;
-
- // Remember the current ID so we can log it
- activityId = newActivity.ActivityId;
-
- if (tplDebug)
- {
- log!.DebugFacilityMessage("OnStartRetActivityState", ActivityInfo.LiveActivities(newActivity));
- log!.DebugFacilityMessage1("OnStartRet", activityId.ToString(), relatedActivityId.ToString());
- }
- }
-
- /// <summary>
- /// Called when a work item stops. The activity name = providerName + activityName without 'Stop' suffix.
- /// It updates m_current variable to track this fact. The Stop event associated with stop should log the ActivityID associated with the event.
- ///
- /// If activity tracing is not on, then activityId and relatedActivityId are not set
- /// </summary>
- public void OnStop(string providerName, string activityName, int task, ref Guid activityId, bool useTplSource = true)
- {
- if (m_current == null) // We are not enabled
- return;
-
- string fullActivityName = NormalizeActivityName(providerName, activityName, task);
-
- TplEventSource? log = useTplSource ? TplEventSource.Log : null;
- bool tplDebug = log != null && log.Debug;
- if (tplDebug)
- {
- log!.DebugFacilityMessage("OnStopEnter", fullActivityName);
- log!.DebugFacilityMessage("OnStopEnterActivityState", ActivityInfo.LiveActivities(m_current.Value));
- }
-
- while (true) // This is a retry loop.
- {
- ActivityInfo? currentActivity = m_current.Value;
- ActivityInfo? newCurrentActivity = null; // if we have seen any live activities (orphans), at he first one we have seen.
-
- // Search to find the activity to stop in one pass. This insures that we don't let one mistake
- // (stopping something that was not started) cause all active starts to be stopped
- // By first finding the target start to stop we are more robust.
- ActivityInfo? activityToStop = FindActiveActivity(fullActivityName, currentActivity);
-
- // ignore stops where we can't find a start because we may have popped them previously.
- if (activityToStop == null)
- {
- activityId = Guid.Empty;
- // TODO add some logging about this. Basically could not find matching start.
- if (tplDebug)
- log!.DebugFacilityMessage("OnStopRET", "Fail");
- return;
- }
-
- activityId = activityToStop.ActivityId;
-
- // See if there are any orphans that need to be stopped.
- ActivityInfo? orphan = currentActivity;
- while (orphan != activityToStop && orphan != null)
- {
- if (orphan.m_stopped != 0) // Skip dead activities.
- {
- orphan = orphan.m_creator;
- continue;
- }
- if (orphan.CanBeOrphan())
- {
- // We can't pop anything after we see a valid orphan, remember this for later when we update m_current.
- newCurrentActivity ??= orphan;
- }
- else
- {
- orphan.m_stopped = 1;
- Debug.Assert(orphan.m_stopped != 0);
- }
- orphan = orphan.m_creator;
- }
-
- // try to Stop the activity atomically. Other threads may be trying to do this as well.
- if (Interlocked.CompareExchange(ref activityToStop.m_stopped, 1, 0) == 0)
- {
- // I succeeded stopping this activity. Now we update our m_current pointer
-
- // If I haven't yet determined the new current activity, it is my creator.
- newCurrentActivity ??= activityToStop.m_creator;
-
- m_current.Value = newCurrentActivity;
-
- if (tplDebug)
- {
- log!.DebugFacilityMessage("OnStopRetActivityState", ActivityInfo.LiveActivities(newCurrentActivity));
- log!.DebugFacilityMessage("OnStopRet", activityId.ToString());
- }
- return;
- }
- // We failed to stop it. We must have hit a race to stop it. Just start over and try again.
- }
- }
-
- /// <summary>
- /// Turns on activity tracking. It is sticky, once on it stays on (race issues otherwise)
- /// </summary>
- public void Enable()
- {
- if (m_current == null)
- {
- // Catch the not Implemented
- try
- {
- m_current = new AsyncLocal<ActivityInfo?>(ActivityChanging);
- }
- catch (NotImplementedException)
- {
-#if (!ES_BUILD_PCL && !ES_BUILD_PN)
- // send message to debugger without delay
- System.Diagnostics.Debugger.Log(0, null, "Activity Enabled() called but AsyncLocals Not Supported (pre V4.6). Ignoring Enable");
-#endif
- }
- }
- }
-
- /// <summary>
- /// An activity tracker is a singleton, this is how you get the one and only instance.
- /// </summary>
- public static ActivityTracker Instance => s_activityTrackerInstance;
-
- #region private
-
- /// <summary>
- /// Searched for a active (nonstopped) activity with the given name. Returns null if not found.
- /// </summary>
- private static ActivityInfo? FindActiveActivity(string name, ActivityInfo? startLocation)
- {
- ActivityInfo? activity = startLocation;
- while (activity != null)
- {
- if (name == activity.m_name && activity.m_stopped == 0)
- return activity;
- activity = activity.m_creator;
- }
- return null;
- }
-
- /// <summary>
- /// Strip out "Start" or "End" suffix from activity name and add providerName prefix.
- /// If 'task' it does not end in Start or Stop and Task is non-zero use that as the name of the activity
- /// </summary>
- private static string NormalizeActivityName(string providerName, string activityName, int task)
- {
- // We use provider name to distinguish between activities from different providers.
-
- if (activityName.EndsWith(EventSource.s_ActivityStartSuffix, StringComparison.Ordinal))
- {
-#if ES_BUILD_STANDALONE
- return string.Concat(providerName, activityName.Substring(0, activityName.Length - EventSource.s_ActivityStartSuffix.Length));
-#else
- return string.Concat(providerName, activityName.AsSpan(0, activityName.Length - EventSource.s_ActivityStartSuffix.Length));
-#endif
- }
- else if (activityName.EndsWith(EventSource.s_ActivityStopSuffix, StringComparison.Ordinal))
- {
-#if ES_BUILD_STANDALONE
- return string.Concat(providerName, activityName.Substring(0, activityName.Length - EventSource.s_ActivityStopSuffix.Length));
-#else
- return string.Concat(providerName, activityName.AsSpan(0, activityName.Length - EventSource.s_ActivityStopSuffix.Length));
-#endif
- }
- else if (task != 0)
- {
- return providerName + "task" + task.ToString();
- }
- else
- {
- return providerName + activityName;
- }
- }
-
- // *******************************************************************************
- /// <summary>
- /// An ActivityInfo represents a particular activity. It is almost read-only. The only
- /// fields that change after creation are
- /// m_lastChildID - used to generate unique IDs for the children activities and for the most part can be ignored.
- /// m_stopped - indicates that this activity is dead
- /// This read-only-ness is important because an activity's m_creator chain forms the
- /// 'Path of creation' for the activity (which is also its unique ID) but is also used as
- /// the 'list of live parents' which indicate of those ancestors, which are alive (if they
- /// are not marked dead they are alive).
- /// </summary>
- private class ActivityInfo
- {
- public ActivityInfo(string name, long uniqueId, ActivityInfo? creator, Guid activityIDToRestore, EventActivityOptions options)
- {
- m_name = name;
- m_eventOptions = options;
- m_creator = creator;
- m_uniqueId = uniqueId;
- m_level = creator != null ? creator.m_level + 1 : 0;
- m_activityIdToRestore = activityIDToRestore;
-
- // Create a nice GUID that encodes the chain of activities that started this one.
- CreateActivityPathGuid(out m_guid, out m_activityPathGuidOffset);
- }
-
- public Guid ActivityId => m_guid;
-
- public static string Path(ActivityInfo? activityInfo)
- {
- if (activityInfo == null)
- return "";
- return Path(activityInfo.m_creator) + "/" + activityInfo.m_uniqueId.ToString();
- }
-
- public override string ToString()
- {
- return m_name + "(" + Path(this) + (m_stopped != 0 ? ",DEAD)" : ")");
- }
-
- public static string LiveActivities(ActivityInfo? list)
- {
- if (list == null)
- return "";
- return list.ToString() + ";" + LiveActivities(list.m_creator);
- }
-
- public bool CanBeOrphan()
- {
- if ((m_eventOptions & EventActivityOptions.Detachable) != 0)
- return true;
- return false;
- }
-
- #region private
-
- #region CreateActivityPathGuid
- /// <summary>
- /// Logically every activity Path (see Path()) that describes the activities that caused this
- /// (rooted in an activity that predates activity tracking.
- ///
- /// We wish to encode this path in the Guid to the extent that we can. Many of the paths have
- /// many small numbers in them and we take advantage of this in the encoding to output as long
- /// a path in the GUID as possible.
- ///
- /// Because of the possibility of GUID collision, we only use 96 of the 128 bits of the GUID
- /// for encoding the path. The last 32 bits are a simple checksum (and random number) that
- /// identifies this as using the convention defined here.
- ///
- /// It returns both the GUID which has the path as well as the offset that points just beyond
- /// the end of the activity (so it can be appended to). Note that if the end is in a nibble
- /// (it uses nibbles instead of bytes as the unit of encoding, then it will point at the unfinished
- /// byte (since the top nibble can't be zero you can determine if this is true by seeing if
- /// this byte is nonZero. This offset is needed to efficiently create the ID for child activities.
- /// </summary>
- private unsafe void CreateActivityPathGuid(out Guid idRet, out int activityPathGuidOffset)
- {
- fixed (Guid* outPtr = &idRet)
- {
- int activityPathGuidOffsetStart = 0;
- if (m_creator != null)
- {
- activityPathGuidOffsetStart = m_creator.m_activityPathGuidOffset;
- idRet = m_creator.m_guid;
- }
- else
- {
- // TODO FIXME - differentiate between AD inside PCL
- int appDomainID = 0;
-#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
- appDomainID = System.Threading.Thread.GetDomainID();
-#endif
- // We start with the appdomain number to make this unique among appdomains.
- activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)appDomainID);
- }
-
- activityPathGuidOffset = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)m_uniqueId);
-
- // If the path does not fit, Make a GUID by incrementing rather than as a path, keeping as much of the path as possible
- if (12 < activityPathGuidOffset)
- CreateOverflowGuid(outPtr);
- }
- }
-
- /// <summary>
- /// If we can't fit the activity Path into the GUID we come here. What we do is simply
- /// generate a 4 byte number (s_nextOverflowId). Then look for an ancestor that has
- /// sufficient space for this ID. By doing this, we preserve the fact that this activity
- /// is a child (of unknown depth) from that ancestor.
- /// </summary>
- private unsafe void CreateOverflowGuid(Guid* outPtr)
- {
- // Search backwards for an ancestor that has sufficient space to put the ID.
- for (ActivityInfo? ancestor = m_creator; ancestor != null; ancestor = ancestor.m_creator)
- {
- if (ancestor.m_activityPathGuidOffset <= 10) // we need at least 2 bytes.
- {
- uint id = unchecked((uint)Interlocked.Increment(ref ancestor.m_lastChildID)); // Get a unique ID
- // Try to put the ID into the GUID
- *outPtr = ancestor.m_guid;
- int endId = AddIdToGuid(outPtr, ancestor.m_activityPathGuidOffset, id, true);
-
- // Does it fit?
- if (endId <= 12)
- break;
- }
- }
- }
-
- /// <summary>
- /// The encoding for a list of numbers used to make Activity GUIDs. Basically
- /// we operate on nibbles (which are nice because they show up as hex digits). The
- /// list is ended with a end nibble (0) and depending on the nibble value (Below)
- /// the value is either encoded into nibble itself or it can spill over into the
- /// bytes that follow.
- /// </summary>
- private enum NumberListCodes : byte
- {
- End = 0x0, // ends the list. No valid value has this prefix.
- LastImmediateValue = 0xA,
-
- PrefixCode = 0xB, // all the 'long' encodings go here. If the next nibble is MultiByte1-4
- // than this is a 'overflow' id. Unlike the hierarchical IDs these are
- // allocated densely but don't tell you anything about nesting. we use
- // these when we run out of space in the GUID to store the path.
-
- MultiByte1 = 0xC, // 1 byte follows. If this Nibble is in the high bits, it the high bits of the number are stored in the low nibble.
- // commented out because the code does not explicitly reference the names (but they are logically defined).
- // MultiByte2 = 0xD, // 2 bytes follow (we don't bother with the nibble optimization)
- // MultiByte3 = 0xE, // 3 bytes follow (we don't bother with the nibble optimization)
- // MultiByte4 = 0xF, // 4 bytes follow (we don't bother with the nibble optimization)
- }
-
- /// Add the activity id 'id' to the output Guid 'outPtr' starting at the offset 'whereToAddId'
- /// Thus if this number is 6 that is where 'id' will be added. This will return 13 (12
- /// is the maximum number of bytes that fit in a GUID) if the path did not fit.
- /// If 'overflow' is true, then the number is encoded as an 'overflow number (which has a
- /// special (longer prefix) that indicates that this ID is allocated differently
- private static unsafe int AddIdToGuid(Guid* outPtr, int whereToAddId, uint id, bool overflow = false)
- {
- byte* ptr = (byte*)outPtr;
- byte* endPtr = ptr + 12;
- ptr += whereToAddId;
- if (endPtr <= ptr)
- return 13; // 12 means we might exactly fit, 13 means we definitely did not fit
-
- if (0 < id && id <= (uint)NumberListCodes.LastImmediateValue && !overflow)
- WriteNibble(ref ptr, endPtr, id);
- else
- {
- uint len = 4;
- if (id <= 0xFF)
- len = 1;
- else if (id <= 0xFFFF)
- len = 2;
- else if (id <= 0xFFFFFF)
- len = 3;
-
- if (overflow)
- {
- if (endPtr <= ptr + 2) // I need at least 2 bytes
- return 13;
-
- // Write out the prefix code nibble and the length nibble
- WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.PrefixCode);
- }
- // The rest is the same for overflow and non-overflow case
- WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.MultiByte1 + (len - 1));
-
- // Do we have an odd nibble? If so flush it or use it for the 12 byte case.
- if (ptr < endPtr && *ptr != 0)
- {
- // If the value < 4096 we can use the nibble we are otherwise just outputting as padding.
- if (id < 4096)
- {
- // Indicate this is a 1 byte multicode with 4 high order bits in the lower nibble.
- *ptr = (byte)(((uint)NumberListCodes.MultiByte1 << 4) + (id >> 8));
- id &= 0xFF; // Now we only want the low order bits.
- }
- ptr++;
- }
-
- // Write out the bytes.
- while (0 < len)
- {
- if (endPtr <= ptr)
- {
- ptr++; // Indicate that we have overflowed
- break;
- }
- *ptr++ = (byte)id;
- id >>= 8;
- --len;
- }
- }
-
- // Compute the checksum
- uint* sumPtr = (uint*)outPtr;
- // We set the last DWORD the sum of the first 3 DWORDS in the GUID. This
- // This last number is a random number (it identifies us as us) the process ID to make it unique per process.
- sumPtr[3] = (sumPtr[0] + sumPtr[1] + sumPtr[2] + 0x599D99AD) ^ EventSource.s_currentPid;
-
- return (int)(ptr - ((byte*)outPtr));
- }
-
- /// <summary>
- /// Write a single Nible 'value' (must be 0-15) to the byte buffer represented by *ptr.
- /// Will not go past 'endPtr'. Also it assumes that we never write 0 so we can detect
- /// whether a nibble has already been written to ptr because it will be nonzero.
- /// Thus if it is non-zero it adds to the current byte, otherwise it advances and writes
- /// the new byte (in the high bits) of the next byte.
- /// </summary>
- private static unsafe void WriteNibble(ref byte* ptr, byte* endPtr, uint value)
- {
- Debug.Assert(value < 16);
- Debug.Assert(ptr < endPtr);
-
- if (*ptr != 0)
- *ptr++ |= (byte)value;
- else
- *ptr = (byte)(value << 4);
- }
-
- #endregion // CreateGuidForActivityPath
-
- internal readonly string m_name; // The name used in the 'start' and 'stop' APIs to help match up
- private readonly long m_uniqueId; // a small number that makes this activity unique among its siblings
- internal readonly Guid m_guid; // Activity Guid, it is basically an encoding of the Path() (see CreateActivityPathGuid)
- internal readonly int m_activityPathGuidOffset; // Keeps track of where in m_guid the causality path stops (used to generated child GUIDs)
- internal readonly int m_level; // current depth of the Path() of the activity (used to keep recursion under control)
- internal readonly EventActivityOptions m_eventOptions; // Options passed to start.
- internal long m_lastChildID; // used to create a unique ID for my children activities
- internal int m_stopped; // This work item has stopped
- internal readonly ActivityInfo? m_creator; // My parent (creator). Forms the Path() for the activity.
- internal readonly Guid m_activityIdToRestore; // The Guid to restore after a stop.
- #endregion
- }
-
- // This callback is used to initialize the m_current AsyncLocal Variable.
- // Its job is to keep the ETW Activity ID (part of thread local storage) in sync
- // with m_current.ActivityID
- private void ActivityChanging(AsyncLocalValueChangedArgs<ActivityInfo?> args)
- {
- ActivityInfo? cur = args.CurrentValue;
- ActivityInfo? prev = args.PreviousValue;
-
- // Are we popping off a value? (we have a prev, and it creator is cur)
- // Then check if we should use the GUID at the time of the start event
- if (prev != null && prev.m_creator == cur)
- {
- // If the saved activity ID is not the same as the creator activity
- // that takes precedence (it means someone explicitly did a SetActivityID)
- // Set it to that and get out
- if (cur == null || prev.m_activityIdToRestore != cur.ActivityId)
- {
- EventSource.SetCurrentThreadActivityId(prev.m_activityIdToRestore);
- return;
- }
- }
-
- // OK we did not have an explicit SetActivityID set. Then we should be
- // setting the activity to current ActivityInfo. However that activity
- // might be dead, in which case we should skip it, so we never set
- // the ID to dead things.
- while (cur != null)
- {
- // We found a live activity (typically the first time), set it to that.
- if (cur.m_stopped == 0)
- {
- EventSource.SetCurrentThreadActivityId(cur.ActivityId);
- return;
- }
- cur = cur.m_creator;
- }
- // we can get here if there is no information on our activity stack (everything is dead)
- // currently we do nothing, as that seems better than setting to Guid.Emtpy.
- }
-
- /// <summary>
- /// Async local variables have the property that the are automatically copied whenever a task is created and used
- /// while that task is running. Thus m_current 'flows' to any task that is caused by the current thread that
- /// last set it.
- ///
- /// This variable points to a linked list that represents all Activities that have started but have not stopped.
- /// </summary>
- private AsyncLocal<ActivityInfo?>? m_current;
- private bool m_checkedForEnable;
-
- // Singleton
- private static readonly ActivityTracker s_activityTrackerInstance = new ActivityTracker();
-
- // Used to create unique IDs at the top level. Not used for nested Ids (each activity has its own id generator)
- private static long m_nextId = 0;
- private const ushort MAX_ACTIVITY_DEPTH = 100; // Limit maximum depth of activities to be tracked at 100.
- // This will avoid leaking memory in case of activities that are never stopped.
-
- #endregion
- }
-
-#if ES_BUILD_STANDALONE
- /******************************** SUPPORT *****************************/
- /// <summary>
- /// This is supplied by the framework. It is has the semantics that the value is copied to any new Tasks that is created
- /// by the current task. Thus all causally related code gets this value. Note that reads and writes to this VARIABLE
- /// (not what it points it) to this does not need to be protected by locks because it is inherently thread local (you always
- /// only get your thread local copy which means that you never have races.
- /// </summary>
- ///
- [EventSource(Name = "Microsoft.Tasks.Nuget")]
- internal class TplEventSource : EventSource
- {
- public class Keywords
- {
- public const EventKeywords TasksFlowActivityIds = (EventKeywords)0x80;
- public const EventKeywords Debug = (EventKeywords)0x20000;
- }
-
- public static TplEventSource Log = new TplEventSource();
- public bool Debug { get { return IsEnabled(EventLevel.Verbose, Keywords.Debug); } }
-
- public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(1, Facility, Message); }
- public void DebugFacilityMessage1(string Facility, string Message, string Arg) { WriteEvent(2, Facility, Message, Arg); }
- public void SetActivityId(Guid Id) { WriteEvent(3, Id); }
- }
-#endif
-
-#if ES_BUILD_AGAINST_DOTNET_V35 || ES_BUILD_PCL || NO_ASYNC_LOCAL
- // In these cases we don't have any Async local support. Do nothing.
- internal sealed class AsyncLocalValueChangedArgs<T>
- {
- public T PreviousValue { get { return default(T); } }
- public T CurrentValue { get { return default(T); } }
-
- }
-
- internal sealed class AsyncLocal<T>
- {
- public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler) {
- throw new NotImplementedException("AsyncLocal only available on V4.6 and above");
- }
- public T Value
- {
- get { return default(T); }
- set { }
- }
- }
-#endif
-
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs
deleted file mode 100644
index e4086d1d6e2..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs
+++ /dev/null
@@ -1,263 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Collections.Generic;
-using System.Threading;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- internal class CounterGroup
- {
- private readonly EventSource _eventSource;
- private readonly List<DiagnosticCounter> _counters;
- private static readonly object s_counterGroupLock = new object();
-
- internal CounterGroup(EventSource eventSource)
- {
- _eventSource = eventSource;
- _counters = new List<DiagnosticCounter>();
- RegisterCommandCallback();
- }
-
- internal void Add(DiagnosticCounter eventCounter)
- {
- lock (s_counterGroupLock) // Lock the CounterGroup
- _counters.Add(eventCounter);
- }
-
- internal void Remove(DiagnosticCounter eventCounter)
- {
- lock (s_counterGroupLock) // Lock the CounterGroup
- _counters.Remove(eventCounter);
- }
-
-#region EventSource Command Processing
-
- private void RegisterCommandCallback()
- {
- _eventSource.EventCommandExecuted += OnEventSourceCommand;
- }
-
- private void OnEventSourceCommand(object? sender, EventCommandEventArgs e)
- {
- if (e.Command == EventCommand.Enable || e.Command == EventCommand.Update)
- {
- Debug.Assert(e.Arguments != null);
-
- if (e.Arguments.TryGetValue("EventCounterIntervalSec", out string? valueStr) && float.TryParse(valueStr, out float value))
- {
- lock (s_counterGroupLock) // Lock the CounterGroup
- {
- EnableTimer(value);
- }
- }
- }
- else if (e.Command == EventCommand.Disable)
- {
- lock (s_counterGroupLock)
- {
- DisableTimer();
- }
- }
- }
-
-#endregion // EventSource Command Processing
-
-#region Global CounterGroup Array management
-
- // We need eventCounters to 'attach' themselves to a particular EventSource.
- // this table provides the mapping from EventSource -> CounterGroup
- // which represents this 'attached' information.
- private static WeakReference<CounterGroup>[]? s_counterGroups;
-
- private static void EnsureEventSourceIndexAvailable(int eventSourceIndex)
- {
- Debug.Assert(Monitor.IsEntered(s_counterGroupLock));
- if (CounterGroup.s_counterGroups == null)
- {
- CounterGroup.s_counterGroups = new WeakReference<CounterGroup>[eventSourceIndex + 1];
- }
- else if (eventSourceIndex >= CounterGroup.s_counterGroups.Length)
- {
- WeakReference<CounterGroup>[] newCounterGroups = new WeakReference<CounterGroup>[eventSourceIndex + 1];
- Array.Copy(CounterGroup.s_counterGroups, newCounterGroups, CounterGroup.s_counterGroups.Length);
- CounterGroup.s_counterGroups = newCounterGroups;
- }
- }
-
- internal static CounterGroup GetCounterGroup(EventSource eventSource)
- {
- lock (s_counterGroupLock)
- {
- int eventSourceIndex = EventListener.EventSourceIndex(eventSource);
- EnsureEventSourceIndexAvailable(eventSourceIndex);
- Debug.Assert(s_counterGroups != null);
- WeakReference<CounterGroup> weakRef = CounterGroup.s_counterGroups[eventSourceIndex];
- CounterGroup? ret = null;
- if (weakRef == null || !weakRef.TryGetTarget(out ret))
- {
- ret = new CounterGroup(eventSource);
- CounterGroup.s_counterGroups[eventSourceIndex] = new WeakReference<CounterGroup>(ret);
- }
- return ret;
- }
- }
-
-#endregion // Global CounterGroup Array management
-
-#region Timer Processing
-
- private DateTime _timeStampSinceCollectionStarted;
- private int _pollingIntervalInMilliseconds;
- private DateTime _nextPollingTimeStamp;
-
- private void EnableTimer(float pollingIntervalInSeconds)
- {
- Debug.Assert(Monitor.IsEntered(s_counterGroupLock));
- if (pollingIntervalInSeconds <= 0)
- {
- _pollingIntervalInMilliseconds = 0;
- }
- else if (_pollingIntervalInMilliseconds == 0 || pollingIntervalInSeconds * 1000 < _pollingIntervalInMilliseconds)
- {
- _pollingIntervalInMilliseconds = (int)(pollingIntervalInSeconds * 1000);
- ResetCounters(); // Reset statistics for counters before we start the thread.
-
- _timeStampSinceCollectionStarted = DateTime.UtcNow;
- // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
- bool restoreFlow = false;
- try
- {
- if (!ExecutionContext.IsFlowSuppressed())
- {
- ExecutionContext.SuppressFlow();
- restoreFlow = true;
- }
-
- _nextPollingTimeStamp = DateTime.UtcNow + new TimeSpan(0, 0, (int)pollingIntervalInSeconds);
-
- // Create the polling thread and init all the shared state if needed
- if (s_pollingThread == null)
- {
- s_pollingThreadSleepEvent = new AutoResetEvent(false);
- s_counterGroupEnabledList = new List<CounterGroup>();
- s_pollingThread = new Thread(PollForValues) { IsBackground = true };
- s_pollingThread.Start();
- }
-
- if (!s_counterGroupEnabledList!.Contains(this))
- {
- s_counterGroupEnabledList.Add(this);
- }
-
- // notify the polling thread that the polling interval may have changed and the sleep should
- // be recomputed
- s_pollingThreadSleepEvent!.Set();
- }
- finally
- {
- // Restore the current ExecutionContext
- if (restoreFlow)
- ExecutionContext.RestoreFlow();
- }
- }
- }
-
- private void DisableTimer()
- {
- _pollingIntervalInMilliseconds = 0;
- s_counterGroupEnabledList?.Remove(this);
- }
-
- private void ResetCounters()
- {
- lock (s_counterGroupLock) // Lock the CounterGroup
- {
- foreach (DiagnosticCounter counter in _counters)
- {
- if (counter is IncrementingEventCounter ieCounter)
- {
- ieCounter.UpdateMetric();
- }
- else if (counter is IncrementingPollingCounter ipCounter)
- {
- ipCounter.UpdateMetric();
- }
- else if (counter is EventCounter eCounter)
- {
- eCounter.ResetStatistics();
- }
- }
- }
- }
-
- private void OnTimer()
- {
- Debug.Assert(Monitor.IsEntered(s_counterGroupLock));
- if (_eventSource.IsEnabled())
- {
- DateTime now = DateTime.UtcNow;
- TimeSpan elapsed = now - _timeStampSinceCollectionStarted;
-
- foreach (DiagnosticCounter counter in _counters)
- {
- counter.WritePayload((float)elapsed.TotalSeconds, _pollingIntervalInMilliseconds);
- }
- _timeStampSinceCollectionStarted = now;
-
- do
- {
- _nextPollingTimeStamp += new TimeSpan(0, 0, 0, 0, _pollingIntervalInMilliseconds);
- } while (_nextPollingTimeStamp <= now);
- }
- }
-
- private static Thread? s_pollingThread;
- // Used for sleeping for a certain amount of time while allowing the thread to be woken up
- private static AutoResetEvent? s_pollingThreadSleepEvent;
-
- private static List<CounterGroup>? s_counterGroupEnabledList;
-
- private static void PollForValues()
- {
- AutoResetEvent? sleepEvent = null;
- while (true)
- {
- int sleepDurationInMilliseconds = int.MaxValue;
- lock (s_counterGroupLock)
- {
- sleepEvent = s_pollingThreadSleepEvent;
- foreach (CounterGroup counterGroup in s_counterGroupEnabledList!)
- {
- DateTime now = DateTime.UtcNow;
- if (counterGroup._nextPollingTimeStamp < now + new TimeSpan(0, 0, 0, 0, 1))
- {
- counterGroup.OnTimer();
- }
-
- int millisecondsTillNextPoll = (int)((counterGroup._nextPollingTimeStamp - now).TotalMilliseconds);
- millisecondsTillNextPoll = Math.Max(1, millisecondsTillNextPoll);
- sleepDurationInMilliseconds = Math.Min(sleepDurationInMilliseconds, millisecondsTillNextPoll);
- }
- }
- if (sleepDurationInMilliseconds == int.MaxValue)
- {
- sleepDurationInMilliseconds = -1; // WaitOne uses -1 to mean infinite
- }
- sleepEvent?.WaitOne(sleepDurationInMilliseconds);
- }
- }
-
-#endregion // Timer Processing
-
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterPayload.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterPayload.cs
deleted file mode 100644
index d81fdafca31..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterPayload.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Collections;
-using System.Collections.Generic;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- [EventData]
- internal class CounterPayload : IEnumerable<KeyValuePair<string, object?>>
- {
- public string? Name { get; set; }
-
- public string? DisplayName { get; set; }
-
- public double Mean { get; set; }
-
- public double StandardDeviation { get; set; }
-
- public int Count { get; set; }
-
- public double Min { get; set; }
-
- public double Max { get; set; }
-
- public float IntervalSec { get; internal set; }
-
- public string? Series { get; set; }
-
- public string? CounterType { get; set; }
-
- public string? Metadata { get; set; }
-
- public string? DisplayUnits { get; set; }
-
-#region Implementation of the IEnumerable interface
-
- public IEnumerator<KeyValuePair<string, object?>> GetEnumerator()
- {
- return ForEnumeration.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return ForEnumeration.GetEnumerator();
- }
-
- private IEnumerable<KeyValuePair<string, object?>> ForEnumeration
- {
- get
- {
- yield return new KeyValuePair<string, object?>("Name", Name);
- yield return new KeyValuePair<string, object?>("DisplayName", DisplayName);
- yield return new KeyValuePair<string, object?>("DisplayUnits", DisplayUnits);
- yield return new KeyValuePair<string, object?>("Mean", Mean);
- yield return new KeyValuePair<string, object?>("StandardDeviation", StandardDeviation);
- yield return new KeyValuePair<string, object?>("Count", Count);
- yield return new KeyValuePair<string, object?>("Min", Min);
- yield return new KeyValuePair<string, object?>("Max", Max);
- yield return new KeyValuePair<string, object?>("IntervalSec", IntervalSec);
- yield return new KeyValuePair<string, object?>("Series", $"Interval={IntervalSec}");
- yield return new KeyValuePair<string, object?>("CounterType", "Mean");
- yield return new KeyValuePair<string, object?>("Metadata", Metadata);
- }
- }
-
-#endregion // Implementation of the IEnumerable interface
- }
-
- [EventData]
- internal class IncrementingCounterPayload : IEnumerable<KeyValuePair<string, object?>>
- {
- public string? Name { get; set; }
-
- public string? DisplayName { get; set; }
-
- public string? DisplayRateTimeScale { get; set; }
-
- public double Increment { get; set; }
-
- public float IntervalSec { get; internal set; }
-
- public string? Metadata { get; set; }
-
- public string? Series { get; set; }
-
- public string? CounterType { get; set; }
-
- public string? DisplayUnits { get; set; }
-
-#region Implementation of the IEnumerable interface
-
- public IEnumerator<KeyValuePair<string, object?>> GetEnumerator()
- {
- return ForEnumeration.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return ForEnumeration.GetEnumerator();
- }
-
- private IEnumerable<KeyValuePair<string, object?>> ForEnumeration
- {
- get
- {
- yield return new KeyValuePair<string, object?>("Name", Name);
- yield return new KeyValuePair<string, object?>("DisplayName", DisplayName);
- yield return new KeyValuePair<string, object?>("DisplayRateTimeScale", DisplayRateTimeScale);
- yield return new KeyValuePair<string, object?>("Increment", Increment);
- yield return new KeyValuePair<string, object?>("IntervalSec", IntervalSec);
- yield return new KeyValuePair<string, object?>("Series", $"Interval={IntervalSec}");
- yield return new KeyValuePair<string, object?>("CounterType", "Sum");
- yield return new KeyValuePair<string, object?>("Metadata", Metadata);
- yield return new KeyValuePair<string, object?>("DisplayUnits", DisplayUnits);
- }
- }
-
-#endregion // Implementation of the IEnumerable interface
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/DiagnosticCounter.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/DiagnosticCounter.cs
deleted file mode 100644
index 577e9f193f8..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/DiagnosticCounter.cs
+++ /dev/null
@@ -1,168 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// DiagnosticCounter is an abstract class that serves as the parent class for various Counter* classes,
- /// namely EventCounter, PollingCounter, IncrementingEventCounter, and IncrementingPollingCounter.
- /// </summary>
- public abstract class DiagnosticCounter : IDisposable
- {
- /// <summary>
- /// All Counters live as long as the EventSource that they are attached to unless they are
- /// explicitly Disposed.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="eventSource">The event source.</param>
- internal DiagnosticCounter(string name, EventSource eventSource)
- {
- if (name == null)
- {
- throw new ArgumentNullException(nameof(Name));
- }
-
- if (eventSource == null)
- {
- throw new ArgumentNullException(nameof(EventSource));
- }
-
- Name = name;
- EventSource = eventSource;
- }
-
- /// <summary>Adds the counter to the set that the EventSource will report on.</summary>
- /// <remarks>
- /// Must only be invoked once, and only after the instance has been fully initialized.
- /// This should be invoked by a derived type's ctor as the last thing it does.
- /// </remarks>
- private protected void Publish()
- {
- Debug.Assert(_group is null);
- Debug.Assert(Name != null);
- Debug.Assert(EventSource != null);
-
- _group = CounterGroup.GetCounterGroup(EventSource);
- _group.Add(this);
- }
-
- /// <summary>
- /// Removes the counter from set that the EventSource will report on. After being disposed, this
- /// counter will do nothing and its resource will be reclaimed if all references to it are removed.
- /// If an EventCounter is not explicitly disposed it will be cleaned up automatically when the
- /// EventSource it is attached to dies.
- /// </summary>
- public void Dispose()
- {
- if (_group != null)
- {
- _group.Remove(this);
- _group = null;
- }
- }
-
- /// <summary>
- /// Adds a key-value metadata to the EventCounter that will be included as a part of the payload
- /// </summary>
- public void AddMetadata(string key, string? value)
- {
- lock (this)
- {
- _metadata ??= new Dictionary<string, string?>();
- _metadata.Add(key, value);
- }
- }
-
- private string _displayName = "";
- public string DisplayName
- {
- get => _displayName;
- set
- {
- if (value == null)
- throw new ArgumentNullException(nameof(DisplayName));
- _displayName = value;
- }
- }
-
- private string _displayUnits = "";
- public string DisplayUnits
- {
- get => _displayUnits;
- set
- {
- if (value == null)
- throw new ArgumentNullException(nameof(DisplayUnits));
- _displayUnits = value;
- }
- }
-
- public string Name { get; }
-
- public EventSource EventSource { get; }
-
- #region private implementation
-
- private CounterGroup? _group;
- private Dictionary<string, string?>? _metadata;
-
- internal abstract void WritePayload(float intervalSec, int pollingIntervalMillisec);
-
- internal void ReportOutOfBandMessage(string message)
- {
- EventSource.ReportOutOfBandMessage(message);
- }
-
- internal string GetMetadataString()
- {
- Debug.Assert(Monitor.IsEntered(this));
-
- if (_metadata == null)
- {
- return "";
- }
-
- // The dictionary is only initialized to non-null when there's metadata to add, and no items
- // are ever removed, so if the dictionary is non-null, there must also be at least one element.
- Dictionary<string, string?>.Enumerator enumerator = _metadata.GetEnumerator();
- Debug.Assert(_metadata.Count > 0);
- bool gotOne = enumerator.MoveNext();
- Debug.Assert(gotOne);
-
- // If there's only one element, just concat a string for it.
- KeyValuePair<string, string?> current = enumerator.Current;
- if (!enumerator.MoveNext())
- {
- return current.Key + ":" + current.Value;
- }
-
- // Otherwise, append it, then append the element we moved to, and then
- // iterate through the remainder of the elements, appending each.
- StringBuilder sb = new StringBuilder().Append(current.Key).Append(':').Append(current.Value);
- do
- {
- current = enumerator.Current;
- sb.Append(',').Append(current.Key).Append(':').Append(current.Value);
- }
- while (enumerator.MoveNext());
-
- // Return the final string.
- return sb.ToString();
- }
-
- #endregion // private implementation
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventActivityOptions.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventActivityOptions.cs
deleted file mode 100644
index 02f60379c1e..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventActivityOptions.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// EventActivityOptions flags allow to specify different activity related characteristics.
- /// </summary>
- [Flags]
- public enum EventActivityOptions
- {
- /// <summary>
- /// No special options are added to the event.
- /// </summary>
- None = 0,
-
- /// <summary>
- /// Disable Implicit Activity Tracking
- /// </summary>
- Disable = 0x2,
-
- /// <summary>
- /// Allow activity event to call itself (directly or indirectly)
- /// </summary>
- Recursive = 0x4,
-
- /// <summary>
- /// Allows event activity to live beyond its parent.
- /// </summary>
- Detachable = 0x8
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventCounter.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventCounter.cs
deleted file mode 100644
index ae3a5d7fceb..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventCounter.cs
+++ /dev/null
@@ -1,202 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Threading;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Provides the ability to collect statistics through EventSource
- ///
- /// See https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.Tracing/documentation/EventCounterTutorial.md
- /// for a tutorial guide.
- ///
- /// See https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs
- /// which shows tests, which are also useful in seeing actual use.
- /// </summary>
- public partial class EventCounter : DiagnosticCounter
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="EventCounter"/> class.
- /// EVentCounters live as long as the EventSource that they are attached to unless they are
- /// explicitly Disposed.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="eventSource">The event source.</param>
- public EventCounter(string name, EventSource eventSource) : base(name, eventSource)
- {
- _min = double.PositiveInfinity;
- _max = double.NegativeInfinity;
-
- InitializeBuffer();
- Publish();
- }
-
- /// <summary>
- /// Writes 'value' to the stream of values tracked by the counter. This updates the sum and other statistics that will
- /// be logged on the next timer interval.
- /// </summary>
- /// <param name="value">The value.</param>
- public void WriteMetric(float value)
- {
- Enqueue((double)value);
- }
-
- public void WriteMetric(double value)
- {
- Enqueue(value);
- }
-
- public override string ToString()
- {
- int count = Volatile.Read(ref _count);
- return count == 0 ?
- $"EventCounter '{Name}' Count 0" :
- $"EventCounter '{Name}' Count {count} Mean {(_sum / count).ToString("n3")}";
- }
-
- #region Statistics Calculation
-
- // Statistics
- private int _count;
- private double _sum;
- private double _sumSquared;
- private double _min;
- private double _max;
-
- internal void OnMetricWritten(double value)
- {
- Debug.Assert(Monitor.IsEntered(this));
- _sum += value;
- _sumSquared += value * value;
- if (value > _max)
- _max = value;
-
- if (value < _min)
- _min = value;
-
- _count++;
- }
-
- internal override void WritePayload(float intervalSec, int pollingIntervalMillisec)
- {
- lock (this)
- {
- Flush();
- CounterPayload payload = new CounterPayload();
- payload.Count = _count;
- payload.IntervalSec = intervalSec;
- if (0 < _count)
- {
- payload.Mean = _sum / _count;
- payload.StandardDeviation = Math.Sqrt(_sumSquared / _count - _sum * _sum / _count / _count);
- }
- else
- {
- payload.Mean = 0;
- payload.StandardDeviation = 0;
- }
- payload.Min = _min;
- payload.Max = _max;
- payload.Series = $"Interval={pollingIntervalMillisec}"; // TODO: This may need to change when we support multi-session
- payload.CounterType = "Mean";
- payload.Metadata = GetMetadataString();
- payload.DisplayName = DisplayName ?? "";
- payload.DisplayUnits = DisplayUnits ?? "";
- payload.Name = Name;
- ResetStatistics();
- EventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new CounterPayloadType(payload));
- }
- }
-
- internal void ResetStatistics()
- {
- lock (this)
- {
- _count = 0;
- _sum = 0;
- _sumSquared = 0;
- _min = double.PositiveInfinity;
- _max = double.NegativeInfinity;
- }
- }
-
- #endregion // Statistics Calculation
-
- // Values buffering
- private const int BufferedSize = 10;
- private const double UnusedBufferSlotValue = double.NegativeInfinity;
- private volatile double[] _bufferedValues = null!;
- private volatile int _bufferedValuesIndex;
-
- private void InitializeBuffer()
- {
- _bufferedValues = new double[BufferedSize];
- for (int i = 0; i < _bufferedValues.Length; i++)
- {
- _bufferedValues[i] = UnusedBufferSlotValue;
- }
- }
-
- private void Enqueue(double value)
- {
- // It is possible that two threads read the same bufferedValuesIndex, but only one will be able to write the slot, so that is okay.
- int i = _bufferedValuesIndex;
- while (true)
- {
- double result = Interlocked.CompareExchange(ref _bufferedValues[i], value, UnusedBufferSlotValue);
- i++;
- if (_bufferedValues.Length <= i)
- {
- // It is possible that two threads both think the buffer is full, but only one get to actually flush it, the other
- // will eventually enter this code path and potentially calling Flushing on a buffer that is not full, and that's okay too.
- lock (this) // Lock the counter
- Flush();
- i = 0;
- }
-
- if (result == UnusedBufferSlotValue)
- {
- // CompareExchange succeeded
- _bufferedValuesIndex = i;
- return;
- }
- }
- }
-
- protected void Flush()
- {
- Debug.Assert(Monitor.IsEntered(this));
- for (int i = 0; i < _bufferedValues.Length; i++)
- {
- double value = Interlocked.Exchange(ref _bufferedValues[i], UnusedBufferSlotValue);
- if (value != UnusedBufferSlotValue)
- {
- OnMetricWritten(value);
- }
- }
-
- _bufferedValuesIndex = 0;
- }
- }
-
-
- /// <summary>
- /// This is the payload that is sent in the with EventSource.Write
- /// </summary>
- [EventData]
- internal class CounterPayloadType
- {
- public CounterPayloadType(CounterPayload payload) { Payload = payload; }
- public CounterPayload Payload { get; set; }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventDescriptor.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventDescriptor.cs
deleted file mode 100644
index 02ba4d715ea..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventDescriptor.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
-#endif
-using System.Runtime.InteropServices;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- [StructLayout(LayoutKind.Explicit, Size = 16)]
-#if ES_BUILD_STANDALONE
- [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
-#endif
-
- /*
- EventDescriptor was public in the separate System.Diagnostics.Tracing assembly(pre NS2.0),
- now the move to CoreLib marked them as private.
- While they are technically private (it's a contract used between the library and the ILC toolchain),
- we need them to be rooted and exported from shared library for the system to work.
- For now I'm simply marking them as public again.A cleaner solution might be to use.rd.xml to
- root them and modify shared library definition to force export them.
- */
-#if ES_BUILD_PN
- public
-#else
- internal
-#endif
- struct EventDescriptor
- {
- #region private
- [FieldOffset(0)]
- private readonly int m_traceloggingId;
- [FieldOffset(0)]
- private readonly ushort m_id;
- [FieldOffset(2)]
- private readonly byte m_version;
- [FieldOffset(3)]
- private readonly byte m_channel;
- [FieldOffset(4)]
- private readonly byte m_level;
- [FieldOffset(5)]
- private readonly byte m_opcode;
- [FieldOffset(6)]
- private readonly ushort m_task;
- [FieldOffset(8)]
- private readonly long m_keywords;
- #endregion
-
- public EventDescriptor(
- int traceloggingId,
- byte level,
- byte opcode,
- long keywords
- )
- {
- this.m_id = 0;
- this.m_version = 0;
- this.m_channel = 0;
- this.m_traceloggingId = traceloggingId;
- this.m_level = level;
- this.m_opcode = opcode;
- this.m_task = 0;
- this.m_keywords = keywords;
- }
-
- public EventDescriptor(
- int id,
- byte version,
- byte channel,
- byte level,
- byte opcode,
- int task,
- long keywords
- )
- {
- if (id < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(id), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
-
- if (id > ushort.MaxValue)
- {
- throw new ArgumentOutOfRangeException(nameof(id), SR.Format(SR.ArgumentOutOfRange_NeedValidId, 1, ushort.MaxValue));
- }
-
- m_traceloggingId = 0;
- m_id = (ushort)id;
- m_version = version;
- m_channel = channel;
- m_level = level;
- m_opcode = opcode;
- m_keywords = keywords;
-
- if (task < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(task), SR.ArgumentOutOfRange_NeedNonNegNum);
- }
-
- if (task > ushort.MaxValue)
- {
- throw new ArgumentOutOfRangeException(nameof(task), SR.Format(SR.ArgumentOutOfRange_NeedValidId, 1, ushort.MaxValue));
- }
-
- m_task = (ushort)task;
- }
-
- public int EventId => m_id;
- public byte Version => m_version;
- public byte Channel => m_channel;
- public byte Level => m_level;
- public byte Opcode => m_opcode;
- public int Task => m_task;
- public long Keywords => m_keywords;
-
- internal int TraceLoggingId => m_traceloggingId;
-
- public override bool Equals(object? obj) =>
- obj is EventDescriptor ed && Equals(ed);
-
- public override int GetHashCode() =>
- m_id ^ m_version ^ m_channel ^ m_level ^ m_opcode ^ m_task ^ (int)m_keywords;
-
- public bool Equals(EventDescriptor other) =>
- m_id == other.m_id &&
- m_version == other.m_version &&
- m_channel == other.m_channel &&
- m_level == other.m_level &&
- m_opcode == other.m_opcode &&
- m_task == other.m_task &&
- m_keywords == other.m_keywords;
-
- public static bool operator ==(EventDescriptor event1, EventDescriptor event2) =>
- event1.Equals(event2);
-
- public static bool operator !=(EventDescriptor event1, EventDescriptor event2) =>
- !event1.Equals(event2);
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs
deleted file mode 100644
index b1787019a16..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs
+++ /dev/null
@@ -1,1353 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using Microsoft.Win32;
-using System;
-using System.Diagnostics;
-using System.Security.Permissions;
-using BitOperations = Microsoft.Diagnostics.Tracing.Internal.BitOperations;
-#endif
-using System.Collections.Generic;
-using System.Globalization;
-using System.Numerics;
-using System.Runtime.InteropServices;
-#if CORECLR && PLATFORM_WINDOWS
-using Internal.Win32;
-#endif
-#if ES_BUILD_AGAINST_DOTNET_V35
-using Microsoft.Internal; // for Tuple (can't define alias for open generic types so we "use" the whole namespace)
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- internal enum EventProviderType
- {
- None = 0,
- ETW,
- EventPipe
- }
-
- internal enum ControllerCommand
- {
- // Strictly Positive numbers are for provider-specific commands, negative number are for 'shared' commands. 256
- // The first 256 negative numbers are reserved for the framework.
- Update = 0, // Not used by EventProviderBase.
- SendManifest = -1,
- Enable = -2,
- Disable = -3,
- }
-
- /// <summary>
- /// Only here because System.Diagnostics.EventProvider needs one more extensibility hook (when it gets a
- /// controller callback)
- /// </summary>
-#if ES_BUILD_STANDALONE
- [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
-#endif
- internal class EventProvider : IDisposable
- {
- // This is the windows EVENT_DATA_DESCRIPTOR structure. We expose it because this is what
- // subclasses of EventProvider use when creating efficient (but unsafe) version of
- // EventWrite. We do make it a nested type because we really don't expect anyone to use
- // it except subclasses (and then only rarely).
- [StructLayout(LayoutKind.Sequential)]
- public struct EventData
- {
- internal unsafe ulong Ptr;
- internal uint Size;
- internal uint Reserved;
- }
-
- /// <summary>
- /// A struct characterizing ETW sessions (identified by the etwSessionId) as
- /// activity-tracing-aware or legacy. A session that's activity-tracing-aware
- /// has specified one non-zero bit in the reserved range 44-47 in the
- /// 'allKeywords' value it passed in for a specific EventProvider.
- /// </summary>
- public struct SessionInfo
- {
- internal int sessionIdBit; // the index of the bit used for tracing in the "reserved" field of AllKeywords
- internal int etwSessionId; // the machine-wide ETW session ID
-
- internal SessionInfo(int sessionIdBit_, int etwSessionId_)
- { sessionIdBit = sessionIdBit_; etwSessionId = etwSessionId_; }
- }
-
- internal IEventProvider m_eventProvider; // The interface that implements the specific logging mechanism functions.
- private Interop.Advapi32.EtwEnableCallback? m_etwCallback; // Trace Callback function
- private long m_regHandle; // Trace Registration Handle
- private byte m_level; // Tracing Level
- private long m_anyKeywordMask; // Trace Enable Flags
- private long m_allKeywordMask; // Match all keyword
- private List<SessionInfo>? m_liveSessions; // current live sessions (Tuple<sessionIdBit, etwSessionId>)
- private bool m_enabled; // Enabled flag from Trace callback
- private string? m_providerName; // Control name
- private Guid m_providerId; // Control Guid
- internal bool m_disposed; // when true provider has unregistered
-
- [ThreadStatic]
- private static WriteEventErrorCode s_returnCode; // The last return code
-
- private const int s_basicTypeAllocationBufferSize = 16;
- private const int s_etwMaxNumberArguments = 128;
- private const int s_etwAPIMaxRefObjCount = 8;
- private const int s_traceEventMaximumSize = 65482;
-
- public enum WriteEventErrorCode : int
- {
- // check mapping to runtime codes
- NoError = 0,
- NoFreeBuffers = 1,
- EventTooBig = 2,
- NullInput = 3,
- TooManyArgs = 4,
- Other = 5,
- }
-
- // Because callbacks happen on registration, and we need the callbacks for those setup
- // we can't call Register in the constructor.
- //
- // Note that EventProvider should ONLY be used by EventSource. In particular because
- // it registers a callback from native code you MUST dispose it BEFORE shutdown, otherwise
- // you may get native callbacks during shutdown when we have destroyed the delegate.
- // EventSource has special logic to do this, no one else should be calling EventProvider.
- internal EventProvider(EventProviderType providerType)
- {
- m_eventProvider = providerType switch
- {
-#if PLATFORM_WINDOWS
- EventProviderType.ETW => new EtwEventProvider(),
-#endif
-#if FEATURE_PERFTRACING
- EventProviderType.EventPipe => new EventPipeEventProvider(),
-#endif
- _ => new NoOpEventProvider(),
- };
- }
-
- /// <summary>
- /// This method registers the controlGuid of this class with ETW. We need to be running on
- /// Vista or above. If not a PlatformNotSupported exception will be thrown. If for some
- /// reason the ETW Register call failed a NotSupported exception will be thrown.
- /// </summary>
- // <SecurityKernel Critical="True" Ring="0">
- // <CallsSuppressUnmanagedCode Name="Interop.Advapi32.EventRegister(System.Guid&,Microsoft.Win32.Interop.Advapi32+EtwEnableCallback,System.Void*,System.Int64&):System.UInt32" />
- // <SatisfiesLinkDemand Name="Win32Exception..ctor(System.Int32)" />
- // <ReferencesCritical Name="Method: EtwEnableCallBack(Guid&, Int32, Byte, Int64, Int64, Void*, Void*):Void" Ring="1" />
- // </SecurityKernel>
- internal unsafe void Register(EventSource eventSource)
- {
- uint status;
- m_etwCallback = new Interop.Advapi32.EtwEnableCallback(EtwEnableCallBack);
-
- status = EventRegister(eventSource, m_etwCallback);
- if (status != 0)
- {
-#if PLATFORM_WINDOWS && !ES_BUILD_STANDALONE
- throw new ArgumentException(Interop.Kernel32.GetMessage(unchecked((int)status)));
-#else
- throw new ArgumentException(Convert.ToString(unchecked((int)status)));
-#endif
- }
- }
-
- //
- // implement Dispose Pattern to early deregister from ETW insted of waiting for
- // the finalizer to call deregistration.
- // Once the user is done with the provider it needs to call Close() or Dispose()
- // If neither are called the finalizer will unregister the provider anyway
- //
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- // <SecurityKernel Critical="True" TreatAsSafe="Does not expose critical resource" Ring="1">
- // <ReferencesCritical Name="Method: Deregister():Void" Ring="1" />
- // </SecurityKernel>
- protected virtual void Dispose(bool disposing)
- {
- //
- // explicit cleanup is done by calling Dispose with true from
- // Dispose() or Close(). The disposing arguement is ignored because there
- // are no unmanaged resources.
- // The finalizer calls Dispose with false.
- //
-
- //
- // check if the object has been already disposed
- //
- if (m_disposed)
- return;
-
- // Disable the provider.
- m_enabled = false;
-
- // Do most of the work under a lock to avoid shutdown race.
-
- long registrationHandle = 0;
- lock (EventListener.EventListenersLock)
- {
- // Double check
- if (m_disposed)
- return;
-
- registrationHandle = m_regHandle;
- m_regHandle = 0;
- m_disposed = true;
- }
-
- // We do the Unregistration outside the EventListenerLock because there is a lock
- // inside the ETW routines. This lock is taken before ETW issues commands
- // Thus the ETW lock gets taken first and then our EventListenersLock gets taken
- // in SendCommand(), and also here. If we called EventUnregister after taking
- // the EventListenersLock then the take-lock order is reversed and we can have
- // deadlocks in race conditions (dispose racing with an ETW command).
- //
- // We solve by Unregistering after releasing the EventListenerLock.
- if (registrationHandle != 0)
- EventUnregister(registrationHandle);
- }
-
- /// <summary>
- /// This method deregisters the controlGuid of this class with ETW.
- ///
- /// </summary>
- public virtual void Close()
- {
- Dispose();
- }
-
- ~EventProvider()
- {
- Dispose(false);
- }
-
- // <SecurityKernel Critical="True" Ring="0">
- // <UsesUnsafeCode Name="Parameter filterData of type: Void*" />
- // <UsesUnsafeCode Name="Parameter callbackContext of type: Void*" />
- // </SecurityKernel>
- private unsafe void EtwEnableCallBack(
- in System.Guid sourceId,
- int controlCode,
- byte setLevel,
- long anyKeyword,
- long allKeyword,
- Interop.Advapi32.EVENT_FILTER_DESCRIPTOR* filterData,
- void* callbackContext
- )
- {
- // This is an optional callback API. We will therefore ignore any failures that happen as a
- // result of turning on this provider as to not crash the app.
- // EventSource has code to validate whether initialization it expected to occur actually occurred
- try
- {
- ControllerCommand command = ControllerCommand.Update;
- IDictionary<string, string?>? args = null;
- bool skipFinalOnControllerCommand = false;
- if (controlCode == Interop.Advapi32.EVENT_CONTROL_CODE_ENABLE_PROVIDER)
- {
- m_enabled = true;
- m_level = setLevel;
- m_anyKeywordMask = anyKeyword;
- m_allKeywordMask = allKeyword;
-
- List<Tuple<SessionInfo, bool>> sessionsChanged = GetSessions();
-
- // The GetSessions() logic was here to support the idea that different ETW sessions
- // could have different user-defined filters. (I believe it is currently broken but that is another matter.)
- // However in particular GetSessions() does not support EventPipe, only ETW, which is
- // the immediate problem. We work-around establishing the invariant that we always get a
- // OnControllerCallback under all circumstances, even if we can't find a delta in the
- // ETW logic. This fixes things for the EventPipe case.
- //
- // All this session based logic should be reviewed and likely removed, but that is a larger
- // change that needs more careful staging.
- if (sessionsChanged.Count == 0)
- sessionsChanged.Add(new Tuple<SessionInfo, bool>(new SessionInfo(0, 0), true));
-
- foreach (Tuple<SessionInfo, bool> session in sessionsChanged)
- {
- int sessionChanged = session.Item1.sessionIdBit;
- int etwSessionId = session.Item1.etwSessionId;
- bool bEnabling = session.Item2;
-
- skipFinalOnControllerCommand = true;
- args = null; // reinitialize args for every session...
-
- // if we get more than one session changed we have no way
- // of knowing which one "filterData" belongs to
- if (sessionsChanged.Count > 1)
- filterData = null;
-
- // read filter data only when a session is being *added*
- byte[]? data;
- int keyIndex;
- if (bEnabling &&
- GetDataFromController(etwSessionId, filterData, out command, out data, out keyIndex))
- {
- args = new Dictionary<string, string?>(4);
- // data can be null if the filterArgs had a very large size which failed our sanity check
- if (data != null)
- {
- while (keyIndex < data.Length)
- {
- int keyEnd = FindNull(data, keyIndex);
- int valueIdx = keyEnd + 1;
- int valueEnd = FindNull(data, valueIdx);
- if (valueEnd < data.Length)
- {
- string key = System.Text.Encoding.UTF8.GetString(data, keyIndex, keyEnd - keyIndex);
- string value = System.Text.Encoding.UTF8.GetString(data, valueIdx, valueEnd - valueIdx);
- args[key] = value;
- }
- keyIndex = valueEnd + 1;
- }
- }
- }
-
- // execute OnControllerCommand once for every session that has changed.
- OnControllerCommand(command, args, bEnabling ? sessionChanged : -sessionChanged, etwSessionId);
- }
- }
- else if (controlCode == Interop.Advapi32.EVENT_CONTROL_CODE_DISABLE_PROVIDER)
- {
- m_enabled = false;
- m_level = 0;
- m_anyKeywordMask = 0;
- m_allKeywordMask = 0;
- m_liveSessions = null;
- }
- else if (controlCode == Interop.Advapi32.EVENT_CONTROL_CODE_CAPTURE_STATE)
- {
- command = ControllerCommand.SendManifest;
- }
- else
- return; // per spec you ignore commands you don't recognize.
-
- if (!skipFinalOnControllerCommand)
- OnControllerCommand(command, args, 0, 0);
- }
- catch
- {
- // We want to ignore any failures that happen as a result of turning on this provider as to
- // not crash the app.
- }
- }
-
- protected virtual void OnControllerCommand(ControllerCommand command, IDictionary<string, string?>? arguments, int sessionId, int etwSessionId) { }
-
- protected EventLevel Level
- {
- get => (EventLevel)m_level;
- set => m_level = (byte)value;
- }
-
- protected EventKeywords MatchAnyKeyword
- {
- get => (EventKeywords)m_anyKeywordMask;
- set => m_anyKeywordMask = unchecked((long)value);
- }
-
- protected EventKeywords MatchAllKeyword
- {
- get => (EventKeywords)m_allKeywordMask;
- set => m_allKeywordMask = unchecked((long)value);
- }
-
- private static int FindNull(byte[] buffer, int idx)
- {
- while (idx < buffer.Length && buffer[idx] != 0)
- idx++;
- return idx;
- }
-
- /// <summary>
- /// Determines the ETW sessions that have been added and/or removed to the set of
- /// sessions interested in the current provider. It does so by (1) enumerating over all
- /// ETW sessions that enabled 'this.m_Guid' for the current process ID, and (2)
- /// comparing the current list with a list it cached on the previous invocation.
- ///
- /// The return value is a list of tuples, where the SessionInfo specifies the
- /// ETW session that was added or remove, and the bool specifies whether the
- /// session was added or whether it was removed from the set.
- /// </summary>
- private List<Tuple<SessionInfo, bool>> GetSessions()
- {
- List<SessionInfo>? liveSessionList = null;
-
- GetSessionInfo(
- (int etwSessionId, long matchAllKeywords, ref List<SessionInfo>? sessionList) =>
- GetSessionInfoCallback(etwSessionId, matchAllKeywords, ref sessionList),
- ref liveSessionList);
-
- List<Tuple<SessionInfo, bool>> changedSessionList = new List<Tuple<SessionInfo, bool>>();
-
- // first look for sessions that have gone away (or have changed)
- // (present in the m_liveSessions but not in the new liveSessionList)
- if (m_liveSessions != null)
- {
- foreach (SessionInfo s in m_liveSessions)
- {
- int idx;
- if ((idx = IndexOfSessionInList(liveSessionList, s.etwSessionId)) < 0 ||
- (liveSessionList![idx].sessionIdBit != s.sessionIdBit))
- changedSessionList.Add(Tuple.Create(s, false));
- }
- }
- // next look for sessions that were created since the last callback (or have changed)
- // (present in the new liveSessionList but not in m_liveSessions)
- if (liveSessionList != null)
- {
- foreach (SessionInfo s in liveSessionList)
- {
- int idx;
- if ((idx = IndexOfSessionInList(m_liveSessions, s.etwSessionId)) < 0 ||
- (m_liveSessions![idx].sessionIdBit != s.sessionIdBit))
- changedSessionList.Add(Tuple.Create(s, true));
- }
- }
-
- m_liveSessions = liveSessionList;
- return changedSessionList;
- }
-
- /// <summary>
- /// This method is the callback used by GetSessions() when it calls into GetSessionInfo().
- /// It updates a List{SessionInfo} based on the etwSessionId and matchAllKeywords that
- /// GetSessionInfo() passes in.
- /// </summary>
- private static void GetSessionInfoCallback(int etwSessionId, long matchAllKeywords,
- ref List<SessionInfo>? sessionList)
- {
- uint sessionIdBitMask = (uint)SessionMask.FromEventKeywords(unchecked((ulong)matchAllKeywords));
- // an ETW controller that specifies more than the mandated bit for our EventSource
- // will be ignored...
- int val = BitOperations.PopCount(sessionIdBitMask);
- if (val > 1)
- return;
-
- sessionList ??= new List<SessionInfo>(8);
-
- if (val == 1)
- {
- // activity-tracing-aware etw session
- val = BitOperations.TrailingZeroCount(sessionIdBitMask);
- }
- else
- {
- // legacy etw session
- val = BitOperations.PopCount((uint)SessionMask.All);
- }
-
- sessionList.Add(new SessionInfo(val + 1, etwSessionId));
- }
-
- private delegate void SessionInfoCallback(int etwSessionId, long matchAllKeywords, ref List<SessionInfo>? sessionList);
-
- /// <summary>
- /// This method enumerates over all active ETW sessions that have enabled 'this.m_Guid'
- /// for the current process ID, calling 'action' for each session, and passing it the
- /// ETW session and the 'AllKeywords' the session enabled for the current provider.
- /// </summary>
- private unsafe void GetSessionInfo(SessionInfoCallback action, ref List<SessionInfo>? sessionList)
- {
- // We wish the EventSource package to be legal for Windows Store applications.
- // Currently EnumerateTraceGuidsEx is not an allowed API, so we avoid its use here
- // and use the information in the registry instead. This means that ETW controllers
- // that do not publish their intent to the registry (basically all controllers EXCEPT
- // TraceEventSesion) will not work properly
-
- // However the framework version of EventSource DOES have ES_SESSION_INFO defined and thus
- // does not have this issue.
-#if (PLATFORM_WINDOWS && (ES_SESSION_INFO || !ES_BUILD_STANDALONE))
- int buffSize = 256; // An initial guess that probably works most of the time.
- byte* buffer;
- while (true)
- {
- byte* space = stackalloc byte[buffSize];
- buffer = space;
- int hr = 0;
-
- fixed (Guid* provider = &m_providerId)
- {
- hr = Interop.Advapi32.EnumerateTraceGuidsEx(Interop.Advapi32.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo,
- provider, sizeof(Guid), buffer, buffSize, out buffSize);
- }
- if (hr == 0)
- break;
- if (hr != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
- return;
- }
-
- var providerInfos = (Interop.Advapi32.TRACE_GUID_INFO*)buffer;
- var providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&providerInfos[1];
- int processId = unchecked((int)Interop.Kernel32.GetCurrentProcessId());
- // iterate over the instances of the EventProvider in all processes
- for (int i = 0; i < providerInfos->InstanceCount; i++)
- {
- if (providerInstance->Pid == processId)
- {
- var enabledInfos = (Interop.Advapi32.TRACE_ENABLE_INFO*)&providerInstance[1];
- // iterate over the list of active ETW sessions "listening" to the current provider
- for (int j = 0; j < providerInstance->EnableCount; j++)
- action(enabledInfos[j].LoggerId, enabledInfos[j].MatchAllKeyword, ref sessionList);
- }
- if (providerInstance->NextOffset == 0)
- break;
- Debug.Assert(0 <= providerInstance->NextOffset && providerInstance->NextOffset < buffSize);
- byte* structBase = (byte*)providerInstance;
- providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset];
- }
-#else
-#if !ES_BUILD_PCL && PLATFORM_WINDOWS // TODO command arguments don't work on PCL builds...
- // This code is only used in the Nuget Package Version of EventSource. because
- // the code above is using APIs baned from UWP apps.
- //
- // TODO: In addition to only working when TraceEventSession enables the provider, this code
- // also has a problem because TraceEvent does not clean up if the registry is stale
- // It is unclear if it is worth keeping, but for now we leave it as it does work
- // at least some of the time.
-
- // Determine our session from what is in the registry.
- string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerName + "}";
- if (IntPtr.Size == 8)
- regKey = @"Software" + @"\Wow6432Node" + regKey;
- else
- regKey = @"Software" + regKey;
-
- using (var key = Registry.LocalMachine.OpenSubKey(regKey))
- {
- if (key != null)
- {
- foreach (string valueName in key.GetValueNames())
- {
- if (valueName.StartsWith("ControllerData_Session_", StringComparison.Ordinal))
- {
- string strId = valueName.Substring(23); // strip of the ControllerData_Session_
- int etwSessionId;
- if (int.TryParse(strId, out etwSessionId))
- {
-#if ES_BUILD_STANDALONE
- // we need to assert this permission for partial trust scenarios
- (new RegistryPermission(RegistryPermissionAccess.Read, regKey)).Assert();
-#endif
- var data = key.GetValue(valueName) as byte[];
- if (data != null)
- {
- var dataAsString = System.Text.Encoding.UTF8.GetString(data);
- int keywordIdx = dataAsString.IndexOf("EtwSessionKeyword", StringComparison.Ordinal);
- if (0 <= keywordIdx)
- {
- int startIdx = keywordIdx + 18;
- int endIdx = dataAsString.IndexOf('\0', startIdx);
- string keywordBitString = dataAsString.Substring(startIdx, endIdx - startIdx);
- int keywordBit;
- if (0 < endIdx && int.TryParse(keywordBitString, out keywordBit))
- action(etwSessionId, 1L << keywordBit, ref sessionList);
- }
- }
- }
- }
- }
- }
- }
-#endif
-#endif
- }
-
- /// <summary>
- /// Returns the index of the SesisonInfo from 'sessions' that has the specified 'etwSessionId'
- /// or -1 if the value is not present.
- /// </summary>
- private static int IndexOfSessionInList(List<SessionInfo>? sessions, int etwSessionId)
- {
- if (sessions == null)
- return -1;
- // for non-coreclr code we could use List<T>.FindIndex(Predicate<T>), but we need this to compile
- // on coreclr as well
- for (int i = 0; i < sessions.Count; ++i)
- if (sessions[i].etwSessionId == etwSessionId)
- return i;
-
- return -1;
- }
-
- /// <summary>
- /// Gets any data to be passed from the controller to the provider. It starts with what is passed
- /// into the callback, but unfortunately this data is only present for when the provider is active
- /// at the time the controller issues the command. To allow for providers to activate after the
- /// controller issued a command, we also check the registry and use that to get the data. The function
- /// returns an array of bytes representing the data, the index into that byte array where the data
- /// starts, and the command being issued associated with that data.
- /// </summary>
- private unsafe bool GetDataFromController(int etwSessionId,
- Interop.Advapi32.EVENT_FILTER_DESCRIPTOR* filterData, out ControllerCommand command, out byte[]? data, out int dataStart)
- {
- data = null;
- dataStart = 0;
- if (filterData == null)
- {
-#if (!ES_BUILD_PCL && !ES_BUILD_PN && PLATFORM_WINDOWS)
- string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}";
- if (IntPtr.Size == 8)
- regKey = @"Software\Wow6432Node" + regKey;
- else
- regKey = "Software" + regKey;
-
- string valueName = "ControllerData_Session_" + etwSessionId.ToString(CultureInfo.InvariantCulture);
-
- // we need to assert this permission for partial trust scenarios
-#if ES_BUILD_STANDALONE
- (new RegistryPermission(RegistryPermissionAccess.Read, regKey)).Assert();
-#endif
- using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(regKey))
- {
- data = key?.GetValue(valueName, null) as byte[];
- if (data != null)
- {
- // We only used the persisted data from the registry for updates.
- command = ControllerCommand.Update;
- return true;
- }
- }
-#endif
- }
- else
- {
- // ETW limited filter data to 1024 bytes but EventPipe doesn't. DiagnosticSourceEventSource
- // can legitimately use large filter data buffers to encode a large set of events and properties
- // that should be gathered so I am bumping the limit from 1K -> 100K.
- if (filterData->Ptr != 0 && 0 < filterData->Size && filterData->Size <= 100*1024)
- {
- data = new byte[filterData->Size];
- Marshal.Copy((IntPtr)filterData->Ptr, data, 0, data.Length);
- }
- command = (ControllerCommand)filterData->Type;
- return true;
- }
-
- command = ControllerCommand.Update;
- return false;
- }
-
- /// <summary>
- /// IsEnabled, method used to test if provider is enabled
- /// </summary>
- public bool IsEnabled()
- {
- return m_enabled;
- }
-
- /// <summary>
- /// IsEnabled, method used to test if event is enabled
- /// </summary>
- /// <param name="level">
- /// Level to test
- /// </param>
- /// <param name="keywords">
- /// Keyword to test
- /// </param>
- public bool IsEnabled(byte level, long keywords)
- {
- //
- // If not enabled at all, return false.
- //
- if (!m_enabled)
- {
- return false;
- }
-
- // This also covers the case of Level == 0.
- if ((level <= m_level) ||
- (m_level == 0))
- {
- //
- // Check if Keyword is enabled
- //
-
- if ((keywords == 0) ||
- (((keywords & m_anyKeywordMask) != 0) &&
- ((keywords & m_allKeywordMask) == m_allKeywordMask)))
- {
- return true;
- }
- }
-
- return false;
- }
-
- public static WriteEventErrorCode GetLastWriteEventError()
- {
- return s_returnCode;
- }
-
- //
- // Helper function to set the last error on the thread
- //
- private static void SetLastError(WriteEventErrorCode error)
- {
- s_returnCode = error;
- }
-
- // <SecurityKernel Critical="True" Ring="0">
- // <UsesUnsafeCode Name="Local intptrPtr of type: IntPtr*" />
- // <UsesUnsafeCode Name="Local intptrPtr of type: Int32*" />
- // <UsesUnsafeCode Name="Local longptr of type: Int64*" />
- // <UsesUnsafeCode Name="Local uintptr of type: UInt32*" />
- // <UsesUnsafeCode Name="Local ulongptr of type: UInt64*" />
- // <UsesUnsafeCode Name="Local charptr of type: Char*" />
- // <UsesUnsafeCode Name="Local byteptr of type: Byte*" />
- // <UsesUnsafeCode Name="Local shortptr of type: Int16*" />
- // <UsesUnsafeCode Name="Local sbyteptr of type: SByte*" />
- // <UsesUnsafeCode Name="Local ushortptr of type: UInt16*" />
- // <UsesUnsafeCode Name="Local floatptr of type: Single*" />
- // <UsesUnsafeCode Name="Local doubleptr of type: Double*" />
- // <UsesUnsafeCode Name="Local boolptr of type: Boolean*" />
- // <UsesUnsafeCode Name="Local guidptr of type: Guid*" />
- // <UsesUnsafeCode Name="Local decimalptr of type: Decimal*" />
- // <UsesUnsafeCode Name="Local booleanptr of type: Boolean*" />
- // <UsesUnsafeCode Name="Parameter dataDescriptor of type: EventData*" />
- // <UsesUnsafeCode Name="Parameter dataBuffer of type: Byte*" />
- // </SecurityKernel>
- private static unsafe object? EncodeObject(ref object? data, ref EventData* dataDescriptor, ref byte* dataBuffer, ref uint totalEventSize)
- /*++
-
- Routine Description:
-
- This routine is used by WriteEvent to unbox the object type and
- to fill the passed in ETW data descriptor.
-
- Arguments:
-
- data - argument to be decoded
-
- dataDescriptor - pointer to the descriptor to be filled (updated to point to the next empty entry)
-
- dataBuffer - storage buffer for storing user data, needed because cant get the address of the object
- (updated to point to the next empty entry)
-
- Return Value:
-
- null if the object is a basic type other than string or byte[]. String otherwise
-
- --*/
- {
- Again:
- dataDescriptor->Reserved = 0;
-
- string? sRet = data as string;
- byte[]? blobRet = null;
-
- if (sRet != null)
- {
- dataDescriptor->Size = ((uint)sRet.Length + 1) * 2;
- }
- else if ((blobRet = data as byte[]) != null)
- {
- // first store array length
- *(int*)dataBuffer = blobRet.Length;
- dataDescriptor->Ptr = (ulong)dataBuffer;
- dataDescriptor->Size = 4;
- totalEventSize += dataDescriptor->Size;
-
- // then the array parameters
- dataDescriptor++;
- dataBuffer += s_basicTypeAllocationBufferSize;
- dataDescriptor->Size = (uint)blobRet.Length;
- }
- else if (data is IntPtr)
- {
- dataDescriptor->Size = (uint)sizeof(IntPtr);
- IntPtr* intptrPtr = (IntPtr*)dataBuffer;
- *intptrPtr = (IntPtr)data;
- dataDescriptor->Ptr = (ulong)intptrPtr;
- }
- else if (data is int)
- {
- dataDescriptor->Size = (uint)sizeof(int);
- int* intptr = (int*)dataBuffer;
- *intptr = (int)data;
- dataDescriptor->Ptr = (ulong)intptr;
- }
- else if (data is long)
- {
- dataDescriptor->Size = (uint)sizeof(long);
- long* longptr = (long*)dataBuffer;
- *longptr = (long)data;
- dataDescriptor->Ptr = (ulong)longptr;
- }
- else if (data is uint)
- {
- dataDescriptor->Size = (uint)sizeof(uint);
- uint* uintptr = (uint*)dataBuffer;
- *uintptr = (uint)data;
- dataDescriptor->Ptr = (ulong)uintptr;
- }
- else if (data is ulong)
- {
- dataDescriptor->Size = (uint)sizeof(ulong);
- ulong* ulongptr = (ulong*)dataBuffer;
- *ulongptr = (ulong)data;
- dataDescriptor->Ptr = (ulong)ulongptr;
- }
- else if (data is char)
- {
- dataDescriptor->Size = (uint)sizeof(char);
- char* charptr = (char*)dataBuffer;
- *charptr = (char)data;
- dataDescriptor->Ptr = (ulong)charptr;
- }
- else if (data is byte)
- {
- dataDescriptor->Size = (uint)sizeof(byte);
- byte* byteptr = (byte*)dataBuffer;
- *byteptr = (byte)data;
- dataDescriptor->Ptr = (ulong)byteptr;
- }
- else if (data is short)
- {
- dataDescriptor->Size = (uint)sizeof(short);
- short* shortptr = (short*)dataBuffer;
- *shortptr = (short)data;
- dataDescriptor->Ptr = (ulong)shortptr;
- }
- else if (data is sbyte)
- {
- dataDescriptor->Size = (uint)sizeof(sbyte);
- sbyte* sbyteptr = (sbyte*)dataBuffer;
- *sbyteptr = (sbyte)data;
- dataDescriptor->Ptr = (ulong)sbyteptr;
- }
- else if (data is ushort)
- {
- dataDescriptor->Size = (uint)sizeof(ushort);
- ushort* ushortptr = (ushort*)dataBuffer;
- *ushortptr = (ushort)data;
- dataDescriptor->Ptr = (ulong)ushortptr;
- }
- else if (data is float)
- {
- dataDescriptor->Size = (uint)sizeof(float);
- float* floatptr = (float*)dataBuffer;
- *floatptr = (float)data;
- dataDescriptor->Ptr = (ulong)floatptr;
- }
- else if (data is double)
- {
- dataDescriptor->Size = (uint)sizeof(double);
- double* doubleptr = (double*)dataBuffer;
- *doubleptr = (double)data;
- dataDescriptor->Ptr = (ulong)doubleptr;
- }
- else if (data is bool)
- {
- // WIN32 Bool is 4 bytes
- dataDescriptor->Size = 4;
- int* intptr = (int*)dataBuffer;
- if ((bool)data)
- {
- *intptr = 1;
- }
- else
- {
- *intptr = 0;
- }
- dataDescriptor->Ptr = (ulong)intptr;
- }
- else if (data is Guid)
- {
- dataDescriptor->Size = (uint)sizeof(Guid);
- Guid* guidptr = (Guid*)dataBuffer;
- *guidptr = (Guid)data;
- dataDescriptor->Ptr = (ulong)guidptr;
- }
- else if (data is decimal)
- {
- dataDescriptor->Size = (uint)sizeof(decimal);
- decimal* decimalptr = (decimal*)dataBuffer;
- *decimalptr = (decimal)data;
- dataDescriptor->Ptr = (ulong)decimalptr;
- }
- else if (data is DateTime)
- {
- const long UTCMinTicks = 504911232000000000;
- long dateTimeTicks = 0;
- // We cannot translate dates sooner than 1/1/1601 in UTC.
- // To avoid getting an ArgumentOutOfRangeException we compare with 1/1/1601 DateTime ticks
- if (((DateTime)data).Ticks > UTCMinTicks)
- dateTimeTicks = ((DateTime)data).ToFileTimeUtc();
- dataDescriptor->Size = (uint)sizeof(long);
- long* longptr = (long*)dataBuffer;
- *longptr = dateTimeTicks;
- dataDescriptor->Ptr = (ulong)longptr;
- }
- else
- {
- if (data is System.Enum)
- {
- try
- {
- Type underlyingType = Enum.GetUnderlyingType(data.GetType());
- if (underlyingType == typeof(ulong))
- data = (ulong)data;
- else if (underlyingType == typeof(long))
- data = (long)data;
- else
- data = (int)Convert.ToInt64(data); // This handles all int/uint or below (we treat them like 32 bit ints)
- goto Again;
- }
- catch { } // On wierd cases (e.g. enums of type double), give up and for compat simply tostring.
- }
-
- // To our eyes, everything else is a just a string
- if (data == null)
- sRet = "";
- else
- sRet = data.ToString()!;
- dataDescriptor->Size = ((uint)sRet.Length + 1) * 2;
- }
-
- totalEventSize += dataDescriptor->Size;
-
- // advance buffers
- dataDescriptor++;
- dataBuffer += s_basicTypeAllocationBufferSize;
-
- return (object?)sRet ?? (object?)blobRet;
- }
-
- /// <summary>
- /// WriteEvent, method to write a parameters with event schema properties
- /// </summary>
- /// <param name="eventDescriptor">
- /// Event Descriptor for this event.
- /// </param>
- /// <param name="activityID">
- /// A pointer to the activity ID GUID to log
- /// </param>
- /// <param name="childActivityID">
- /// childActivityID is marked as 'related' to the current activity ID.
- /// </param>
- /// <param name="eventPayload">
- /// Payload for the ETW event.
- /// </param>
- // <SecurityKernel Critical="True" Ring="0">
- // <CallsSuppressUnmanagedCode Name="Interop.Advapi32.EventWrite(System.Int64,EventDescriptor&,System.UInt32,System.Void*):System.UInt32" />
- // <UsesUnsafeCode Name="Local dataBuffer of type: Byte*" />
- // <UsesUnsafeCode Name="Local pdata of type: Char*" />
- // <UsesUnsafeCode Name="Local userData of type: EventData*" />
- // <UsesUnsafeCode Name="Local userDataPtr of type: EventData*" />
- // <UsesUnsafeCode Name="Local currentBuffer of type: Byte*" />
- // <UsesUnsafeCode Name="Local v0 of type: Char*" />
- // <UsesUnsafeCode Name="Local v1 of type: Char*" />
- // <UsesUnsafeCode Name="Local v2 of type: Char*" />
- // <UsesUnsafeCode Name="Local v3 of type: Char*" />
- // <UsesUnsafeCode Name="Local v4 of type: Char*" />
- // <UsesUnsafeCode Name="Local v5 of type: Char*" />
- // <UsesUnsafeCode Name="Local v6 of type: Char*" />
- // <UsesUnsafeCode Name="Local v7 of type: Char*" />
- // <ReferencesCritical Name="Method: EncodeObject(Object&, EventData*, Byte*):String" Ring="1" />
- // </SecurityKernel>
- internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, params object?[] eventPayload)
- {
- WriteEventErrorCode status = WriteEventErrorCode.NoError;
-
- if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
- {
- int argCount = eventPayload.Length;
-
- if (argCount > s_etwMaxNumberArguments)
- {
- s_returnCode = WriteEventErrorCode.TooManyArgs;
- return false;
- }
-
- uint totalEventSize = 0;
- int index;
- int refObjIndex = 0;
- List<int> refObjPosition = new List<int>(s_etwAPIMaxRefObjCount);
- List<object?> dataRefObj = new List<object?>(s_etwAPIMaxRefObjCount);
- EventData* userData = stackalloc EventData[2 * argCount];
- for (int i = 0; i < 2 * argCount; i++)
- userData[i] = default;
- EventData* userDataPtr = (EventData*)userData;
- byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize * 2 * argCount]; // Assume 16 chars for non-string argument
- byte* currentBuffer = dataBuffer;
-
- //
- // The loop below goes through all the arguments and fills in the data
- // descriptors. For strings save the location in the dataString array.
- // Calculates the total size of the event by adding the data descriptor
- // size value set in EncodeObject method.
- //
- bool hasNonStringRefArgs = false;
- for (index = 0; index < eventPayload.Length; index++)
- {
- if (eventPayload[index] != null)
- {
- object? supportedRefObj = EncodeObject(ref eventPayload[index], ref userDataPtr, ref currentBuffer, ref totalEventSize);
-
- if (supportedRefObj != null)
- {
- // EncodeObject advanced userDataPtr to the next empty slot
- int idx = (int)(userDataPtr - userData - 1);
- if (!(supportedRefObj is string))
- {
- if (eventPayload.Length + idx + 1 - index > s_etwMaxNumberArguments)
- {
- s_returnCode = WriteEventErrorCode.TooManyArgs;
- return false;
- }
- hasNonStringRefArgs = true;
- }
- dataRefObj.Add(supportedRefObj);
- refObjPosition.Add(idx);
- refObjIndex++;
- }
- }
- else
- {
- s_returnCode = WriteEventErrorCode.NullInput;
- return false;
- }
- }
-
- // update argCount based on actual number of arguments written to 'userData'
- argCount = (int)(userDataPtr - userData);
-
- if (totalEventSize > s_traceEventMaximumSize)
- {
- s_returnCode = WriteEventErrorCode.EventTooBig;
- return false;
- }
-
- // the optimized path (using "fixed" instead of allocating pinned GCHandles
- if (!hasNonStringRefArgs && (refObjIndex < s_etwAPIMaxRefObjCount))
- {
- // Fast path: at most 8 string arguments
-
- // ensure we have at least s_etwAPIMaxStringCount in dataString, so that
- // the "fixed" statement below works
- while (refObjIndex < s_etwAPIMaxRefObjCount)
- {
- dataRefObj.Add(null);
- ++refObjIndex;
- }
-
- //
- // now fix any string arguments and set the pointer on the data descriptor
- //
- fixed (char* v0 = (string?)dataRefObj[0], v1 = (string?)dataRefObj[1], v2 = (string?)dataRefObj[2], v3 = (string?)dataRefObj[3],
- v4 = (string?)dataRefObj[4], v5 = (string?)dataRefObj[5], v6 = (string?)dataRefObj[6], v7 = (string?)dataRefObj[7])
- {
- userDataPtr = (EventData*)userData;
- if (dataRefObj[0] != null)
- {
- userDataPtr[refObjPosition[0]].Ptr = (ulong)v0;
- }
- if (dataRefObj[1] != null)
- {
- userDataPtr[refObjPosition[1]].Ptr = (ulong)v1;
- }
- if (dataRefObj[2] != null)
- {
- userDataPtr[refObjPosition[2]].Ptr = (ulong)v2;
- }
- if (dataRefObj[3] != null)
- {
- userDataPtr[refObjPosition[3]].Ptr = (ulong)v3;
- }
- if (dataRefObj[4] != null)
- {
- userDataPtr[refObjPosition[4]].Ptr = (ulong)v4;
- }
- if (dataRefObj[5] != null)
- {
- userDataPtr[refObjPosition[5]].Ptr = (ulong)v5;
- }
- if (dataRefObj[6] != null)
- {
- userDataPtr[refObjPosition[6]].Ptr = (ulong)v6;
- }
- if (dataRefObj[7] != null)
- {
- userDataPtr[refObjPosition[7]].Ptr = (ulong)v7;
- }
-
- status = m_eventProvider.EventWriteTransfer(m_regHandle, in eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData);
- }
- }
- else
- {
- // Slow path: use pinned handles
- userDataPtr = (EventData*)userData;
-
- GCHandle[] rgGCHandle = new GCHandle[refObjIndex];
- for (int i = 0; i < refObjIndex; ++i)
- {
- // below we still use "fixed" to avoid taking dependency on the offset of the first field
- // in the object (the way we would need to if we used GCHandle.AddrOfPinnedObject)
- rgGCHandle[i] = GCHandle.Alloc(dataRefObj[i], GCHandleType.Pinned);
- if (dataRefObj[i] is string)
- {
- fixed (char* p = (string?)dataRefObj[i])
- userDataPtr[refObjPosition[i]].Ptr = (ulong)p;
- }
- else
- {
- fixed (byte* p = (byte[]?)dataRefObj[i])
- userDataPtr[refObjPosition[i]].Ptr = (ulong)p;
- }
- }
-
- status = m_eventProvider.EventWriteTransfer(m_regHandle, in eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData);
-
- for (int i = 0; i < refObjIndex; ++i)
- {
- rgGCHandle[i].Free();
- }
- }
- }
-
- if (status != WriteEventErrorCode.NoError)
- {
- SetLastError(status);
- return false;
- }
-
- return true;
- }
-
- /// <summary>
- /// WriteEvent, method to be used by generated code on a derived class
- /// </summary>
- /// <param name="eventDescriptor">
- /// Event Descriptor for this event.
- /// </param>
- /// <param name="activityID">
- /// A pointer to the activity ID to log
- /// </param>
- /// <param name="childActivityID">
- /// If this event is generating a child activity (WriteEventTransfer related activity) this is child activity
- /// This can be null for events that do not generate a child activity.
- /// </param>
- /// <param name="dataCount">
- /// number of event descriptors
- /// </param>
- /// <param name="data">
- /// pointer do the event data
- /// </param>
- // <SecurityKernel Critical="True" Ring="0">
- // <CallsSuppressUnmanagedCode Name="Interop.Advapi32.EventWrite(System.Int64,EventDescriptor&,System.UInt32,System.Void*):System.UInt32" />
- // </SecurityKernel>
- protected internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data)
- {
- if (childActivityID != null)
- {
- // activity transfers are supported only for events that specify the Send or Receive opcode
- Debug.Assert((EventOpcode)eventDescriptor.Opcode == EventOpcode.Send ||
- (EventOpcode)eventDescriptor.Opcode == EventOpcode.Receive ||
- (EventOpcode)eventDescriptor.Opcode == EventOpcode.Start ||
- (EventOpcode)eventDescriptor.Opcode == EventOpcode.Stop);
- }
-
- WriteEventErrorCode status = m_eventProvider.EventWriteTransfer(m_regHandle, in eventDescriptor, eventHandle, activityID, childActivityID, dataCount, (EventData*)data);
-
- if (status != 0)
- {
- SetLastError(status);
- return false;
- }
- return true;
- }
-
- internal unsafe bool WriteEventRaw(
- ref EventDescriptor eventDescriptor,
- IntPtr eventHandle,
- Guid* activityID,
- Guid* relatedActivityID,
- int dataCount,
- IntPtr data)
- {
- WriteEventErrorCode status = m_eventProvider.EventWriteTransfer(
- m_regHandle,
- in eventDescriptor,
- eventHandle,
- activityID,
- relatedActivityID,
- dataCount,
- (EventData*)data);
-
- if (status != WriteEventErrorCode.NoError)
- {
- SetLastError(status);
- return false;
- }
-
- return true;
- }
-
- // These are look-alikes to the Manifest based ETW OS APIs that have been shimmed to work
- // either with Manifest ETW or Classic ETW (if Manifest based ETW is not available).
- private unsafe uint EventRegister(EventSource eventSource, Interop.Advapi32.EtwEnableCallback enableCallback)
- {
- m_providerName = eventSource.Name;
- m_providerId = eventSource.Guid;
- m_etwCallback = enableCallback;
- return m_eventProvider.EventRegister(eventSource, enableCallback, null, ref m_regHandle);
- }
-
- private void EventUnregister(long registrationHandle) =>
- m_eventProvider.EventUnregister(registrationHandle);
-
-#if PLATFORM_WINDOWS
- private static bool m_setInformationMissing;
-
- internal unsafe int SetInformation(
- Interop.Advapi32.EVENT_INFO_CLASS eventInfoClass,
- IntPtr data,
- uint dataSize)
- {
- int status = Interop.Errors.ERROR_NOT_SUPPORTED;
-
- if (!m_setInformationMissing)
- {
- try
- {
- status = Interop.Advapi32.EventSetInformation(
- m_regHandle,
- eventInfoClass,
- (void*)data,
- (int)dataSize);
- }
- catch (TypeLoadException)
- {
- m_setInformationMissing = true;
- }
- }
-
- return status;
- }
-#endif
- }
-
-#if PLATFORM_WINDOWS
-
- // A wrapper around the ETW-specific API calls.
- internal sealed class EtwEventProvider : IEventProvider
- {
- // Register an event provider.
- unsafe uint IEventProvider.EventRegister(
- EventSource eventSource,
- Interop.Advapi32.EtwEnableCallback enableCallback,
- void* callbackContext,
- ref long registrationHandle)
- {
- Guid providerId = eventSource.Guid;
- return Interop.Advapi32.EventRegister(
- in providerId,
- enableCallback,
- callbackContext,
- ref registrationHandle);
- }
-
- // Unregister an event provider.
- uint IEventProvider.EventUnregister(long registrationHandle)
- {
- return Interop.Advapi32.EventUnregister(registrationHandle);
- }
-
- // Write an event.
- unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer(
- long registrationHandle,
- in EventDescriptor eventDescriptor,
- IntPtr eventHandle,
- Guid* activityId,
- Guid* relatedActivityId,
- int userDataCount,
- EventProvider.EventData* userData)
- {
- int error = Interop.Advapi32.EventWriteTransfer(
- registrationHandle,
- in eventDescriptor,
- activityId,
- relatedActivityId,
- userDataCount,
- userData);
-
- switch (error)
- {
- case Interop.Errors.ERROR_ARITHMETIC_OVERFLOW:
- case Interop.Errors.ERROR_MORE_DATA:
- return EventProvider.WriteEventErrorCode.EventTooBig;
- case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY:
- return EventProvider.WriteEventErrorCode.NoFreeBuffers;
- }
-
- return EventProvider.WriteEventErrorCode.NoError;
- }
-
- // Get or set the per-thread activity ID.
- int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId)
- {
- return Interop.Advapi32.EventActivityIdControl(
- ControlCode,
- ref ActivityId);
- }
-
- // Define an EventPipeEvent handle.
- unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength)
- {
- throw new System.NotSupportedException();
- }
- }
-
-#endif
- internal sealed class NoOpEventProvider : IEventProvider
- {
- unsafe uint IEventProvider.EventRegister(
- EventSource eventSource,
- Interop.Advapi32.EtwEnableCallback enableCallback,
- void* callbackContext,
- ref long registrationHandle)
- {
- return 0;
- }
-
- uint IEventProvider.EventUnregister(long registrationHandle)
- {
- return 0;
- }
-
- unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer(
- long registrationHandle,
- in EventDescriptor eventDescriptor,
- IntPtr eventHandle,
- Guid* activityId,
- Guid* relatedActivityId,
- int userDataCount,
- EventProvider.EventData* userData)
- {
- return EventProvider.WriteEventErrorCode.NoError;
- }
-
- int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId)
- {
- return 0;
- }
-
- // Define an EventPipeEvent handle.
- unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength)
- {
- return IntPtr.Zero;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs
deleted file mode 100644
index e639f7c610c..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs
+++ /dev/null
@@ -1,6204 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
-// It is available from http://www.codeplex.com/hyperAddin
-#if ES_BUILD_STANDALONE
-#define FEATURE_MANAGED_ETW_CHANNELS
-// #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
-#endif
-
-/* DESIGN NOTES DESIGN NOTES DESIGN NOTES DESIGN NOTES */
-// DESIGN NOTES
-// Over the years EventSource has become more complex and so it is important to understand
-// the basic structure of the code to insure that it does not grow more complex.
-//
-// Basic Model
-//
-// PRINCIPLE: EventSource - ETW decoupling
-//
-// Conceptually an EventSouce is something that takes event logging data from the source methods
-// to the EventListener that can subscribe to them. Note that CONCEPTUALLY EVENTSOURCES DON'T
-// KNOW ABOUT ETW!. The MODEL of the system is that there is a special EventListener which
-// we will call the EtwEventListener, that forwards commands from ETW to EventSources and
-// listens to EventSources and forwards on those events to ETW. Thus the model should
-// be that you DON'T NEED ETW.
-//
-// Now in actual practice, EventSouce have rather intimate knowledge of ETW and send events
-// to it directly, but this can be VIEWED AS AN OPTIMIZATION.
-//
-// Basic Event Data Flow:
-//
-// There are two ways for event Data to enter the system
-// 1) WriteEvent* and friends. This is called the 'contract' based approach because
-// you write a method per event which forms a contract that is know at compile time.
-// In this scheme each event is given an EVENTID (small integer), which is its identity
-// 2) Write<T> methods. This is called the 'dynamic' approach because new events
-// can be created on the fly. Event identity is determined by the event NAME, and these
-// are not quite as efficient at runtime since you have at least a hash table lookup
-// on every event write.
-//
-// EventSource-EventListener transfer fully supports both ways of writing events (either contract
-// based (WriteEvent*) or dynamic (Write<T>)). Both ways fully support the same set of data
-// types. It is recommended, however, that you use the contract based approach when the event scheme
-// is known at compile time (that is whenever possible). It is more efficient, but more importantly
-// it makes the contract very explicit, and centralizes all policy about logging. These are good
-// things. The Write<T> API is really meant for more ad-hoc cases.
-//
-// Allowed Data:
-//
-// Note that EventSource-EventListeners have a conceptual serialization-deserialization that happens
-// during the transfer. In particular object identity is not preserved, some objects are morphed,
-// and not all data types are supported. In particular you can pass
-//
-// A Valid type to log to an EventSource include
-// * Primitive data types
-// * IEnumerable<T> of valid types T (this include arrays) (* New for V4.6)
-// * Explicitly Opted in class or struct with public property Getters over Valid types. (* New for V4.6)
-//
-// This set of types is roughly a generalization of JSON support (basically primitives, bags, and arrays).
-//
-// Explicitly allowed structs include (* New for V4.6)
-// * Marked with the EventData attribute
-// * implicitly defined (e.g the C# new {x = 3, y = 5} syntax)
-// * KeyValuePair<K,V> (thus dictionaries can be passed since they are an IEnumerable of KeyValuePair)
-//
-// When classes are returned in an EventListener, what is returned is something that implements
-// IDictionary<string, T>. Thus when objects are passed to an EventSource they are transformed
-// into a key-value bag (the IDictionary<string, T>) for consumption in the listener. These
-// are obviously NOT the original objects.
-//
-// ETW serialization formats:
-//
-// As mentioned, conceptually EventSources send data to EventListeners and there is a conceptual
-// copy/morph of that data as described above. In addition the .NET framework supports a conceptual
-// ETWListener that will send the data to the ETW stream. If you use this feature, the data needs
-// to be serialized in a way that ETW supports. ETW supports the following serialization formats
-//
-// 1) Manifest Based serialization.
-// 2) SelfDescribing serialization (TraceLogging style in the TraceLogging directory)
-//
-// A key factor is that the Write<T> method, which supports on the fly definition of events, can't
-// support the manifest based serialization because the manifest needs the schema of all events
-// to be known before any events are emitted. This implies the following:
-//
-// If you use Write<T> and the output goes to ETW it will use the SelfDescribing format.
-// If you use the EventSource(string) constructor for an eventSource (in which you don't
-// create a subclass), the default is also to use Self-Describing serialization. In addition
-// you can use the EventSoruce(EventSourceSettings) constructor to also explicitly specify
-// Self-Describing serialization format. These affect the WriteEvent* APIs going to ETW.
-//
-// Note that none of this ETW serialization logic affects EventListeners. Only the ETW listener.
-//
-// *************************************************************************************
-// *** INTERNALS: Event Propagation
-//
-// Data enters the system either though
-//
-// 1) A user defined method in the user defined subclass of EventSource which calls
-// A) A typesafe type specific overload of WriteEvent(ID, ...) e.g. WriteEvent(ID, string, string)
-// * which calls into the unsafe WriteEventCore(ID COUNT EventData*) WriteEventWithRelatedActivityIdCore()
-// B) The typesafe overload WriteEvent(ID, object[]) which calls the private helper WriteEventVarargs(ID, Guid* object[])
-// C) Directly into the unsafe WriteEventCore(ID, COUNT EventData*) or WriteEventWithRelatedActivityIdCore()
-//
-// All event data eventually flows to one of
-// * WriteEventWithRelatedActivityIdCore(ID, Guid*, COUNT, EventData*)
-// * WriteEventVarargs(ID, Guid*, object[])
-//
-// 2) A call to one of the overloads of Write<T>. All these overloads end up in
-// * WriteImpl<T>(EventName, Options, Data, Guid*, Guid*)
-//
-// On output there are the following routines
-// Writing to all listeners that are NOT ETW, we have the following routines
-// * WriteToAllListeners(ID, Guid*, Guid*, COUNT, EventData*)
-// * WriteToAllListeners(ID, Guid*, Guid*, object[])
-// * WriteToAllListeners(NAME, Guid*, Guid*, EventPayload)
-//
-// EventPayload is the internal type that implements the IDictionary<string, object> interface
-// The EventListeners will pass back for serialized classes for nested object, but
-// WriteToAllListeners(NAME, Guid*, Guid*, EventPayload) unpacks this and uses the fields as if they
-// were parameters to a method.
-//
-// The first two are used for the WriteEvent* case, and the later is used for the Write<T> case.
-//
-// Writing to ETW, Manifest Based
-// EventProvider.WriteEvent(EventDescriptor, Guid*, COUNT, EventData*)
-// EventProvider.WriteEvent(EventDescriptor, Guid*, object[])
-// Writing to ETW, Self-Describing format
-// WriteMultiMerge(NAME, Options, Types, EventData*)
-// WriteMultiMerge(NAME, Options, Types, object[])
-// WriteImpl<T> has logic that knows how to serialize (like WriteMultiMerge) but also knows
-// where it will write it to
-//
-// All ETW writes eventually call
-// EventWriteTransfer
-// EventProvider.WriteEventRaw - sets last error
-// EventSource.WriteEventRaw - Does EventSource exception handling logic
-// WriteMultiMerge
-// WriteImpl<T>
-// EventProvider.WriteEvent(EventDescriptor, Guid*, COUNT, EventData*)
-// EventProvider.WriteEvent(EventDescriptor, Guid*, object[])
-//
-// Serialization: We have a bit of a hodge-podge of serializers right now. Only the one for ETW knows
-// how to deal with nested classes or arrays. I will call this serializer the 'TypeInfo' serializer
-// since it is the TraceLoggingTypeInfo structure that knows how to do this. Effectively for a type you
-// can call one of these
-// WriteMetadata - transforms the type T into serialization meta data blob for that type
-// WriteObjectData - transforms an object of T into serialization data blob for that instance
-// GetData - transforms an object of T into its deserialized form suitable for passing to EventListener.
-// The first two are used to serialize something for ETW. The second one is used to transform the object
-// for use by the EventListener. We also have a 'DecodeObject' method that will take a EventData* and
-// deserialize to pass to an EventListener, but it only works on primitive types (types supported in version V4.5).
-//
-// It is an important observation that while EventSource does support users directly calling with EventData*
-// blobs, we ONLY support that for the primitive types (V4.5 level support). Thus while there is a EventData*
-// path through the system it is only for some types. The object[] path is the more general (but less efficient) path.
-//
-// TODO There is cleanup needed There should be no divergence until WriteEventRaw.
-//
-// TODO: We should have a single choke point (right now we always have this parallel EventData* and object[] path. This
-// was historical (at one point we tried to pass object directly from EventSoruce to EventListener. That was always
-// fragile and a compatibility headache, but we have finally been forced into the idea that there is always a transformation.
-// This allows us to use the EventData* form to be the canonical data format in the low level APIs. This also gives us the
-// opportunity to expose this format to EventListeners in the future.
-//
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-using System.Security.Permissions;
-using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
-using BitOperations = Microsoft.Diagnostics.Tracing.Internal.BitOperations;
-#else
-using System.Threading.Tasks;
-#endif
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Numerics;
-using System.Reflection;
-using System.Resources;
-using System.Text;
-using System.Threading;
-using Microsoft.Reflection;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// This class is meant to be inherited by a user-defined event source in order to define a managed
- /// ETW provider. Please See DESIGN NOTES above for the internal architecture.
- /// The minimal definition of an EventSource simply specifies a number of ETW event methods that
- /// call one of the EventSource.WriteEvent overloads, <see cref="EventSource.WriteEventCore"/>,
- /// or <see cref="EventSource.WriteEventWithRelatedActivityIdCore"/> to log them. This functionality
- /// is sufficient for many users.
- /// <para>
- /// To achieve more control over the ETW provider manifest exposed by the event source type, the
- /// [<see cref="EventAttribute"/>] attributes can be specified for the ETW event methods.
- /// </para><para>
- /// For very advanced EventSources, it is possible to intercept the commands being given to the
- /// eventSource and change what filtering is done (see EventListener.EnableEvents and
- /// <see cref="EventListener.DisableEvents"/>) or cause actions to be performed by the eventSource,
- /// e.g. dumping a data structure (see EventSource.SendCommand and
- /// <see cref="EventSource.OnEventCommand"/>).
- /// </para><para>
- /// The eventSources can be turned on with Windows ETW controllers (e.g. logman), immediately.
- /// It is also possible to control and intercept the data dispatcher programmatically. See
- /// <see cref="EventListener"/> for more.
- /// </para>
- /// </summary>
- /// <remarks>
- /// This is a minimal definition for a custom event source:
- /// <code>
- /// [EventSource(Name="Samples-Demos-Minimal")]
- /// sealed class MinimalEventSource : EventSource
- /// {
- /// public static MinimalEventSource Log = new MinimalEventSource();
- /// public void Load(long ImageBase, string Name) { WriteEvent(1, ImageBase, Name); }
- /// public void Unload(long ImageBase) { WriteEvent(2, ImageBase); }
- /// private MinimalEventSource() {}
- /// }
- /// </code>
- /// </remarks>
- public partial class EventSource : IDisposable
- {
-#if FEATURE_EVENTSOURCE_XPLAT
-#pragma warning disable CA1823 // field is used to keep listener alive
- private static readonly EventListener? persistent_Xplat_Listener = XplatEventLogger.InitializePersistentListener();
-#pragma warning restore CA1823
-#endif //FEATURE_EVENTSOURCE_XPLAT
-
- /// <summary>
- /// The human-friendly name of the eventSource. It defaults to the simple name of the class
- /// </summary>
- public string Name => m_name;
- /// <summary>
- /// Every eventSource is assigned a GUID to uniquely identify it to the system.
- /// </summary>
- public Guid Guid => m_guid;
-
- /// <summary>
- /// Returns true if the eventSource has been enabled at all. This is the preferred test
- /// to be performed before a relatively expensive EventSource operation.
- /// </summary>
- public bool IsEnabled()
- {
- return m_eventSourceEnabled;
- }
-
- /// <summary>
- /// Returns true if events with greater than or equal 'level' and have one of 'keywords' set are enabled.
- ///
- /// Note that the result of this function is only an approximation on whether a particular
- /// event is active or not. It is only meant to be used as way of avoiding expensive
- /// computation for logging when logging is not on, therefore it sometimes returns false
- /// positives (but is always accurate when returning false). EventSources are free to
- /// have additional filtering.
- /// </summary>
- public bool IsEnabled(EventLevel level, EventKeywords keywords)
- {
- return IsEnabled(level, keywords, EventChannel.None);
- }
-
- /// <summary>
- /// Returns true if events with greater than or equal 'level' and have one of 'keywords' set are enabled, or
- /// if 'keywords' specifies a channel bit for a channel that is enabled.
- ///
- /// Note that the result of this function only an approximation on whether a particular
- /// event is active or not. It is only meant to be used as way of avoiding expensive
- /// computation for logging when logging is not on, therefore it sometimes returns false
- /// positives (but is always accurate when returning false). EventSources are free to
- /// have additional filtering.
- /// </summary>
- public bool IsEnabled(EventLevel level, EventKeywords keywords, EventChannel channel)
- {
- if (!m_eventSourceEnabled)
- return false;
-
- if (!IsEnabledCommon(m_eventSourceEnabled, m_level, m_matchAnyKeyword, level, keywords, channel))
- return false;
-
- return true;
- }
-
- /// <summary>
- /// Returns the settings for the event source instance
- /// </summary>
- public EventSourceSettings Settings => m_config;
-
- // Manifest support
- /// <summary>
- /// Returns the GUID that uniquely identifies the eventSource defined by 'eventSourceType'.
- /// This API allows you to compute this without actually creating an instance of the EventSource.
- /// It only needs to reflect over the type.
- /// </summary>
- public static Guid GetGuid(Type eventSourceType)
- {
- if (eventSourceType == null)
- throw new ArgumentNullException(nameof(eventSourceType));
-
- EventSourceAttribute? attrib = (EventSourceAttribute?)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute));
- string name = eventSourceType.Name;
- if (attrib != null)
- {
- if (attrib.Guid != null)
- {
-#if !ES_BUILD_AGAINST_DOTNET_V35
- if (Guid.TryParse(attrib.Guid, out Guid g))
- return g;
-#else
- try { return new Guid(attrib.Guid); }
- catch (Exception) { }
-#endif
- }
-
- if (attrib.Name != null)
- name = attrib.Name;
- }
-
- if (name == null)
- {
- throw new ArgumentException(SR.Argument_InvalidTypeName, nameof(eventSourceType));
- }
- return GenerateGuidFromName(name.ToUpperInvariant()); // Make it case insensitive.
- }
- /// <summary>
- /// Returns the official ETW Provider name for the eventSource defined by 'eventSourceType'.
- /// This API allows you to compute this without actually creating an instance of the EventSource.
- /// It only needs to reflect over the type.
- /// </summary>
- public static string GetName(Type eventSourceType)
- {
- return GetName(eventSourceType, EventManifestOptions.None);
- }
-
- /// <summary>
- /// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is
- /// documented at in EventManifest Schema https://docs.microsoft.com/en-us/windows/desktop/WES/eventmanifestschema-schema.
- /// This is the preferred way of generating a manifest to be embedded in the ETW stream as it is fast and
- /// the fact that it only includes localized entries for the current UI culture is an acceptable tradeoff.
- /// </summary>
- /// <param name="eventSourceType">The type of the event source class for which the manifest is generated</param>
- /// <param name="assemblyPathToIncludeInManifest">The manifest XML fragment contains the string name of the DLL name in
- /// which it is embedded. This parameter specifies what name will be used</param>
- /// <returns>The XML data string</returns>
- public static string? GenerateManifest(Type eventSourceType, string? assemblyPathToIncludeInManifest)
- {
- return GenerateManifest(eventSourceType, assemblyPathToIncludeInManifest, EventManifestOptions.None);
- }
- /// <summary>
- /// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is
- /// documented at in EventManifest Schema https://docs.microsoft.com/en-us/windows/desktop/WES/eventmanifestschema-schema.
- /// Pass EventManifestOptions.AllCultures when generating a manifest to be registered on the machine. This
- /// ensures that the entries in the event log will be "optimally" localized.
- /// </summary>
- /// <param name="eventSourceType">The type of the event source class for which the manifest is generated</param>
- /// <param name="assemblyPathToIncludeInManifest">The manifest XML fragment contains the string name of the DLL name in
- /// which it is embedded. This parameter specifies what name will be used</param>
- /// <param name="flags">The flags to customize manifest generation. If flags has bit OnlyIfNeededForRegistration specified
- /// this returns null when the eventSourceType does not require explicit registration</param>
- /// <returns>The XML data string or null</returns>
- public static string? GenerateManifest(Type eventSourceType, string? assemblyPathToIncludeInManifest, EventManifestOptions flags)
- {
- if (eventSourceType == null)
- throw new ArgumentNullException(nameof(eventSourceType));
-
- byte[]? manifestBytes = EventSource.CreateManifestAndDescriptors(eventSourceType, assemblyPathToIncludeInManifest, null, flags);
- return (manifestBytes == null) ? null : Encoding.UTF8.GetString(manifestBytes, 0, manifestBytes.Length);
- }
-
- // EventListener support
- /// <summary>
- /// returns a list (IEnumerable) of all sources in the appdomain). EventListeners typically need this.
- /// </summary>
- /// <returns></returns>
- public static IEnumerable<EventSource> GetSources()
- {
- var ret = new List<EventSource>();
- lock (EventListener.EventListenersLock)
- {
- Debug.Assert(EventListener.s_EventSources != null);
-
- foreach (WeakReference<EventSource> eventSourceRef in EventListener.s_EventSources)
- {
- if (eventSourceRef.TryGetTarget(out EventSource? eventSource) && !eventSource.IsDisposed)
- ret.Add(eventSource);
- }
- }
- return ret;
- }
-
- /// <summary>
- /// Send a command to a particular EventSource identified by 'eventSource'.
- /// Calling this routine simply forwards the command to the EventSource.OnEventCommand
- /// callback. What the EventSource does with the command and its arguments are from
- /// that point EventSource-specific.
- /// </summary>
- /// <param name="eventSource">The instance of EventSource to send the command to</param>
- /// <param name="command">A positive user-defined EventCommand, or EventCommand.SendManifest</param>
- /// <param name="commandArguments">A set of (name-argument, value-argument) pairs associated with the command</param>
- public static void SendCommand(EventSource eventSource, EventCommand command, IDictionary<string, string?>? commandArguments)
- {
- if (eventSource == null)
- throw new ArgumentNullException(nameof(eventSource));
-
- // User-defined EventCommands should not conflict with the reserved commands.
- if ((int)command <= (int)EventCommand.Update && (int)command != (int)EventCommand.SendManifest)
- {
- throw new ArgumentException(SR.EventSource_InvalidCommand, nameof(command));
- }
-
- eventSource.SendCommand(null, EventProviderType.ETW, 0, 0, command, true, EventLevel.LogAlways, EventKeywords.None, commandArguments);
- }
-
- // Error APIs. (We don't throw by default, but you can probe for status)
- /// <summary>
- /// Because
- ///
- /// 1) Logging is often optional and thus should not generate fatal errors (exceptions)
- /// 2) EventSources are often initialized in class constructors (which propagate exceptions poorly)
- ///
- /// The event source constructor does not throw exceptions. Instead we remember any exception that
- /// was generated (it is also logged to Trace.WriteLine).
- /// </summary>
- public Exception? ConstructionException => m_constructionException;
-
- /// <summary>
- /// EventSources can have arbitrary string key-value pairs associated with them called Traits.
- /// These traits are not interpreted by the EventSource but may be interpreted by EventListeners
- /// (e.g. like the built in ETW listener). These traits are specified at EventSource
- /// construction time and can be retrieved by using this GetTrait API.
- /// </summary>
- /// <param name="key">The key to look up in the set of key-value pairs passed to the EventSource constructor</param>
- /// <returns>The value string associated with key. Will return null if there is no such key.</returns>
- public string? GetTrait(string key)
- {
- if (m_traits != null)
- {
- for (int i = 0; i < m_traits.Length - 1; i += 2)
- {
- if (m_traits[i] == key)
- return m_traits[i + 1];
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Displays the name and GUID for the eventSource for debugging purposes.
- /// </summary>
- public override string ToString()
- {
- return SR.Format(SR.EventSource_ToString, Name, Guid);
- }
-
- /// <summary>
- /// Fires when a Command (e.g. Enable) comes from a an EventListener.
- /// </summary>
- public event EventHandler<EventCommandEventArgs>? EventCommandExecuted
- {
- add
- {
- if (value == null)
- return;
-
- m_eventCommandExecuted += value;
-
- // If we have an EventHandler<EventCommandEventArgs> attached to the EventSource before the first command arrives
- // It should get a chance to handle the deferred commands.
- EventCommandEventArgs? deferredCommands = m_deferredCommands;
- while (deferredCommands != null)
- {
- value(this, deferredCommands);
- deferredCommands = deferredCommands.nextCommand;
- }
- }
- remove
- {
- m_eventCommandExecuted -= value;
- }
- }
-
-#region ActivityID
-
- /// <summary>
- /// When a thread starts work that is on behalf of 'something else' (typically another
- /// thread or network request) it should mark the thread as working on that other work.
- /// This API marks the current thread as working on activity 'activityID'. This API
- /// should be used when the caller knows the thread's current activity (the one being
- /// overwritten) has completed. Otherwise, callers should prefer the overload that
- /// return the oldActivityThatWillContinue (below).
- ///
- /// All events created with the EventSource on this thread are also tagged with the
- /// activity ID of the thread.
- ///
- /// It is common, and good practice after setting the thread to an activity to log an event
- /// with a 'start' opcode to indicate that precise time/thread where the new activity
- /// started.
- /// </summary>
- /// <param name="activityId">A Guid that represents the new activity with which to mark
- /// the current thread</param>
- public static void SetCurrentThreadActivityId(Guid activityId)
- {
- if (TplEventSource.Log != null)
- TplEventSource.Log.SetActivityId(activityId);
-
- // We ignore errors to keep with the convention that EventSources do not throw errors.
- // Note we can't access m_throwOnWrites because this is a static method.
-#if FEATURE_MANAGED_ETW
-#if FEATURE_PERFTRACING
- // Set the activity id via EventPipe.
- EventPipeInternal.EventActivityIdControl(
- (uint)Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID,
- ref activityId);
-#endif // FEATURE_PERFTRACING
-#if PLATFORM_WINDOWS
- // Set the activity id via ETW.
- Interop.Advapi32.EventActivityIdControl(
- Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID,
- ref activityId);
-#endif // PLATFORM_WINDOWS
-#endif // FEATURE_MANAGED_ETW
- }
-
- /// <summary>
- /// Retrieves the ETW activity ID associated with the current thread.
- /// </summary>
- public static Guid CurrentThreadActivityId
- {
- get
- {
- // We ignore errors to keep with the convention that EventSources do not throw
- // errors. Note we can't access m_throwOnWrites because this is a static method.
- Guid retVal = default;
-#if FEATURE_MANAGED_ETW
-#if PLATFORM_WINDOWS
- Interop.Advapi32.EventActivityIdControl(
- Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID,
- ref retVal);
-#elif FEATURE_PERFTRACING
- EventPipeInternal.EventActivityIdControl(
- (uint)Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID,
- ref retVal);
-#endif // PLATFORM_WINDOWS
-#endif // FEATURE_MANAGED_ETW
- return retVal;
- }
- }
-
- /// <summary>
- /// When a thread starts work that is on behalf of 'something else' (typically another
- /// thread or network request) it should mark the thread as working on that other work.
- /// This API marks the current thread as working on activity 'activityID'. It returns
- /// whatever activity the thread was previously marked with. There is a convention that
- /// callers can assume that callees restore this activity mark before the callee returns.
- /// To encourage this, this API returns the old activity, so that it can be restored later.
- ///
- /// All events created with the EventSource on this thread are also tagged with the
- /// activity ID of the thread.
- ///
- /// It is common, and good practice after setting the thread to an activity to log an event
- /// with a 'start' opcode to indicate that precise time/thread where the new activity
- /// started.
- /// </summary>
- /// <param name="activityId">A Guid that represents the new activity with which to mark
- /// the current thread</param>
- /// <param name="oldActivityThatWillContinue">The Guid that represents the current activity
- /// which will continue at some point in the future, on the current thread</param>
- public static void SetCurrentThreadActivityId(Guid activityId, out Guid oldActivityThatWillContinue)
- {
- oldActivityThatWillContinue = activityId;
-#if FEATURE_MANAGED_ETW
- // We ignore errors to keep with the convention that EventSources do not throw errors.
- // Note we can't access m_throwOnWrites because this is a static method.
-
-#if FEATURE_PERFTRACING && PLATFORM_WINDOWS
- EventPipeInternal.EventActivityIdControl(
- (uint)Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID,
- ref oldActivityThatWillContinue);
-#elif FEATURE_PERFTRACING
- EventPipeInternal.EventActivityIdControl(
- (uint)Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID,
- ref oldActivityThatWillContinue);
-#endif // FEATURE_PERFTRACING && PLATFORM_WINDOWS
-
-#if PLATFORM_WINDOWS
- Interop.Advapi32.EventActivityIdControl(
- Interop.Advapi32.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID,
- ref oldActivityThatWillContinue);
-#endif // PLATFORM_WINDOWS
-#endif // FEATURE_MANAGED_ETW
-
- // We don't call the activityDying callback here because the caller has declared that
- // it is not dying.
- if (TplEventSource.Log != null)
- TplEventSource.Log.SetActivityId(activityId);
- }
-#endregion
-
-#region protected
- /// <summary>
- /// This is the constructor that most users will use to create their eventSource. It takes
- /// no parameters. The ETW provider name and GUID of the EventSource are determined by the EventSource
- /// custom attribute (so you can determine these things declaratively). If the GUID for the eventSource
- /// is not specified in the EventSourceAttribute (recommended), it is Generated by hashing the name.
- /// If the ETW provider name of the EventSource is not given, the name of the EventSource class is used as
- /// the ETW provider name.
- /// </summary>
- protected EventSource()
- : this(EventSourceSettings.EtwManifestEventFormat)
- {
- }
-
- /// <summary>
- /// By default calling the 'WriteEvent' methods do NOT throw on errors (they silently discard the event).
- /// This is because in most cases users assume logging is not 'precious' and do NOT wish to have logging failures
- /// crash the program. However for those applications where logging is 'precious' and if it fails the caller
- /// wishes to react, setting 'throwOnEventWriteErrors' will cause an exception to be thrown if WriteEvent
- /// fails. Note the fact that EventWrite succeeds does not necessarily mean that the event reached its destination
- /// only that operation of writing it did not fail. These EventSources will not generate self-describing ETW events.
- ///
- /// For compatibility only use the EventSourceSettings.ThrowOnEventWriteErrors flag instead.
- /// </summary>
- // [Obsolete("Use the EventSource(EventSourceSettings) overload")]
- protected EventSource(bool throwOnEventWriteErrors)
- : this(EventSourceSettings.EtwManifestEventFormat | (throwOnEventWriteErrors ? EventSourceSettings.ThrowOnEventWriteErrors : 0))
- { }
-
- /// <summary>
- /// Construct an EventSource with additional non-default settings (see EventSourceSettings for more)
- /// </summary>
- protected EventSource(EventSourceSettings settings) : this(settings, null) { }
-
- /// <summary>
- /// Construct an EventSource with additional non-default settings.
- ///
- /// Also specify a list of key-value pairs called traits (you must pass an even number of strings).
- /// The first string is the key and the second is the value. These are not interpreted by EventSource
- /// itself but may be interpreted the listeners. Can be fetched with GetTrait(string).
- /// </summary>
- /// <param name="settings">See EventSourceSettings for more.</param>
- /// <param name="traits">A collection of key-value strings (must be an even number).</param>
- protected EventSource(EventSourceSettings settings, params string[]? traits)
- {
- m_config = ValidateSettings(settings);
-
- Guid eventSourceGuid;
- string? eventSourceName;
-
- GetMetadata(out eventSourceGuid, out eventSourceName, out _, out _);
-
- if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null)
- {
- Type myType = this.GetType();
- eventSourceGuid = GetGuid(myType);
- eventSourceName = GetName(myType);
- }
-
- Initialize(eventSourceGuid, eventSourceName, traits);
- }
-
-#if FEATURE_PERFTRACING
- // Generate the serialized blobs that describe events for all strongly typed events (that is events that define strongly
- // typed event methods. Dynamically defined events (that use Write) hare defined on the fly and are handled elsewhere.
- private unsafe void DefineEventPipeEvents()
- {
- // If the EventSource is set to emit all events as TraceLogging events, skip this initialization.
- // Events will be defined when they are emitted for the first time.
- if (SelfDescribingEvents)
- {
- return;
- }
-
- Debug.Assert(m_eventData != null);
- Debug.Assert(m_eventPipeProvider != null);
- int cnt = m_eventData.Length;
- for (int i = 0; i < cnt; i++)
- {
- uint eventID = (uint)m_eventData[i].Descriptor.EventId;
- if (eventID == 0)
- continue;
-
- byte[]? metadata = EventPipeMetadataGenerator.Instance.GenerateEventMetadata(m_eventData[i]);
- uint metadataLength = (metadata != null) ? (uint)metadata.Length : 0;
-
- string eventName = m_eventData[i].Name;
- long keywords = m_eventData[i].Descriptor.Keywords;
- uint eventVersion = m_eventData[i].Descriptor.Version;
- uint level = m_eventData[i].Descriptor.Level;
-
- fixed (byte* pMetadata = metadata)
- {
- IntPtr eventHandle = m_eventPipeProvider.m_eventProvider.DefineEventHandle(
- eventID,
- eventName,
- keywords,
- eventVersion,
- level,
- pMetadata,
- metadataLength);
-
- Debug.Assert(eventHandle != IntPtr.Zero);
- m_eventData[i].EventHandle = eventHandle;
- }
- }
- }
-#endif
-
- internal virtual void GetMetadata(out Guid eventSourceGuid, out string? eventSourceName, out EventMetadata[]? eventData, out byte[]? manifestBytes)
- {
- //
- // In ProjectN subclasses need to override this method, and return the data from their EventSourceAttribute and EventAttribute annotations.
- // On other architectures it is a no-op.
- //
- // eventDescriptors needs to contain one EventDescriptor for each event; the event's ID should be the same as its index in this array.
- // manifestBytes is a UTF-8 encoding of the ETW manifest for the type.
- //
- // This will be implemented by an IL rewriter, so we can't make this method abstract or the initial build of the subclass would fail.
- //
- eventSourceGuid = Guid.Empty;
- eventSourceName = null;
- eventData = null;
- manifestBytes = null;
-
- return;
- }
-
- /// <summary>
- /// This method is called when the eventSource is updated by the controller.
- /// </summary>
- protected virtual void OnEventCommand(EventCommandEventArgs command) { }
-
-#pragma warning disable 1591
- // optimized for common signatures (no args)
- protected unsafe void WriteEvent(int eventId)
- {
- WriteEventCore(eventId, 0, null);
- }
-
- // optimized for common signatures (ints)
- protected unsafe void WriteEvent(int eventId, int arg1)
- {
- if (m_eventSourceEnabled)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 4;
- descrs[0].Reserved = 0;
- WriteEventCore(eventId, 1, descrs);
- }
- }
-
- protected unsafe void WriteEvent(int eventId, int arg1, int arg2)
- {
- if (m_eventSourceEnabled)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 4;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 4;
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- }
-
- protected unsafe void WriteEvent(int eventId, int arg1, int arg2, int arg3)
- {
- if (m_eventSourceEnabled)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 4;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 4;
- descrs[1].Reserved = 0;
- descrs[2].DataPointer = (IntPtr)(&arg3);
- descrs[2].Size = 4;
- descrs[2].Reserved = 0;
- WriteEventCore(eventId, 3, descrs);
- }
- }
-
- // optimized for common signatures (longs)
- protected unsafe void WriteEvent(int eventId, long arg1)
- {
- if (m_eventSourceEnabled)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 8;
- descrs[0].Reserved = 0;
- WriteEventCore(eventId, 1, descrs);
- }
- }
-
- protected unsafe void WriteEvent(int eventId, long arg1, long arg2)
- {
- if (m_eventSourceEnabled)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 8;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 8;
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- }
-
- protected unsafe void WriteEvent(int eventId, long arg1, long arg2, long arg3)
- {
- if (m_eventSourceEnabled)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 8;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 8;
- descrs[1].Reserved = 0;
- descrs[2].DataPointer = (IntPtr)(&arg3);
- descrs[2].Size = 8;
- descrs[2].Reserved = 0;
- WriteEventCore(eventId, 3, descrs);
- }
- }
-
- // optimized for common signatures (strings)
- protected unsafe void WriteEvent(int eventId, string? arg1)
- {
- if (m_eventSourceEnabled)
- {
- arg1 ??= "";
- fixed (char* string1Bytes = arg1)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
- descrs[0].DataPointer = (IntPtr)string1Bytes;
- descrs[0].Size = ((arg1.Length + 1) * 2);
- descrs[0].Reserved = 0;
- WriteEventCore(eventId, 1, descrs);
- }
- }
- }
-
- protected unsafe void WriteEvent(int eventId, string? arg1, string? arg2)
- {
- if (m_eventSourceEnabled)
- {
- arg1 ??= "";
- arg2 ??= "";
- fixed (char* string1Bytes = arg1)
- fixed (char* string2Bytes = arg2)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- descrs[0].DataPointer = (IntPtr)string1Bytes;
- descrs[0].Size = ((arg1.Length + 1) * 2);
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)string2Bytes;
- descrs[1].Size = ((arg2.Length + 1) * 2);
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- }
- }
-
- protected unsafe void WriteEvent(int eventId, string? arg1, string? arg2, string? arg3)
- {
- if (m_eventSourceEnabled)
- {
- arg1 ??= "";
- arg2 ??= "";
- arg3 ??= "";
- fixed (char* string1Bytes = arg1)
- fixed (char* string2Bytes = arg2)
- fixed (char* string3Bytes = arg3)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
- descrs[0].DataPointer = (IntPtr)string1Bytes;
- descrs[0].Size = ((arg1.Length + 1) * 2);
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)string2Bytes;
- descrs[1].Size = ((arg2.Length + 1) * 2);
- descrs[1].Reserved = 0;
- descrs[2].DataPointer = (IntPtr)string3Bytes;
- descrs[2].Size = ((arg3.Length + 1) * 2);
- descrs[2].Reserved = 0;
- WriteEventCore(eventId, 3, descrs);
- }
- }
- }
-
- // optimized for common signatures (string and ints)
- protected unsafe void WriteEvent(int eventId, string? arg1, int arg2)
- {
- if (m_eventSourceEnabled)
- {
- arg1 ??= "";
- fixed (char* string1Bytes = arg1)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- descrs[0].DataPointer = (IntPtr)string1Bytes;
- descrs[0].Size = ((arg1.Length + 1) * 2);
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 4;
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- }
- }
-
- protected unsafe void WriteEvent(int eventId, string? arg1, int arg2, int arg3)
- {
- if (m_eventSourceEnabled)
- {
- arg1 ??= "";
- fixed (char* string1Bytes = arg1)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
- descrs[0].DataPointer = (IntPtr)string1Bytes;
- descrs[0].Size = ((arg1.Length + 1) * 2);
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 4;
- descrs[1].Reserved = 0;
- descrs[2].DataPointer = (IntPtr)(&arg3);
- descrs[2].Size = 4;
- descrs[2].Reserved = 0;
- WriteEventCore(eventId, 3, descrs);
- }
- }
- }
-
- // optimized for common signatures (string and longs)
- protected unsafe void WriteEvent(int eventId, string? arg1, long arg2)
- {
- if (m_eventSourceEnabled)
- {
- arg1 ??= "";
- fixed (char* string1Bytes = arg1)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- descrs[0].DataPointer = (IntPtr)string1Bytes;
- descrs[0].Size = ((arg1.Length + 1) * 2);
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 8;
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- }
- }
-
- // optimized for common signatures (long and string)
- protected unsafe void WriteEvent(int eventId, long arg1, string? arg2)
- {
- if (m_eventSourceEnabled)
- {
- arg2 ??= "";
- fixed (char* string2Bytes = arg2)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 8;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)string2Bytes;
- descrs[1].Size = ((arg2.Length + 1) * 2);
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- }
- }
-
- // optimized for common signatures (int and string)
- protected unsafe void WriteEvent(int eventId, int arg1, string? arg2)
- {
- if (m_eventSourceEnabled)
- {
- arg2 ??= "";
- fixed (char* string2Bytes = arg2)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 4;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)string2Bytes;
- descrs[1].Size = ((arg2.Length + 1) * 2);
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- }
- }
-
- protected unsafe void WriteEvent(int eventId, byte[]? arg1)
- {
- if (m_eventSourceEnabled)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- if (arg1 == null || arg1.Length == 0)
- {
- int blobSize = 0;
- descrs[0].DataPointer = (IntPtr)(&blobSize);
- descrs[0].Size = 4;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&blobSize); // valid address instead of empty content
- descrs[1].Size = 0;
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- else
- {
- int blobSize = arg1.Length;
- fixed (byte* blob = &arg1[0])
- {
- descrs[0].DataPointer = (IntPtr)(&blobSize);
- descrs[0].Size = 4;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)blob;
- descrs[1].Size = blobSize;
- descrs[1].Reserved = 0;
- WriteEventCore(eventId, 2, descrs);
- }
- }
- }
- }
-
- protected unsafe void WriteEvent(int eventId, long arg1, byte[]? arg2)
- {
- if (m_eventSourceEnabled)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 8;
- descrs[0].Reserved = 0;
- if (arg2 == null || arg2.Length == 0)
- {
- int blobSize = 0;
- descrs[1].DataPointer = (IntPtr)(&blobSize);
- descrs[1].Size = 4;
- descrs[1].Reserved = 0;
- descrs[2].DataPointer = (IntPtr)(&blobSize); // valid address instead of empty contents
- descrs[2].Size = 0;
- descrs[2].Reserved = 0;
- WriteEventCore(eventId, 3, descrs);
- }
- else
- {
- int blobSize = arg2.Length;
- fixed (byte* blob = &arg2[0])
- {
- descrs[1].DataPointer = (IntPtr)(&blobSize);
- descrs[1].Size = 4;
- descrs[1].Reserved = 0;
- descrs[2].DataPointer = (IntPtr)blob;
- descrs[2].Size = blobSize;
- descrs[2].Reserved = 0;
- WriteEventCore(eventId, 3, descrs);
- }
- }
- }
- }
-
-#pragma warning restore 1591
-
- /// <summary>
- /// Used to construct the data structure to be passed to the native ETW APIs - EventWrite and EventWriteTransfer.
- /// </summary>
- protected internal struct EventData
- {
- /// <summary>
- /// Address where the one argument lives (if this points to managed memory you must ensure the
- /// managed object is pinned.
- /// </summary>
- public unsafe IntPtr DataPointer
- {
- get => (IntPtr)(void*)m_Ptr;
- set => m_Ptr = unchecked((ulong)(void*)value);
- }
-
- /// <summary>
- /// Size of the argument referenced by DataPointer
- /// </summary>
- public int Size
- {
- get => m_Size;
- set => m_Size = value;
- }
-
- /// <summary>
- /// Reserved by ETW. This property is present to ensure that we can zero it
- /// since System.Private.CoreLib uses are not zero'd.
- /// </summary>
- internal int Reserved
- {
- get => m_Reserved;
- set => m_Reserved = value;
- }
-
-#region private
- /// <summary>
- /// Initializes the members of this EventData object to point at a previously-pinned
- /// tracelogging-compatible metadata blob.
- /// </summary>
- /// <param name="pointer">Pinned tracelogging-compatible metadata blob.</param>
- /// <param name="size">The size of the metadata blob.</param>
- /// <param name="reserved">Value for reserved: 2 for per-provider metadata, 1 for per-event metadata</param>
- internal unsafe void SetMetadata(byte* pointer, int size, int reserved)
- {
- this.m_Ptr = (ulong)pointer;
- this.m_Size = size;
- this.m_Reserved = reserved; // Mark this descriptor as containing tracelogging-compatible metadata.
- }
-
- // Important, we pass this structure directly to the Win32 EventWrite API, so this structure must
- // be layed out exactly the way EventWrite wants it.
- internal ulong m_Ptr;
- internal int m_Size;
-#pragma warning disable 0649
- internal int m_Reserved; // Used to pad the size to match the Win32 API
-#pragma warning restore 0649
-#endregion
- }
-
- /// <summary>
- /// This routine allows you to create efficient WriteEvent helpers, however the code that you use to
- /// do this, while straightforward, is unsafe.
- /// </summary>
- /// <remarks>
- /// <code>
- /// protected unsafe void WriteEvent(int eventId, string arg1, long arg2)
- /// {
- /// if (IsEnabled())
- /// {
- /// arg2 ??= "";
- /// fixed (char* string2Bytes = arg2)
- /// {
- /// EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- /// descrs[0].DataPointer = (IntPtr)(&amp;arg1);
- /// descrs[0].Size = 8;
- /// descrs[0].Reserved = 0;
- /// descrs[1].DataPointer = (IntPtr)string2Bytes;
- /// descrs[1].Size = ((arg2.Length + 1) * 2);
- /// descrs[1].Reserved = 0;
- /// WriteEventCore(eventId, 2, descrs);
- /// }
- /// }
- /// }
- /// </code>
- /// </remarks>
- [CLSCompliant(false)]
- protected unsafe void WriteEventCore(int eventId, int eventDataCount, EventSource.EventData* data)
- {
- WriteEventWithRelatedActivityIdCore(eventId, null, eventDataCount, data);
- }
-
- /// <summary>
- /// This routine allows you to create efficient WriteEventWithRelatedActivityId helpers, however the code
- /// that you use to do this, while straightforward, is unsafe. The only difference from
- /// <see cref="WriteEventCore"/> is that you pass the relatedActivityId from caller through to this API
- /// </summary>
- /// <remarks>
- /// <code>
- /// protected unsafe void WriteEventWithRelatedActivityId(int eventId, Guid relatedActivityId, string arg1, long arg2)
- /// {
- /// if (IsEnabled())
- /// {
- /// arg2 ??= "";
- /// fixed (char* string2Bytes = arg2)
- /// {
- /// EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
- /// descrs[0].DataPointer = (IntPtr)(&amp;arg1);
- /// descrs[0].Size = 8;
- /// descrs[1].DataPointer = (IntPtr)string2Bytes;
- /// descrs[1].Size = ((arg2.Length + 1) * 2);
- /// WriteEventWithRelatedActivityIdCore(eventId, relatedActivityId, 2, descrs);
- /// }
- /// }
- /// }
- /// </code>
- /// </remarks>
- [CLSCompliant(false)]
- protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* relatedActivityId, int eventDataCount, EventSource.EventData* data)
- {
- if (m_eventSourceEnabled)
- {
- Debug.Assert(m_eventData != null); // You must have initialized this if you enabled the source.
- try
- {
- if (relatedActivityId != null)
- ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name);
-
- EventOpcode opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode;
- EventActivityOptions activityOptions = m_eventData[eventId].ActivityOptions;
- Guid* pActivityId = null;
- Guid activityId = Guid.Empty;
- Guid relActivityId = Guid.Empty;
-
- if (opcode != EventOpcode.Info && relatedActivityId == null &&
- ((activityOptions & EventActivityOptions.Disable) == 0))
- {
- if (opcode == EventOpcode.Start)
- {
- m_activityTracker.OnStart(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId, ref relActivityId, m_eventData[eventId].ActivityOptions);
- }
- else if (opcode == EventOpcode.Stop)
- {
- m_activityTracker.OnStop(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId);
- }
-
- if (activityId != Guid.Empty)
- pActivityId = &activityId;
- if (relActivityId != Guid.Empty)
- relatedActivityId = &relActivityId;
- }
-
-#if FEATURE_MANAGED_ETW
- if (m_eventData[eventId].EnabledForETW
-#if FEATURE_PERFTRACING
- || m_eventData[eventId].EnabledForEventPipe
-#endif // FEATURE_PERFTRACING
- )
- {
- if (!SelfDescribingEvents)
- {
- if (!m_etwProvider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
- ThrowEventSourceException(m_eventData[eventId].Name);
-#if FEATURE_PERFTRACING
- if (!m_eventPipeProvider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
- ThrowEventSourceException(m_eventData[eventId].Name);
-#endif // FEATURE_PERFTRACING
- }
- else
- {
- TraceLoggingEventTypes? tlet = m_eventData[eventId].TraceLoggingEventTypes;
- if (tlet == null)
- {
- tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
- m_eventData[eventId].Tags,
- m_eventData[eventId].Parameters);
- Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
- }
- EventSourceOptions opt = new EventSourceOptions
- {
- Keywords = (EventKeywords)m_eventData[eventId].Descriptor.Keywords,
- Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
- Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
- };
-
- WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, relatedActivityId, data);
- }
- }
-#endif // FEATURE_MANAGED_ETW
-
- if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
- WriteToAllListeners(eventId, pActivityId, relatedActivityId, eventDataCount, data);
- }
- catch (Exception ex)
- {
- if (ex is EventSourceException)
- throw;
- else
- ThrowEventSourceException(m_eventData[eventId].Name, ex);
- }
- }
- }
-
- // fallback varags helpers.
- /// <summary>
- /// This is the varargs helper for writing an event. It does create an array and box all the arguments so it is
- /// relatively inefficient and should only be used for relatively rare events (e.g. less than 100 / sec). If your
- /// rates are faster than that you should use <see cref="WriteEventCore"/> to create fast helpers for your particular
- /// method signature. Even if you use this for rare events, this call should be guarded by an <see cref="IsEnabled()"/>
- /// check so that the varargs call is not made when the EventSource is not active.
- /// </summary>
- protected unsafe void WriteEvent(int eventId, params object?[] args)
- {
- WriteEventVarargs(eventId, null, args);
- }
-
- /// <summary>
- /// This is the varargs helper for writing an event which also specifies a related activity. It is completely analogous
- /// to corresponding WriteEvent (they share implementation). It does create an array and box all the arguments so it is
- /// relatively inefficient and should only be used for relatively rare events (e.g. less than 100 / sec). If your
- /// rates are faster than that you should use <see cref="WriteEventWithRelatedActivityIdCore"/> to create fast helpers for your
- /// particular method signature. Even if you use this for rare events, this call should be guarded by an <see cref="IsEnabled()"/>
- /// check so that the varargs call is not made when the EventSource is not active.
- /// </summary>
- protected unsafe void WriteEventWithRelatedActivityId(int eventId, Guid relatedActivityId, params object?[] args)
- {
- WriteEventVarargs(eventId, &relatedActivityId, args);
- }
-
-#endregion
-
-#region IDisposable Members
- /// <summary>
- /// Disposes of an EventSource.
- /// </summary>
- public void Dispose()
- {
- this.Dispose(true);
- GC.SuppressFinalize(this);
- }
- /// <summary>
- /// Disposes of an EventSource.
- /// </summary>
- /// <remarks>
- /// Called from Dispose() with disposing=true, and from the finalizer (~EventSource) with disposing=false.
- /// Guidelines:
- /// 1. We may be called more than once: do nothing after the first call.
- /// 2. Avoid throwing exceptions if disposing is false, i.e. if we're being finalized.
- /// </remarks>
- /// <param name="disposing">True if called from Dispose(), false if called from the finalizer.</param>
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
-#if FEATURE_MANAGED_ETW
- // Send the manifest one more time to ensure circular buffers have a chance to get to this information
- // even in scenarios with a high volume of ETW events.
- if (m_eventSourceEnabled)
- {
- try
- {
- SendManifest(m_rawManifest);
- }
- catch { } // If it fails, simply give up.
- m_eventSourceEnabled = false;
- }
- if (m_etwProvider != null)
- {
- m_etwProvider.Dispose();
- m_etwProvider = null!; // TODO-NULLABLE: Avoid nulling out in Dispose
- }
-#endif
-#if FEATURE_PERFTRACING
- if (m_eventPipeProvider != null)
- {
- m_eventPipeProvider.Dispose();
- m_eventPipeProvider = null!; // TODO-NULLABLE: Avoid nulling out in Dispose
- }
-#endif
- }
- m_eventSourceEnabled = false;
- m_eventSourceDisposed = true;
- }
- /// <summary>
- /// Finalizer for EventSource
- /// </summary>
- ~EventSource()
- {
- this.Dispose(false);
- }
-#endregion
-
-#region private
-
- private unsafe void WriteEventRaw(
- string? eventName,
- ref EventDescriptor eventDescriptor,
- IntPtr eventHandle,
- Guid* activityID,
- Guid* relatedActivityID,
- int dataCount,
- IntPtr data)
- {
-#if FEATURE_MANAGED_ETW
- if (m_etwProvider == null)
- {
- ThrowEventSourceException(eventName);
- }
- else
- {
- if (!m_etwProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data))
- ThrowEventSourceException(eventName);
- }
-#endif // FEATURE_MANAGED_ETW
-#if FEATURE_PERFTRACING
- if (m_eventPipeProvider == null)
- {
- ThrowEventSourceException(eventName);
- }
- else
- {
- if (!m_eventPipeProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data))
- ThrowEventSourceException(eventName);
- }
-#endif // FEATURE_PERFTRACING
- }
-
- // FrameworkEventSource is on the startup path for the framework, so we have this internal overload that it can use
- // to prevent the working set hit from looking at the custom attributes on the type to get the Guid.
- internal EventSource(Guid eventSourceGuid, string eventSourceName)
- : this(eventSourceGuid, eventSourceName, EventSourceSettings.EtwManifestEventFormat)
- { }
-
- // Used by the internal FrameworkEventSource constructor and the TraceLogging-style event source constructor
- internal EventSource(Guid eventSourceGuid, string eventSourceName, EventSourceSettings settings, string[]? traits = null)
- {
- m_config = ValidateSettings(settings);
- Initialize(eventSourceGuid, eventSourceName, traits);
- }
-
- /// <summary>
- /// This method is responsible for the common initialization path from our constructors. It must
- /// not leak any exceptions (otherwise, since most EventSource classes define a static member,
- /// "Log", such an exception would become a cached exception for the initialization of the static
- /// member, and any future access to the "Log" would throw the cached exception).
- /// </summary>
- private unsafe void Initialize(Guid eventSourceGuid, string eventSourceName, string[]? traits)
- {
- try
- {
- m_traits = traits;
- if (m_traits != null && m_traits.Length % 2 != 0)
- {
- throw new ArgumentException(SR.EventSource_TraitEven, nameof(traits));
- }
-
- if (eventSourceGuid == Guid.Empty)
- {
- throw new ArgumentException(SR.EventSource_NeedGuid);
- }
-
- if (eventSourceName == null)
- {
- throw new ArgumentException(SR.EventSource_NeedName);
- }
-
- m_name = eventSourceName;
- m_guid = eventSourceGuid;
-
- // Enable Implicit Activity tracker
- m_activityTracker = ActivityTracker.Instance;
-
-#if FEATURE_MANAGED_ETW || FEATURE_PERFTRACING
- // Create and register our provider traits. We do this early because it is needed to log errors
- // In the self-describing event case.
- this.InitializeProviderMetadata();
-#endif
-#if FEATURE_MANAGED_ETW
- // Register the provider with ETW
- var etwProvider = new OverideEventProvider(this, EventProviderType.ETW);
- etwProvider.Register(this);
-#endif
-#if FEATURE_PERFTRACING
- // Register the provider with EventPipe
- var eventPipeProvider = new OverideEventProvider(this, EventProviderType.EventPipe);
- lock (EventListener.EventListenersLock)
- {
- eventPipeProvider.Register(this);
- }
-#endif
- // Add the eventSource to the global (weak) list.
- // This also sets m_id, which is the index in the list.
- EventListener.AddEventSource(this);
-
-#if FEATURE_MANAGED_ETW
- // OK if we get this far without an exception, then we can at least write out error messages.
- // Set m_provider, which allows this.
- m_etwProvider = etwProvider;
-
-#if PLATFORM_WINDOWS
-#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
- // API available on OS >= Win 8 and patched Win 7.
- // Disable only for FrameworkEventSource to avoid recursion inside exception handling.
- if (this.Name != "System.Diagnostics.Eventing.FrameworkEventSource" || Environment.IsWindows8OrAbove)
-#endif
- {
- int setInformationResult;
- System.Runtime.InteropServices.GCHandle metadataHandle =
- System.Runtime.InteropServices.GCHandle.Alloc(this.providerMetadata, System.Runtime.InteropServices.GCHandleType.Pinned);
- IntPtr providerMetadata = metadataHandle.AddrOfPinnedObject();
-
- setInformationResult = m_etwProvider.SetInformation(
- Interop.Advapi32.EVENT_INFO_CLASS.SetTraits,
- providerMetadata,
- (uint)this.providerMetadata.Length);
-
- metadataHandle.Free();
- }
-#endif // PLATFORM_WINDOWS
-#endif // FEATURE_MANAGED_ETW
-
-#if FEATURE_PERFTRACING
- m_eventPipeProvider = eventPipeProvider;
-#endif
- Debug.Assert(!m_eventSourceEnabled); // We can't be enabled until we are completely initted.
- // We are logically completely initialized at this point.
- m_completelyInited = true;
- }
- catch (Exception e)
- {
- m_constructionException ??= e;
- ReportOutOfBandMessage("ERROR: Exception during construction of EventSource " + Name + ": " + e.Message);
- }
-
- // Once m_completelyInited is set, you can have concurrency, so all work is under the lock.
- lock (EventListener.EventListenersLock)
- {
- // If there are any deferred commands, we can do them now.
- // This is the most likely place for exceptions to happen.
- // Note that we are NOT resetting m_deferredCommands to NULL here,
- // We are giving for EventHandler<EventCommandEventArgs> that will be attached later
- EventCommandEventArgs? deferredCommands = m_deferredCommands;
- while (deferredCommands != null)
- {
- DoCommand(deferredCommands); // This can never throw, it catches them and reports the errors.
- deferredCommands = deferredCommands.nextCommand;
- }
- }
- }
-
- private static string GetName(Type eventSourceType, EventManifestOptions flags)
- {
- if (eventSourceType == null)
- throw new ArgumentNullException(nameof(eventSourceType));
-
- EventSourceAttribute? attrib = (EventSourceAttribute?)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute), flags);
- if (attrib != null && attrib.Name != null)
- return attrib.Name;
-
- return eventSourceType.Name;
- }
-
- /// <summary>
- /// Implements the SHA1 hashing algorithm. Note that this
- /// implementation is for hashing public information. Do not
- /// use this code to hash private data, as this implementation does
- /// not take any steps to avoid information disclosure.
- /// </summary>
- private struct Sha1ForNonSecretPurposes
- {
- private long length; // Total message length in bits
- private uint[] w; // Workspace
- private int pos; // Length of current chunk in bytes
-
- /// <summary>
- /// Call Start() to initialize the hash object.
- /// </summary>
- public void Start()
- {
- this.w ??= new uint[85];
-
- this.length = 0;
- this.pos = 0;
- this.w[80] = 0x67452301;
- this.w[81] = 0xEFCDAB89;
- this.w[82] = 0x98BADCFE;
- this.w[83] = 0x10325476;
- this.w[84] = 0xC3D2E1F0;
- }
-
- /// <summary>
- /// Adds an input byte to the hash.
- /// </summary>
- /// <param name="input">Data to include in the hash.</param>
- public void Append(byte input)
- {
- this.w[this.pos / 4] = (this.w[this.pos / 4] << 8) | input;
- if (64 == ++this.pos)
- {
- this.Drain();
- }
- }
-
- /// <summary>
- /// Adds input bytes to the hash.
- /// </summary>
- /// <param name="input">
- /// Data to include in the hash. Must not be null.
- /// </param>
- public void Append(byte[] input)
- {
- foreach (byte b in input)
- {
- this.Append(b);
- }
- }
-
- /// <summary>
- /// Retrieves the hash value.
- /// Note that after calling this function, the hash object should
- /// be considered uninitialized. Subsequent calls to Append or
- /// Finish will produce useless results. Call Start() to
- /// reinitialize.
- /// </summary>
- /// <param name="output">
- /// Buffer to receive the hash value. Must not be null.
- /// Up to 20 bytes of hash will be written to the output buffer.
- /// If the buffer is smaller than 20 bytes, the remaining hash
- /// bytes will be lost. If the buffer is larger than 20 bytes, the
- /// rest of the buffer is left unmodified.
- /// </param>
- public void Finish(byte[] output)
- {
- long l = this.length + 8 * this.pos;
- this.Append(0x80);
- while (this.pos != 56)
- {
- this.Append(0x00);
- }
-
- unchecked
- {
- this.Append((byte)(l >> 56));
- this.Append((byte)(l >> 48));
- this.Append((byte)(l >> 40));
- this.Append((byte)(l >> 32));
- this.Append((byte)(l >> 24));
- this.Append((byte)(l >> 16));
- this.Append((byte)(l >> 8));
- this.Append((byte)l);
-
- int end = output.Length < 20 ? output.Length : 20;
- for (int i = 0; i != end; i++)
- {
- uint temp = this.w[80 + i / 4];
- output[i] = (byte)(temp >> 24);
- this.w[80 + i / 4] = temp << 8;
- }
- }
- }
-
- /// <summary>
- /// Called when this.pos reaches 64.
- /// </summary>
- private void Drain()
- {
- for (int i = 16; i != 80; i++)
- {
- this.w[i] = BitOperations.RotateLeft(this.w[i - 3] ^ this.w[i - 8] ^ this.w[i - 14] ^ this.w[i - 16], 1);
- }
-
- unchecked
- {
- uint a = this.w[80];
- uint b = this.w[81];
- uint c = this.w[82];
- uint d = this.w[83];
- uint e = this.w[84];
-
- for (int i = 0; i != 20; i++)
- {
- const uint k = 0x5A827999;
- uint f = (b & c) | ((~b) & d);
- uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp;
- }
-
- for (int i = 20; i != 40; i++)
- {
- uint f = b ^ c ^ d;
- const uint k = 0x6ED9EBA1;
- uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp;
- }
-
- for (int i = 40; i != 60; i++)
- {
- uint f = (b & c) | (b & d) | (c & d);
- const uint k = 0x8F1BBCDC;
- uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp;
- }
-
- for (int i = 60; i != 80; i++)
- {
- uint f = b ^ c ^ d;
- const uint k = 0xCA62C1D6;
- uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp;
- }
-
- this.w[80] += a;
- this.w[81] += b;
- this.w[82] += c;
- this.w[83] += d;
- this.w[84] += e;
- }
-
- this.length += 512; // 64 bytes == 512 bits
- this.pos = 0;
- }
- }
-
- private static Guid GenerateGuidFromName(string name)
- {
- if (namespaceBytes == null)
- {
- namespaceBytes = new byte[] {
- 0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8,
- 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB,
- };
- }
-
- byte[] bytes = Encoding.BigEndianUnicode.GetBytes(name);
- Sha1ForNonSecretPurposes hash = default;
- hash.Start();
- hash.Append(namespaceBytes);
- hash.Append(bytes);
- Array.Resize(ref bytes, 16);
- hash.Finish(bytes);
-
- bytes[7] = unchecked((byte)((bytes[7] & 0x0F) | 0x50)); // Set high 4 bits of octet 7 to 5, as per RFC 4122
- return new Guid(bytes);
- }
-
- private unsafe object? DecodeObject(int eventId, int parameterId, ref EventSource.EventData* data)
- {
- // TODO FIX : We use reflection which in turn uses EventSource, right now we carefully avoid
- // the recursion, but can we do this in a robust way?
-
- IntPtr dataPointer = data->DataPointer;
- // advance to next EventData in array
- ++data;
-
- Debug.Assert(m_eventData != null);
- Type dataType = GetDataType(m_eventData[eventId], parameterId);
-
- Again:
- if (dataType == typeof(IntPtr))
- {
- return *((IntPtr*)dataPointer);
- }
- else if (dataType == typeof(int))
- {
- return *((int*)dataPointer);
- }
- else if (dataType == typeof(uint))
- {
- return *((uint*)dataPointer);
- }
- else if (dataType == typeof(long))
- {
- return *((long*)dataPointer);
- }
- else if (dataType == typeof(ulong))
- {
- return *((ulong*)dataPointer);
- }
- else if (dataType == typeof(byte))
- {
- return *((byte*)dataPointer);
- }
- else if (dataType == typeof(sbyte))
- {
- return *((sbyte*)dataPointer);
- }
- else if (dataType == typeof(short))
- {
- return *((short*)dataPointer);
- }
- else if (dataType == typeof(ushort))
- {
- return *((ushort*)dataPointer);
- }
- else if (dataType == typeof(float))
- {
- return *((float*)dataPointer);
- }
- else if (dataType == typeof(double))
- {
- return *((double*)dataPointer);
- }
- else if (dataType == typeof(decimal))
- {
- return *((decimal*)dataPointer);
- }
- else if (dataType == typeof(bool))
- {
- // The manifest defines a bool as a 32bit type (WIN32 BOOL), not 1 bit as CLR Does.
- return *((int*)dataPointer) == 1;
- }
- else if (dataType == typeof(Guid))
- {
- return *((Guid*)dataPointer);
- }
- else if (dataType == typeof(char))
- {
- return *((char*)dataPointer);
- }
- else if (dataType == typeof(DateTime))
- {
- long dateTimeTicks = *((long*)dataPointer);
- return DateTime.FromFileTimeUtc(dateTimeTicks);
- }
- else if (dataType == typeof(byte[]))
- {
- // byte[] are written to EventData* as an int followed by a blob
- int cbSize = *((int*)dataPointer);
- byte[] blob = new byte[cbSize];
- dataPointer = data->DataPointer;
- data++;
- for (int i = 0; i < cbSize; ++i)
- blob[i] = *((byte*)(dataPointer + i));
- return blob;
- }
- else if (dataType == typeof(byte*))
- {
- // TODO: how do we want to handle this? For now we ignore it...
- return null;
- }
- else
- {
- if (m_EventSourcePreventRecursion && m_EventSourceInDecodeObject)
- {
- return null;
- }
-
- try
- {
- m_EventSourceInDecodeObject = true;
-
- if (dataType.IsEnum())
- {
- dataType = Enum.GetUnderlyingType(dataType);
-#if ES_BUILD_PN
- int dataTypeSize = (int)dataType.TypeHandle.ToEETypePtr().ValueTypeSize;
-#else
- int dataTypeSize = System.Runtime.InteropServices.Marshal.SizeOf(dataType);
-#endif
- if (dataTypeSize < sizeof(int))
- dataType = typeof(int);
- goto Again;
- }
-
- // Everything else is marshaled as a string.
- // ETW strings are NULL-terminated, so marshal everything up to the first
- // null in the string.
- if (dataPointer == IntPtr.Zero)
- {
- return null;
- }
-
- return new string((char*)dataPointer);
- }
- finally
- {
- m_EventSourceInDecodeObject = false;
- }
- }
- }
-
- // Finds the Dispatcher (which holds the filtering state), for a given dispatcher for the current
- // eventSource).
- private EventDispatcher? GetDispatcher(EventListener? listener)
- {
- EventDispatcher? dispatcher = m_Dispatchers;
- while (dispatcher != null)
- {
- if (dispatcher.m_Listener == listener)
- return dispatcher;
- dispatcher = dispatcher.m_Next;
- }
- return dispatcher;
- }
-
- private unsafe void WriteEventVarargs(int eventId, Guid* childActivityID, object?[] args)
- {
- if (m_eventSourceEnabled)
- {
- Debug.Assert(m_eventData != null); // You must have initialized this if you enabled the source.
- try
- {
- if (childActivityID != null)
- {
- ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name);
-
- // If you use WriteEventWithRelatedActivityID you MUST declare the first argument to be a GUID
- // with the name 'relatedActivityID, and NOT pass this argument to the WriteEvent method.
- // During manifest creation we modify the ParameterInfo[] that we store to strip out any
- // first parameter that is of type Guid and named "relatedActivityId." Thus, if you call
- // WriteEventWithRelatedActivityID from a method that doesn't name its first parameter correctly
- // we can end up in a state where the ParameterInfo[] doesn't have its first parameter stripped,
- // and this leads to a mismatch between the number of arguments and the number of ParameterInfos,
- // which would cause a cryptic IndexOutOfRangeException later if we don't catch it here.
- if (!m_eventData[eventId].HasRelatedActivityID)
- {
- throw new ArgumentException(SR.EventSource_NoRelatedActivityId);
- }
- }
-
- LogEventArgsMismatches(eventId, args);
-
- Guid* pActivityId = null;
- Guid activityId = Guid.Empty;
- Guid relatedActivityId = Guid.Empty;
- EventOpcode opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode;
- EventActivityOptions activityOptions = m_eventData[eventId].ActivityOptions;
-
- if (childActivityID == null &&
- ((activityOptions & EventActivityOptions.Disable) == 0))
- {
- if (opcode == EventOpcode.Start)
- {
- m_activityTracker.OnStart(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId, ref relatedActivityId, m_eventData[eventId].ActivityOptions);
- }
- else if (opcode == EventOpcode.Stop)
- {
- m_activityTracker.OnStop(m_name, m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Task, ref activityId);
- }
-
- if (activityId != Guid.Empty)
- pActivityId = &activityId;
- if (relatedActivityId != Guid.Empty)
- childActivityID = &relatedActivityId;
- }
-
-#if FEATURE_MANAGED_ETW
- if (m_eventData[eventId].EnabledForETW
-#if FEATURE_PERFTRACING
- || m_eventData[eventId].EnabledForEventPipe
-#endif // FEATURE_PERFTRACING
- )
- {
- if (!SelfDescribingEvents)
- {
- if (!m_etwProvider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
- ThrowEventSourceException(m_eventData[eventId].Name);
-#if FEATURE_PERFTRACING
- if (!m_eventPipeProvider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
- ThrowEventSourceException(m_eventData[eventId].Name);
-#endif // FEATURE_PERFTRACING
- }
- else
- {
- TraceLoggingEventTypes? tlet = m_eventData[eventId].TraceLoggingEventTypes;
- if (tlet == null)
- {
- tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
- EventTags.None,
- m_eventData[eventId].Parameters);
- Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
- }
- // TODO: activity ID support
- EventSourceOptions opt = new EventSourceOptions
- {
- Keywords = (EventKeywords)m_eventData[eventId].Descriptor.Keywords,
- Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
- Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
- };
-
- WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, childActivityID, args);
- }
- }
-#endif // FEATURE_MANAGED_ETW
- if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
- {
-#if !ES_BUILD_STANDALONE
- // Maintain old behavior - object identity is preserved
- if (LocalAppContextSwitches.PreserveEventListnerObjectIdentity)
- {
- WriteToAllListeners(
- eventId: eventId,
- osThreadId: null,
- timeStamp: null,
- activityID: pActivityId,
- childActivityID: childActivityID,
- args: args);
- }
- else
-#endif // !ES_BUILD_STANDALONE
- {
- object?[] serializedArgs = SerializeEventArgs(eventId, args);
- WriteToAllListeners(
- eventId: eventId,
- osThreadId: null,
- timeStamp: null,
- activityID: pActivityId,
- childActivityID: childActivityID,
- args: serializedArgs);
- }
- }
- }
- catch (Exception ex)
- {
- if (ex is EventSourceException)
- throw;
- else
- ThrowEventSourceException(m_eventData[eventId].Name, ex);
- }
- }
- }
-
- private unsafe object?[] SerializeEventArgs(int eventId, object?[] args)
- {
- Debug.Assert(m_eventData != null);
- TraceLoggingEventTypes? eventTypes = m_eventData[eventId].TraceLoggingEventTypes;
- if (eventTypes == null)
- {
- eventTypes = new TraceLoggingEventTypes(m_eventData[eventId].Name,
- EventTags.None,
- m_eventData[eventId].Parameters);
- Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, eventTypes, null);
- }
- int paramCount = Math.Min(eventTypes.typeInfos.Length, args.Length); // parameter count mismatch get logged in LogEventArgsMismatches
- var eventData = new object?[eventTypes.typeInfos.Length];
- for (int i = 0; i < paramCount; i++)
- {
- eventData[i] = eventTypes.typeInfos[i].GetData(args[i]);
- }
- return eventData;
- }
-
- /// <summary>
- /// We expect that the arguments to the Event method and the arguments to WriteEvent match. This function
- /// checks that they in fact match and logs a warning to the debugger if they don't.
- /// </summary>
- /// <param name="eventId"></param>
- /// <param name="args"></param>
- private void LogEventArgsMismatches(int eventId, object?[] args)
- {
- Debug.Assert(m_eventData != null);
- ParameterInfo[] infos = m_eventData[eventId].Parameters;
-
- if (args.Length != infos.Length)
- {
- ReportOutOfBandMessage(SR.Format(SR.EventSource_EventParametersMismatch, eventId, args.Length, infos.Length));
- return;
- }
-
- int i = 0;
- while (i < args.Length)
- {
- Type pType = infos[i].ParameterType;
- object? arg = args[i];
-
- // Checking to see if the Parameter types (from the Event method) match the supplied argument types.
- // Fail if one of two things hold : either the argument type is not equal or assignable to the parameter type, or the
- // argument is null and the parameter type is a non-Nullable<T> value type.
- if ((arg != null && !pType.IsAssignableFrom(arg.GetType()))
- || (arg == null && (pType.IsValueType && !(pType.IsGenericType && pType.GetGenericTypeDefinition() == typeof(Nullable<>))))
- )
- {
- ReportOutOfBandMessage(SR.Format(SR.EventSource_VarArgsParameterMismatch, eventId, infos[i].Name));
- return;
- }
-
- ++i;
- }
- }
-
- private unsafe void WriteToAllListeners(int eventId, Guid* activityID, Guid* childActivityID, int eventDataCount, EventSource.EventData* data)
- {
- Debug.Assert(m_eventData != null);
- // We represent a byte[] as a integer denoting the length and then a blob of bytes in the data pointer. This causes a spurious
- // warning because eventDataCount is off by one for the byte[] case since a byte[] has 2 items associated it. So we want to check
- // that the number of parameters is correct against the byte[] case, but also we the args array would be one too long if
- // we just used the modifiedParamCount here -- so we need both.
- int paramCount = GetParameterCount(m_eventData[eventId]);
- int modifiedParamCount = 0;
- for (int i = 0; i < paramCount; i++)
- {
- Type parameterType = GetDataType(m_eventData[eventId], i);
- if (parameterType == typeof(byte[]))
- {
- modifiedParamCount += 2;
- }
- else
- {
- modifiedParamCount++;
- }
- }
- if (eventDataCount != modifiedParamCount)
- {
- ReportOutOfBandMessage(SR.Format(SR.EventSource_EventParametersMismatch, eventId, eventDataCount, paramCount));
- paramCount = Math.Min(paramCount, eventDataCount);
- }
-
- object?[] args = new object[paramCount];
-
- EventSource.EventData* dataPtr = data;
- for (int i = 0; i < paramCount; i++)
- args[i] = DecodeObject(eventId, i, ref dataPtr);
- WriteToAllListeners(
- eventId: eventId,
- osThreadId: null,
- timeStamp: null,
- activityID: activityID,
- childActivityID: childActivityID,
- args: args);
- }
-
- // helper for writing to all EventListeners attached the current eventSource.
- internal unsafe void WriteToAllListeners(int eventId, uint* osThreadId, DateTime* timeStamp, Guid* activityID, Guid* childActivityID, params object?[] args)
- {
- EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
- eventCallbackArgs.EventId = eventId;
- if (osThreadId != null)
- eventCallbackArgs.OSThreadId = (int)*osThreadId;
- if (timeStamp != null)
- eventCallbackArgs.TimeStamp = *timeStamp;
- if (activityID != null)
- eventCallbackArgs.ActivityId = *activityID;
- if (childActivityID != null)
- eventCallbackArgs.RelatedActivityId = *childActivityID;
-
- Debug.Assert(m_eventData != null);
- eventCallbackArgs.EventName = m_eventData[eventId].Name;
- eventCallbackArgs.Message = m_eventData[eventId].Message;
- eventCallbackArgs.Payload = new ReadOnlyCollection<object?>(args);
-
- DispatchToAllListeners(eventId, eventCallbackArgs);
- }
-
- private unsafe void DispatchToAllListeners(int eventId, EventWrittenEventArgs eventCallbackArgs)
- {
- Exception? lastThrownException = null;
- for (EventDispatcher? dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
- {
- Debug.Assert(dispatcher.m_EventEnabled != null);
- if (eventId == -1 || dispatcher.m_EventEnabled[eventId])
- {
- {
- try
- {
- dispatcher.m_Listener.OnEventWritten(eventCallbackArgs);
- }
- catch (Exception e)
- {
- ReportOutOfBandMessage("ERROR: Exception during EventSource.OnEventWritten: "
- + e.Message);
- lastThrownException = e;
- }
- }
- }
- }
-
- if (lastThrownException != null)
- {
- throw new EventSourceException(lastThrownException);
- }
- }
-
- private unsafe void WriteEventString(EventLevel level, long keywords, string msgString)
- {
-#if FEATURE_MANAGED_ETW
- if (m_etwProvider != null)
- {
- const string EventName = "EventSourceMessage";
- if (SelfDescribingEvents)
- {
- EventSourceOptions opt = new EventSourceOptions
- {
- Keywords = (EventKeywords)unchecked(keywords),
- Level = level
- };
- var msg = new { message = msgString };
- var tlet = new TraceLoggingEventTypes(EventName, EventTags.None, new Type[] { msg.GetType() });
- WriteMultiMergeInner(EventName, ref opt, tlet, null, null, msg);
- }
- else
- {
- // We want the name of the provider to show up so if we don't have a manifest we create
- // on that at least has the provider name (I don't define any events).
- if (m_rawManifest == null && m_outOfBandMessageCount == 1)
- {
- ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None);
- manifestBuilder.StartEvent(EventName, new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE });
- manifestBuilder.AddEventParameter(typeof(string), "message");
- manifestBuilder.EndEvent();
- SendManifest(manifestBuilder.CreateManifest());
- }
-
- // We use this low level routine to bypass the enabled checking, since the eventSource itself is only partially inited.
- fixed (char* msgStringPtr = msgString)
- {
- EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords);
- EventProvider.EventData data = default;
- data.Ptr = (ulong)msgStringPtr;
- data.Size = (uint)(2 * (msgString.Length + 1));
- data.Reserved = 0;
- m_etwProvider.WriteEvent(ref descr, IntPtr.Zero, null, null, 1, (IntPtr)((void*)&data));
- }
- }
- }
-#endif // FEATURE_MANAGED_ETW
- }
-
- /// <summary>
- /// Since this is a means of reporting errors (see ReportoutOfBandMessage) any failure encountered
- /// while writing the message to any one of the listeners will be silently ignored.
- /// </summary>
- private void WriteStringToAllListeners(string eventName, string msg)
- {
- EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
- eventCallbackArgs.EventId = 0;
- eventCallbackArgs.Message = msg;
- eventCallbackArgs.Payload = new ReadOnlyCollection<object?>(new List<object?>() { msg });
- eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>(new List<string> { "message" });
- eventCallbackArgs.EventName = eventName;
-
- for (EventDispatcher? dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
- {
- bool dispatcherEnabled = false;
- if (dispatcher.m_EventEnabled == null)
- {
- // if the listeners that weren't correctly initialized, we will send to it
- // since this is an error message and we want to see it go out.
- dispatcherEnabled = true;
- }
- else
- {
- // if there's *any* enabled event on the dispatcher we'll write out the string
- // otherwise we'll treat the listener as disabled and skip it
- for (int evtId = 0; evtId < dispatcher.m_EventEnabled.Length; ++evtId)
- {
- if (dispatcher.m_EventEnabled[evtId])
- {
- dispatcherEnabled = true;
- break;
- }
- }
- }
- try
- {
- if (dispatcherEnabled)
- dispatcher.m_Listener.OnEventWritten(eventCallbackArgs);
- }
- catch
- {
- // ignore any exceptions thrown by listeners' OnEventWritten
- }
- }
- }
-
- /// <summary>
- /// Returns true if 'eventNum' is enabled if you only consider the level and matchAnyKeyword filters.
- /// It is possible that eventSources turn off the event based on additional filtering criteria.
- /// </summary>
- private bool IsEnabledByDefault(int eventNum, bool enable, EventLevel currentLevel, EventKeywords currentMatchAnyKeyword)
- {
- if (!enable)
- return false;
-
- Debug.Assert(m_eventData != null);
- EventLevel eventLevel = (EventLevel)m_eventData[eventNum].Descriptor.Level;
- EventKeywords eventKeywords = unchecked((EventKeywords)((ulong)m_eventData[eventNum].Descriptor.Keywords & (~(SessionMask.All.ToEventKeywords()))));
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- EventChannel channel = unchecked((EventChannel)m_eventData[eventNum].Descriptor.Channel);
-#else
- EventChannel channel = EventChannel.None;
-#endif
-
- return IsEnabledCommon(enable, currentLevel, currentMatchAnyKeyword, eventLevel, eventKeywords, channel);
- }
-
- private bool IsEnabledCommon(bool enabled, EventLevel currentLevel, EventKeywords currentMatchAnyKeyword,
- EventLevel eventLevel, EventKeywords eventKeywords, EventChannel eventChannel)
- {
- if (!enabled)
- return false;
-
- // does is pass the level test?
- if ((currentLevel != 0) && (currentLevel < eventLevel))
- return false;
-
- // if yes, does it pass the keywords test?
- if (currentMatchAnyKeyword != 0 && eventKeywords != 0)
- {
-#if FEATURE_MANAGED_ETW_CHANNELS
- // is there a channel with keywords that match currentMatchAnyKeyword?
- if (eventChannel != EventChannel.None && this.m_channelData != null && this.m_channelData.Length > (int)eventChannel)
- {
- EventKeywords channel_keywords = unchecked((EventKeywords)(m_channelData[(int)eventChannel] | (ulong)eventKeywords));
- if (channel_keywords != 0 && (channel_keywords & currentMatchAnyKeyword) == 0)
- return false;
- }
- else
-#endif
- {
- if ((unchecked((ulong)eventKeywords & (ulong)currentMatchAnyKeyword)) == 0)
- return false;
- }
- }
- return true;
- }
- [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
- private void ThrowEventSourceException(string? eventName, Exception? innerEx = null)
- {
- // If we fail during out of band logging we may end up trying
- // to throw another EventSourceException, thus hitting a StackOverflowException.
- // Avoid StackOverflow by making sure we do not recursively call this method.
- if (m_EventSourceExceptionRecurenceCount > 0)
- return;
- try
- {
- m_EventSourceExceptionRecurenceCount++;
-
- string errorPrefix = "EventSourceException";
- if (eventName != null)
- {
- errorPrefix += " while processing event \"" + eventName + "\"";
- }
-
- // TODO Create variations of EventSourceException that indicate more information using the error code.
- switch (EventProvider.GetLastWriteEventError())
- {
- case EventProvider.WriteEventErrorCode.EventTooBig:
- ReportOutOfBandMessage(errorPrefix + ": " + SR.EventSource_EventTooBig);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(SR.EventSource_EventTooBig, innerEx);
- break;
- case EventProvider.WriteEventErrorCode.NoFreeBuffers:
- ReportOutOfBandMessage(errorPrefix + ": " + SR.EventSource_NoFreeBuffers);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(SR.EventSource_NoFreeBuffers, innerEx);
- break;
- case EventProvider.WriteEventErrorCode.NullInput:
- ReportOutOfBandMessage(errorPrefix + ": " + SR.EventSource_NullInput);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(SR.EventSource_NullInput, innerEx);
- break;
- case EventProvider.WriteEventErrorCode.TooManyArgs:
- ReportOutOfBandMessage(errorPrefix + ": " + SR.EventSource_TooManyArgs);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(SR.EventSource_TooManyArgs, innerEx);
- break;
- default:
- if (innerEx != null)
- {
- innerEx = innerEx.GetBaseException();
- ReportOutOfBandMessage(errorPrefix + ": " + innerEx.GetType() + ":" + innerEx.Message);
- }
- else
- ReportOutOfBandMessage(errorPrefix);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(innerEx);
- break;
- }
- }
- finally
- {
- m_EventSourceExceptionRecurenceCount--;
- }
- }
-
- private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData, string? eventName)
- {
- if ((EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Send &&
- (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive &&
- (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Start)
- {
- ThrowEventSourceException(eventName);
- }
- }
-
- internal static EventOpcode GetOpcodeWithDefault(EventOpcode opcode, string? eventName)
- {
- if (opcode == EventOpcode.Info && eventName != null)
- {
- if (eventName.EndsWith(s_ActivityStartSuffix, StringComparison.Ordinal))
- {
- return EventOpcode.Start;
- }
- else if (eventName.EndsWith(s_ActivityStopSuffix, StringComparison.Ordinal))
- {
- return EventOpcode.Stop;
- }
- }
-
- return opcode;
- }
-
-#if FEATURE_MANAGED_ETW
- /// <summary>
- /// This class lets us hook the 'OnEventCommand' from the eventSource.
- /// </summary>
- private class OverideEventProvider : EventProvider
- {
- public OverideEventProvider(EventSource eventSource, EventProviderType providerType)
- : base(providerType)
- {
- this.m_eventSource = eventSource;
- this.m_eventProviderType = providerType;
- }
- protected override void OnControllerCommand(ControllerCommand command, IDictionary<string, string?>? arguments,
- int perEventSourceSessionId, int etwSessionId)
- {
- // We use null to represent the ETW EventListener.
- EventListener? listener = null;
- m_eventSource.SendCommand(listener, m_eventProviderType, perEventSourceSessionId, etwSessionId,
- (EventCommand)command, IsEnabled(), Level, MatchAnyKeyword, arguments);
- }
- private readonly EventSource m_eventSource;
- private readonly EventProviderType m_eventProviderType;
- }
-#endif
-
- /// <summary>
- /// Used to hold all the static information about an event. This includes everything in the event
- /// descriptor as well as some stuff we added specifically for EventSource. see the
- /// code:m_eventData for where we use this.
- /// </summary>
-
- /*
- EventMetadata was public in the separate System.Diagnostics.Tracing assembly(pre NS2.0),
- now the move to CoreLib marked them as private.
- While they are technically private (it's a contract used between the library and the ILC toolchain),
- we need them to be rooted and exported from shared library for the system to work.
- For now I'm simply marking them as public again.A cleaner solution might be to use.rd.xml to
- root them and modify shared library definition to force export them.
- */
-#if ES_BUILD_PN
- public
-#else
- internal
-#endif
- partial struct EventMetadata
- {
-#if ES_BUILD_PN
- public EventMetadata(EventDescriptor descriptor,
- EventTags tags,
- bool enabledForAnyListener,
- bool enabledForETW,
- string name,
- string message,
- EventParameterType[] parameterTypes)
- {
- this.Descriptor = descriptor;
- this.Tags = tags;
- this.EnabledForAnyListener = enabledForAnyListener;
- this.EnabledForETW = enabledForETW;
-#if FEATURE_PERFTRACING
- this.EnabledForEventPipe = false;
-#endif
- this.TriggersActivityTracking = 0;
- this.Name = name;
- this.Message = message;
- this.Parameters = null!;
- this.TraceLoggingEventTypes = null;
- this.ActivityOptions = EventActivityOptions.None;
- this.ParameterTypes = parameterTypes;
- this.HasRelatedActivityID = false;
- this.EventHandle = IntPtr.Zero;
- }
-#endif
-
- public EventDescriptor Descriptor;
- public IntPtr EventHandle; // EventPipeEvent handle.
- public EventTags Tags;
- public bool EnabledForAnyListener; // true if any dispatcher has this event turned on
- public bool EnabledForETW; // is this event on for ETW?
-#if FEATURE_PERFTRACING
- public bool EnabledForEventPipe; // is this event on for EventPipe?
-#endif
-
- public bool HasRelatedActivityID; // Set if the event method's first parameter is a Guid named 'relatedActivityId'
-#pragma warning disable 0649
- public byte TriggersActivityTracking; // count of listeners that marked this event as trigger for start of activity logging.
-#pragma warning restore 0649
- public string Name; // the name of the event
- public string? Message; // If the event has a message associated with it, this is it.
- public ParameterInfo[] Parameters; // TODO can we remove?
-
- public TraceLoggingEventTypes? TraceLoggingEventTypes;
- public EventActivityOptions ActivityOptions;
-
-#if ES_BUILD_PN
- public EventParameterType[] ParameterTypes;
-#endif
- }
-
-#if !ES_BUILD_PN
- private static int GetParameterCount(EventMetadata eventData)
- {
- return eventData.Parameters.Length;
- }
-
- private static Type GetDataType(EventMetadata eventData, int parameterId)
- {
- return eventData.Parameters[parameterId].ParameterType;
- }
-
- private const bool m_EventSourcePreventRecursion = false;
-#else
- private static int GetParameterCount(EventMetadata eventData)
- {
- int paramCount;
- if (eventData.Parameters == null)
- {
- paramCount = eventData.ParameterTypes.Length;
- }
- else
- {
- paramCount = eventData.Parameters.Length;
- }
-
- return paramCount;
- }
-
- private static Type GetDataType(EventMetadata eventData, int parameterId)
- {
- Type dataType;
- if (eventData.Parameters == null)
- {
- dataType = EventTypeToType(eventData.ParameterTypes[parameterId]);
- }
- else
- {
- dataType = eventData.Parameters[parameterId].ParameterType;
- }
-
- return dataType;
- }
-
- private static readonly bool m_EventSourcePreventRecursion = true;
-
- public enum EventParameterType
- {
- Boolean,
- Byte,
- SByte,
- Char,
- Int16,
- UInt16,
- Int32,
- UInt32,
- Int64,
- UInt64,
- IntPtr,
- Single,
- Double,
- Decimal,
- Guid,
- String
- }
-
- private static Type EventTypeToType(EventParameterType type)
- {
- switch (type)
- {
- case EventParameterType.Boolean:
- return typeof(bool);
- case EventParameterType.Byte:
- return typeof(byte);
- case EventParameterType.SByte:
- return typeof(sbyte);
- case EventParameterType.Char:
- return typeof(char);
- case EventParameterType.Int16:
- return typeof(short);
- case EventParameterType.UInt16:
- return typeof(ushort);
- case EventParameterType.Int32:
- return typeof(int);
- case EventParameterType.UInt32:
- return typeof(uint);
- case EventParameterType.Int64:
- return typeof(long);
- case EventParameterType.UInt64:
- return typeof(ulong);
- case EventParameterType.IntPtr:
- return typeof(IntPtr);
- case EventParameterType.Single:
- return typeof(float);
- case EventParameterType.Double:
- return typeof(double);
- case EventParameterType.Decimal:
- return typeof(decimal);
- case EventParameterType.Guid:
- return typeof(Guid);
- case EventParameterType.String:
- return typeof(string);
- default:
- // TODO: should I throw an exception here?
- return null!;
- }
- }
-#endif
-
- // This is the internal entry point that code:EventListeners call when wanting to send a command to a
- // eventSource. The logic is as follows
- //
- // * if Command == Update
- // * perEventSourceSessionId specifies the per-provider ETW session ID that the command applies
- // to (if listener != null)
- // perEventSourceSessionId = 0 - reserved for EventListeners
- // perEventSourceSessionId = 1..SessionMask.MAX - reserved for activity tracing aware ETW sessions
- // perEventSourceSessionId-1 represents the bit in the reserved field (bits 44..47) in
- // Keywords that identifies the session
- // perEventSourceSessionId = SessionMask.MAX+1 - reserved for legacy ETW sessions; these are
- // discriminated by etwSessionId
- // * etwSessionId specifies a machine-wide ETW session ID; this allows correlation of
- // activity tracing across different providers (which might have different sessionIds
- // for the same ETW session)
- // * enable, level, matchAnyKeywords are used to set a default for all events for the
- // eventSource. In particular, if 'enabled' is false, 'level' and
- // 'matchAnyKeywords' are not used.
- // * OnEventCommand is invoked, which may cause calls to
- // code:EventSource.EnableEventForDispatcher which may cause changes in the filtering
- // depending on the logic in that routine.
- // * else (command != Update)
- // * Simply call OnEventCommand. The expectation is that filtering is NOT changed.
- // * The 'enabled' 'level', matchAnyKeyword' arguments are ignored (must be true, 0, 0).
- //
- // dispatcher == null has special meaning. It is the 'ETW' dispatcher.
- internal void SendCommand(EventListener? listener, EventProviderType eventProviderType, int perEventSourceSessionId, int etwSessionId,
- EventCommand command, bool enable,
- EventLevel level, EventKeywords matchAnyKeyword,
- IDictionary<string, string?>? commandArguments)
- {
- var commandArgs = new EventCommandEventArgs(command, commandArguments, this, listener, eventProviderType, perEventSourceSessionId, etwSessionId, enable, level, matchAnyKeyword);
- lock (EventListener.EventListenersLock)
- {
- if (m_completelyInited)
- {
- // After the first command arrive after construction, we are ready to get rid of the deferred commands
- this.m_deferredCommands = null;
- // We are fully initialized, do the command
- DoCommand(commandArgs);
- }
- else
- {
- // We can't do the command, simply remember it and we do it when we are fully constructed.
- if (m_deferredCommands == null)
- {
- m_deferredCommands = commandArgs; // create the first entry
- }
- else
- {
- // We have one or more entries, find the last one and add it to that.
- EventCommandEventArgs lastCommand = m_deferredCommands;
- while (lastCommand.nextCommand != null)
- lastCommand = lastCommand.nextCommand;
- lastCommand.nextCommand = commandArgs;
- }
- }
- }
- }
-
- /// <summary>
- /// We want the eventSource to be fully initialized when we do commands because that way we can send
- /// error messages and other logging directly to the event stream. Unfortunately we can get callbacks
- /// when we are not fully initialized. In that case we store them in 'commandArgs' and do them later.
- /// This helper actually does all actual command logic.
- /// </summary>
- internal void DoCommand(EventCommandEventArgs commandArgs)
- {
- // PRECONDITION: We should be holding the EventListener.EventListenersLock
- // We defer commands until we are completely inited. This allows error messages to be sent.
- Debug.Assert(m_completelyInited);
-
-#if FEATURE_MANAGED_ETW
- if (m_etwProvider == null) // If we failed to construct
- return;
-#endif // FEATURE_MANAGED_ETW
-#if FEATURE_PERFTRACING
- if (m_eventPipeProvider == null)
- return;
-#endif
-
- m_outOfBandMessageCount = 0;
- try
- {
- EnsureDescriptorsInitialized();
- Debug.Assert(m_eventData != null);
-
- // Find the per-EventSource dispatcher corresponding to registered dispatcher
- commandArgs.dispatcher = GetDispatcher(commandArgs.listener);
- if (commandArgs.dispatcher == null && commandArgs.listener != null) // dispatcher == null means ETW dispatcher
- {
- throw new ArgumentException(SR.EventSource_ListenerNotFound);
- }
-
- commandArgs.Arguments ??= new Dictionary<string, string?>();
-
- if (commandArgs.Command == EventCommand.Update)
- {
- // Set it up using the 'standard' filtering bitfields (use the "global" enable, not session specific one)
- for (int i = 0; i < m_eventData.Length; i++)
- EnableEventForDispatcher(commandArgs.dispatcher, commandArgs.eventProviderType, i, IsEnabledByDefault(i, commandArgs.enable, commandArgs.level, commandArgs.matchAnyKeyword));
-
- if (commandArgs.enable)
- {
- if (!m_eventSourceEnabled)
- {
- // EventSource turned on for the first time, simply copy the bits.
- m_level = commandArgs.level;
- m_matchAnyKeyword = commandArgs.matchAnyKeyword;
- }
- else
- {
- // Already enabled, make it the most verbose of the existing and new filter
- if (commandArgs.level > m_level)
- m_level = commandArgs.level;
- if (commandArgs.matchAnyKeyword == 0)
- m_matchAnyKeyword = 0;
- else if (m_matchAnyKeyword != 0)
- m_matchAnyKeyword = unchecked(m_matchAnyKeyword | commandArgs.matchAnyKeyword);
- }
- }
-
- // interpret perEventSourceSessionId's sign, and adjust perEventSourceSessionId to
- // represent 0-based positive values
- bool bSessionEnable = (commandArgs.perEventSourceSessionId >= 0);
- if (commandArgs.perEventSourceSessionId == 0 && !commandArgs.enable)
- bSessionEnable = false;
-
- if (commandArgs.listener == null)
- {
- if (!bSessionEnable)
- commandArgs.perEventSourceSessionId = -commandArgs.perEventSourceSessionId;
- // for "global" enable/disable (passed in with listener == null and
- // perEventSourceSessionId == 0) perEventSourceSessionId becomes -1
- --commandArgs.perEventSourceSessionId;
- }
-
- commandArgs.Command = bSessionEnable ? EventCommand.Enable : EventCommand.Disable;
-
- // perEventSourceSessionId = -1 when ETW sent a notification, but the set of active sessions
- // hasn't changed.
- // sesisonId = SessionMask.MAX when one of the legacy ETW sessions changed
- // 0 <= perEventSourceSessionId < SessionMask.MAX for activity-tracing aware sessions
- Debug.Assert(commandArgs.perEventSourceSessionId >= -1 && commandArgs.perEventSourceSessionId <= SessionMask.MAX);
-
- // Send the manifest if we are enabling an ETW session
- if (bSessionEnable && commandArgs.dispatcher == null)
- {
- // eventSourceDispatcher == null means this is the ETW manifest
-
- // Note that we unconditionally send the manifest whenever we are enabled, even if
- // we were already enabled. This is because there may be multiple sessions active
- // and we can't know that all the sessions have seen the manifest.
- if (!SelfDescribingEvents)
- SendManifest(m_rawManifest);
- }
-
- // Turn on the enable bit before making the OnEventCommand callback This allows you to do useful
- // things like log messages, or test if keywords are enabled in the callback.
- if (commandArgs.enable)
- {
- Debug.Assert(m_eventData != null);
- m_eventSourceEnabled = true;
- }
-
- this.OnEventCommand(commandArgs);
- this.m_eventCommandExecuted?.Invoke(this, commandArgs);
-
- 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.
- for (int i = 0; i < m_eventData.Length; i++)
- {
- bool isEnabledForAnyListener = false;
- for (EventDispatcher? dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
- {
- Debug.Assert(dispatcher.m_EventEnabled != null);
-
- if (dispatcher.m_EventEnabled[i])
- {
- isEnabledForAnyListener = true;
- break;
- }
- }
- m_eventData[i].EnabledForAnyListener = isEnabledForAnyListener;
- }
-
- // If no events are enabled, disable the global enabled bit.
- if (!AnyEventEnabled())
- {
- m_level = 0;
- m_matchAnyKeyword = 0;
- m_eventSourceEnabled = false;
- }
- }
- }
- else
- {
-#if !FEATURE_PERFTRACING
- if (commandArgs.Command == EventCommand.SendManifest)
- {
- // TODO: should we generate the manifest here if we hadn't already?
- if (m_rawManifest != null)
- SendManifest(m_rawManifest);
- }
-#endif
-
- // These are not used for non-update commands and thus should always be 'default' values
- // Debug.Assert(enable == true);
- // Debug.Assert(level == EventLevel.LogAlways);
- // Debug.Assert(matchAnyKeyword == EventKeywords.None);
-
- this.OnEventCommand(commandArgs);
- m_eventCommandExecuted?.Invoke(this, commandArgs);
- }
- }
- catch (Exception e)
- {
- // When the ETW session is created after the EventSource has registered with the ETW system
- // we can send any error messages here.
- ReportOutOfBandMessage("ERROR: Exception in Command Processing for EventSource " + Name + ": " + e.Message);
- // We never throw when doing a command.
- }
- }
-
- /// <summary>
- /// If 'value is 'true' then set the eventSource so that 'dispatcher' will receive event with the eventId
- /// of 'eventId. If value is 'false' disable the event for that dispatcher. If 'eventId' is out of
- /// range return false, otherwise true.
- /// </summary>
- internal bool EnableEventForDispatcher(EventDispatcher? dispatcher, EventProviderType eventProviderType, int eventId, bool value)
- {
- Debug.Assert(m_eventData != null);
-
- if (dispatcher == null)
- {
- if (eventId >= m_eventData.Length)
- return false;
-#if FEATURE_MANAGED_ETW
- if (m_etwProvider != null && eventProviderType == EventProviderType.ETW)
- m_eventData[eventId].EnabledForETW = value;
-#endif
-#if FEATURE_PERFTRACING
- if (m_eventPipeProvider != null && eventProviderType == EventProviderType.EventPipe)
- m_eventData[eventId].EnabledForEventPipe = value;
-#endif
- }
- else
- {
- Debug.Assert(dispatcher.m_EventEnabled != null);
- if (eventId >= dispatcher.m_EventEnabled.Length)
- return false;
- dispatcher.m_EventEnabled[eventId] = value;
- if (value)
- m_eventData[eventId].EnabledForAnyListener = true;
- }
- return true;
- }
-
- /// <summary>
- /// Returns true if any event at all is on.
- /// </summary>
- private bool AnyEventEnabled()
- {
- Debug.Assert(m_eventData != null);
-
- for (int i = 0; i < m_eventData.Length; i++)
- if (m_eventData[i].EnabledForETW || m_eventData[i].EnabledForAnyListener
-#if FEATURE_PERFTRACING
- || m_eventData[i].EnabledForEventPipe
-#endif // FEATURE_PERFTRACING
- )
- return true;
- return false;
- }
-
- private bool IsDisposed => m_eventSourceDisposed;
-
- private void EnsureDescriptorsInitialized()
- {
-#if !ES_BUILD_STANDALONE
- Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
-#endif
- if (m_eventData == null)
- {
- Guid eventSourceGuid = Guid.Empty;
- string? eventSourceName = null;
- EventMetadata[]? eventData = null;
- byte[]? manifest = null;
-
- // Try the GetMetadata provided by the ILTransform in ProjectN. The default sets all to null, and in that case we fall back
- // to the reflection approach.
- GetMetadata(out eventSourceGuid, out eventSourceName, out eventData, out manifest);
-
- if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null || eventData == null || manifest == null)
- {
- // GetMetadata failed, so we have to set it via reflection.
- Debug.Assert(m_rawManifest == null);
-
- m_rawManifest = CreateManifestAndDescriptors(this.GetType(), Name, this);
- Debug.Assert(m_eventData != null);
- }
- else
- {
- // GetMetadata worked, so set the fields as appropriate.
- m_name = eventSourceName;
- m_guid = eventSourceGuid;
- m_eventData = eventData;
- m_rawManifest = manifest;
- }
- // TODO Enforce singleton pattern
- Debug.Assert(EventListener.s_EventSources != null, "should be called within lock on EventListener.EventListenersLock which ensures s_EventSources to be initialized");
- foreach (WeakReference<EventSource> eventSourceRef in EventListener.s_EventSources)
- {
- if (eventSourceRef.TryGetTarget(out EventSource? eventSource) && eventSource.Guid == m_guid && !eventSource.IsDisposed)
- {
- if (eventSource != this)
- {
- throw new ArgumentException(SR.Format(SR.EventSource_EventSourceGuidInUse, m_guid));
- }
- }
- }
-
- // Make certain all dispatchers also have their arrays initialized
- EventDispatcher? dispatcher = m_Dispatchers;
- while (dispatcher != null)
- {
- dispatcher.m_EventEnabled ??= new bool[m_eventData.Length];
- dispatcher = dispatcher.m_Next;
- }
-#if FEATURE_PERFTRACING
- // Initialize the EventPipe event handles.
- DefineEventPipeEvents();
-#endif
- }
- if (s_currentPid == 0)
- {
-#if ES_BUILD_STANDALONE
- // for non-BCL EventSource we must assert SecurityPermission
- new SecurityPermission(PermissionState.Unrestricted).Assert();
-#endif
- s_currentPid = Interop.GetCurrentProcessId();
- }
- }
-
- // Send out the ETW manifest XML out to ETW
- // Today, we only send the manifest to ETW, custom listeners don't get it.
- private unsafe void SendManifest(byte[]? rawManifest)
- {
- if (rawManifest == null)
- return;
-
- Debug.Assert(!SelfDescribingEvents);
-
-#if FEATURE_MANAGED_ETW
- fixed (byte* dataPtr = rawManifest)
- {
- // we don't want the manifest to show up in the event log channels so we specify as keywords
- // everything but the first 8 bits (reserved for the 8 channels)
- var manifestDescr = new EventDescriptor(0xFFFE, 1, 0, 0, 0xFE, 0xFFFE, 0x00ffFFFFffffFFFF);
- ManifestEnvelope envelope = default;
-
- envelope.Format = ManifestEnvelope.ManifestFormats.SimpleXmlFormat;
- envelope.MajorVersion = 1;
- envelope.MinorVersion = 0;
- envelope.Magic = 0x5B; // An unusual number that can be checked for consistency.
- int dataLeft = rawManifest.Length;
- envelope.ChunkNumber = 0;
-
- EventProvider.EventData* dataDescrs = stackalloc EventProvider.EventData[2];
-
- dataDescrs[0].Ptr = (ulong)&envelope;
- dataDescrs[0].Size = (uint)sizeof(ManifestEnvelope);
- dataDescrs[0].Reserved = 0;
-
- dataDescrs[1].Ptr = (ulong)dataPtr;
- dataDescrs[1].Reserved = 0;
-
- int chunkSize = ManifestEnvelope.MaxChunkSize;
- TRY_AGAIN_WITH_SMALLER_CHUNK_SIZE:
- envelope.TotalChunks = (ushort)((dataLeft + (chunkSize - 1)) / chunkSize);
- while (dataLeft > 0)
- {
- dataDescrs[1].Size = (uint)Math.Min(dataLeft, chunkSize);
- if (m_etwProvider != null)
- {
- if (!m_etwProvider.WriteEvent(ref manifestDescr, IntPtr.Zero, null, null, 2, (IntPtr)dataDescrs))
- {
- // Turns out that if users set the BufferSize to something less than 64K then WriteEvent
- // can fail. If we get this failure on the first chunk try again with something smaller
- // The smallest BufferSize is 1K so if we get to 256 (to account for envelope overhead), we can give up making it smaller.
- if (EventProvider.GetLastWriteEventError() == EventProvider.WriteEventErrorCode.EventTooBig)
- {
- if (envelope.ChunkNumber == 0 && chunkSize > 256)
- {
- chunkSize /= 2;
- goto TRY_AGAIN_WITH_SMALLER_CHUNK_SIZE;
- }
- }
-
- if (ThrowOnEventWriteErrors)
- ThrowEventSourceException("SendManifest");
- break;
- }
- }
- dataLeft -= chunkSize;
- dataDescrs[1].Ptr += (uint)chunkSize;
- envelope.ChunkNumber++;
-
- // For large manifests we want to not overflow any receiver's buffer. Most manifests will fit within
- // 5 chunks, so only the largest manifests will hit the pause.
- if ((envelope.ChunkNumber % 5) == 0)
- {
- Thread.Sleep(15);
- }
- }
- }
-#endif // FEATURE_MANAGED_ETW
- }
-
-#if (ES_BUILD_PCL)
- internal static Attribute GetCustomAttributeHelper(Type type, Type attributeType, EventManifestOptions flags = EventManifestOptions.None)
- {
- return GetCustomAttributeHelper(type.GetTypeInfo(), attributeType, flags);
- }
-#endif
-
- // Helper to deal with the fact that the type we are reflecting over might be loaded in the ReflectionOnly context.
- // When that is the case, we have the build the custom assemblies on a member by hand.
- internal static Attribute? GetCustomAttributeHelper(MemberInfo member, Type attributeType, EventManifestOptions flags = EventManifestOptions.None)
- {
-#if !ES_BUILD_PN
- // On ProjectN, ReflectionOnly() always equals false. AllowEventSourceOverride is an option that allows either Microsoft.Diagnostics.Tracing or
- // System.Diagnostics.Tracing EventSource to be considered valid. This should not mattter anywhere but in Microsoft.Diagnostics.Tracing (nuget package).
- if (!member.Module.Assembly.ReflectionOnly() && (flags & EventManifestOptions.AllowEventSourceOverride) == 0)
-#endif // !ES_BUILD_PN
- {
- // Let the runtime to the work for us, since we can execute code in this context.
- Attribute? firstAttribute = null;
- foreach (object attribute in member.GetCustomAttributes(attributeType, false))
- {
- firstAttribute = (Attribute)attribute;
- break;
- }
- return firstAttribute;
- }
-
-#if (!ES_BUILD_PCL && !ES_BUILD_PN)
- foreach (CustomAttributeData data in CustomAttributeData.GetCustomAttributes(member))
- {
- if (AttributeTypeNamesMatch(attributeType, data.Constructor.ReflectedType!))
- {
- Attribute? attr = null;
-
- Debug.Assert(data.ConstructorArguments.Count <= 1);
-
- if (data.ConstructorArguments.Count == 1)
- {
- attr = (Attribute?)Activator.CreateInstance(attributeType, new object?[] { data.ConstructorArguments[0].Value });
- }
- else if (data.ConstructorArguments.Count == 0)
- {
- attr = (Attribute?)Activator.CreateInstance(attributeType);
- }
-
- if (attr != null)
- {
- Type t = attr.GetType();
-
- foreach (CustomAttributeNamedArgument namedArgument in data.NamedArguments)
- {
- PropertyInfo p = t.GetProperty(namedArgument.MemberInfo.Name, BindingFlags.Public | BindingFlags.Instance)!;
- object value = namedArgument.TypedValue.Value!;
-
- if (p.PropertyType.IsEnum)
- {
- string val = value.ToString()!;
- value = Enum.Parse(p.PropertyType, val);
- }
-
- p.SetValue(attr, value, null);
- }
-
- return attr;
- }
- }
- }
-
- return null;
-#else // ES_BUILD_PCL && ES_BUILD_PN
- // Don't use nameof here because the resource doesn't exist on some platforms, which results in a compilation error.
- throw new ArgumentException("EventSource_PCLPlatformNotSupportedReflection", "EventSource");
-#endif
- }
-
- /// <summary>
- /// Evaluates if two related "EventSource"-domain types should be considered the same
- /// </summary>
- /// <param name="attributeType">The attribute type in the load context - it's associated with the running
- /// EventSource type. This type may be different fromt he base type of the user-defined EventSource.</param>
- /// <param name="reflectedAttributeType">The attribute type in the reflection context - it's associated with
- /// the user-defined EventSource, and is in the same assembly as the eventSourceType passed to
- /// </param>
- /// <returns>True - if the types should be considered equivalent, False - otherwise</returns>
- private static bool AttributeTypeNamesMatch(Type attributeType, Type reflectedAttributeType)
- {
- return
- // are these the same type?
- attributeType == reflectedAttributeType ||
- // are the full typenames equal?
- string.Equals(attributeType.FullName, reflectedAttributeType.FullName, StringComparison.Ordinal) ||
- // are the typenames equal and the namespaces under "Diagnostics.Tracing" (typically
- // either Microsoft.Diagnostics.Tracing or System.Diagnostics.Tracing)?
- string.Equals(attributeType.Name, reflectedAttributeType.Name, StringComparison.Ordinal) &&
- attributeType.Namespace!.EndsWith("Diagnostics.Tracing", StringComparison.Ordinal) &&
- (reflectedAttributeType.Namespace!.EndsWith("Diagnostics.Tracing", StringComparison.Ordinal)
-#if EVENT_SOURCE_LEGACY_NAMESPACE_SUPPORT
- || reflectedAttributeType.Namespace.EndsWith("Diagnostics.Eventing", StringComparison.Ordinal)
-#endif
-);
- }
-
- private static Type? GetEventSourceBaseType(Type eventSourceType, bool allowEventSourceOverride, bool reflectionOnly)
- {
- Type? ret = eventSourceType;
-
- // return false for "object" and interfaces
- if (ret.BaseType() == null)
- return null;
-
- // now go up the inheritance chain until hitting a concrete type ("object" at worse)
- do
- {
- ret = ret.BaseType();
- }
- while (ret != null && ret.IsAbstract());
-
- if (ret != null)
- {
- if (!allowEventSourceOverride)
- {
- if (reflectionOnly && ret.FullName != typeof(EventSource).FullName ||
- !reflectionOnly && ret != typeof(EventSource))
- return null;
- }
- else
- {
- if (ret.Name != "EventSource")
- return null;
- }
- }
- return ret;
- }
-
- // Use reflection to look at the attributes of a class, and generate a manifest for it (as UTF8) and
- // return the UTF8 bytes. It also sets up the code:EventData structures needed to dispatch events
- // at run time. 'source' is the event source to place the descriptors. If it is null,
- // then the descriptors are not creaed, and just the manifest is generated.
- private static byte[]? CreateManifestAndDescriptors(Type eventSourceType, string? eventSourceDllName, EventSource? source,
- EventManifestOptions flags = EventManifestOptions.None)
- {
- ManifestBuilder? manifest = null;
- bool bNeedsManifest = source != null ? !source.SelfDescribingEvents : true;
- Exception? exception = null; // exception that might get raised during validation b/c we couldn't/didn't recover from a previous error
- byte[]? res = null;
-
- if (eventSourceType.IsAbstract() && (flags & EventManifestOptions.Strict) == 0)
- return null;
-
- try
- {
- MethodInfo[] methods = eventSourceType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
- EventAttribute defaultEventAttribute;
- int eventId = 1; // The number given to an event that does not have a explicitly given ID.
- EventMetadata[]? eventData = null;
- Dictionary<string, string>? eventsByName = null;
- if (source != null || (flags & EventManifestOptions.Strict) != 0)
- {
- eventData = new EventMetadata[methods.Length + 1];
- eventData[0].Name = ""; // Event 0 is the 'write messages string' event, and has an empty name.
- }
-
- // See if we have localization information.
- ResourceManager? resources = null;
- EventSourceAttribute? eventSourceAttrib = (EventSourceAttribute?)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute), flags);
- if (eventSourceAttrib != null && eventSourceAttrib.LocalizationResources != null)
- resources = new ResourceManager(eventSourceAttrib.LocalizationResources, eventSourceType.Assembly());
-
- manifest = new ManifestBuilder(GetName(eventSourceType, flags), GetGuid(eventSourceType), eventSourceDllName,
- resources, flags);
-
- // Add an entry unconditionally for event ID 0 which will be for a string message.
- manifest.StartEvent("EventSourceMessage", new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE });
- manifest.AddEventParameter(typeof(string), "message");
- manifest.EndEvent();
-
- // eventSourceType must be sealed and must derive from this EventSource
- if ((flags & EventManifestOptions.Strict) != 0)
- {
- bool typeMatch = GetEventSourceBaseType(eventSourceType, (flags & EventManifestOptions.AllowEventSourceOverride) != 0, eventSourceType.Assembly().ReflectionOnly()) != null;
-
- if (!typeMatch)
- {
- manifest.ManifestError(SR.EventSource_TypeMustDeriveFromEventSource);
- }
- if (!eventSourceType.IsAbstract() && !eventSourceType.IsSealed())
- {
- manifest.ManifestError(SR.EventSource_TypeMustBeSealedOrAbstract);
- }
- }
-
- // Collect task, opcode, keyword and channel information
-#if FEATURE_MANAGED_ETW_CHANNELS && FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes", "Channels" })
-#else
- foreach (string providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes" })
-#endif
- {
- Type? nestedType = eventSourceType.GetNestedType(providerEnumKind);
- if (nestedType != null)
- {
- if (eventSourceType.IsAbstract())
- {
- manifest.ManifestError(SR.Format(SR.EventSource_AbstractMustNotDeclareKTOC, nestedType.Name));
- }
- else
- {
- foreach (FieldInfo staticField in nestedType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
- {
- AddProviderEnumKind(manifest, staticField, providerEnumKind);
- }
- }
- }
- }
- // ensure we have keywords for the session-filtering reserved bits
- {
- manifest.AddKeyword("Session3", (long)0x1000 << 32);
- manifest.AddKeyword("Session2", (long)0x2000 << 32);
- manifest.AddKeyword("Session1", (long)0x4000 << 32);
- manifest.AddKeyword("Session0", (long)0x8000 << 32);
- }
-
- if (eventSourceType != typeof(EventSource))
- {
- for (int i = 0; i < methods.Length; i++)
- {
- MethodInfo method = methods[i];
- ParameterInfo[] args = method.GetParameters();
-
- // Get the EventDescriptor (from the Custom attributes)
- EventAttribute? eventAttribute = (EventAttribute?)GetCustomAttributeHelper(method, typeof(EventAttribute), flags);
-
- // Compat: until v4.5.1 we ignored any non-void returning methods as well as virtual methods for
- // the only reason of limiting the number of methods considered to be events. This broke a common
- // design of having event sources implement specific interfaces. To fix this in a compatible way
- // we will now allow both non-void returning and virtual methods to be Event methods, as long
- // as they are marked with the [Event] attribute
- if (/* method.IsVirtual || */ method.IsStatic)
- {
- continue;
- }
-
- if (eventSourceType.IsAbstract())
- {
- if (eventAttribute != null)
- {
- manifest.ManifestError(SR.Format(SR.EventSource_AbstractMustNotDeclareEventMethods, method.Name, eventAttribute.EventId));
- }
- continue;
- }
- else if (eventAttribute == null)
- {
- // Methods that don't return void can't be events, if they're NOT marked with [Event].
- // (see Compat comment above)
- if (method.ReturnType != typeof(void))
- {
- continue;
- }
-
- // Continue to ignore virtual methods if they do NOT have the [Event] attribute
- // (see Compat comment above)
- if (method.IsVirtual)
- {
- continue;
- }
-
- // If we explicitly mark the method as not being an event, then honor that.
- if (GetCustomAttributeHelper(method, typeof(NonEventAttribute), flags) != null)
- continue;
-
- defaultEventAttribute = new EventAttribute(eventId);
- eventAttribute = defaultEventAttribute;
- }
- else if (eventAttribute.EventId <= 0)
- {
- manifest.ManifestError(SR.Format(SR.EventSource_NeedPositiveId, method.Name), true);
- continue; // don't validate anything else for this event
- }
- if (method.Name.LastIndexOf('.') >= 0)
- {
- manifest.ManifestError(SR.Format(SR.EventSource_EventMustNotBeExplicitImplementation, method.Name, eventAttribute.EventId));
- }
-
- eventId++;
- string eventName = method.Name;
-
- if (eventAttribute.Opcode == EventOpcode.Info) // We are still using the default opcode.
- {
- // By default pick a task ID derived from the EventID, starting with the highest task number and working back
- bool noTask = (eventAttribute.Task == EventTask.None);
- if (noTask)
- eventAttribute.Task = (EventTask)(0xFFFE - eventAttribute.EventId);
-
- // Unless we explicitly set the opcode to Info (to override the auto-generate of Start or Stop opcodes,
- // pick a default opcode based on the event name (either Info or start or stop if the name ends with that suffix).
- if (!eventAttribute.IsOpcodeSet)
- eventAttribute.Opcode = GetOpcodeWithDefault(EventOpcode.Info, eventName);
-
- // Make the stop opcode have the same task as the start opcode.
- if (noTask)
- {
- if (eventAttribute.Opcode == EventOpcode.Start)
- {
- string taskName = eventName.Substring(0, eventName.Length - s_ActivityStartSuffix.Length); // Remove the Stop suffix to get the task name
- if (string.Compare(eventName, 0, taskName, 0, taskName.Length) == 0 &&
- string.Compare(eventName, taskName.Length, s_ActivityStartSuffix, 0, Math.Max(eventName.Length - taskName.Length, s_ActivityStartSuffix.Length)) == 0)
- {
- // Add a task that is just the task name for the start event. This suppress the auto-task generation
- // That would otherwise happen (and create 'TaskName'Start as task name rather than just 'TaskName'
- manifest.AddTask(taskName, (int)eventAttribute.Task);
- }
- }
- else if (eventAttribute.Opcode == EventOpcode.Stop)
- {
- // Find the start associated with this stop event. We require start to be immediately before the stop
- int startEventId = eventAttribute.EventId - 1;
- if (eventData != null && startEventId < eventData.Length)
- {
- Debug.Assert(0 <= startEventId); // Since we reserve id 0, we know that id-1 is <= 0
- EventMetadata startEventMetadata = eventData[startEventId];
-
- // If you remove the Stop and add a Start does that name match the Start Event's Name?
- // Ideally we would throw an error
- string taskName = eventName.Substring(0, eventName.Length - s_ActivityStopSuffix.Length); // Remove the Stop suffix to get the task name
- if (startEventMetadata.Descriptor.Opcode == (byte)EventOpcode.Start &&
- string.Compare(startEventMetadata.Name, 0, taskName, 0, taskName.Length) == 0 &&
- string.Compare(startEventMetadata.Name, taskName.Length, s_ActivityStartSuffix, 0, Math.Max(startEventMetadata.Name.Length - taskName.Length, s_ActivityStartSuffix.Length)) == 0)
- {
- // Make the stop event match the start event
- eventAttribute.Task = (EventTask)startEventMetadata.Descriptor.Task;
- noTask = false;
- }
- }
- if (noTask && (flags & EventManifestOptions.Strict) != 0) // Throw an error if we can compatibly.
- {
- throw new ArgumentException(SR.EventSource_StopsFollowStarts);
- }
- }
- }
- }
-
- bool hasRelatedActivityID = RemoveFirstArgIfRelatedActivityId(ref args);
- if (!(source != null && source.SelfDescribingEvents))
- {
- manifest.StartEvent(eventName, eventAttribute);
- for (int fieldIdx = 0; fieldIdx < args.Length; fieldIdx++)
- {
- manifest.AddEventParameter(args[fieldIdx].ParameterType, args[fieldIdx].Name!);
- }
- manifest.EndEvent();
- }
-
- if (source != null || (flags & EventManifestOptions.Strict) != 0)
- {
- Debug.Assert(eventData != null);
- // Do checking for user errors (optional, but not a big deal so we do it).
- DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute, manifest, flags);
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- // add the channel keyword for Event Viewer channel based filters. This is added for creating the EventDescriptors only
- // and is not required for the manifest
- if (eventAttribute.Channel != EventChannel.None)
- {
- unchecked
- {
- eventAttribute.Keywords |= (EventKeywords)manifest.GetChannelKeyword(eventAttribute.Channel, (ulong)eventAttribute.Keywords);
- }
- }
-#endif
- string eventKey = "event_" + eventName;
- string? msg = manifest.GetLocalizedMessage(eventKey, CultureInfo.CurrentUICulture, etwFormat: false);
- // overwrite inline message with the localized message
- if (msg != null) eventAttribute.Message = msg;
-
- AddEventDescriptor(ref eventData, eventName, eventAttribute, args, hasRelatedActivityID);
- }
- }
- }
-
- // Tell the TraceLogging stuff where to start allocating its own IDs.
- NameInfo.ReserveEventIDsBelow(eventId);
-
- if (source != null)
- {
- Debug.Assert(eventData != null);
- TrimEventDescriptors(ref eventData);
- source.m_eventData = eventData; // officially initialize it. We do this at most once (it is racy otherwise).
-#if FEATURE_MANAGED_ETW_CHANNELS
- source.m_channelData = manifest.GetChannelData();
-#endif
- }
-
- // if this is an abstract event source we've already performed all the validation we can
- if (!eventSourceType.IsAbstract() && (source == null || !source.SelfDescribingEvents))
- {
- bNeedsManifest = (flags & EventManifestOptions.OnlyIfNeededForRegistration) == 0
-#if FEATURE_MANAGED_ETW_CHANNELS
- || manifest.GetChannelData().Length > 0
-#endif
-;
-
- // if the manifest is not needed and we're not requested to validate the event source return early
- if (!bNeedsManifest && (flags & EventManifestOptions.Strict) == 0)
- return null;
-
- res = manifest.CreateManifest();
- }
- }
- catch (Exception e)
- {
- // if this is a runtime manifest generation let the exception propagate
- if ((flags & EventManifestOptions.Strict) == 0)
- throw;
- // else store it to include it in the Argument exception we raise below
- exception = e;
- }
-
- if ((flags & EventManifestOptions.Strict) != 0 && (manifest?.Errors.Count > 0 || exception != null))
- {
- string msg = string.Empty;
-
- if (manifest?.Errors.Count > 0)
- {
- bool firstError = true;
- foreach (string error in manifest.Errors)
- {
- if (!firstError)
- msg += Environment.NewLine;
- firstError = false;
- msg += error;
- }
- }
- else
- msg = "Unexpected error: " + exception!.Message;
-
- throw new ArgumentException(msg, exception);
- }
-
- return bNeedsManifest ? res : null;
- }
-
- private static bool RemoveFirstArgIfRelatedActivityId(ref ParameterInfo[] args)
- {
- // If the first parameter is (case insensitive) 'relatedActivityId' then skip it.
- if (args.Length > 0 && args[0].ParameterType == typeof(Guid) &&
- string.Equals(args[0].Name, "relatedActivityId", StringComparison.OrdinalIgnoreCase))
- {
- var newargs = new ParameterInfo[args.Length - 1];
- Array.Copy(args, 1, newargs, 0, args.Length - 1);
- args = newargs;
-
- return true;
- }
-
- return false;
- }
-
- // adds a enumeration (keyword, opcode, task or channel) represented by 'staticField'
- // to the manifest.
- private static void AddProviderEnumKind(ManifestBuilder manifest, FieldInfo staticField, string providerEnumKind)
- {
- bool reflectionOnly = staticField.Module.Assembly.ReflectionOnly();
- Type staticFieldType = staticField.FieldType;
- if (!reflectionOnly && (staticFieldType == typeof(EventOpcode)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventOpcode)))
- {
- if (providerEnumKind != "Opcodes") goto Error;
- int value = (int)staticField.GetRawConstantValue()!;
- manifest.AddOpcode(staticField.Name, value);
- }
- else if (!reflectionOnly && (staticFieldType == typeof(EventTask)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventTask)))
- {
- if (providerEnumKind != "Tasks") goto Error;
- int value = (int)staticField.GetRawConstantValue()!;
- manifest.AddTask(staticField.Name, value);
- }
- else if (!reflectionOnly && (staticFieldType == typeof(EventKeywords)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventKeywords)))
- {
- if (providerEnumKind != "Keywords") goto Error;
- ulong value = unchecked((ulong)(long)staticField.GetRawConstantValue()!);
- manifest.AddKeyword(staticField.Name, value);
- }
-#if FEATURE_MANAGED_ETW_CHANNELS && FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- else if (!reflectionOnly && (staticFieldType == typeof(EventChannel)) || AttributeTypeNamesMatch(staticFieldType, typeof(EventChannel)))
- {
- if (providerEnumKind != "Channels") goto Error;
- var channelAttribute = (EventChannelAttribute)GetCustomAttributeHelper(staticField, typeof(EventChannelAttribute));
- manifest.AddChannel(staticField.Name, (byte)staticField.GetRawConstantValue(), channelAttribute);
- }
-#endif
- return;
- Error:
- manifest.ManifestError(SR.Format(SR.EventSource_EnumKindMismatch, staticField.Name, staticField.FieldType.Name, providerEnumKind));
- }
-
- // Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method
- // with the code:EventAttribute 'eventAttribute'. resourceManger may be null in which case we populate it
- // it is populated if we need to look up message resources
- private static void AddEventDescriptor(
- [NotNull] ref EventMetadata[] eventData,
- string eventName,
- EventAttribute eventAttribute,
- ParameterInfo[] eventParameters,
- bool hasRelatedActivityID)
- {
- if (eventData.Length <= eventAttribute.EventId)
- {
- EventMetadata[] newValues = new EventMetadata[Math.Max(eventData.Length + 16, eventAttribute.EventId + 1)];
- Array.Copy(eventData, newValues, eventData.Length);
- eventData = newValues;
- }
-
- eventData[eventAttribute.EventId].Descriptor = new EventDescriptor(
- eventAttribute.EventId,
- eventAttribute.Version,
-#if FEATURE_MANAGED_ETW_CHANNELS
- (byte)eventAttribute.Channel,
-#else
- (byte)0,
-#endif
- (byte)eventAttribute.Level,
- (byte)eventAttribute.Opcode,
- (int)eventAttribute.Task,
- unchecked((long)((ulong)eventAttribute.Keywords | SessionMask.All.ToEventKeywords())));
-
- eventData[eventAttribute.EventId].Tags = eventAttribute.Tags;
- eventData[eventAttribute.EventId].Name = eventName;
- eventData[eventAttribute.EventId].Parameters = eventParameters;
- eventData[eventAttribute.EventId].Message = eventAttribute.Message;
- eventData[eventAttribute.EventId].ActivityOptions = eventAttribute.ActivityOptions;
- eventData[eventAttribute.EventId].HasRelatedActivityID = hasRelatedActivityID;
- eventData[eventAttribute.EventId].EventHandle = IntPtr.Zero;
- }
-
- // Helper used by code:CreateManifestAndDescriptors that trims the m_eventData array to the correct
- // size after all event descriptors have been added.
- private static void TrimEventDescriptors(ref EventMetadata[] eventData)
- {
- int idx = eventData.Length;
- while (0 < idx)
- {
- --idx;
- if (eventData[idx].Descriptor.EventId != 0)
- break;
- }
- if (eventData.Length - idx > 2) // allow one wasted slot.
- {
- EventMetadata[] newValues = new EventMetadata[idx + 1];
- Array.Copy(eventData, newValues, newValues.Length);
- eventData = newValues;
- }
- }
-
- // Helper used by code:EventListener.AddEventSource and code:EventListener.EventListener
- // when a listener gets attached to a eventSource
- internal void AddListener(EventListener listener)
- {
- lock (EventListener.EventListenersLock)
- {
- bool[]? enabledArray = null;
- if (m_eventData != null)
- enabledArray = new bool[m_eventData.Length];
- m_Dispatchers = new EventDispatcher(m_Dispatchers, enabledArray, listener);
- listener.OnEventSourceCreated(this);
- }
- }
-
- // Helper used by code:CreateManifestAndDescriptors to find user mistakes like reusing an event
- // index for two distinct events etc. Throws exceptions when it finds something wrong.
- private static void DebugCheckEvent(ref Dictionary<string, string>? eventsByName,
- EventMetadata[] eventData, MethodInfo method, EventAttribute eventAttribute,
- ManifestBuilder manifest, EventManifestOptions options)
- {
- int evtId = eventAttribute.EventId;
- string evtName = method.Name;
- int eventArg = GetHelperCallFirstArg(method);
- if (eventArg >= 0 && evtId != eventArg)
- {
- manifest.ManifestError(SR.Format(SR.EventSource_MismatchIdToWriteEvent, evtName, evtId, eventArg), true);
- }
-
- if (evtId < eventData.Length && eventData[evtId].Descriptor.EventId != 0)
- {
- manifest.ManifestError(SR.Format(SR.EventSource_EventIdReused, evtName, evtId, eventData[evtId].Name), true);
- }
-
- // We give a task to things if they don't have one.
- // TODO this is moderately expensive (N*N). We probably should not even bother....
- Debug.Assert(eventAttribute.Task != EventTask.None || eventAttribute.Opcode != EventOpcode.Info);
- for (int idx = 0; idx < eventData.Length; ++idx)
- {
- // skip unused Event IDs.
- if (eventData[idx].Name == null)
- continue;
-
- if (eventData[idx].Descriptor.Task == (int)eventAttribute.Task && eventData[idx].Descriptor.Opcode == (int)eventAttribute.Opcode)
- {
- manifest.ManifestError(SR.Format(SR.EventSource_TaskOpcodePairReused,
- evtName, evtId, eventData[idx].Name, idx));
- // If we are not strict stop on first error. We have had problems with really large providers taking forever. because of many errors.
- if ((options & EventManifestOptions.Strict) == 0)
- break;
- }
- }
-
- // for non-default event opcodes the user must define a task!
- if (eventAttribute.Opcode != EventOpcode.Info)
- {
- bool failure = false;
- if (eventAttribute.Task == EventTask.None)
- failure = true;
- else
- {
- // If you have the auto-assigned Task, then you did not explicitly set one.
- // This is OK for Start events because we have special logic to assign the task to a prefix derived from the event name
- // But all other cases we want to catch the omission.
- var autoAssignedTask = (EventTask)(0xFFFE - evtId);
- if (eventAttribute.Opcode != EventOpcode.Start && eventAttribute.Opcode != EventOpcode.Stop && eventAttribute.Task == autoAssignedTask)
- failure = true;
- }
- if (failure)
- {
- manifest.ManifestError(SR.Format(SR.EventSource_EventMustHaveTaskIfNonDefaultOpcode, evtName, evtId));
- }
- }
-
- // If we ever want to enforce the rule: MethodName = TaskName + OpcodeName here's how:
- // (the reason we don't is backwards compat and the need for handling this as a non-fatal error
- // by eventRegister.exe)
- // taskName & opcodeName could be passed in by the caller which has opTab & taskTab handy
- // if (!(((int)eventAttribute.Opcode == 0 && evtName == taskName) || (evtName == taskName+opcodeName)))
- // {
- // throw new WarningException(SR.EventSource_EventNameDoesNotEqualTaskPlusOpcode);
- // }
-
- eventsByName ??= new Dictionary<string, string>();
-
- if (eventsByName.ContainsKey(evtName))
- {
- manifest.ManifestError(SR.Format(SR.EventSource_EventNameReused, evtName), true);
- }
-
- eventsByName[evtName] = evtName;
- }
-
- /// <summary>
- /// This method looks at the IL and tries to pattern match against the standard
- /// 'boilerplate' event body
- /// <code>
- /// { if (Enabled()) WriteEvent(#, ...) }
- /// </code>
- /// If the pattern matches, it returns the literal number passed as the first parameter to
- /// the WriteEvent. This is used to find common user errors (mismatching this
- /// number with the EventAttribute ID). It is only used for validation.
- /// </summary>
- /// <param name="method">The method to probe.</param>
- /// <returns>The literal value or -1 if the value could not be determined. </returns>
- private static int GetHelperCallFirstArg(MethodInfo method)
- {
-#if (!ES_BUILD_PCL && !ES_BUILD_PN)
- // Currently searches for the following pattern
- //
- // ... // CAN ONLY BE THE INSTRUCTIONS BELOW
- // LDARG0
- // LDC.I4 XXX
- // ... // CAN ONLY BE THE INSTRUCTIONS BELOW CAN'T BE A BRANCH OR A CALL
- // CALL
- // NOP // 0 or more times
- // RET
- //
- // If we find this pattern we return the XXX. Otherwise we return -1.
-#if ES_BUILD_STANDALONE
- (new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)).Assert();
-#endif
- byte[] instrs = method.GetMethodBody()!.GetILAsByteArray()!;
- int retVal = -1;
- for (int idx = 0; idx < instrs.Length;)
- {
- switch (instrs[idx])
- {
- case 0: // NOP
- case 1: // BREAK
- case 2: // LDARG_0
- case 3: // LDARG_1
- case 4: // LDARG_2
- case 5: // LDARG_3
- case 6: // LDLOC_0
- case 7: // LDLOC_1
- case 8: // LDLOC_2
- case 9: // LDLOC_3
- case 10: // STLOC_0
- case 11: // STLOC_1
- case 12: // STLOC_2
- case 13: // STLOC_3
- break;
- case 14: // LDARG_S
- case 16: // STARG_S
- idx++;
- break;
- case 20: // LDNULL
- break;
- case 21: // LDC_I4_M1
- case 22: // LDC_I4_0
- case 23: // LDC_I4_1
- case 24: // LDC_I4_2
- case 25: // LDC_I4_3
- case 26: // LDC_I4_4
- case 27: // LDC_I4_5
- case 28: // LDC_I4_6
- case 29: // LDC_I4_7
- case 30: // LDC_I4_8
- if (idx > 0 && instrs[idx - 1] == 2) // preceeded by LDARG0
- retVal = instrs[idx] - 22;
- break;
- case 31: // LDC_I4_S
- if (idx > 0 && instrs[idx - 1] == 2) // preceeded by LDARG0
- retVal = instrs[idx + 1];
- idx++;
- break;
- case 32: // LDC_I4
- idx += 4;
- break;
- case 37: // DUP
- break;
- case 40: // CALL
- idx += 4;
-
- if (retVal >= 0)
- {
- // Is this call just before return?
- for (int search = idx + 1; search < instrs.Length; search++)
- {
- if (instrs[search] == 42) // RET
- return retVal;
- if (instrs[search] != 0) // NOP
- break;
- }
- }
- retVal = -1;
- break;
- case 44: // BRFALSE_S
- case 45: // BRTRUE_S
- retVal = -1;
- idx++;
- break;
- case 57: // BRFALSE
- case 58: // BRTRUE
- retVal = -1;
- idx += 4;
- break;
- case 103: // CONV_I1
- case 104: // CONV_I2
- case 105: // CONV_I4
- case 106: // CONV_I8
- case 109: // CONV_U4
- case 110: // CONV_U8
- break;
- case 140: // BOX
- case 141: // NEWARR
- idx += 4;
- break;
- case 162: // STELEM_REF
- break;
- case 254: // PREFIX
- idx++;
- // Covers the CEQ instructions used in debug code for some reason.
- if (idx >= instrs.Length || instrs[idx] >= 6)
- goto default;
- break;
- default:
- /* Debug.Fail("Warning: User validation code sub-optimial: Unsuported opcode " + instrs[idx] +
- " at " + idx + " in method " + method.Name); */
- return -1;
- }
- idx++;
- }
-#endif
- return -1;
- }
-
- /// <summary>
- /// Sends an error message to the debugger (outputDebugString), as well as the EventListeners
- /// It will do this even if the EventSource is not enabled.
- /// </summary>
- internal void ReportOutOfBandMessage(string msg)
- {
- try
- {
-#if (!ES_BUILD_PCL && !ES_BUILD_PN)
- // send message to debugger without delay
- System.Diagnostics.Debugger.Log(0, null, string.Format("EventSource Error: {0}{1}", msg, Environment.NewLine));
-#endif
-
- // Send it to all listeners.
- if (m_outOfBandMessageCount < 16 - 1) // Note this is only if size byte
- m_outOfBandMessageCount++;
- else
- {
- if (m_outOfBandMessageCount == 16)
- return;
- m_outOfBandMessageCount = 16; // Mark that we hit the limit. Notify them that this is the case.
- msg = "Reached message limit. End of EventSource error messages.";
- }
-
- WriteEventString(EventLevel.LogAlways, -1, msg);
- WriteStringToAllListeners("EventSourceMessage", msg);
- }
- catch { } // If we fail during last chance logging, well, we have to give up....
- }
-
- private EventSourceSettings ValidateSettings(EventSourceSettings settings)
- {
- const EventSourceSettings evtFormatMask = EventSourceSettings.EtwManifestEventFormat |
- EventSourceSettings.EtwSelfDescribingEventFormat;
- if ((settings & evtFormatMask) == evtFormatMask)
- {
- throw new ArgumentException(SR.EventSource_InvalidEventFormat, nameof(settings));
- }
-
- // If you did not explicitly ask for manifest, you get self-describing.
- if ((settings & evtFormatMask) == 0)
- settings |= EventSourceSettings.EtwSelfDescribingEventFormat;
- return settings;
- }
-
- private bool ThrowOnEventWriteErrors => (m_config & EventSourceSettings.ThrowOnEventWriteErrors) != 0;
-
- private bool SelfDescribingEvents
- {
- get
- {
- Debug.Assert(((m_config & EventSourceSettings.EtwManifestEventFormat) != 0) !=
- ((m_config & EventSourceSettings.EtwSelfDescribingEventFormat) != 0));
- return (m_config & EventSourceSettings.EtwSelfDescribingEventFormat) != 0;
- }
- }
-
- // private instance state
- private string m_name = null!; // My friendly name (privided in ctor)
- internal int m_id; // A small integer that is unique to this instance.
- private Guid m_guid; // GUID representing the ETW eventSource to the OS.
- internal volatile EventMetadata[]? m_eventData; // None per-event data
- private volatile byte[]? m_rawManifest; // Bytes to send out representing the event schema
-
- private EventHandler<EventCommandEventArgs>? m_eventCommandExecuted;
-
- private readonly EventSourceSettings m_config; // configuration information
-
- private bool m_eventSourceDisposed; // has Dispose been called.
-
- // Enabling bits
- private bool m_eventSourceEnabled; // am I enabled (any of my events are enabled for any dispatcher)
- internal EventLevel m_level; // highest level enabled by any output dispatcher
- internal EventKeywords m_matchAnyKeyword; // the logical OR of all levels enabled by any output dispatcher (zero is a special case) meaning 'all keywords'
-
- // Dispatching state
- internal volatile EventDispatcher? m_Dispatchers; // Linked list of code:EventDispatchers we write the data to (we also do ETW specially)
-#if FEATURE_MANAGED_ETW
- private volatile OverideEventProvider m_etwProvider = null!; // This hooks up ETW commands to our 'OnEventCommand' callback
-#endif
-#if FEATURE_PERFTRACING
- private volatile OverideEventProvider m_eventPipeProvider = null!;
-#endif
- private bool m_completelyInited; // The EventSource constructor has returned without exception.
- private Exception? m_constructionException; // If there was an exception construction, this is it
- private byte m_outOfBandMessageCount; // The number of out of band messages sent (we throttle them
- private EventCommandEventArgs? m_deferredCommands; // If we get commands before we are fully we store them here and run the when we are fully inited.
-
- private string[]? m_traits; // Used to implement GetTraits
-
- internal static uint s_currentPid; // current process id, used in synthesizing quasi-GUIDs
- [ThreadStatic]
- private static byte m_EventSourceExceptionRecurenceCount; // current recursion count inside ThrowEventSourceException
-
- [ThreadStatic]
- private static bool m_EventSourceInDecodeObject;
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- internal volatile ulong[]? m_channelData;
-#endif
-
- // We use a single instance of ActivityTracker for all EventSources instances to allow correlation between multiple event providers.
- // We have m_activityTracker field simply because instance field is more efficient than static field fetch.
- private ActivityTracker m_activityTracker = null!;
- internal const string s_ActivityStartSuffix = "Start";
- internal const string s_ActivityStopSuffix = "Stop";
-
- // WARNING: Do not depend upon initialized statics during creation of EventSources, as it is possible for creation of an EventSource to trigger
- // creation of yet another EventSource. When this happens, these statics may not yet be initialized.
- // Rather than depending on initialized statics, use lazy initialization to ensure that the statics are initialized exactly when they are needed.
-
- // used for generating GUID from eventsource name
- private static byte[]? namespaceBytes;
-
-#endregion
- }
-
- /// <summary>
- /// Enables specifying event source configuration options to be used in the EventSource constructor.
- /// </summary>
- [Flags]
- public enum EventSourceSettings
- {
- /// <summary>
- /// This specifies none of the special configuration options should be enabled.
- /// </summary>
- Default = 0,
- /// <summary>
- /// Normally an EventSource NEVER throws; setting this option will tell it to throw when it encounters errors.
- /// </summary>
- ThrowOnEventWriteErrors = 1,
- /// <summary>
- /// Setting this option is a directive to the ETW listener should use manifest-based format when
- /// firing events. This is the default option when defining a type derived from EventSource
- /// (using the protected EventSource constructors).
- /// Only one of EtwManifestEventFormat or EtwSelfDescribingEventFormat should be specified
- /// </summary>
- EtwManifestEventFormat = 4,
- /// <summary>
- /// Setting this option is a directive to the ETW listener should use self-describing event format
- /// when firing events. This is the default option when creating a new instance of the EventSource
- /// type (using the public EventSource constructors).
- /// Only one of EtwManifestEventFormat or EtwSelfDescribingEventFormat should be specified
- /// </summary>
- EtwSelfDescribingEventFormat = 8,
- }
-
- /// <summary>
- /// An EventListener represents a target for the events generated by EventSources (that is subclasses
- /// of <see cref="EventSource"/>), in the current appdomain. When a new EventListener is created
- /// it is logically attached to all eventSources in that appdomain. When the EventListener is Disposed, then
- /// it is disconnected from the event eventSources. Note that there is a internal list of STRONG references
- /// to EventListeners, which means that relying on the lack of references to EventListeners to clean up
- /// EventListeners will NOT work. You must call EventListener.Dispose explicitly when a dispatcher is no
- /// longer needed.
- /// <para>
- /// Once created, EventListeners can enable or disable on a per-eventSource basis using verbosity levels
- /// (<see cref="EventLevel"/>) and bitfields (<see cref="EventKeywords"/>) to further restrict the set of
- /// events to be sent to the dispatcher. The dispatcher can also send arbitrary commands to a particular
- /// eventSource using the 'SendCommand' method. The meaning of the commands are eventSource specific.
- /// </para><para>
- /// The Null Guid (that is (new Guid()) has special meaning as a wildcard for 'all current eventSources in
- /// the appdomain'. Thus it is relatively easy to turn on all events in the appdomain if desired.
- /// </para><para>
- /// It is possible for there to be many EventListener's defined in a single appdomain. Each dispatcher is
- /// logically independent of the other listeners. Thus when one dispatcher enables or disables events, it
- /// affects only that dispatcher (other listeners get the events they asked for). It is possible that
- /// commands sent with 'SendCommand' would do a semantic operation that would affect the other listeners
- /// (like doing a GC, or flushing data ...), but this is the exception rather than the rule.
- /// </para><para>
- /// Thus the model is that each EventSource keeps a list of EventListeners that it is sending events
- /// to. Associated with each EventSource-dispatcher pair is a set of filtering criteria that determine for
- /// that eventSource what events that dispatcher will receive.
- /// </para><para>
- /// Listeners receive the events on their 'OnEventWritten' method. Thus subclasses of EventListener must
- /// override this method to do something useful with the data.
- /// </para><para>
- /// In addition, when new eventSources are created, the 'OnEventSourceCreate' method is called. The
- /// invariant associated with this callback is that every eventSource gets exactly one
- /// 'OnEventSourceCreate' call for ever eventSource that can potentially send it log messages. In
- /// particular when a EventListener is created, typically a series of OnEventSourceCreate' calls are
- /// made to notify the new dispatcher of all the eventSources that existed before the EventListener was
- /// created.
- /// </para>
- /// </summary>
- public class EventListener : IDisposable
- {
- private event EventHandler<EventSourceCreatedEventArgs>? _EventSourceCreated;
-
- /// <summary>
- /// This event is raised whenever a new eventSource is 'attached' to the dispatcher.
- /// This can happen for all existing EventSources when the EventListener is created
- /// as well as for any EventSources that come into existence after the EventListener
- /// has been created.
- ///
- /// These 'catch up' events are called during the construction of the EventListener.
- /// Subclasses need to be prepared for that.
- ///
- /// In a multi-threaded environment, it is possible that 'EventSourceEventWrittenCallback'
- /// events for a particular eventSource to occur BEFORE the EventSourceCreatedCallback is issued.
- /// </summary>
- public event EventHandler<EventSourceCreatedEventArgs>? EventSourceCreated
- {
- add
- {
- CallBackForExistingEventSources(false, value);
-
- this._EventSourceCreated = (EventHandler<EventSourceCreatedEventArgs>?)Delegate.Combine(_EventSourceCreated, value);
- }
- remove
- {
- this._EventSourceCreated = (EventHandler<EventSourceCreatedEventArgs>?)Delegate.Remove(_EventSourceCreated, value);
- }
- }
-
- /// <summary>
- /// This event is raised whenever an event has been written by a EventSource for which
- /// the EventListener has enabled events.
- /// </summary>
- public event EventHandler<EventWrittenEventArgs>? EventWritten;
-
- static EventListener()
- {
-#if FEATURE_PERFTRACING
- // Ensure that NativeRuntimeEventSource is initialized so that EventListeners get an opportunity to subscribe to its events.
- // This is required because NativeRuntimeEventSource never emit events on its own, and thus will never be initialized
- // in the normal way that EventSources are initialized.
- GC.KeepAlive(NativeRuntimeEventSource.Log);
-#endif // FEATURE_PERFTRACING
- }
-
- /// <summary>
- /// Create a new EventListener in which all events start off turned off (use EnableEvents to turn
- /// them on).
- /// </summary>
- public EventListener()
- {
- // This will cause the OnEventSourceCreated callback to fire.
- CallBackForExistingEventSources(true, (obj, args) =>
- args.EventSource!.AddListener((EventListener)obj!));
- }
-
- /// <summary>
- /// Dispose should be called when the EventListener no longer desires 'OnEvent*' callbacks. Because
- /// there is an internal list of strong references to all EventListeners, calling 'Dispose' directly
- /// is the only way to actually make the listen die. Thus it is important that users of EventListener
- /// call Dispose when they are done with their logging.
- /// </summary>
-#if ES_BUILD_STANDALONE
-#endif
- public virtual void Dispose()
- {
- lock (EventListenersLock)
- {
- if (s_Listeners != null)
- {
- if (this == s_Listeners)
- {
- EventListener cur = s_Listeners;
- s_Listeners = this.m_Next;
- RemoveReferencesToListenerInEventSources(cur);
- }
- else
- {
- // Find 'this' from the s_Listeners linked list.
- EventListener prev = s_Listeners;
- while (true)
- {
- EventListener? cur = prev.m_Next;
- if (cur == null)
- break;
- if (cur == this)
- {
- // Found our Listener, remove references to it in the eventSources
- prev.m_Next = cur.m_Next; // Remove entry.
- RemoveReferencesToListenerInEventSources(cur);
- break;
- }
- prev = cur;
- }
- }
- }
- Validate();
- }
- }
- // We don't expose a Dispose(bool), because the contract is that you don't have any non-syncronous
- // 'cleanup' associated with this object
-
- /// <summary>
- /// Enable all events from the eventSource identified by 'eventSource' to the current
- /// dispatcher that have a verbosity level of 'level' or lower.
- ///
- /// This call can have the effect of REDUCING the number of events sent to the
- /// dispatcher if 'level' indicates a less verbose level than was previously enabled.
- ///
- /// This call never has an effect on other EventListeners.
- ///
- /// </summary>
- public void EnableEvents(EventSource eventSource, EventLevel level)
- {
- EnableEvents(eventSource, level, EventKeywords.None);
- }
- /// <summary>
- /// Enable all events from the eventSource identified by 'eventSource' to the current
- /// dispatcher that have a verbosity level of 'level' or lower and have a event keyword
- /// matching any of the bits in 'matchAnyKeyword'.
- ///
- /// This call can have the effect of REDUCING the number of events sent to the
- /// dispatcher if 'level' indicates a less verbose level than was previously enabled or
- /// if 'matchAnyKeyword' has fewer keywords set than where previously set.
- ///
- /// This call never has an effect on other EventListeners.
- /// </summary>
- public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword)
- {
- EnableEvents(eventSource, level, matchAnyKeyword, null);
- }
- /// <summary>
- /// Enable all events from the eventSource identified by 'eventSource' to the current
- /// dispatcher that have a verbosity level of 'level' or lower and have a event keyword
- /// matching any of the bits in 'matchAnyKeyword' as well as any (eventSource specific)
- /// effect passing additional 'key-value' arguments 'arguments' might have.
- ///
- /// This call can have the effect of REDUCING the number of events sent to the
- /// dispatcher if 'level' indicates a less verbose level than was previously enabled or
- /// if 'matchAnyKeyword' has fewer keywords set than where previously set.
- ///
- /// This call never has an effect on other EventListeners.
- /// </summary>
- public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword, IDictionary<string, string?>? arguments)
- {
- if (eventSource == null)
- {
- throw new ArgumentNullException(nameof(eventSource));
- }
-
- eventSource.SendCommand(this, EventProviderType.None, 0, 0, EventCommand.Update, true, level, matchAnyKeyword, arguments);
-
-#if FEATURE_PERFTRACING
- if (eventSource.GetType() == typeof(NativeRuntimeEventSource))
- {
- EventPipeEventDispatcher.Instance.SendCommand(this, EventCommand.Update, true, level, matchAnyKeyword);
- }
-#endif // FEATURE_PERFTRACING
- }
- /// <summary>
- /// Disables all events coming from eventSource identified by 'eventSource'.
- ///
- /// This call never has an effect on other EventListeners.
- /// </summary>
- public void DisableEvents(EventSource eventSource)
- {
- if (eventSource == null)
- {
- throw new ArgumentNullException(nameof(eventSource));
- }
-
- eventSource.SendCommand(this, EventProviderType.None, 0, 0, EventCommand.Update, false, EventLevel.LogAlways, EventKeywords.None, null);
-
-#if FEATURE_PERFTRACING
- if (eventSource.GetType() == typeof(NativeRuntimeEventSource))
- {
- EventPipeEventDispatcher.Instance.SendCommand(this, EventCommand.Update, false, EventLevel.LogAlways, EventKeywords.None);
- }
-#endif // FEATURE_PERFTRACING
- }
-
- /// <summary>
- /// EventSourceIndex is small non-negative integer (suitable for indexing in an array)
- /// identifying EventSource. It is unique per-appdomain. Some EventListeners might find
- /// it useful to store additional information about each eventSource connected to it,
- /// and EventSourceIndex allows this extra information to be efficiently stored in a
- /// (growable) array (eg List(T)).
- /// </summary>
- public static int EventSourceIndex(EventSource eventSource) { return eventSource.m_id; }
-
- /// <summary>
- /// This method is called whenever a new eventSource is 'attached' to the dispatcher.
- /// This can happen for all existing EventSources when the EventListener is created
- /// as well as for any EventSources that come into existence after the EventListener
- /// has been created.
- ///
- /// These 'catch up' events are called during the construction of the EventListener.
- /// Subclasses need to be prepared for that.
- ///
- /// In a multi-threaded environment, it is possible that 'OnEventWritten' callbacks
- /// for a particular eventSource to occur BEFORE the OnEventSourceCreated is issued.
- /// </summary>
- /// <param name="eventSource"></param>
- protected internal virtual void OnEventSourceCreated(EventSource eventSource)
- {
- EventHandler<EventSourceCreatedEventArgs>? callBack = this._EventSourceCreated;
- if (callBack != null)
- {
- EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
- args.EventSource = eventSource;
- callBack(this, args);
- }
- }
-
- /// <summary>
- /// This method is called whenever an event has been written by a EventSource for which
- /// the EventListener has enabled events.
- /// </summary>
- /// <param name="eventData"></param>
- protected internal virtual void OnEventWritten(EventWrittenEventArgs eventData)
- {
- this.EventWritten?.Invoke(this, eventData);
- }
-
-#region private
- /// <summary>
- /// This routine adds newEventSource to the global list of eventSources, it also assigns the
- /// ID to the eventSource (which is simply the ordinal in the global list).
- ///
- /// EventSources currently do not pro-actively remove themselves from this list. Instead
- /// when eventSources's are GCed, the weak handle in this list naturally gets nulled, and
- /// we will reuse the slot. Today this list never shrinks (but we do reuse entries
- /// that are in the list). This seems OK since the expectation is that EventSources
- /// tend to live for the lifetime of the appdomain anyway (they tend to be used in
- /// global variables).
- /// </summary>
- /// <param name="newEventSource"></param>
- internal static void AddEventSource(EventSource newEventSource)
- {
- lock (EventListenersLock)
- {
- s_EventSources ??= new List<WeakReference<EventSource>>(2);
-
- if (!s_EventSourceShutdownRegistered)
- {
- s_EventSourceShutdownRegistered = true;
-#if ES_BUILD_STANDALONE
- AppDomain.CurrentDomain.ProcessExit += DisposeOnShutdown;
- AppDomain.CurrentDomain.DomainUnload += DisposeOnShutdown;
-#else
- AppContext.ProcessExit += DisposeOnShutdown;
-#endif
- }
-
- // Periodically search the list for existing entries to reuse, this avoids
- // unbounded memory use if we keep recycling eventSources (an unlikely thing).
- int newIndex = -1;
- if (s_EventSources.Count % 64 == 63) // on every block of 64, fill up the block before continuing
- {
- int i = s_EventSources.Count; // Work from the top down.
- while (0 < i)
- {
- --i;
- WeakReference<EventSource> weakRef = s_EventSources[i];
- if (!weakRef.TryGetTarget(out _))
- {
- newIndex = i;
- weakRef.SetTarget(newEventSource);
- break;
- }
- }
- }
- if (newIndex < 0)
- {
- newIndex = s_EventSources.Count;
- s_EventSources.Add(new WeakReference<EventSource>(newEventSource));
- }
- newEventSource.m_id = newIndex;
-
-#if DEBUG
- // Disable validation of EventSource/EventListener connections in case a call to EventSource.AddListener
- // causes a recursive call into this method.
- bool previousValue = s_ConnectingEventSourcesAndListener;
- s_ConnectingEventSourcesAndListener = true;
- try
- {
-#endif
- // Add every existing dispatcher to the new EventSource
- for (EventListener? listener = s_Listeners; listener != null; listener = listener.m_Next)
- newEventSource.AddListener(listener);
-#if DEBUG
- }
- finally
- {
- s_ConnectingEventSourcesAndListener = previousValue;
- }
-#endif
-
- Validate();
- }
- }
-
- // Whenver we have async callbacks from native code, there is an ugly issue where
- // during .NET shutdown native code could be calling the callback, but the CLR
- // has already prohibited callbacks to managed code in the appdomain, causing the CLR
- // to throw a COMPLUS_BOOT_EXCEPTION. The guideline we give is that you must unregister
- // such callbacks on process shutdown or appdomain so that unmanaged code will never
- // do this. This is what this callback is for.
- // See bug 724140 for more
- private static void DisposeOnShutdown(object? sender, EventArgs e)
- {
- lock (EventListenersLock)
- {
- Debug.Assert(s_EventSources != null);
- foreach (WeakReference<EventSource> esRef in s_EventSources)
- {
- if (esRef.TryGetTarget(out EventSource? es))
- es.Dispose();
- }
- }
- }
-
- /// <summary>
- /// Helper used in code:Dispose that removes any references to 'listenerToRemove' in any of the
- /// eventSources in the appdomain.
- ///
- /// The EventListenersLock must be held before calling this routine.
- /// </summary>
- private static void RemoveReferencesToListenerInEventSources(EventListener listenerToRemove)
- {
-#if !ES_BUILD_STANDALONE
- Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
-#endif
- // Foreach existing EventSource in the appdomain
- Debug.Assert(s_EventSources != null);
- foreach (WeakReference<EventSource> eventSourceRef in s_EventSources)
- {
- if (eventSourceRef.TryGetTarget(out EventSource? eventSource))
- {
- Debug.Assert(eventSource.m_Dispatchers != null);
- // Is the first output dispatcher the dispatcher we are removing?
- if (eventSource.m_Dispatchers.m_Listener == listenerToRemove)
- eventSource.m_Dispatchers = eventSource.m_Dispatchers.m_Next;
- else
- {
- // Remove 'listenerToRemove' from the eventSource.m_Dispatchers linked list.
- EventDispatcher? prev = eventSource.m_Dispatchers;
- while (true)
- {
- EventDispatcher? cur = prev.m_Next;
- if (cur == null)
- {
- Debug.Fail("EventSource did not have a registered EventListener!");
- break;
- }
- if (cur.m_Listener == listenerToRemove)
- {
- prev.m_Next = cur.m_Next; // Remove entry.
- break;
- }
- prev = cur;
- }
- }
- }
- }
-
-#if FEATURE_PERFTRACING
- // Remove the listener from the EventPipe dispatcher.
- EventPipeEventDispatcher.Instance.RemoveEventListener(listenerToRemove);
-#endif // FEATURE_PERFTRACING
- }
-
- /// <summary>
- /// Checks internal consistency of EventSources/Listeners.
- /// </summary>
- [Conditional("DEBUG")]
- internal static void Validate()
- {
-#if DEBUG
- // Don't run validation code if we're in the middle of modifying the connections between EventSources and EventListeners.
- if (s_ConnectingEventSourcesAndListener)
- {
- return;
- }
-#endif
-
- lock (EventListenersLock)
- {
- Debug.Assert(s_EventSources != null);
- // Get all listeners
- Dictionary<EventListener, bool> allListeners = new Dictionary<EventListener, bool>();
- EventListener? cur = s_Listeners;
- while (cur != null)
- {
- allListeners.Add(cur, true);
- cur = cur.m_Next;
- }
-
- // For all eventSources
- int id = -1;
- foreach (WeakReference<EventSource> eventSourceRef in s_EventSources)
- {
- id++;
- if (!eventSourceRef.TryGetTarget(out EventSource? eventSource))
- continue;
- Debug.Assert(eventSource.m_id == id, "Unexpected event source ID.");
-
- // None listeners on eventSources exist in the dispatcher list.
- EventDispatcher? dispatcher = eventSource.m_Dispatchers;
- while (dispatcher != null)
- {
- Debug.Assert(allListeners.ContainsKey(dispatcher.m_Listener), "EventSource has a listener not on the global list.");
- dispatcher = dispatcher.m_Next;
- }
-
- // Every dispatcher is on Dispatcher List of every eventSource.
- foreach (EventListener listener in allListeners.Keys)
- {
- dispatcher = eventSource.m_Dispatchers;
- while (true)
- {
- Debug.Assert(dispatcher != null, "Listener is not on all eventSources.");
- if (dispatcher.m_Listener == listener)
- break;
- dispatcher = dispatcher.m_Next;
- }
- }
- }
- }
- }
-
- /// <summary>
- /// Gets a global lock that is intended to protect the code:s_Listeners linked list and the
- /// code:s_EventSources list. (We happen to use the s_EventSources list as the lock object)
- /// </summary>
- internal static object EventListenersLock
- {
- get
- {
- if (s_EventSources == null)
- Interlocked.CompareExchange(ref s_EventSources, new List<WeakReference<EventSource>>(2), null);
- return s_EventSources;
- }
- }
-
- private void CallBackForExistingEventSources(bool addToListenersList, EventHandler<EventSourceCreatedEventArgs>? callback)
- {
- lock (EventListenersLock)
- {
- Debug.Assert(s_EventSources != null);
-
- // Disallow creating EventListener reentrancy.
- if (s_CreatingListener)
- {
- throw new InvalidOperationException(SR.EventSource_ListenerCreatedInsideCallback);
- }
-
- try
- {
- s_CreatingListener = true;
-
- if (addToListenersList)
- {
- // Add to list of listeners in the system, do this BEFORE firing the 'OnEventSourceCreated' so that
- // Those added sources see this listener.
- this.m_Next = s_Listeners;
- s_Listeners = this;
- }
-
- if (callback != null)
- {
- // Find all existing eventSources call OnEventSourceCreated to 'catchup'
- // Note that we DO have reentrancy here because 'AddListener' calls out to user code (via OnEventSourceCreated callback)
- // We tolerate this by iterating over a copy of the list here. New event sources will take care of adding listeners themselves
- // EventSources are not guaranteed to be added at the end of the s_EventSource list -- We re-use slots when a new source
- // is created.
- WeakReference<EventSource>[] eventSourcesSnapshot = s_EventSources.ToArray();
-
-#if DEBUG
- bool previousValue = s_ConnectingEventSourcesAndListener;
- s_ConnectingEventSourcesAndListener = true;
- try
- {
-#endif
- for (int i = 0; i < eventSourcesSnapshot.Length; i++)
- {
- WeakReference<EventSource> eventSourceRef = eventSourcesSnapshot[i];
- if (eventSourceRef.TryGetTarget(out EventSource? eventSource))
- {
- EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
- args.EventSource = eventSource;
- callback(this, args);
- }
- }
-#if DEBUG
- }
- finally
- {
- s_ConnectingEventSourcesAndListener = previousValue;
- }
-#endif
- }
-
- Validate();
- }
- finally
- {
- s_CreatingListener = false;
- }
- }
- }
-
- // Instance fields
- internal volatile EventListener? m_Next; // These form a linked list in s_Listeners
-
- // static fields
-
- /// <summary>
- /// The list of all listeners in the appdomain. Listeners must be explicitly disposed to remove themselves
- /// from this list. Note that EventSources point to their listener but NOT the reverse.
- /// </summary>
- internal static EventListener? s_Listeners;
- /// <summary>
- /// The list of all active eventSources in the appdomain. Note that eventSources do NOT
- /// remove themselves from this list this is a weak list and the GC that removes them may
- /// not have happened yet. Thus it can contain event sources that are dead (thus you have
- /// to filter those out.
- /// </summary>
- internal static List<WeakReference<EventSource>>? s_EventSources;
-
- /// <summary>
- /// Used to disallow reentrancy.
- /// </summary>
- private static bool s_CreatingListener = false;
-
-#if DEBUG
- /// <summary>
- /// Used to disable validation of EventSource and EventListener connectivity.
- /// This is needed when an EventListener is in the middle of being published to all EventSources
- /// and another EventSource is created as part of the process.
- /// </summary>
- [ThreadStatic]
- private static bool s_ConnectingEventSourcesAndListener;
-#endif
-
- /// <summary>
- /// Used to register AD/Process shutdown callbacks.
- /// </summary>
- private static bool s_EventSourceShutdownRegistered = false;
-#endregion
- }
-
- /// <summary>
- /// Passed to the code:EventSource.OnEventCommand callback
- /// </summary>
- public class EventCommandEventArgs : EventArgs
- {
- /// <summary>
- /// Gets the command for the callback.
- /// </summary>
- public EventCommand Command { get; internal set; }
-
- /// <summary>
- /// Gets the arguments for the callback.
- /// </summary>
- public IDictionary<string, string?>? Arguments { get; internal set; }
-
- /// <summary>
- /// Enables the event that has the specified identifier.
- /// </summary>
- /// <param name="eventId">Event ID of event to be enabled</param>
- /// <returns>true if eventId is in range</returns>
- public bool EnableEvent(int eventId)
- {
- if (Command != EventCommand.Enable && Command != EventCommand.Disable)
- throw new InvalidOperationException();
- return eventSource.EnableEventForDispatcher(dispatcher, eventProviderType, eventId, true);
- }
-
- /// <summary>
- /// Disables the event that have the specified identifier.
- /// </summary>
- /// <param name="eventId">Event ID of event to be disabled</param>
- /// <returns>true if eventId is in range</returns>
- public bool DisableEvent(int eventId)
- {
- if (Command != EventCommand.Enable && Command != EventCommand.Disable)
- throw new InvalidOperationException();
- return eventSource.EnableEventForDispatcher(dispatcher, eventProviderType, eventId, false);
- }
-
-#region private
-
- internal EventCommandEventArgs(EventCommand command, IDictionary<string, string?>? arguments, EventSource eventSource,
- EventListener? listener, EventProviderType eventProviderType, int perEventSourceSessionId, int etwSessionId, bool enable, EventLevel level, EventKeywords matchAnyKeyword)
- {
- this.Command = command;
- this.Arguments = arguments;
- this.eventSource = eventSource;
- this.listener = listener;
- this.eventProviderType = eventProviderType;
- this.perEventSourceSessionId = perEventSourceSessionId;
- this.etwSessionId = etwSessionId;
- this.enable = enable;
- this.level = level;
- this.matchAnyKeyword = matchAnyKeyword;
- }
-
- internal EventSource eventSource;
- internal EventDispatcher? dispatcher;
- internal EventProviderType eventProviderType;
-
- // These are the arguments of sendCommand and are only used for deferring commands until after we are fully initialized.
- internal EventListener? listener;
- internal int perEventSourceSessionId;
- internal int etwSessionId;
- internal bool enable;
- internal EventLevel level;
- internal EventKeywords matchAnyKeyword;
- internal EventCommandEventArgs? nextCommand; // We form a linked list of these deferred commands.
-
-#endregion
- }
-
- /// <summary>
- /// EventSourceCreatedEventArgs is passed to <see cref="EventListener.EventSourceCreated"/>
- /// </summary>
- public class EventSourceCreatedEventArgs : EventArgs
- {
- /// <summary>
- /// The EventSource that is attaching to the listener.
- /// </summary>
- public EventSource? EventSource
- {
- get;
- internal set;
- }
- }
-
- /// <summary>
- /// EventWrittenEventArgs is passed to the user-provided override for
- /// <see cref="EventListener.OnEventWritten"/> when an event is fired.
- /// </summary>
- public class EventWrittenEventArgs : EventArgs
- {
- /// <summary>
- /// The name of the event.
- /// </summary>
- public string? EventName
- {
- get
- {
- if (m_eventName != null || EventId < 0) // TraceLogging convention EventID == -1
- {
- return m_eventName;
- }
- else
- {
- Debug.Assert(m_eventSource.m_eventData != null);
- return m_eventSource.m_eventData[EventId].Name;
- }
- }
- internal set => m_eventName = value;
- }
-
- /// <summary>
- /// Gets the event ID for the event that was written.
- /// </summary>
- public int EventId { get; internal set; }
-
- /// <summary>
- /// Gets the activity ID for the thread on which the event was written.
- /// </summary>
- public Guid ActivityId
- {
- get
- {
- Guid activityId = m_activityId;
- if (activityId == Guid.Empty)
- {
- activityId = EventSource.CurrentThreadActivityId;
- }
-
- return activityId;
- }
- internal set => m_activityId = value;
- }
-
- /// <summary>
- /// Gets the related activity ID if one was specified when the event was written.
- /// </summary>
- public Guid RelatedActivityId
- {
- get;
- internal set;
- }
-
- /// <summary>
- /// Gets the payload for the event.
- /// </summary>
- public ReadOnlyCollection<object?>? Payload { get; internal set; }
-
- /// <summary>
- /// Gets the payload argument names.
- /// </summary>
- public ReadOnlyCollection<string>? PayloadNames
- {
- get
- {
- // For contract based events we create the list lazily.
- // You can have m_payloadNames be null in the TraceLogging case (EventID < 0) so only
- // do the lazy init if you know it is contract based (EventID >= 0)
- if (EventId >= 0 && m_payloadNames == null)
- {
- var names = new List<string>();
- Debug.Assert(m_eventSource.m_eventData != null);
- foreach (ParameterInfo parameter in m_eventSource.m_eventData[EventId].Parameters)
- {
- names.Add(parameter.Name!);
- }
-
- m_payloadNames = new ReadOnlyCollection<string>(names);
- }
-
- return m_payloadNames;
- }
-
- internal set => m_payloadNames = value;
- }
-
- /// <summary>
- /// Gets the event source object.
- /// </summary>
- public EventSource EventSource => m_eventSource;
-
- /// <summary>
- /// Gets the keywords for the event.
- /// </summary>
- public EventKeywords Keywords
- {
- get
- {
- if (EventId < 0) // TraceLogging convention EventID == -1
- return m_keywords;
-
- Debug.Assert(m_eventSource.m_eventData != null);
- return (EventKeywords)m_eventSource.m_eventData[EventId].Descriptor.Keywords;
- }
- }
-
- /// <summary>
- /// Gets the operation code for the event.
- /// </summary>
- public EventOpcode Opcode
- {
- get
- {
- if (EventId <= 0) // TraceLogging convention EventID == -1
- return m_opcode;
-
- Debug.Assert(m_eventSource.m_eventData != null);
- return (EventOpcode)m_eventSource.m_eventData[EventId].Descriptor.Opcode;
- }
- }
-
- /// <summary>
- /// Gets the task for the event.
- /// </summary>
- public EventTask Task
- {
- get
- {
- if (EventId <= 0) // TraceLogging convention EventID == -1
- return EventTask.None;
-
- Debug.Assert(m_eventSource.m_eventData != null);
- return (EventTask)m_eventSource.m_eventData[EventId].Descriptor.Task;
- }
- }
-
- /// <summary>
- /// Any provider/user defined options associated with the event.
- /// </summary>
- public EventTags Tags
- {
- get
- {
- if (EventId <= 0) // TraceLogging convention EventID == -1
- return m_tags;
-
- Debug.Assert(m_eventSource.m_eventData != null);
- return m_eventSource.m_eventData[EventId].Tags;
- }
- }
-
- /// <summary>
- /// Gets the message for the event. If the message has {N} parameters they are NOT substituted.
- /// </summary>
- public string? Message
- {
- get
- {
- if (EventId <= 0) // TraceLogging convention EventID == -1
- {
- return m_message;
- }
- else
- {
- Debug.Assert(m_eventSource.m_eventData != null);
- return m_eventSource.m_eventData[EventId].Message;
- }
- }
- internal set => m_message = value;
- }
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- /// <summary>
- /// Gets the channel for the event.
- /// </summary>
- public EventChannel Channel
- {
- get
- {
- if (EventId <= 0) // TraceLogging convention EventID == -1
- return EventChannel.None;
-
- Debug.Assert(m_eventSource.m_eventData != null);
- return (EventChannel)m_eventSource.m_eventData[EventId].Descriptor.Channel;
- }
- }
-#endif
-
- /// <summary>
- /// Gets the version of the event.
- /// </summary>
- public byte Version
- {
- get
- {
- if (EventId <= 0) // TraceLogging convention EventID == -1
- return 0;
-
- Debug.Assert(m_eventSource.m_eventData != null);
- return m_eventSource.m_eventData[EventId].Descriptor.Version;
- }
- }
-
- /// <summary>
- /// Gets the level for the event.
- /// </summary>
- public EventLevel Level
- {
- get
- {
- if (EventId <= 0) // TraceLogging convention EventID == -1
- return m_level;
-
- Debug.Assert(m_eventSource.m_eventData != null);
- return (EventLevel)m_eventSource.m_eventData[EventId].Descriptor.Level;
- }
- }
-
- /// <summary>
- /// Gets the identifier for the OS thread that wrote the event.
- /// </summary>
- public long OSThreadId
- {
- get
- {
- if (!m_osThreadId.HasValue)
- {
-#if ES_BUILD_STANDALONE
- m_osThreadId = (long)Interop.Kernel32.GetCurrentThreadId();
-#else
- m_osThreadId = (long)Thread.CurrentOSThreadId;
-#endif
- }
-
- return m_osThreadId.Value;
- }
- internal set => m_osThreadId = value;
- }
-
- /// <summary>
- /// Gets a UTC DateTime that specifies when the event was written.
- /// </summary>
- public DateTime TimeStamp
- {
- get;
- internal set;
- }
-
-#region private
- internal EventWrittenEventArgs(EventSource eventSource)
- {
- m_eventSource = eventSource;
- TimeStamp = DateTime.UtcNow;
- }
- private string? m_message;
- private string? m_eventName;
- private readonly EventSource m_eventSource;
- private ReadOnlyCollection<string>? m_payloadNames;
- private Guid m_activityId;
- private long? m_osThreadId;
- internal EventTags m_tags;
- internal EventOpcode m_opcode;
- internal EventLevel m_level;
- internal EventKeywords m_keywords;
-#endregion
- }
-
- /// <summary>
- /// Allows customizing defaults and specifying localization support for the event source class to which it is applied.
- /// </summary>
- [AttributeUsage(AttributeTargets.Class)]
- public sealed class EventSourceAttribute : Attribute
- {
- /// <summary>
- /// Overrides the ETW name of the event source (which defaults to the class name)
- /// </summary>
- public string? Name { get; set; }
-
- /// <summary>
- /// Overrides the default (calculated) Guid of an EventSource type. Explicitly defining a GUID is discouraged,
- /// except when upgrading existing ETW providers to using event sources.
- /// </summary>
- public string? Guid { get; set; }
-
- /// <summary>
- /// <para>
- /// EventSources support localization of events. The names used for events, opcodes, tasks, keywords and maps
- /// can be localized to several languages if desired. This works by creating a ResX style string table
- /// (by simply adding a 'Resource File' to your project). This resource file is given a name e.g.
- /// 'DefaultNameSpace.ResourceFileName' which can be passed to the ResourceManager constructor to read the
- /// resources. This name is the value of the LocalizationResources property.
- /// </para><para>
- /// If LocalizationResources property is non-null, then EventSource will look up the localized strings for events by
- /// using the following resource naming scheme
- /// </para>
- /// <para>* event_EVENTNAME</para>
- /// <para>* task_TASKNAME</para>
- /// <para>* keyword_KEYWORDNAME</para>
- /// <para>* map_MAPNAME</para>
- /// <para>
- /// where the capitalized name is the name of the event, task, keyword, or map value that should be localized.
- /// Note that the localized string for an event corresponds to the Message string, and can have {0} values
- /// which represent the payload values.
- /// </para>
- /// </summary>
- public string? LocalizationResources { get; set; }
- }
-
- /// <summary>
- /// Any instance methods in a class that subclasses <see cref="EventSource"/> and that return void are
- /// assumed by default to be methods that generate an ETW event. Enough information can be deduced from the
- /// name of the method and its signature to generate basic schema information for the event. The
- /// <see cref="EventAttribute"/> class allows you to specify additional event schema information for an event if
- /// desired.
- /// </summary>
- [AttributeUsage(AttributeTargets.Method)]
- public sealed class EventAttribute : Attribute
- {
- /// <summary>Construct an EventAttribute with specified eventId</summary>
- /// <param name="eventId">ID of the ETW event (an integer between 1 and 65535)</param>
- public EventAttribute(int eventId) { this.EventId = eventId; Level = EventLevel.Informational; this.m_opcodeSet = false; }
- /// <summary>Event's ID</summary>
- public int EventId { get; private set; }
- /// <summary>Event's severity level: indicates the severity or verbosity of the event</summary>
- public EventLevel Level { get; set; }
- /// <summary>Event's keywords: allows classification of events by "categories"</summary>
- public EventKeywords Keywords { get; set; }
- /// <summary>Event's operation code: allows defining operations, generally used with Tasks</summary>
- public EventOpcode Opcode
- {
- get => m_opcode;
- set
- {
- this.m_opcode = value;
- this.m_opcodeSet = true;
- }
- }
-
- internal bool IsOpcodeSet => m_opcodeSet;
-
- /// <summary>Event's task: allows logical grouping of events</summary>
- public EventTask Task { get; set; }
-#if FEATURE_MANAGED_ETW_CHANNELS
- /// <summary>Event's channel: defines an event log as an additional destination for the event</summary>
- public EventChannel Channel { get; set; }
-#endif
- /// <summary>Event's version</summary>
- public byte Version { get; set; }
-
- /// <summary>
- /// This can be specified to enable formatting and localization of the event's payload. You can
- /// use standard .NET substitution operators (eg {1}) in the string and they will be replaced
- /// with the 'ToString()' of the corresponding part of the event payload.
- /// </summary>
- public string? Message { get; set; }
-
- /// <summary>
- /// User defined options associated with the event. These do not have meaning to the EventSource but
- /// are passed through to listeners which given them semantics.
- /// </summary>
- public EventTags Tags { get; set; }
-
- /// <summary>
- /// Allows fine control over the Activity IDs generated by start and stop events
- /// </summary>
- public EventActivityOptions ActivityOptions { get; set; }
-
-#region private
- private EventOpcode m_opcode;
- private bool m_opcodeSet;
-#endregion
- }
-
- /// <summary>
- /// By default all instance methods in a class that subclasses code:EventSource that and return
- /// void are assumed to be methods that generate an event. This default can be overridden by specifying
- /// the code:NonEventAttribute
- /// </summary>
- [AttributeUsage(AttributeTargets.Method)]
- public sealed class NonEventAttribute : Attribute
- {
- /// <summary>
- /// Constructs a default NonEventAttribute
- /// </summary>
- public NonEventAttribute() { }
- }
-
- // FUTURE we may want to expose this at some point once we have a partner that can help us validate the design.
-#if FEATURE_MANAGED_ETW_CHANNELS
- /// <summary>
- /// EventChannelAttribute allows customizing channels supported by an EventSource. This attribute must be
- /// applied to an member of type EventChannel defined in a Channels class nested in the EventSource class:
- /// <code>
- /// public static class Channels
- /// {
- /// [Channel(Enabled = true, EventChannelType = EventChannelType.Admin)]
- /// public const EventChannel Admin = (EventChannel)16;
- ///
- /// [Channel(Enabled = false, EventChannelType = EventChannelType.Operational)]
- /// public const EventChannel Operational = (EventChannel)17;
- /// }
- /// </code>
- /// </summary>
- [AttributeUsage(AttributeTargets.Field)]
-#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- public
-#else
- internal
-#endif
- class EventChannelAttribute : Attribute
- {
- /// <summary>
- /// Specified whether the channel is enabled by default
- /// </summary>
- public bool Enabled { get; set; }
-
- /// <summary>
- /// Legal values are in EventChannelType
- /// </summary>
- public EventChannelType EventChannelType { get; set; }
-
-#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- /// <summary>
- /// Specifies the isolation for the channel
- /// </summary>
- public EventChannelIsolation Isolation { get; set; }
-
- /// <summary>
- /// Specifies an SDDL access descriptor that controls access to the log file that backs the channel.
- /// See MSDN (https://docs.microsoft.com/en-us/windows/desktop/WES/eventmanifestschema-channeltype-complextype) for details.
- /// </summary>
- public string? Access { get; set; }
-
- /// <summary>
- /// Allows importing channels defined in external manifests
- /// </summary>
- public string? ImportChannel { get; set; }
-#endif
-
- // TODO: there is a convention that the name is the Provider/Type Should we provide an override?
- // public string Name { get; set; }
- }
-
- /// <summary>
- /// Allowed channel types
- /// </summary>
-#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- public
-#else
- internal
-#endif
- enum EventChannelType
- {
- /// <summary>The admin channel</summary>
- Admin = 1,
- /// <summary>The operational channel</summary>
- Operational,
- /// <summary>The Analytic channel</summary>
- Analytic,
- /// <summary>The debug channel</summary>
- Debug,
- }
-
-#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- /// <summary>
- /// Allowed isolation levels. See MSDN (https://docs.microsoft.com/en-us/windows/desktop/WES/eventmanifestschema-channeltype-complextype)
- /// for the default permissions associated with each level. EventChannelIsolation and Access allows control over the
- /// access permissions for the channel and backing file.
- /// </summary>
- public
- enum EventChannelIsolation
- {
- /// <summary>
- /// This is the default isolation level. All channels that specify Application isolation use the same ETW session
- /// </summary>
- Application = 1,
- /// <summary>
- /// All channels that specify System isolation use the same ETW session
- /// </summary>
- System,
- /// <summary>
- /// Use sparingly! When specifying Custom isolation, a separate ETW session is created for the channel.
- /// Using Custom isolation lets you control the access permissions for the channel and backing file.
- /// Because there are only 64 ETW sessions available, you should limit your use of Custom isolation.
- /// </summary>
- Custom,
- }
-#endif
-#endif
-
- /// <summary>
- /// Describes the pre-defined command (EventCommandEventArgs.Command property) that is passed to the OnEventCommand callback.
- /// </summary>
- public enum EventCommand
- {
- /// <summary>
- /// Update EventSource state
- /// </summary>
- Update = 0,
- /// <summary>
- /// Request EventSource to generate and send its manifest
- /// </summary>
- SendManifest = -1,
- /// <summary>
- /// Enable event
- /// </summary>
- Enable = -2,
- /// <summary>
- /// Disable event
- /// </summary>
- Disable = -3
- }
-
-#region private classes
-
- // holds a bitfield representing a session mask
- /// <summary>
- /// A SessionMask represents a set of (at most MAX) sessions as a bit mask. The perEventSourceSessionId
- /// is the index in the SessionMask of the bit that will be set. These can translate to
- /// EventSource's reserved keywords bits using the provided ToEventKeywords() and
- /// FromEventKeywords() methods.
- /// </summary>
- internal struct SessionMask
- {
- public SessionMask(SessionMask m)
- { m_mask = m.m_mask; }
-
- public SessionMask(uint mask = 0)
- { m_mask = mask & MASK; }
-
- public bool IsEqualOrSupersetOf(SessionMask m)
- {
- return (this.m_mask | m.m_mask) == this.m_mask;
- }
-
- public static SessionMask All => new SessionMask(MASK);
-
- public static SessionMask FromId(int perEventSourceSessionId)
- {
- Debug.Assert(perEventSourceSessionId < MAX);
- return new SessionMask((uint)1 << perEventSourceSessionId);
- }
-
- public ulong ToEventKeywords()
- {
- return (ulong)m_mask << SHIFT_SESSION_TO_KEYWORD;
- }
-
- public static SessionMask FromEventKeywords(ulong m)
- {
- return new SessionMask((uint)(m >> SHIFT_SESSION_TO_KEYWORD));
- }
-
- public bool this[int perEventSourceSessionId]
- {
- get
- {
- Debug.Assert(perEventSourceSessionId < MAX);
- return (m_mask & (1 << perEventSourceSessionId)) != 0;
- }
- set
- {
- Debug.Assert(perEventSourceSessionId < MAX);
- if (value) m_mask |= ((uint)1 << perEventSourceSessionId);
- else m_mask &= ~((uint)1 << perEventSourceSessionId);
- }
- }
-
- public static SessionMask operator |(SessionMask m1, SessionMask m2) =>
- new SessionMask(m1.m_mask | m2.m_mask);
-
- public static SessionMask operator &(SessionMask m1, SessionMask m2) =>
- new SessionMask(m1.m_mask & m2.m_mask);
-
- public static SessionMask operator ^(SessionMask m1, SessionMask m2) =>
- new SessionMask(m1.m_mask ^ m2.m_mask);
-
- public static SessionMask operator ~(SessionMask m) =>
- new SessionMask(MASK & ~(m.m_mask));
-
- public static explicit operator ulong(SessionMask m) => m.m_mask;
-
- public static explicit operator uint(SessionMask m) => m.m_mask;
-
- private uint m_mask;
-
- internal const int SHIFT_SESSION_TO_KEYWORD = 44; // bits 44-47 inclusive are reserved
- internal const uint MASK = 0x0fU; // the mask of 4 reserved bits
- internal const uint MAX = 4; // maximum number of simultaneous ETW sessions supported
- }
-
- /// <summary>
- /// code:EventDispatchers are a simple 'helper' structure that holds the filtering state
- /// (m_EventEnabled) for a particular EventSource X EventListener tuple
- ///
- /// Thus a single EventListener may have many EventDispatchers (one for every EventSource
- /// that EventListener has activate) and a Single EventSource may also have many
- /// event Dispatchers (one for every EventListener that has activated it).
- ///
- /// Logically a particular EventDispatcher belongs to exactly one EventSource and exactly
- /// one EventListener (although EventDispatcher does not 'remember' the EventSource it is
- /// associated with.
- /// </summary>
- internal class EventDispatcher
- {
- internal EventDispatcher(EventDispatcher? next, bool[]? eventEnabled, EventListener listener)
- {
- m_Next = next;
- m_EventEnabled = eventEnabled;
- m_Listener = listener;
- }
-
- // Instance fields
- internal readonly EventListener m_Listener; // The dispatcher this entry is for
- internal bool[]? m_EventEnabled; // For every event in a the eventSource, is it enabled?
-
- // Only guaranteed to exist after a InsureInit()
- internal EventDispatcher? m_Next; // These form a linked list in code:EventSource.m_Dispatchers
- // Of all listeners for that eventSource.
- }
-
- /// <summary>
- /// Flags that can be used with EventSource.GenerateManifest to control how the ETW manifest for the EventSource is
- /// generated.
- /// </summary>
- [Flags]
- public enum EventManifestOptions
- {
- /// <summary>
- /// Only the resources associated with current UI culture are included in the manifest
- /// </summary>
- None = 0x0,
- /// <summary>
- /// Throw exceptions for any inconsistency encountered
- /// </summary>
- Strict = 0x1,
- /// <summary>
- /// Generate a "resources" node under "localization" for every satellite assembly provided
- /// </summary>
- AllCultures = 0x2,
- /// <summary>
- /// Generate the manifest only if the event source needs to be registered on the machine,
- /// otherwise return null (but still perform validation if Strict is specified)
- /// </summary>
- OnlyIfNeededForRegistration = 0x4,
- /// <summary>
- /// When generating the manifest do *not* enforce the rule that the current EventSource class
- /// must be the base class for the user-defined type passed in. This allows validation of .net
- /// event sources using the new validation code
- /// </summary>
- AllowEventSourceOverride = 0x8,
- }
-
- /// <summary>
- /// ManifestBuilder is designed to isolate the details of the message of the event from the
- /// rest of EventSource. This one happens to create XML.
- /// </summary>
- internal class ManifestBuilder
- {
- /// <summary>
- /// Build a manifest for 'providerName' with the given GUID, which will be packaged into 'dllName'.
- /// 'resources, is a resource manager. If specified all messages are localized using that manager.
- /// </summary>
- public ManifestBuilder(string providerName, Guid providerGuid, string? dllName, ResourceManager? resources,
- EventManifestOptions flags)
- {
-#if FEATURE_MANAGED_ETW_CHANNELS
- this.providerName = providerName;
-#endif
- this.flags = flags;
-
- this.resources = resources;
- sb = new StringBuilder();
- events = new StringBuilder();
- templates = new StringBuilder();
- opcodeTab = new Dictionary<int, string>();
- stringTab = new Dictionary<string, string>();
- errors = new List<string>();
- perEventByteArrayArgIndices = new Dictionary<string, List<int>>();
-
- sb.AppendLine("<instrumentationManifest xmlns=\"http://schemas.microsoft.com/win/2004/08/events\">");
- sb.AppendLine(" <instrumentation xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:win=\"http://manifests.microsoft.com/win/2004/08/windows/events\">");
- sb.AppendLine(" <events xmlns=\"http://schemas.microsoft.com/win/2004/08/events\">");
- sb.Append("<provider name=\"").Append(providerName).
- Append("\" guid=\"{").Append(providerGuid.ToString()).Append("}");
- if (dllName != null)
- sb.Append("\" resourceFileName=\"").Append(dllName).Append("\" messageFileName=\"").Append(dllName);
-
- string symbolsName = providerName.Replace("-", "").Replace('.', '_'); // Period and - are illegal replace them.
- sb.Append("\" symbol=\"").Append(symbolsName);
- sb.AppendLine("\">");
- }
-
- public void AddOpcode(string name, int value)
- {
- if ((flags & EventManifestOptions.Strict) != 0)
- {
- if (value <= 10 || value >= 239)
- {
- ManifestError(SR.Format(SR.EventSource_IllegalOpcodeValue, name, value));
- }
-
- if (opcodeTab.TryGetValue(value, out string? prevName) && !name.Equals(prevName, StringComparison.Ordinal))
- {
- ManifestError(SR.Format(SR.EventSource_OpcodeCollision, name, prevName, value));
- }
- }
-
- opcodeTab[value] = name;
- }
-
- public void AddTask(string name, int value)
- {
- if ((flags & EventManifestOptions.Strict) != 0)
- {
- if (value <= 0 || value >= 65535)
- {
- ManifestError(SR.Format(SR.EventSource_IllegalTaskValue, name, value));
- }
-
- if (taskTab != null && taskTab.TryGetValue(value, out string? prevName) && !name.Equals(prevName, StringComparison.Ordinal))
- {
- ManifestError(SR.Format(SR.EventSource_TaskCollision, name, prevName, value));
- }
- }
-
- taskTab ??= new Dictionary<int, string>();
- taskTab[value] = name;
- }
-
- public void AddKeyword(string name, ulong value)
- {
- if ((value & (value - 1)) != 0) // Is it a power of 2?
- {
- ManifestError(SR.Format(SR.EventSource_KeywordNeedPowerOfTwo, "0x" + value.ToString("x", CultureInfo.CurrentCulture), name), true);
- }
- if ((flags & EventManifestOptions.Strict) != 0)
- {
- if (value >= 0x0000100000000000UL && !name.StartsWith("Session", StringComparison.Ordinal))
- {
- ManifestError(SR.Format(SR.EventSource_IllegalKeywordsValue, name, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
- }
-
- if (keywordTab != null && keywordTab.TryGetValue(value, out string? prevName) && !name.Equals(prevName, StringComparison.Ordinal))
- {
- ManifestError(SR.Format(SR.EventSource_KeywordCollision, name, prevName, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
- }
- }
-
- keywordTab ??= new Dictionary<ulong, string>();
- keywordTab[value] = name;
- }
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- /// <summary>
- /// Add a channel. channelAttribute can be null
- /// </summary>
- public void AddChannel(string? name, int value, EventChannelAttribute? channelAttribute)
- {
- EventChannel chValue = (EventChannel)value;
- if (value < (int)EventChannel.Admin || value > 255)
- ManifestError(SR.Format(SR.EventSource_EventChannelOutOfRange, name, value));
- else if (chValue >= EventChannel.Admin && chValue <= EventChannel.Debug &&
- channelAttribute != null && EventChannelToChannelType(chValue) != channelAttribute.EventChannelType)
- {
- // we want to ensure developers do not define EventChannels that conflict with the builtin ones,
- // but we want to allow them to override the default ones...
- ManifestError(SR.Format(SR.EventSource_ChannelTypeDoesNotMatchEventChannelValue,
- name, ((EventChannel)value).ToString()));
- }
-
- // TODO: validate there are no conflicting manifest exposed names (generally following the format "provider/type")
-
- ulong kwd = GetChannelKeyword(chValue);
-
- channelTab ??= new Dictionary<int, ChannelInfo>(4);
- channelTab[value] = new ChannelInfo { Name = name, Keywords = kwd, Attribs = channelAttribute };
- }
-
- private static EventChannelType EventChannelToChannelType(EventChannel channel)
- {
-#if !ES_BUILD_STANDALONE
- Debug.Assert(channel >= EventChannel.Admin && channel <= EventChannel.Debug);
-#endif
- return (EventChannelType)((int)channel - (int)EventChannel.Admin + (int)EventChannelType.Admin);
- }
-
- private static EventChannelAttribute GetDefaultChannelAttribute(EventChannel channel)
- {
- EventChannelAttribute attrib = new EventChannelAttribute();
- attrib.EventChannelType = EventChannelToChannelType(channel);
- if (attrib.EventChannelType <= EventChannelType.Operational)
- attrib.Enabled = true;
- return attrib;
- }
-
- public ulong[] GetChannelData()
- {
- if (this.channelTab == null)
- {
- return Array.Empty<ulong>();
- }
-
- // We create an array indexed by the channel id for fast look up.
- // E.g. channelMask[Admin] will give you the bit mask for Admin channel.
- int maxkey = -1;
- foreach (int item in this.channelTab.Keys)
- {
- if (item > maxkey)
- {
- maxkey = item;
- }
- }
-
- ulong[] channelMask = new ulong[maxkey + 1];
- foreach (KeyValuePair<int, ChannelInfo> item in this.channelTab)
- {
- channelMask[item.Key] = item.Value.Keywords;
- }
-
- return channelMask;
- }
-
-#endif
- public void StartEvent(string eventName, EventAttribute eventAttribute)
- {
- Debug.Assert(numParams == 0);
- Debug.Assert(this.eventName == null);
- this.eventName = eventName;
- numParams = 0;
- byteArrArgIndices = null;
-
- events.Append(" <event").
- Append(" value=\"").Append(eventAttribute.EventId).Append("\"").
- Append(" version=\"").Append(eventAttribute.Version).Append("\"").
- Append(" level=\"").Append(GetLevelName(eventAttribute.Level)).Append("\"").
- Append(" symbol=\"").Append(eventName).Append("\"");
-
- // at this point we add to the manifest's stringTab a message that is as-of-yet
- // "untranslated to manifest convention", b/c we don't have the number or position
- // of any byte[] args (which require string format index updates)
- WriteMessageAttrib(events, "event", eventName, eventAttribute.Message);
-
- if (eventAttribute.Keywords != 0)
- events.Append(" keywords=\"").Append(GetKeywords((ulong)eventAttribute.Keywords, eventName)).Append("\"");
- if (eventAttribute.Opcode != 0)
- events.Append(" opcode=\"").Append(GetOpcodeName(eventAttribute.Opcode, eventName)).Append("\"");
- if (eventAttribute.Task != 0)
- events.Append(" task=\"").Append(GetTaskName(eventAttribute.Task, eventName)).Append("\"");
-#if FEATURE_MANAGED_ETW_CHANNELS
- if (eventAttribute.Channel != 0)
- {
- events.Append(" channel=\"").Append(GetChannelName(eventAttribute.Channel, eventName, eventAttribute.Message)).Append("\"");
- }
-#endif
- }
-
- public void AddEventParameter(Type type, string name)
- {
- if (numParams == 0)
- templates.Append(" <template tid=\"").Append(eventName).AppendLine("Args\">");
- if (type == typeof(byte[]))
- {
- // mark this index as "extraneous" (it has no parallel in the managed signature)
- // we use these values in TranslateToManifestConvention()
- byteArrArgIndices ??= new List<int>(4);
- byteArrArgIndices.Add(numParams);
-
- // add an extra field to the template representing the length of the binary blob
- numParams++;
- templates.Append(" <data name=\"").Append(name).AppendLine("Size\" inType=\"win:UInt32\"/>");
- }
- numParams++;
- templates.Append(" <data name=\"").Append(name).Append("\" inType=\"").Append(GetTypeName(type)).Append("\"");
- // TODO: for 'byte*' types it assumes the user provided length is named using the same naming convention
- // as for 'byte[]' args (blob_arg_name + "Size")
- if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte))
- {
- // add "length" attribute to the "blob" field in the template (referencing the field added above)
- templates.Append(" length=\"").Append(name).Append("Size\"");
- }
- // ETW does not support 64-bit value maps, so we don't specify these as ETW maps
- if (type.IsEnum() && Enum.GetUnderlyingType(type) != typeof(ulong) && Enum.GetUnderlyingType(type) != typeof(long))
- {
- templates.Append(" map=\"").Append(type.Name).Append("\"");
- mapsTab ??= new Dictionary<string, Type>();
- if (!mapsTab.ContainsKey(type.Name))
- mapsTab.Add(type.Name, type); // Remember that we need to dump the type enumeration
- }
-
- templates.AppendLine("/>");
- }
- public void EndEvent()
- {
- Debug.Assert(eventName != null);
-
- if (numParams > 0)
- {
- templates.AppendLine(" </template>");
- events.Append(" template=\"").Append(eventName).Append("Args\"");
- }
- events.AppendLine("/>");
-
- if (byteArrArgIndices != null)
- perEventByteArrayArgIndices[eventName] = byteArrArgIndices;
-
- // at this point we have all the information we need to translate the C# Message
- // to the manifest string we'll put in the stringTab
- if (stringTab.TryGetValue("event_" + eventName, out string? msg))
- {
- msg = TranslateToManifestConvention(msg, eventName);
- stringTab["event_" + eventName] = msg;
- }
-
- eventName = null;
- numParams = 0;
- byteArrArgIndices = null;
- }
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- // Channel keywords are generated one per channel to allow channel based filtering in event viewer. These keywords are autogenerated
- // by mc.exe for compiling a manifest and are based on the order of the channels (fields) in the Channels inner class (when advanced
- // channel support is enabled), or based on the order the predefined channels appear in the EventAttribute properties (for simple
- // support). The manifest generated *MUST* have the channels specified in the same order (that's how our computed keywords are mapped
- // to channels by the OS infrastructure).
- // If channelKeyworkds is present, and has keywords bits in the ValidPredefinedChannelKeywords then it is
- // assumed that the keyword for that channel should be that bit.
- // otherwise we allocate a channel bit for the channel.
- // explicit channel bits are only used by WCF to mimic an existing manifest,
- // so we don't dont do error checking.
- public ulong GetChannelKeyword(EventChannel channel, ulong channelKeyword = 0)
- {
- // strip off any non-channel keywords, since we are only interested in channels here.
- channelKeyword &= ValidPredefinedChannelKeywords;
- channelTab ??= new Dictionary<int, ChannelInfo>(4);
-
- if (channelTab.Count == MaxCountChannels)
- ManifestError(SR.EventSource_MaxChannelExceeded);
-
- ChannelInfo? info;
- if (!channelTab.TryGetValue((int)channel, out info))
- {
- // If we were not given an explicit channel, allocate one.
- if (channelKeyword != 0)
- {
- channelKeyword = nextChannelKeywordBit;
- nextChannelKeywordBit >>= 1;
- }
- }
- else
- {
- channelKeyword = info.Keywords;
- }
-
- return channelKeyword;
- }
-#endif
-
- public byte[] CreateManifest()
- {
- string str = CreateManifestString();
- return Encoding.UTF8.GetBytes(str);
- }
-
- public IList<string> Errors => errors;
-
- /// <summary>
- /// When validating an event source it adds the error to the error collection.
- /// When not validating it throws an exception if runtimeCritical is "true".
- /// Otherwise the error is ignored.
- /// </summary>
- /// <param name="msg"></param>
- /// <param name="runtimeCritical"></param>
- public void ManifestError(string msg, bool runtimeCritical = false)
- {
- if ((flags & EventManifestOptions.Strict) != 0)
- errors.Add(msg);
- else if (runtimeCritical)
- throw new ArgumentException(msg);
- }
-
- private string CreateManifestString()
- {
-#if FEATURE_MANAGED_ETW_CHANNELS
- // Write out the channels
- if (channelTab != null)
- {
- sb.AppendLine(" <channels>");
- var sortedChannels = new List<KeyValuePair<int, ChannelInfo>>();
- foreach (KeyValuePair<int, ChannelInfo> p in channelTab) { sortedChannels.Add(p); }
- sortedChannels.Sort((p1, p2) => -Comparer<ulong>.Default.Compare(p1.Value.Keywords, p2.Value.Keywords));
- foreach (KeyValuePair<int, ChannelInfo> kvpair in sortedChannels)
- {
- int channel = kvpair.Key;
- ChannelInfo channelInfo = kvpair.Value;
-
- string? channelType = null;
- const string ElementName = "channel";
- bool enabled = false;
- string? fullName = null;
-#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- string? isolation = null;
- string? access = null;
-#endif
- if (channelInfo.Attribs != null)
- {
- EventChannelAttribute attribs = channelInfo.Attribs;
- if (Enum.IsDefined(typeof(EventChannelType), attribs.EventChannelType))
- channelType = attribs.EventChannelType.ToString();
- enabled = attribs.Enabled;
-#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- if (attribs.ImportChannel != null)
- {
- fullName = attribs.ImportChannel;
- elementName = "importChannel";
- }
- if (Enum.IsDefined(typeof(EventChannelIsolation), attribs.Isolation))
- isolation = attribs.Isolation.ToString();
- access = attribs.Access;
-#endif
- }
-
- fullName ??= providerName + "/" + channelInfo.Name;
-
- sb.Append(" <").Append(ElementName);
- sb.Append(" chid=\"").Append(channelInfo.Name).Append("\"");
- sb.Append(" name=\"").Append(fullName).Append("\"");
- if (ElementName == "channel") // not applicable to importChannels.
- {
- Debug.Assert(channelInfo.Name != null);
- WriteMessageAttrib(sb, "channel", channelInfo.Name, null);
- sb.Append(" value=\"").Append(channel).Append("\"");
- if (channelType != null)
- sb.Append(" type=\"").Append(channelType).Append("\"");
- sb.Append(" enabled=\"").Append(enabled ? "true" : "false").Append("\"");
-#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
- if (access != null)
- sb.Append(" access=\"").Append(access).Append("\"");
- if (isolation != null)
- sb.Append(" isolation=\"").Append(isolation).Append("\"");
-#endif
- }
- sb.AppendLine("/>");
- }
- sb.AppendLine(" </channels>");
- }
-#endif
-
- // Write out the tasks
- if (taskTab != null)
- {
- sb.AppendLine(" <tasks>");
- var sortedTasks = new List<int>(taskTab.Keys);
- sortedTasks.Sort();
- foreach (int task in sortedTasks)
- {
- sb.Append(" <task");
- WriteNameAndMessageAttribs(sb, "task", taskTab[task]);
- sb.Append(" value=\"").Append(task).AppendLine("\"/>");
- }
- sb.AppendLine(" </tasks>");
- }
-
- // Write out the maps
- if (mapsTab != null)
- {
- sb.AppendLine(" <maps>");
- foreach (Type enumType in mapsTab.Values)
- {
- bool isbitmap = EventSource.GetCustomAttributeHelper(enumType, typeof(FlagsAttribute), flags) != null;
- string mapKind = isbitmap ? "bitMap" : "valueMap";
- sb.Append(" <").Append(mapKind).Append(" name=\"").Append(enumType.Name).AppendLine("\">");
-
- // write out each enum value
- FieldInfo[] staticFields = enumType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static);
- bool anyValuesWritten = false;
- foreach (FieldInfo staticField in staticFields)
- {
- object? constantValObj = staticField.GetRawConstantValue();
-
- if (constantValObj != null)
- {
- ulong hexValue;
- if (constantValObj is ulong)
- hexValue = (ulong)constantValObj; // This is the only integer type that can't be represented by a long.
- else
- hexValue = (ulong)Convert.ToInt64(constantValObj); // Handles all integer types except ulong.
-
- // ETW requires all bitmap values to be powers of 2. Skip the ones that are not.
- // TODO: Warn people about the dropping of values.
- if (isbitmap && ((hexValue & (hexValue - 1)) != 0 || hexValue == 0))
- continue;
- sb.Append(" <map value=\"0x").Append(hexValue.ToString("x", CultureInfo.InvariantCulture)).Append("\"");
- WriteMessageAttrib(sb, "map", enumType.Name + "." + staticField.Name, staticField.Name);
- sb.AppendLine("/>");
- anyValuesWritten = true;
- }
- }
-
- // the OS requires that bitmaps and valuemaps have at least one value or it reject the whole manifest.
- // To avoid that put a 'None' entry if there are no other values.
- if (!anyValuesWritten)
- {
- sb.Append(" <map value=\"0x0\"");
- WriteMessageAttrib(sb, "map", enumType.Name + ".None", "None");
- sb.AppendLine("/>");
- }
- sb.Append(" </").Append(mapKind).AppendLine(">");
- }
- sb.AppendLine(" </maps>");
- }
-
- // Write out the opcodes
- sb.AppendLine(" <opcodes>");
- var sortedOpcodes = new List<int>(opcodeTab.Keys);
- sortedOpcodes.Sort();
- foreach (int opcode in sortedOpcodes)
- {
- sb.Append(" <opcode");
- WriteNameAndMessageAttribs(sb, "opcode", opcodeTab[opcode]);
- sb.Append(" value=\"").Append(opcode).AppendLine("\"/>");
- }
- sb.AppendLine(" </opcodes>");
-
- // Write out the keywords
- if (keywordTab != null)
- {
- sb.AppendLine(" <keywords>");
- var sortedKeywords = new List<ulong>(keywordTab.Keys);
- sortedKeywords.Sort();
- foreach (ulong keyword in sortedKeywords)
- {
- sb.Append(" <keyword");
- WriteNameAndMessageAttribs(sb, "keyword", keywordTab[keyword]);
- sb.Append(" mask=\"0x").Append(keyword.ToString("x", CultureInfo.InvariantCulture)).AppendLine("\"/>");
- }
- sb.AppendLine(" </keywords>");
- }
-
- sb.AppendLine(" <events>");
- sb.Append(events);
- sb.AppendLine(" </events>");
-
- sb.AppendLine(" <templates>");
- if (templates.Length > 0)
- {
- sb.Append(templates);
- }
- else
- {
- // Work around a cornercase ETW issue where a manifest with no templates causes
- // ETW events to not get sent to their associated channel.
- sb.AppendLine(" <template tid=\"_empty\"></template>");
- }
- sb.AppendLine(" </templates>");
-
- sb.AppendLine("</provider>");
- sb.AppendLine("</events>");
- sb.AppendLine("</instrumentation>");
-
- // Output the localization information.
- sb.AppendLine("<localization>");
-
- List<CultureInfo> cultures = (resources != null && (flags & EventManifestOptions.AllCultures) != 0) ?
- GetSupportedCultures() :
- new List<CultureInfo>() { CultureInfo.CurrentUICulture };
-
- var sortedStrings = new string[stringTab.Keys.Count];
- stringTab.Keys.CopyTo(sortedStrings, 0);
- Array.Sort<string>(sortedStrings, 0, sortedStrings.Length);
-
- foreach (CultureInfo ci in cultures)
- {
- sb.Append(" <resources culture=\"").Append(ci.Name).AppendLine("\">");
- sb.AppendLine(" <stringTable>");
-
- foreach (string stringKey in sortedStrings)
- {
- string? val = GetLocalizedMessage(stringKey, ci, etwFormat: true);
- sb.Append(" <string id=\"").Append(stringKey).Append("\" value=\"").Append(val).AppendLine("\"/>");
- }
- sb.AppendLine(" </stringTable>");
- sb.AppendLine(" </resources>");
- }
- sb.AppendLine("</localization>");
- sb.AppendLine("</instrumentationManifest>");
- return sb.ToString();
- }
-
-#region private
- private void WriteNameAndMessageAttribs(StringBuilder stringBuilder, string elementName, string name)
- {
- stringBuilder.Append(" name=\"").Append(name).Append("\"");
- WriteMessageAttrib(sb, elementName, name, name);
- }
- private void WriteMessageAttrib(StringBuilder stringBuilder, string elementName, string name, string? value)
- {
- string key = elementName + "_" + name;
- // See if the user wants things localized.
- if (resources != null)
- {
- // resource fallback: strings in the neutral culture will take precedence over inline strings
- string? localizedString = resources.GetString(key, CultureInfo.InvariantCulture);
- if (localizedString != null)
- value = localizedString;
- }
- if (value == null)
- return;
-
- stringBuilder.Append(" message=\"$(string.").Append(key).Append(")\"");
-
- if (stringTab.TryGetValue(key, out string? prevValue) && !prevValue.Equals(value))
- {
- ManifestError(SR.Format(SR.EventSource_DuplicateStringKey, key), true);
- return;
- }
-
- stringTab[key] = value;
- }
- internal string? GetLocalizedMessage(string key, CultureInfo ci, bool etwFormat)
- {
- string? value = null;
- if (resources != null)
- {
- string? localizedString = resources.GetString(key, ci);
- if (localizedString != null)
- {
- value = localizedString;
- if (etwFormat && key.StartsWith("event_", StringComparison.Ordinal))
- {
- string evtName = key.Substring("event_".Length);
- value = TranslateToManifestConvention(value, evtName);
- }
- }
- }
- if (etwFormat && value == null)
- stringTab.TryGetValue(key, out value);
-
- return value;
- }
-
- /// <summary>
- /// There's no API to enumerate all languages an assembly is localized into, so instead
- /// we enumerate through all the "known" cultures and attempt to load a corresponding satellite
- /// assembly
- /// </summary>
- /// <returns></returns>
- private static List<CultureInfo> GetSupportedCultures()
- {
- var cultures = new List<CultureInfo>();
-
- if (!cultures.Contains(CultureInfo.CurrentUICulture))
- cultures.Insert(0, CultureInfo.CurrentUICulture);
- return cultures;
- }
-
- private static string GetLevelName(EventLevel level)
- {
- return (((int)level >= 16) ? "" : "win:") + level.ToString();
- }
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- private string? GetChannelName(EventChannel channel, string eventName, string? eventMessage)
- {
- ChannelInfo? info = null;
- if (channelTab == null || !channelTab.TryGetValue((int)channel, out info))
- {
- if (channel < EventChannel.Admin) // || channel > EventChannel.Debug)
- ManifestError(SR.Format(SR.EventSource_UndefinedChannel, channel, eventName));
-
- // allow channels to be auto-defined. The well known ones get their well known names, and the
- // rest get names Channel<N>. This allows users to modify the Manifest if they want more advanced features.
- channelTab ??= new Dictionary<int, ChannelInfo>(4);
-
- string channelName = channel.ToString(); // For well know channels this is a nice name, otherwise a number
- if (EventChannel.Debug < channel)
- channelName = "Channel" + channelName; // Add a 'Channel' prefix for numbers.
-
- AddChannel(channelName, (int)channel, GetDefaultChannelAttribute(channel));
- if (!channelTab.TryGetValue((int)channel, out info))
- ManifestError(SR.Format(SR.EventSource_UndefinedChannel, channel, eventName));
- }
- // events that specify admin channels *must* have non-null "Message" attributes
- if (resources != null)
- eventMessage ??= resources.GetString("event_" + eventName, CultureInfo.InvariantCulture);
-
- Debug.Assert(info!.Attribs != null);
- if (info.Attribs.EventChannelType == EventChannelType.Admin && eventMessage == null)
- ManifestError(SR.Format(SR.EventSource_EventWithAdminChannelMustHaveMessage, eventName, info.Name));
- return info.Name;
- }
-#endif
- private string GetTaskName(EventTask task, string eventName)
- {
- if (task == EventTask.None)
- return "";
-
- string? ret;
- taskTab ??= new Dictionary<int, string>();
- if (!taskTab.TryGetValue((int)task, out ret))
- ret = taskTab[(int)task] = eventName;
- return ret;
- }
-
- private string? GetOpcodeName(EventOpcode opcode, string eventName)
- {
- switch (opcode)
- {
- case EventOpcode.Info:
- return "win:Info";
- case EventOpcode.Start:
- return "win:Start";
- case EventOpcode.Stop:
- return "win:Stop";
- case EventOpcode.DataCollectionStart:
- return "win:DC_Start";
- case EventOpcode.DataCollectionStop:
- return "win:DC_Stop";
- case EventOpcode.Extension:
- return "win:Extension";
- case EventOpcode.Reply:
- return "win:Reply";
- case EventOpcode.Resume:
- return "win:Resume";
- case EventOpcode.Suspend:
- return "win:Suspend";
- case EventOpcode.Send:
- return "win:Send";
- case EventOpcode.Receive:
- return "win:Receive";
- }
-
- string? ret;
- if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out ret))
- {
- ManifestError(SR.Format(SR.EventSource_UndefinedOpcode, opcode, eventName), true);
- ret = null;
- }
-
- return ret;
- }
-
- private string GetKeywords(ulong keywords, string eventName)
- {
-#if FEATURE_MANAGED_ETW_CHANNELS
- // ignore keywords associate with channels
- // See ValidPredefinedChannelKeywords def for more.
- keywords &= ~ValidPredefinedChannelKeywords;
-#endif
-
- string ret = "";
- for (ulong bit = 1; bit != 0; bit <<= 1)
- {
- if ((keywords & bit) != 0)
- {
- string? keyword = null;
- if ((keywordTab == null || !keywordTab.TryGetValue(bit, out keyword)) &&
- (bit >= (ulong)0x1000000000000))
- {
- // do not report Windows reserved keywords in the manifest (this allows the code
- // to be resilient to potential renaming of these keywords)
- keyword = string.Empty;
- }
- if (keyword == null)
- {
- ManifestError(SR.Format(SR.EventSource_UndefinedKeyword, "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true);
- keyword = string.Empty;
- }
- if (ret.Length != 0 && keyword.Length != 0)
- ret += " ";
- ret += keyword;
- }
- }
- return ret;
- }
-
- private string GetTypeName(Type type)
- {
- if (type.IsEnum())
- {
- FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
- string typeName = GetTypeName(fields[0].FieldType);
- return typeName.Replace("win:Int", "win:UInt"); // ETW requires enums to be unsigned.
- }
-
- switch (type.GetTypeCode())
- {
- case TypeCode.Boolean:
- return "win:Boolean";
- case TypeCode.Byte:
- return "win:UInt8";
- case TypeCode.Char:
- case TypeCode.UInt16:
- return "win:UInt16";
- case TypeCode.UInt32:
- return "win:UInt32";
- case TypeCode.UInt64:
- return "win:UInt64";
- case TypeCode.SByte:
- return "win:Int8";
- case TypeCode.Int16:
- return "win:Int16";
- case TypeCode.Int32:
- return "win:Int32";
- case TypeCode.Int64:
- return "win:Int64";
- case TypeCode.String:
- return "win:UnicodeString";
- case TypeCode.Single:
- return "win:Float";
- case TypeCode.Double:
- return "win:Double";
- case TypeCode.DateTime:
- return "win:FILETIME";
- default:
- if (type == typeof(Guid))
- return "win:GUID";
- else if (type == typeof(IntPtr))
- return "win:Pointer";
- else if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte))
- return "win:Binary";
-
- ManifestError(SR.Format(SR.EventSource_UnsupportedEventTypeInManifest, type.Name), true);
- return string.Empty;
- }
- }
-
- private static void UpdateStringBuilder([NotNull] ref StringBuilder? stringBuilder, string eventMessage, int startIndex, int count)
- {
- stringBuilder ??= new StringBuilder();
- stringBuilder.Append(eventMessage, startIndex, count);
- }
-
- private static readonly string[] s_escapes = { "&amp;", "&lt;", "&gt;", "&apos;", "&quot;", "%r", "%n", "%t" };
- // Manifest messages use %N conventions for their message substitutions. Translate from
- // .NET conventions. We can't use RegEx for this (we are in mscorlib), so we do it 'by hand'
- private string TranslateToManifestConvention(string eventMessage, string evtName)
- {
- StringBuilder? stringBuilder = null; // We lazily create this
- int writtenSoFar = 0;
- int chIdx = -1;
- for (int i = 0; ;)
- {
- if (i >= eventMessage.Length)
- {
- if (stringBuilder == null)
- return eventMessage;
- UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
- return stringBuilder.ToString();
- }
-
- if (eventMessage[i] == '%')
- {
- // handle format message escaping character '%' by escaping it
- UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
- stringBuilder.Append("%%");
- i++;
- writtenSoFar = i;
- }
- else if (i < eventMessage.Length - 1 &&
- (eventMessage[i] == '{' && eventMessage[i + 1] == '{' || eventMessage[i] == '}' && eventMessage[i + 1] == '}'))
- {
- // handle C# escaped '{" and '}'
- UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
- stringBuilder.Append(eventMessage[i]);
- i++; i++;
- writtenSoFar = i;
- }
- else if (eventMessage[i] == '{')
- {
- int leftBracket = i;
- i++;
- int argNum = 0;
- while (i < eventMessage.Length && char.IsDigit(eventMessage[i]))
- {
- argNum = argNum * 10 + eventMessage[i] - '0';
- i++;
- }
- if (i < eventMessage.Length && eventMessage[i] == '}')
- {
- i++;
- UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, leftBracket - writtenSoFar);
- int manIndex = TranslateIndexToManifestConvention(argNum, evtName);
- stringBuilder.Append('%').Append(manIndex);
- // An '!' after the insert specifier {n} will be interpreted as a literal.
- // We'll escape it so that mc.exe does not attempt to consider it the
- // beginning of a format string.
- if (i < eventMessage.Length && eventMessage[i] == '!')
- {
- i++;
- stringBuilder.Append("%!");
- }
- writtenSoFar = i;
- }
- else
- {
- ManifestError(SR.Format(SR.EventSource_UnsupportedMessageProperty, evtName, eventMessage));
- }
- }
- else if ((chIdx = "&<>'\"\r\n\t".IndexOf(eventMessage[i])) >= 0)
- {
- UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar);
- i++;
- stringBuilder.Append(s_escapes[chIdx]);
- writtenSoFar = i;
- }
- else
- i++;
- }
- }
-
- private int TranslateIndexToManifestConvention(int idx, string evtName)
- {
- List<int>? byteArrArgIndices;
- if (perEventByteArrayArgIndices.TryGetValue(evtName, out byteArrArgIndices))
- {
- foreach (int byArrIdx in byteArrArgIndices)
- {
- if (idx >= byArrIdx)
- ++idx;
- else
- break;
- }
- }
- return idx + 1;
- }
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- private class ChannelInfo
- {
- public string? Name;
- public ulong Keywords;
- public EventChannelAttribute? Attribs;
- }
-#endif
-
- private readonly Dictionary<int, string> opcodeTab;
- private Dictionary<int, string>? taskTab;
-#if FEATURE_MANAGED_ETW_CHANNELS
- private Dictionary<int, ChannelInfo>? channelTab;
-#endif
- private Dictionary<ulong, string>? keywordTab;
- private Dictionary<string, Type>? mapsTab;
- private readonly Dictionary<string, string> stringTab; // Maps unlocalized strings to localized ones
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- // WCF used EventSource to mimic a existing ETW manifest. To support this
- // in just their case, we allowed them to specify the keywords associated
- // with their channels explicitly. ValidPredefinedChannelKeywords is
- // this set of channel keywords that we allow to be explicitly set. You
- // can ignore these bits otherwise.
- internal const ulong ValidPredefinedChannelKeywords = 0xF000000000000000;
- private ulong nextChannelKeywordBit = 0x8000000000000000; // available Keyword bit to be used for next channel definition, grows down
- private const int MaxCountChannels = 8; // a manifest can defined at most 8 ETW channels
-#endif
-
- private readonly StringBuilder sb; // Holds the provider information.
- private readonly StringBuilder events; // Holds the events.
- private readonly StringBuilder templates;
-
-#if FEATURE_MANAGED_ETW_CHANNELS
- private readonly string providerName;
-#endif
- private readonly ResourceManager? resources; // Look up localized strings here.
- private readonly EventManifestOptions flags;
- private readonly IList<string> errors; // list of currently encountered errors
- private readonly Dictionary<string, List<int>> perEventByteArrayArgIndices; // "event_name" -> List_of_Indices_of_Byte[]_Arg
-
- // State we track between StartEvent and EndEvent.
- private string? eventName; // Name of the event currently being processed.
- private int numParams; // keeps track of the number of args the event has.
- private List<int>? byteArrArgIndices; // keeps track of the index of each byte[] argument
-#endregion
- }
-
- /// <summary>
- /// Used to send the m_rawManifest into the event dispatcher as a series of events.
- /// </summary>
- internal struct ManifestEnvelope
- {
- public const int MaxChunkSize = 0xFF00;
- public enum ManifestFormats : byte
- {
- SimpleXmlFormat = 1, // simply dump the XML manifest as UTF8
- }
-
-#if FEATURE_MANAGED_ETW
- public ManifestFormats Format;
- public byte MajorVersion;
- public byte MinorVersion;
- public byte Magic;
- public ushort TotalChunks;
- public ushort ChunkNumber;
-#endif
- }
-
-#endregion
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSourceException.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSourceException.cs
deleted file mode 100644
index 2a8515ad615..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSourceException.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
-#endif
-using System.Runtime.Serialization;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Exception that is thrown when an error occurs during EventSource operation.
- /// </summary>
-#if !ES_BUILD_PCL
- [Serializable]
-#endif
- public class EventSourceException : Exception
- {
- /// <summary>
- /// Initializes a new instance of the EventSourceException class.
- /// </summary>
- public EventSourceException() :
- base(SR.EventSource_ListenerWriteFailure) { }
-
- /// <summary>
- /// Initializes a new instance of the EventSourceException class with a specified error message.
- /// </summary>
- public EventSourceException(string? message) : base(message) { }
-
- /// <summary>
- /// Initializes a new instance of the EventSourceException class with a specified error message
- /// and a reference to the inner exception that is the cause of this exception.
- /// </summary>
- public EventSourceException(string? message, Exception? innerException) : base(message, innerException) { }
-
-#if !ES_BUILD_PCL
- /// <summary>
- /// Initializes a new instance of the EventSourceException class with serialized data.
- /// </summary>
- protected EventSourceException(SerializationInfo info, StreamingContext context) : base(info, context) { }
-#endif
-
- internal EventSourceException(Exception? innerException) :
- base(SR.EventSource_ListenerWriteFailure, innerException) { }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/FrameworkEventSource.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/FrameworkEventSource.cs
deleted file mode 100644
index 321ae819f50..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/FrameworkEventSource.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Internal.Runtime.CompilerServices;
-
-namespace System.Diagnostics.Tracing
-{
- [EventSource(Guid = "8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1", Name = "System.Diagnostics.Eventing.FrameworkEventSource")]
- internal sealed class FrameworkEventSource : EventSource
- {
- public static readonly FrameworkEventSource Log = new FrameworkEventSource();
-
- // Keyword definitions. These represent logical groups of events that can be turned on and off independently
- // Often each task has a keyword, but where tasks are determined by subsystem, keywords are determined by
- // usefulness to end users to filter. Generally users don't mind extra events if they are not high volume
- // so grouping low volume events together in a single keywords is OK (users can post-filter by task if desired)
- public static class Keywords
- {
- public const EventKeywords ThreadPool = (EventKeywords)0x0002;
- public const EventKeywords ThreadTransfer = (EventKeywords)0x0010;
- }
-
- /// <summary>ETW tasks that have start/stop events.</summary>
- public static class Tasks // this name is important for EventSource
- {
- /// <summary>Send / Receive - begin transfer/end transfer</summary>
- public const EventTask ThreadTransfer = (EventTask)3;
- }
-
- // The FrameworkEventSource GUID is {8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1}
- private FrameworkEventSource() : base(new Guid(0x8e9f5090, 0x2d75, 0x4d03, 0x8a, 0x81, 0xe5, 0xaf, 0xbf, 0x85, 0xda, 0xf1), "System.Diagnostics.Eventing.FrameworkEventSource") { }
-
- // optimized for common signatures (used by the ThreadTransferSend/Receive events)
- [NonEvent]
- private unsafe void WriteEvent(int eventId, long arg1, int arg2, string? arg3, bool arg4, int arg5, int arg6)
- {
- if (IsEnabled())
- {
- arg3 ??= "";
- fixed (char* string3Bytes = arg3)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[6];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 8;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 4;
- descrs[1].Reserved = 0;
- descrs[2].DataPointer = (IntPtr)string3Bytes;
- descrs[2].Size = ((arg3.Length + 1) * 2);
- descrs[2].Reserved = 0;
- descrs[3].DataPointer = (IntPtr)(&arg4);
- descrs[3].Size = 4;
- descrs[3].Reserved = 0;
- descrs[4].DataPointer = (IntPtr)(&arg5);
- descrs[4].Size = 4;
- descrs[4].Reserved = 0;
- descrs[5].DataPointer = (IntPtr)(&arg6);
- descrs[5].Size = 4;
- descrs[5].Reserved = 0;
- WriteEventCore(eventId, 6, descrs);
- }
- }
- }
-
- // optimized for common signatures (used by the ThreadTransferSend/Receive events)
- [NonEvent]
- private unsafe void WriteEvent(int eventId, long arg1, int arg2, string? arg3)
- {
- if (IsEnabled())
- {
- arg3 ??= "";
- fixed (char* string3Bytes = arg3)
- {
- EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = 8;
- descrs[0].Reserved = 0;
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = 4;
- descrs[1].Reserved = 0;
- descrs[2].DataPointer = (IntPtr)string3Bytes;
- descrs[2].Size = ((arg3.Length + 1) * 2);
- descrs[2].Reserved = 0;
- WriteEventCore(eventId, 3, descrs);
- }
- }
- }
-
- [Event(30, Level = EventLevel.Verbose, Keywords = Keywords.ThreadPool | Keywords.ThreadTransfer)]
- public void ThreadPoolEnqueueWork(long workID)
- {
- WriteEvent(30, workID);
- }
-
- [NonEvent]
- public unsafe void ThreadPoolEnqueueWorkObject(object workID)
- {
- // convert the Object Id to a long
- ThreadPoolEnqueueWork((long)*((void**)Unsafe.AsPointer(ref workID)));
- }
-
- [Event(31, Level = EventLevel.Verbose, Keywords = Keywords.ThreadPool | Keywords.ThreadTransfer)]
- public void ThreadPoolDequeueWork(long workID)
- {
- WriteEvent(31, workID);
- }
-
- [NonEvent]
- public unsafe void ThreadPoolDequeueWorkObject(object workID)
- {
- // convert the Object Id to a long
- ThreadPoolDequeueWork((long)*((void**)Unsafe.AsPointer(ref workID)));
- }
-
- // id - represents a correlation ID that allows correlation of two activities, one stamped by
- // ThreadTransferSend, the other by ThreadTransferReceive
- // kind - identifies the transfer: values below 64 are reserved for the runtime. Currently used values:
- // 1 - managed Timers ("roaming" ID)
- // 2 - managed async IO operations (FileStream, PipeStream, a.o.)
- // 3 - WinRT dispatch operations
- // info - any additional information user code might consider interesting
- // intInfo1/2 - any additional integer information user code might consider interesting
- [Event(150, Level = EventLevel.Informational, Keywords = Keywords.ThreadTransfer, Task = Tasks.ThreadTransfer, Opcode = EventOpcode.Send)]
- public void ThreadTransferSend(long id, int kind, string info, bool multiDequeues, int intInfo1, int intInfo2)
- {
- WriteEvent(150, id, kind, info, multiDequeues, intInfo1, intInfo2);
- }
-
- // id - is a managed object. it gets translated to the object's address. ETW listeners must
- // keep track of GC movements in order to correlate the value passed to XyzSend with the
- // (possibly changed) value passed to XyzReceive
- [NonEvent]
- public unsafe void ThreadTransferSendObj(object id, int kind, string info, bool multiDequeues, int intInfo1, int intInfo2)
- {
- ThreadTransferSend((long)*((void**)Unsafe.AsPointer(ref id)), kind, info, multiDequeues, intInfo1, intInfo2);
- }
-
- // id - represents a correlation ID that allows correlation of two activities, one stamped by
- // ThreadTransferSend, the other by ThreadTransferReceive
- // kind - identifies the transfer: values below 64 are reserved for the runtime. Currently used values:
- // 1 - managed Timers ("roaming" ID)
- // 2 - managed async IO operations (FileStream, PipeStream, a.o.)
- // 3 - WinRT dispatch operations
- // info - any additional information user code might consider interesting
- [Event(151, Level = EventLevel.Informational, Keywords = Keywords.ThreadTransfer, Task = Tasks.ThreadTransfer, Opcode = EventOpcode.Receive)]
- public void ThreadTransferReceive(long id, int kind, string? info)
- {
- WriteEvent(151, id, kind, info);
- }
- // id - is a managed object. it gets translated to the object's address. ETW listeners must
- // keep track of GC movements in order to correlate the value passed to XyzSend with the
- // (possibly changed) value passed to XyzReceive
- [NonEvent]
- public unsafe void ThreadTransferReceiveObj(object id, int kind, string? info)
- {
- ThreadTransferReceive((long)*((void**)Unsafe.AsPointer(ref id)), kind, info);
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IEventProvider.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IEventProvider.cs
deleted file mode 100644
index 2ceb92f99c0..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IEventProvider.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- // Represents the interface between EventProvider and an external logging mechanism.
- internal interface IEventProvider
- {
- // Register an event provider.
- unsafe uint EventRegister(
- EventSource eventSource,
- Interop.Advapi32.EtwEnableCallback enableCallback,
- void* callbackContext,
- ref long registrationHandle);
-
- // Unregister an event provider.
- uint EventUnregister(long registrationHandle);
-
- // Write an event.
- unsafe EventProvider.WriteEventErrorCode EventWriteTransfer(
- long registrationHandle,
- in EventDescriptor eventDescriptor,
- IntPtr eventHandle,
- Guid* activityId,
- Guid* relatedActivityId,
- int userDataCount,
- EventProvider.EventData* userData);
-
- // Get or set the per-thread activity ID.
- int EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId);
-
- // Define an EventPipeEvent handle.
- unsafe IntPtr DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength);
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IncrementingEventCounter.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IncrementingEventCounter.cs
deleted file mode 100644
index 895ebe59fb2..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IncrementingEventCounter.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// IncrementingEventCounter is a variant of EventCounter for variables that are ever-increasing.
- /// Ex) # of exceptions in the runtime.
- /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates
- /// the counter value.
- /// </summary>
- public partial class IncrementingEventCounter : DiagnosticCounter
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="IncrementingEventCounter"/> class.
- /// IncrementingEventCounter live as long as the EventSource that they are attached to unless they are
- /// explicitly Disposed.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="eventSource">The event source.</param>
- public IncrementingEventCounter(string name, EventSource eventSource) : base(name, eventSource)
- {
- Publish();
- }
-
- /// <summary>
- /// Writes 'value' to the stream of values tracked by the counter. This updates the sum and other statistics that will
- /// be logged on the next timer interval.
- /// </summary>
- /// <param name="increment">The value to increment by.</param>
- public void Increment(double increment = 1)
- {
- lock (this)
- {
- _increment += increment;
- }
- }
-
- public TimeSpan DisplayRateTimeScale { get; set; }
- private double _increment;
- private double _prevIncrement;
-
- public override string ToString() => $"IncrementingEventCounter '{Name}' Increment {_increment}";
-
- internal override void WritePayload(float intervalSec, int pollingIntervalMillisec)
- {
- lock (this) // Lock the counter
- {
- IncrementingCounterPayload payload = new IncrementingCounterPayload();
- payload.Name = Name;
- payload.IntervalSec = intervalSec;
- payload.DisplayName = DisplayName ?? "";
- payload.DisplayRateTimeScale = (DisplayRateTimeScale == TimeSpan.Zero) ? "" : DisplayRateTimeScale.ToString("c");
- payload.Series = $"Interval={pollingIntervalMillisec}"; // TODO: This may need to change when we support multi-session
- payload.CounterType = "Sum";
- payload.Metadata = GetMetadataString();
- payload.Increment = _increment - _prevIncrement;
- payload.DisplayUnits = DisplayUnits ?? "";
- _prevIncrement = _increment;
- EventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new IncrementingEventCounterPayloadType(payload));
- }
- }
-
- // Updates the value.
- internal void UpdateMetric()
- {
- lock (this)
- {
- _prevIncrement = _increment;
- }
- }
- }
-
-
- /// <summary>
- /// This is the payload that is sent in the with EventSource.Write
- /// </summary>
- [EventData]
- internal class IncrementingEventCounterPayloadType
- {
- public IncrementingEventCounterPayloadType(IncrementingCounterPayload payload) { Payload = payload; }
- public IncrementingCounterPayload Payload { get; set; }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IncrementingPollingCounter.cs
deleted file mode 100644
index 0cdbac7e6a0..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/IncrementingPollingCounter.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// IncrementingPollingCounter is a variant of EventCounter for variables that are ever-increasing.
- /// Ex) # of exceptions in the runtime.
- /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates
- /// the counter value.
- /// Unlike IncrementingEventCounter, this takes in a polling callback that it can call to update
- /// its own metric periodically.
- /// </summary>
- public partial class IncrementingPollingCounter : DiagnosticCounter
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="IncrementingPollingCounter"/> class.
- /// IncrementingPollingCounter live as long as the EventSource that they are attached to unless they are
- /// explicitly Disposed.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="eventSource">The event source.</param>
- public IncrementingPollingCounter(string name, EventSource eventSource, Func<double> totalValueProvider) : base(name, eventSource)
- {
- if (totalValueProvider == null)
- throw new ArgumentNullException(nameof(totalValueProvider));
-
- _totalValueProvider = totalValueProvider;
- Publish();
- }
-
- public override string ToString() => $"IncrementingPollingCounter '{Name}' Increment {_increment}";
-
- public TimeSpan DisplayRateTimeScale { get; set; }
- private double _increment;
- private double _prevIncrement;
- private readonly Func<double> _totalValueProvider;
-
- /// <summary>
- /// Calls "_totalValueProvider" to enqueue the counter value to the queue.
- /// </summary>
- internal void UpdateMetric()
- {
- try
- {
- lock (this)
- {
- _prevIncrement = _increment;
- _increment = _totalValueProvider();
- }
- }
- catch (Exception ex)
- {
- ReportOutOfBandMessage($"ERROR: Exception during EventCounter {Name} getMetricFunction callback: " + ex.Message);
- }
- }
-
- internal override void WritePayload(float intervalSec, int pollingIntervalMillisec)
- {
- UpdateMetric();
- lock (this) // Lock the counter
- {
- IncrementingCounterPayload payload = new IncrementingCounterPayload();
- payload.Name = Name;
- payload.DisplayName = DisplayName ?? "";
- payload.DisplayRateTimeScale = (DisplayRateTimeScale == TimeSpan.Zero) ? "" : DisplayRateTimeScale.ToString("c");
- payload.IntervalSec = intervalSec;
- payload.Series = $"Interval={pollingIntervalMillisec}"; // TODO: This may need to change when we support multi-session
- payload.CounterType = "Sum";
- payload.Metadata = GetMetadataString();
- payload.Increment = _increment - _prevIncrement;
- payload.DisplayUnits = DisplayUnits ?? "";
- EventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new IncrementingPollingCounterPayloadType(payload));
- }
- }
- }
-
- /// <summary>
- /// This is the payload that is sent in the with EventSource.Write
- /// </summary>
- [EventData]
- internal class IncrementingPollingCounterPayloadType
- {
- public IncrementingPollingCounterPayloadType(IncrementingCounterPayload payload) { Payload = payload; }
- public IncrementingCounterPayload Payload { get; set; }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/PollingCounter.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/PollingCounter.cs
deleted file mode 100644
index 3dd3d832ea9..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/PollingCounter.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// PollingCounter is a variant of EventCounter - it collects and calculates similar statistics
- /// as EventCounter. PollingCounter differs from EventCounter in that it takes in a callback
- /// function to collect metrics on its own rather than the user having to call WriteMetric()
- /// every time.
- /// </summary>
- public partial class PollingCounter : DiagnosticCounter
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="PollingCounter"/> class.
- /// PollingCounter live as long as the EventSource that they are attached to unless they are
- /// explicitly Disposed.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="eventSource">The event source.</param>
- public PollingCounter(string name, EventSource eventSource, Func<double> metricProvider) : base(name, eventSource)
- {
- if (metricProvider == null)
- throw new ArgumentNullException(nameof(metricProvider));
-
- _metricProvider = metricProvider;
- Publish();
- }
-
- public override string ToString() => $"PollingCounter '{Name}' Count 1 Mean {_lastVal.ToString("n3")}";
-
- private readonly Func<double> _metricProvider;
- private double _lastVal;
-
- internal override void WritePayload(float intervalSec, int pollingIntervalMillisec)
- {
- lock (this)
- {
- double value = 0;
- try
- {
- value = _metricProvider();
- }
- catch (Exception ex)
- {
- ReportOutOfBandMessage($"ERROR: Exception during EventCounter {Name} metricProvider callback: " + ex.Message);
- }
-
- CounterPayload payload = new CounterPayload();
- payload.Name = Name;
- payload.DisplayName = DisplayName ?? "";
- payload.Count = 1; // NOTE: These dumb-looking statistics is intentional
- payload.IntervalSec = intervalSec;
- payload.Series = $"Interval={pollingIntervalMillisec}"; // TODO: This may need to change when we support multi-session
- payload.CounterType = "Mean";
- payload.Mean = value;
- payload.Max = value;
- payload.Min = value;
- payload.Metadata = GetMetadataString();
- payload.StandardDeviation = 0;
- payload.DisplayUnits = DisplayUnits ?? "";
- _lastVal = value;
- EventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new PollingPayloadType(payload));
- }
- }
- }
-
- /// <summary>
- /// This is the payload that is sent in the with EventSource.Write
- /// </summary>
- [EventData]
- internal class PollingPayloadType
- {
- public PollingPayloadType(CounterPayload payload) { Payload = payload; }
- public CounterPayload Payload { get; set; }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/StubEnvironment.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/StubEnvironment.cs
deleted file mode 100644
index 236e0cbbc40..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/StubEnvironment.cs
+++ /dev/null
@@ -1,376 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-#if ES_BUILD_PCL || ES_BUILD_PN
-using System.Collections.Generic;
-#endif
-using System.Reflection;
-#if ES_BUILD_STANDALONE
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Security;
-#endif
-#if ES_BUILD_AGAINST_DOTNET_V35
-using Microsoft.Internal;
-#endif
-using Microsoft.Reflection;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing.Internal
-#else
-namespace System.Diagnostics.Tracing.Internal
-#endif
-{
- internal static class Environment
- {
- public static readonly string NewLine = System.Environment.NewLine;
-
- public static int TickCount => System.Environment.TickCount;
-
- public static string GetResourceString(string key, params object?[] args)
- {
- string? fmt = rm.GetString(key);
- if (fmt != null)
- return string.Format(fmt, args);
-
- string sargs = string.Join(", ", args);
-
- return key + " (" + sargs + ")";
- }
-
- public static string GetRuntimeResourceString(string key, params object?[] args)
- {
- return GetResourceString(key, args);
- }
-
- private static readonly System.Resources.ResourceManager rm = new System.Resources.ResourceManager("Microsoft.Diagnostics.Tracing.Messages", typeof(Environment).Assembly());
- }
-
-#if ES_BUILD_STANDALONE
- internal static class BitOperations
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint RotateLeft(uint value, int offset)
- => (value << offset) | (value >> (32 - offset));
-
- public static int PopCount(uint value)
- {
- const uint c1 = 0x_55555555u;
- const uint c2 = 0x_33333333u;
- const uint c3 = 0x_0F0F0F0Fu;
- const uint c4 = 0x_01010101u;
-
- value = value - ((value >> 1) & c1);
- value = (value & c2) + ((value >> 2) & c2);
- value = (((value + (value >> 4)) & c3) * c4) >> 24;
-
- return (int)value;
- }
-
- public static int TrailingZeroCount(uint value)
- {
- if (value == 0)
- return 32;
-
- int count = 0;
- while ((value & 1) == 0)
- {
- value >>= 1;
- count++;
- }
- return count;
- }
- }
-#endif
-}
-
-#if ES_BUILD_AGAINST_DOTNET_V35
-
-namespace Microsoft.Internal
-{
- using System.Text;
-
- internal static class Tuple
- {
- public static Tuple<T1> Create<T1>(T1 item1)
- {
- return new Tuple<T1>(item1);
- }
-
- public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
- {
- return new Tuple<T1, T2>(item1, item2);
- }
- }
-
- [Serializable]
- internal class Tuple<T1>
- {
- private readonly T1 m_Item1;
-
- public T1 Item1 { get { return m_Item1; } }
-
- public Tuple(T1 item1)
- {
- m_Item1 = item1;
- }
-
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("(");
- sb.Append(m_Item1);
- sb.Append(")");
- return sb.ToString();
- }
-
- int Size
- {
- get
- {
- return 1;
- }
- }
- }
-
- [Serializable]
- public class Tuple<T1, T2>
- {
- private readonly T1 m_Item1;
- private readonly T2 m_Item2;
-
- public T1 Item1 { get { return m_Item1; } }
- public T2 Item2 { get { return m_Item2; } }
-
- public Tuple(T1 item1, T2 item2)
- {
- m_Item1 = item1;
- m_Item2 = item2;
- }
-
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("(");
- sb.Append(m_Item1);
- sb.Append(", ");
- sb.Append(m_Item2);
- sb.Append(")");
- return sb.ToString();
- }
-
- int Size
- {
- get
- {
- return 2;
- }
- }
- }
-}
-
-#endif
-
-namespace Microsoft.Reflection
-{
-#if ES_BUILD_PCL
- [Flags]
- public enum BindingFlags
- {
- DeclaredOnly = 0x02, // Only look at the members declared on the Type
- Instance = 0x04, // Include Instance members in search
- Static = 0x08, // Include Static members in search
- Public = 0x10, // Include Public members in search
- NonPublic = 0x20, // Include Non-Public members in search
- }
-
- public enum TypeCode {
- Empty = 0, // Null reference
- Object = 1, // Instance that isn't a value
- DBNull = 2, // Database null value
- Boolean = 3, // Boolean
- Char = 4, // Unicode character
- SByte = 5, // Signed 8-bit integer
- Byte = 6, // Unsigned 8-bit integer
- Int16 = 7, // Signed 16-bit integer
- UInt16 = 8, // Unsigned 16-bit integer
- Int32 = 9, // Signed 32-bit integer
- UInt32 = 10, // Unsigned 32-bit integer
- Int64 = 11, // Signed 64-bit integer
- UInt64 = 12, // Unsigned 64-bit integer
- Single = 13, // IEEE 32-bit float
- Double = 14, // IEEE 64-bit double
- Decimal = 15, // Decimal
- DateTime = 16, // DateTime
- String = 18, // Unicode character string
- }
-#endif
- internal static class ReflectionExtensions
- {
-#if (!ES_BUILD_PCL && !ES_BUILD_PN)
-
- //
- // Type extension methods
- //
- public static bool IsEnum(this Type type) { return type.IsEnum; }
- public static bool IsAbstract(this Type type) { return type.IsAbstract; }
- public static bool IsSealed(this Type type) { return type.IsSealed; }
- public static bool IsValueType(this Type type) { return type.IsValueType; }
- public static bool IsGenericType(this Type type) { return type.IsGenericType; }
- public static Type? BaseType(this Type type) { return type.BaseType; }
- public static Assembly Assembly(this Type type) { return type.Assembly; }
- public static TypeCode GetTypeCode(this Type type) { return Type.GetTypeCode(type); }
-
- public static bool ReflectionOnly(this Assembly assm) { return assm.ReflectionOnly; }
-
-#else
-
- //
- // Type extension methods
- //
- public static bool IsEnum(this Type type) { return type.GetTypeInfo().IsEnum; }
- public static bool IsAbstract(this Type type) { return type.GetTypeInfo().IsAbstract; }
- public static bool IsSealed(this Type type) { return type.GetTypeInfo().IsSealed; }
- public static bool IsValueType(this Type type) { return type.GetTypeInfo().IsValueType; }
- public static bool IsGenericType(this Type type) { return type.IsConstructedGenericType; }
- public static Type? BaseType(this Type type) { return type.GetTypeInfo().BaseType; }
- public static Assembly Assembly(this Type type) { return type.GetTypeInfo().Assembly; }
- public static IEnumerable<PropertyInfo> GetProperties(this Type type)
- {
-#if ES_BUILD_PN
- return type.GetProperties();
-#else
- return type.GetRuntimeProperties();
-#endif
- }
- public static MethodInfo? GetGetMethod(this PropertyInfo propInfo) { return propInfo.GetMethod; }
- public static Type[] GetGenericArguments(this Type type) { return type.GenericTypeArguments; }
-
- public static MethodInfo[] GetMethods(this Type type, BindingFlags flags)
- {
- // Minimal implementation to cover only the cases we need
- System.Diagnostics.Debug.Assert((flags & BindingFlags.DeclaredOnly) != 0);
- System.Diagnostics.Debug.Assert((flags & ~(BindingFlags.DeclaredOnly|BindingFlags.Instance|BindingFlags.Static|BindingFlags.Public|BindingFlags.NonPublic)) == 0);
- Func<MethodInfo, bool> visFilter;
- Func<MethodInfo, bool> instFilter;
- switch (flags & (BindingFlags.Public | BindingFlags.NonPublic))
- {
- case 0: visFilter = mi => false; break;
- case BindingFlags.Public: visFilter = mi => mi.IsPublic; break;
- case BindingFlags.NonPublic: visFilter = mi => !mi.IsPublic; break;
- default: visFilter = mi => true; break;
- }
- switch (flags & (BindingFlags.Instance | BindingFlags.Static))
- {
- case 0: instFilter = mi => false; break;
- case BindingFlags.Instance: instFilter = mi => !mi.IsStatic; break;
- case BindingFlags.Static: instFilter = mi => mi.IsStatic; break;
- default: instFilter = mi => true; break;
- }
- List<MethodInfo> methodInfos = new List<MethodInfo>();
- foreach (var declaredMethod in type.GetTypeInfo().DeclaredMethods)
- {
- if (visFilter(declaredMethod) && instFilter(declaredMethod))
- methodInfos.Add(declaredMethod);
- }
- return methodInfos.ToArray();
- }
- public static FieldInfo[] GetFields(this Type type, BindingFlags flags)
- {
- // Minimal implementation to cover only the cases we need
- System.Diagnostics.Debug.Assert((flags & BindingFlags.DeclaredOnly) != 0);
- System.Diagnostics.Debug.Assert((flags & ~(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) == 0);
- Func<FieldInfo, bool> visFilter;
- Func<FieldInfo, bool> instFilter;
- switch (flags & (BindingFlags.Public | BindingFlags.NonPublic))
- {
- case 0: visFilter = fi => false; break;
- case BindingFlags.Public: visFilter = fi => fi.IsPublic; break;
- case BindingFlags.NonPublic: visFilter = fi => !fi.IsPublic; break;
- default: visFilter = fi => true; break;
- }
- switch (flags & (BindingFlags.Instance | BindingFlags.Static))
- {
- case 0: instFilter = fi => false; break;
- case BindingFlags.Instance: instFilter = fi => !fi.IsStatic; break;
- case BindingFlags.Static: instFilter = fi => fi.IsStatic; break;
- default: instFilter = fi => true; break;
- }
- List<FieldInfo> fieldInfos = new List<FieldInfo>();
- foreach (var declaredField in type.GetTypeInfo().DeclaredFields)
- {
- if (visFilter(declaredField) && instFilter(declaredField))
- fieldInfos.Add(declaredField);
- }
- return fieldInfos.ToArray();
- }
- public static Type? GetNestedType(this Type type, string nestedTypeName)
- {
- TypeInfo? ti = null;
- foreach (var nt in type.GetTypeInfo().DeclaredNestedTypes)
- {
- if (nt.Name == nestedTypeName)
- {
- ti = nt;
- break;
- }
- }
- return ti == null ? null : ti.AsType();
- }
- public static TypeCode GetTypeCode(this Type type)
- {
- if (type == typeof(bool)) return TypeCode.Boolean;
- else if (type == typeof(byte)) return TypeCode.Byte;
- else if (type == typeof(char)) return TypeCode.Char;
- else if (type == typeof(ushort)) return TypeCode.UInt16;
- else if (type == typeof(uint)) return TypeCode.UInt32;
- else if (type == typeof(ulong)) return TypeCode.UInt64;
- else if (type == typeof(sbyte)) return TypeCode.SByte;
- else if (type == typeof(short)) return TypeCode.Int16;
- else if (type == typeof(int)) return TypeCode.Int32;
- else if (type == typeof(long)) return TypeCode.Int64;
- else if (type == typeof(string)) return TypeCode.String;
- else if (type == typeof(float)) return TypeCode.Single;
- else if (type == typeof(double)) return TypeCode.Double;
- else if (type == typeof(DateTime)) return TypeCode.DateTime;
- else if (type == (typeof(decimal))) return TypeCode.Decimal;
- else return TypeCode.Object;
- }
-
- //
- // FieldInfo extension methods
- //
- public static object? GetRawConstantValue(this FieldInfo fi)
- { return fi.GetValue(null); }
-
- //
- // Assembly extension methods
- //
- public static bool ReflectionOnly(this Assembly assm)
- {
- // In PCL we can't load in reflection-only context
- return false;
- }
-
-#endif
- }
-}
-
-#if ES_BUILD_STANDALONE
-internal static partial class Interop
-{
- [SuppressUnmanagedCodeSecurityAttribute]
- internal static partial class Kernel32
- {
- [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
- internal static extern int GetCurrentThreadId();
-
- [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
- internal static extern uint GetCurrentProcessId();
- }
-
- internal static uint GetCurrentProcessId() => Kernel32.GetCurrentProcessId();
-}
-#endif
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ArrayTypeInfo.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ArrayTypeInfo.cs
deleted file mode 100644
index b9f4864089b..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ArrayTypeInfo.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- internal sealed class ArrayTypeInfo : TraceLoggingTypeInfo
- {
- private readonly TraceLoggingTypeInfo elementInfo;
-
- public ArrayTypeInfo(Type type, TraceLoggingTypeInfo elementInfo)
- : base(type)
- {
- this.elementInfo = elementInfo;
- }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- collector.BeginBufferedArray();
- this.elementInfo.WriteMetadata(collector, name, format);
- collector.EndBufferedArray();
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- int bookmark = collector.BeginBufferedArray();
-
- int count = 0;
- Array? array = (Array?)value.ReferenceValue;
- if (array != null)
- {
- count = array.Length;
- for (int i = 0; i < array.Length; i++)
- {
- this.elementInfo.WriteData(collector, elementInfo.PropertyValueFactory(array.GetValue(i)));
- }
- }
-
- collector.EndBufferedArray(bookmark, count);
- }
-
- public override object? GetData(object? value)
- {
- Debug.Assert(value != null, "null accepted only for some overrides");
- var array = (Array)value;
- var serializedArray = new object?[array.Length];
- for (int i = 0; i < array.Length; i++)
- {
- serializedArray[i] = this.elementInfo.GetData(array.GetValue(i));
- }
- return serializedArray;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs
deleted file mode 100644
index f87d6070050..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-using System.Threading;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: A very simple lock-free add-only dictionary.
- /// Warning: this is a copy-by-value type. Copying performs a snapshot.
- /// Accessing a readonly field always makes a copy of the field, so the
- /// GetOrAdd method will not work as expected if called on a readonly field.
- /// </summary>
- /// <typeparam name="KeyType">
- /// The type of the key, used for TryGet.
- /// </typeparam>
- /// <typeparam name="ItemType">
- /// The type of the item, used for GetOrAdd.
- /// </typeparam>
- internal struct ConcurrentSet<KeyType, ItemType>
- where ItemType : ConcurrentSetItem<KeyType, ItemType>
- {
- private ItemType[]? items;
-
- public ItemType? TryGet(KeyType key)
- {
- ItemType? item;
- ItemType[]? oldItems = this.items;
-
- if (oldItems != null)
- {
- int lo = 0;
- int hi = oldItems.Length;
- do
- {
- int i = (lo + hi) / 2;
- item = oldItems[i];
-
- int cmp = item.Compare(key);
- if (cmp == 0)
- {
- goto Done;
- }
- else if (cmp < 0)
- {
- lo = i + 1;
- }
- else
- {
- hi = i;
- }
- }
- while (lo != hi);
- }
-
- item = null;
-
- Done:
-
- return item;
- }
-
- public ItemType GetOrAdd(ItemType newItem)
- {
- ItemType item;
- ItemType[]? oldItems = this.items;
- ItemType[] newItems;
-
- Retry:
-
- if (oldItems == null)
- {
- newItems = new ItemType[] { newItem };
- }
- else
- {
- int lo = 0;
- int hi = oldItems.Length;
- do
- {
- int i = (lo + hi) / 2;
- item = oldItems[i];
-
- int cmp = item.Compare(newItem);
- if (cmp == 0)
- {
- goto Done;
- }
- else if (cmp < 0)
- {
- lo = i + 1;
- }
- else
- {
- hi = i;
- }
- }
- while (lo != hi);
-
- int oldLength = oldItems.Length;
- newItems = new ItemType[oldLength + 1];
- Array.Copy(oldItems, newItems, lo);
- newItems[lo] = newItem;
- Array.Copy(oldItems, lo, newItems, lo + 1, oldLength - lo);
- }
-
- newItems = Interlocked.CompareExchange(ref this.items, newItems, oldItems)!;
- if (oldItems != newItems)
- {
- oldItems = newItems;
- goto Retry;
- }
-
- item = newItem;
-
- Done:
-
- return item;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSetItem.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSetItem.cs
deleted file mode 100644
index 7ef078f9090..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSetItem.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Abstract base class that must be inherited by items in a
- /// ConcurrentSet.
- /// </summary>
- /// <typeparam name="KeyType">Type of the set's key.</typeparam>
- /// <typeparam name="ItemType">Type of the derived class.</typeparam>
- internal abstract class ConcurrentSetItem<KeyType, ItemType>
- where ItemType : ConcurrentSetItem<KeyType, ItemType>
- {
- public abstract int Compare(ItemType other);
- public abstract int Compare(KeyType key);
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
deleted file mode 100644
index d6886b8b105..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
+++ /dev/null
@@ -1,368 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
-#endif
-using System.Runtime.InteropServices;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: This is the implementation of the DataCollector
- /// functionality. To enable safe access to the DataCollector from
- /// untrusted code, there is one thread-local instance of this structure
- /// per thread. The instance must be Enabled before any data is written to
- /// it. The instance must be Finished before the data is passed to
- /// EventWrite. The instance must be Disabled before the arrays referenced
- /// by the pointers are freed or unpinned.
- /// </summary>
- internal unsafe struct DataCollector
- {
- [ThreadStatic]
- internal static DataCollector ThreadInstance;
-
- private byte* scratchEnd;
- private EventSource.EventData* datasEnd;
- private GCHandle* pinsEnd;
- private EventSource.EventData* datasStart;
- private byte* scratch;
- private EventSource.EventData* datas;
- private GCHandle* pins;
- private byte[]? buffer;
- private int bufferPos;
- private int bufferNesting; // We may merge many fields int a single blob. If we are doing this we increment this.
- private bool writingScalars;
-
- internal void Enable(
- byte* scratch,
- int scratchSize,
- EventSource.EventData* datas,
- int dataCount,
- GCHandle* pins,
- int pinCount)
- {
- this.datasStart = datas;
- this.scratchEnd = scratch + scratchSize;
- this.datasEnd = datas + dataCount;
- this.pinsEnd = pins + pinCount;
- this.scratch = scratch;
- this.datas = datas;
- this.pins = pins;
- this.writingScalars = false;
- }
-
- internal void Disable()
- {
- this = default;
- }
-
- /// <summary>
- /// Completes the list of scalars. Finish must be called before the data
- /// descriptor array is passed to EventWrite.
- /// </summary>
- /// <returns>
- /// A pointer to the next unused data descriptor, or datasEnd if they were
- /// all used. (Descriptors may be unused if a string or array was null.)
- /// </returns>
- internal EventSource.EventData* Finish()
- {
- this.ScalarsEnd();
- return this.datas;
- }
-
- internal void AddScalar(void* value, int size)
- {
- var pb = (byte*)value;
- if (this.bufferNesting == 0)
- {
- byte* scratchOld = this.scratch;
- byte* scratchNew = scratchOld + size;
- if (this.scratchEnd < scratchNew)
- {
- throw new IndexOutOfRangeException(SR.EventSource_AddScalarOutOfRange);
- }
-
- this.ScalarsBegin();
- this.scratch = scratchNew;
-
- for (int i = 0; i != size; i++)
- {
- scratchOld[i] = pb[i];
- }
- }
- else
- {
- int oldPos = this.bufferPos;
- this.bufferPos = checked(this.bufferPos + size);
- this.EnsureBuffer();
- Debug.Assert(buffer != null);
-
- for (int i = 0; i != size; i++, oldPos++)
- {
- this.buffer[oldPos] = pb[i];
- }
- }
- }
-
- internal void AddBinary(string? value, int size)
- {
- if (size > ushort.MaxValue)
- {
- size = ushort.MaxValue - 1;
- }
-
- if (this.bufferNesting != 0)
- {
- this.EnsureBuffer(size + 2);
- }
-
- this.AddScalar(&size, 2);
-
- if (size != 0)
- {
- if (this.bufferNesting == 0)
- {
- this.ScalarsEnd();
- this.PinArray(value, size);
- }
- else
- {
- int oldPos = this.bufferPos;
- this.bufferPos = checked(this.bufferPos + size);
- this.EnsureBuffer();
- Debug.Assert(buffer != null);
-
- fixed (void* p = value)
- {
- Marshal.Copy((IntPtr)p, buffer, oldPos, size);
- }
- }
- }
- }
-
- internal void AddNullTerminatedString(string? value)
- {
- // Treat null strings as empty strings.
- if (value == null)
- {
- value = string.Empty;
- }
-
- // Calculate the size of the string including the trailing NULL char.
- // Don't use value.Length here because string allows for embedded NULL characters.
- int nullCharIndex = value.IndexOf((char)0);
- if (nullCharIndex < 0)
- {
- nullCharIndex = value.Length;
- }
- int size = (nullCharIndex + 1) * 2;
-
- if (this.bufferNesting != 0)
- {
- this.EnsureBuffer(size);
- }
-
- if (this.bufferNesting == 0)
- {
- this.ScalarsEnd();
- this.PinArray(value, size);
- }
- else
- {
- int oldPos = this.bufferPos;
- this.bufferPos = checked(this.bufferPos + size);
- this.EnsureBuffer();
- Debug.Assert(buffer != null);
-
- fixed (void* p = value)
- {
- Marshal.Copy((IntPtr)p, buffer, oldPos, size);
- }
- }
- }
-
- internal void AddBinary(Array value, int size)
- {
- this.AddArray(value, size, 1);
- }
-
- internal void AddArray(Array? value, int length, int itemSize)
- {
- if (length > ushort.MaxValue)
- {
- length = ushort.MaxValue;
- }
-
- int size = length * itemSize;
- if (this.bufferNesting != 0)
- {
- this.EnsureBuffer(size + 2);
- }
-
- this.AddScalar(&length, 2);
-
- if (length != 0)
- {
- if (this.bufferNesting == 0)
- {
- this.ScalarsEnd();
- this.PinArray(value, size);
- }
- else
- {
- int oldPos = this.bufferPos;
- this.bufferPos = checked(this.bufferPos + size);
- this.EnsureBuffer();
- Debug.Assert(value != null && buffer != null);
- Buffer.BlockCopy(value, 0, this.buffer, oldPos, size);
- }
- }
- }
-
- /// <summary>
- /// Marks the start of a non-blittable array or enumerable.
- /// </summary>
- /// <returns>Bookmark to be passed to EndBufferedArray.</returns>
- internal int BeginBufferedArray()
- {
- this.BeginBuffered();
- this.bufferPos += 2; // Reserve space for the array length (filled in by EndEnumerable)
- return this.bufferPos;
- }
-
- /// <summary>
- /// Marks the end of a non-blittable array or enumerable.
- /// </summary>
- /// <param name="bookmark">The value returned by BeginBufferedArray.</param>
- /// <param name="count">The number of items in the array.</param>
- internal void EndBufferedArray(int bookmark, int count)
- {
- this.EnsureBuffer();
- Debug.Assert(buffer != null);
- this.buffer[bookmark - 2] = unchecked((byte)count);
- this.buffer[bookmark - 1] = unchecked((byte)(count >> 8));
- this.EndBuffered();
- }
-
- /// <summary>
- /// Marks the start of dynamically-buffered data.
- /// </summary>
- internal void BeginBuffered()
- {
- this.ScalarsEnd();
- this.bufferNesting++;
- }
-
- /// <summary>
- /// Marks the end of dynamically-buffered data.
- /// </summary>
- internal void EndBuffered()
- {
- this.bufferNesting--;
-
- if (this.bufferNesting == 0)
- {
- /*
- TODO (perf): consider coalescing adjacent buffered regions into a
- single buffer, similar to what we're already doing for adjacent
- scalars. In addition, if a type contains a buffered region adjacent
- to a blittable array, and the blittable array is small, it would be
- more efficient to buffer the array instead of pinning it.
- */
-
- this.EnsureBuffer();
- Debug.Assert(buffer != null);
- this.PinArray(this.buffer, this.bufferPos);
- this.buffer = null;
- this.bufferPos = 0;
- }
- }
-
- private void EnsureBuffer()
- {
- int required = this.bufferPos;
- if (this.buffer == null || this.buffer.Length < required)
- {
- this.GrowBuffer(required);
- }
- }
-
- private void EnsureBuffer(int additionalSize)
- {
- int required = this.bufferPos + additionalSize;
- if (this.buffer == null || this.buffer.Length < required)
- {
- this.GrowBuffer(required);
- }
- }
-
- private void GrowBuffer(int required)
- {
- int newSize = this.buffer == null ? 64 : this.buffer.Length;
-
- do
- {
- newSize *= 2;
- }
- while (newSize < required);
-
- Array.Resize(ref this.buffer, newSize);
- }
-
- private void PinArray(object? value, int size)
- {
- GCHandle* pinsTemp = this.pins;
- if (this.pinsEnd <= pinsTemp)
- {
- throw new IndexOutOfRangeException(SR.EventSource_PinArrayOutOfRange);
- }
-
- EventSource.EventData* datasTemp = this.datas;
- if (this.datasEnd <= datasTemp)
- {
- throw new IndexOutOfRangeException(SR.EventSource_DataDescriptorsOutOfRange);
- }
-
- this.pins = pinsTemp + 1;
- this.datas = datasTemp + 1;
-
- *pinsTemp = GCHandle.Alloc(value, GCHandleType.Pinned);
- datasTemp->DataPointer = pinsTemp->AddrOfPinnedObject();
- datasTemp->m_Size = size;
- }
-
- private void ScalarsBegin()
- {
- if (!this.writingScalars)
- {
- EventSource.EventData* datasTemp = this.datas;
- if (this.datasEnd <= datasTemp)
- {
- throw new IndexOutOfRangeException(SR.EventSource_DataDescriptorsOutOfRange);
- }
-
- datasTemp->DataPointer = (IntPtr)this.scratch;
- this.writingScalars = true;
- }
- }
-
- private void ScalarsEnd()
- {
- if (this.writingScalars)
- {
- EventSource.EventData* datasTemp = this.datas;
- datasTemp->m_Size = checked((int)(this.scratch - (byte*)datasTemp->m_Ptr));
- this.datas = datasTemp + 1;
- this.writingScalars = false;
- }
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EmptyStruct.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EmptyStruct.cs
deleted file mode 100644
index bc7fb8c3462..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EmptyStruct.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Empty struct indicating no payload data.
- /// </summary>
- internal struct EmptyStruct
- {
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EnumHelper.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EnumHelper.cs
deleted file mode 100644
index 33c085dcd17..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EnumHelper.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if EVENTSOURCE_GENERICS
-?using System;
-using System.Reflection;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Provides support for casting enums to their underlying type
- /// from within generic context.
- /// </summary>
- /// <typeparam name="UnderlyingType">
- /// The underlying type of the enum.
- /// </typeparam>
- internal static class EnumHelper<UnderlyingType>
- {
- public static UnderlyingType Cast<ValueType>(ValueType value)
- {
- return (UnderlyingType)(object)value;
- }
- }
-
-}
-#endif
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs
deleted file mode 100644
index 92a1a823f94..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Collections;
-using System.Collections.Generic;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- internal sealed class EnumerableTypeInfo : TraceLoggingTypeInfo
- {
- private readonly TraceLoggingTypeInfo elementInfo;
-
- public EnumerableTypeInfo(Type type, TraceLoggingTypeInfo elementInfo)
- : base(type)
- {
- this.elementInfo = elementInfo;
- }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- collector.BeginBufferedArray();
- this.elementInfo.WriteMetadata(collector, name, format);
- collector.EndBufferedArray();
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- int bookmark = collector.BeginBufferedArray();
-
- int count = 0;
- IEnumerable? enumerable = (IEnumerable?)value.ReferenceValue;
- if (enumerable != null)
- {
- foreach (object? element in enumerable)
- {
- this.elementInfo.WriteData(collector, elementInfo.PropertyValueFactory(element));
- count++;
- }
- }
-
- collector.EndBufferedArray(bookmark, count);
- }
-
- public override object? GetData(object? value)
- {
- Debug.Assert(value != null, "null accepted only for some overrides");
- var iterType = (IEnumerable)value;
- List<object?> serializedEnumerable = new List<object?>();
- foreach (object? element in iterType)
- {
- serializedEnumerable.Add(elementInfo.GetData(element));
- }
- return serializedEnumerable.ToArray();
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventDataAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventDataAttribute.cs
deleted file mode 100644
index cd88c81c3dc..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventDataAttribute.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Used when authoring types that will be passed to EventSource.Write.
- /// EventSource.Write&lt;T> only works when T is either an anonymous type
- /// or a type with an [EventData] attribute. In addition, the properties
- /// of T must be supported property types. Supported property types include
- /// simple built-in types (int, string, Guid, DateTime, DateTimeOffset,
- /// KeyValuePair, etc.), anonymous types that only contain supported types,
- /// types with an [EventData] attribute, arrays of the above, and IEnumerable
- /// of the above.
- /// </summary>
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)]
- public class EventDataAttribute
- : Attribute
- {
- private EventLevel level = (EventLevel)(-1);
- private EventOpcode opcode = (EventOpcode)(-1);
-
- /// <summary>
- /// Gets or sets the name to use if this type is used for an
- /// implicitly-named event or an implicitly-named property.
- ///
- /// Example 1:
- ///
- /// EventSource.Write(null, new T()); // implicitly-named event
- ///
- /// The name of the event will be determined as follows:
- ///
- /// if (T has an EventData attribute and attribute.Name != null)
- /// eventName = attribute.Name;
- /// else
- /// eventName = typeof(T).Name;
- ///
- /// Example 2:
- ///
- /// EventSource.Write(name, new { _1 = new T() }); // implicitly-named field
- ///
- /// The name of the field will be determined as follows:
- ///
- /// if (T has an EventData attribute and attribute.Name != null)
- /// fieldName = attribute.Name;
- /// else
- /// fieldName = typeof(T).Name;
- /// </summary>
- public string? Name
- {
- get;
- set;
- }
-
- /// <summary>
- /// Gets or sets the level to use for the event.
- /// Invalid levels (outside the range 0..255) are treated as unset.
- /// Note that the Level attribute can bubble-up, i.e. if a type contains
- /// a sub-object (a field or property), and the sub-object's type has a
- /// TraceLoggingEvent attribute, the Level from the sub-object's attribute
- /// can affect the event's level.
- ///
- /// Example: for EventSource.Write(name, options, data), the level of the
- /// event will be determined as follows:
- ///
- /// if (options.Level has been set)
- /// eventLevel = options.Level;
- /// else if (data.GetType() has a TraceLoggingEvent attribute and attribute.Level has been set)
- /// eventLevel = attribute.Level;
- /// else if (a field/property contained in data has a TraceLoggingEvent attribute and attribute.Level has been set)
- /// eventLevel = attribute.Level;
- /// else
- /// eventLevel = EventLevel.LogAlways;
- /// </summary>
- internal EventLevel Level
- {
- get => this.level;
- set => this.level = value;
- }
-
- /// <summary>
- /// Gets or sets the opcode to use for the event.
- /// Invalid opcodes (outside the range 0..255) are treated as unset.
- /// Note that the Opcode attribute can bubble-up, i.e. if a type contains
- /// a sub-object (a field or property), and the sub-object's type has a
- /// TraceLoggingEvent attribute, the Opcode from the sub-object's attribute
- /// can affect the event's opcode.
- ///
- /// Example: for EventSource.Write(name, options, data), the opcode of the
- /// event will be determined as follows:
- ///
- /// if (options.Opcode has been set)
- /// eventOpcode = options.Opcode;
- /// else if (data.GetType() has a TraceLoggingEvent attribute and attribute.Opcode has been set)
- /// eventOpcode = attribute.Opcode;
- /// else if (a field/property contained in data has a TraceLoggingEvent attribute and attribute.Opcode has been set)
- /// eventOpcode = attribute.Opcode;
- /// else
- /// eventOpcode = EventOpcode.Info;
- /// </summary>
- internal EventOpcode Opcode
- {
- get => this.opcode;
- set => this.opcode = value;
- }
-
- /// <summary>
- /// Gets or sets the keywords to use for the event.
- /// Note that the Keywords attribute can bubble-up, i.e. if a type contains
- /// a sub-object (a field or property), and the sub-object's type has a
- /// TraceLoggingEvent attribute, the Keywords from the sub-object's attribute
- /// can affect the event's keywords.
- ///
- /// Example: for EventSource.Write(name, options, data), the keywords of the
- /// event will be determined as follows:
- ///
- /// eventKeywords = options.Keywords;
- /// if (data.GetType() has a TraceLoggingEvent attribute)
- /// eventKeywords |= attribute.Keywords;
- /// if (a field/property contained in data has a TraceLoggingEvent attribute)
- /// eventKeywords |= attribute.Keywords;
- /// </summary>
- internal EventKeywords Keywords
- {
- get;
- set;
- }
-
- /// <summary>
- /// Gets or sets the flags for an event. These flags are ignored by ETW,
- /// but can have meaning to the event consumer.
- /// </summary>
- internal EventTags Tags
- {
- get;
- set;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldAttribute.cs
deleted file mode 100644
index cad4a9a0683..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldAttribute.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Tags are flags that are not interpreted by EventSource but are passed along
- /// to the EventListener. The EventListener determines the semantics of the flags.
- /// </summary>
- [Flags]
- public enum EventFieldTags
- {
- /// <summary>
- /// No special traits are added to the field.
- /// </summary>
- None = 0,
-
- /* Bits below 0x10000 are available for any use by the provider. */
- /* Bits at or above 0x10000 are reserved for definition by Microsoft. */
- }
-
- /// <summary>
- /// TraceLogging: used when authoring types that will be passed to EventSource.Write.
- /// Controls how a field or property is handled when it is written as a
- /// field in a TraceLogging event. Apply this attribute to a field or
- /// property if the default handling is not correct. (Apply the
- /// TraceLoggingIgnore attribute if the property should not be
- /// included as a field in the event.)
- /// The default for Name is null, which means that the name of the
- /// underlying field or property will be used as the event field's name.
- /// The default for PiiTag is 0, which means that the event field does not
- /// contain personally-identifiable information.
- /// </summary>
- [AttributeUsage(AttributeTargets.Property)]
- public class EventFieldAttribute
- : Attribute
- {
- /// <summary>
- /// User defined options for the field. These are not interpreted by the EventSource
- /// but are available to the Listener. See EventFieldSettings for details
- /// </summary>
- public EventFieldTags Tags
- {
- get;
- set;
- }
-
- /// <summary>
- /// Gets or sets the name to use for the field. This defaults to null.
- /// If null, the name of the corresponding property will be used
- /// as the event field's name.
- /// TODO REMOVE
- /// </summary>
- internal string? Name
- {
- get;
- set;
- }
-
- /// <summary>
- /// Gets or sets a field formatting hint.
- /// </summary>
- public EventFieldFormat Format
- {
- get;
- set;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldFormat.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldFormat.cs
deleted file mode 100644
index 20672e68aa9..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventFieldFormat.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Provides a hint that may be used by an event listener when formatting
- /// an event field for display. Note that the event listener may ignore the
- /// hint if it does not recognize a particular combination of type and format.
- /// Similar to TDH_OUTTYPE.
- /// </summary>
- public enum EventFieldFormat
- {
- /// <summary>
- /// Field receives default formatting based on the field's underlying type.
- /// </summary>
- Default = 0,
-#if false
- /// <summary>
- /// Field should not be displayed.
- /// </summary>
- NoPrint = 1,
-#endif
- /// <summary>
- /// Field should be formatted as character or string data.
- /// Typically applied to 8-bit or 16-bit integers.
- /// This is the default format for String and Char types.
- /// </summary>
- String = 2,
-
- /// <summary>
- /// Field should be formatted as boolean data. Typically applied to 8-bit
- /// or 32-bit integers. This is the default format for the Boolean type.
- /// </summary>
- Boolean = 3,
-
- /// <summary>
- /// Field should be formatted as hexadecimal data. Typically applied to
- /// integer types.
- /// </summary>
- Hexadecimal = 4,
-
-#if false
- /// <summary>
- /// Field should be formatted as a process identifier. Typically applied to
- /// 32-bit integer types.
- /// </summary>
- ProcessId = 5,
-
- /// <summary>
- /// Field should be formatted as a thread identifier. Typically applied to
- /// 32-bit integer types.
- /// </summary>
- ThreadId = 6,
-
- /// <summary>
- /// Field should be formatted as an Internet port. Typically applied to 16-bit integer
- /// types.
- /// </summary>
- Port = 7,
- /// <summary>
- /// Field should be formatted as an Internet Protocol v4 address. Typically applied to
- /// 32-bit integer types.
- /// </summary>
- Ipv4Address = 8,
-
- /// <summary>
- /// Field should be formatted as an Internet Protocol v6 address. Typically applied to
- /// byte[] types.
- /// </summary>
- Ipv6Address = 9,
- /// <summary>
- /// Field should be formatted as a SOCKADDR. Typically applied to byte[] types.
- /// </summary>
- SocketAddress = 10,
-#endif
- /// <summary>
- /// Field should be formatted as XML string data. Typically applied to
- /// strings or arrays of 8-bit or 16-bit integers.
- /// </summary>
- Xml = 11,
-
- /// <summary>
- /// Field should be formatted as JSON string data. Typically applied to
- /// strings or arrays of 8-bit or 16-bit integers.
- /// </summary>
- Json = 12,
-#if false
- /// <summary>
- /// Field should be formatted as a Win32 error code. Typically applied to
- /// 32-bit integer types.
- /// </summary>
- Win32Error = 13,
-
- /// <summary>
- /// Field should be formatted as an NTSTATUS code. Typically applied to
- /// 32-bit integer types.
- /// </summary>
- NTStatus = 14,
-#endif
- /// <summary>
- /// Field should be formatted as an HRESULT code. Typically applied to
- /// 32-bit integer types.
- /// </summary>
- HResult = 15,
-#if false
- /// <summary>
- /// Field should be formatted as a FILETIME. Typically applied to 64-bit
- /// integer types. This is the default format for DateTime types.
- /// </summary>
- FileTime = 16,
- /// <summary>
- /// When applied to a numeric type, indicates that the type should be formatted
- /// as a signed integer. This is the default format for signed integer types.
- /// </summary>
- Signed = 17,
-
- /// <summary>
- /// When applied to a numeric type, indicates that the type should be formatted
- /// as an unsigned integer. This is the default format for unsigned integer types.
- /// </summary>
- Unsigned = 18,
-#endif
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventIgnoreAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventIgnoreAttribute.cs
deleted file mode 100644
index 81411ebe2d3..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventIgnoreAttribute.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Used when authoring types that will be passed to EventSource.Write.
- /// By default, EventSource.Write will write all of an object's public
- /// properties to the event payload. Apply [EventIgnore] to a public
- /// property to prevent EventSource.Write from including the property in
- /// the event.
- /// </summary>
- [AttributeUsage(AttributeTargets.Property)]
- public class EventIgnoreAttribute
- : Attribute
- {
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
deleted file mode 100644
index b177a7526d3..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
+++ /dev/null
@@ -1,150 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// EventPayload class holds the list of parameters and their corresponding values for user defined types passed to
- /// EventSource APIs.
- /// Preserving the order of the elements as they were found inside user defined types is the most important characteristic of this class.
- /// </summary>
- internal class EventPayload : IDictionary<string, object?>
- {
- internal EventPayload(List<string> payloadNames, List<object?> payloadValues)
- {
- Debug.Assert(payloadNames.Count == payloadValues.Count);
-
- m_names = payloadNames;
- m_values = payloadValues;
- }
-
- public ICollection<string> Keys => m_names;
- public ICollection<object?> Values => m_values;
-
- public object? this[string key]
- {
- get
- {
- if (key == null)
- throw new System.ArgumentNullException(nameof(key));
-
- int position = 0;
- foreach (string name in m_names)
- {
- if (name == key)
- {
- return m_values[position];
- }
- position++;
- }
-
- throw new System.Collections.Generic.KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key));
- }
- set => throw new System.NotSupportedException();
- }
-
- public void Add(string key, object? value)
- {
- throw new System.NotSupportedException();
- }
-
- public void Add(KeyValuePair<string, object?> payloadEntry)
- {
- throw new System.NotSupportedException();
- }
-
- public void Clear()
- {
- throw new System.NotSupportedException();
- }
-
- public bool Contains(KeyValuePair<string, object?> entry)
- {
- return ContainsKey(entry.Key);
- }
-
- public bool ContainsKey(string key)
- {
- if (key == null)
- throw new System.ArgumentNullException(nameof(key));
-
- foreach (string item in m_names)
- {
- if (item == key)
- return true;
- }
- return false;
- }
-
- public int Count => m_names.Count;
-
- public bool IsReadOnly => true;
-
- public IEnumerator<KeyValuePair<string, object?>> GetEnumerator()
- {
- for (int i = 0; i < Keys.Count; i++)
- {
- yield return new KeyValuePair<string, object?>(this.m_names[i], this.m_values[i]);
- }
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- var instance = this as IEnumerable<KeyValuePair<string, object?>>;
- return instance.GetEnumerator();
- }
-
- public void CopyTo(KeyValuePair<string, object?>[] payloadEntries, int count)
- {
- throw new System.NotSupportedException();
- }
-
- public bool Remove(string key)
- {
- throw new System.NotSupportedException();
- }
-
- public bool Remove(KeyValuePair<string, object?> entry)
- {
- throw new System.NotSupportedException();
- }
-
- public bool TryGetValue(string key, [MaybeNullWhen(false)] out object? value)
- {
- if (key == null)
- throw new System.ArgumentNullException(nameof(key));
-
- int position = 0;
- foreach (string name in m_names)
- {
- if (name == key)
- {
- value = m_values[position];
- return true;
- }
- position++;
- }
-
- value = default;
- return false;
- }
-
-#region private
- private readonly List<string> m_names;
- private readonly List<object?> m_values;
-#endregion
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
deleted file mode 100644
index 25c8563346a..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
+++ /dev/null
@@ -1,314 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Provides support for EventSource activities by marking the start and
- /// end of a particular operation.
- /// </summary>
- internal sealed class EventSourceActivity
- : IDisposable
- {
- /// <summary>
- /// Initializes a new instance of the EventSourceActivity class that
- /// is attached to the specified event source. The new activity will
- /// not be attached to any related (parent) activity.
- /// The activity is created in the Initialized state.
- /// </summary>
- /// <param name="eventSource">
- /// The event source to which the activity information is written.
- /// </param>
- public EventSourceActivity(EventSource eventSource)
- {
- if (eventSource == null)
- throw new ArgumentNullException(nameof(eventSource));
-
- this.eventSource = eventSource;
- }
-
- /// <summary>
- /// You can make an activity out of just an EventSource.
- /// </summary>
- public static implicit operator EventSourceActivity(EventSource eventSource) =>
- new EventSourceActivity(eventSource);
-
- /* Properties */
- /// <summary>
- /// Gets the event source to which this activity writes events.
- /// </summary>
- public EventSource EventSource => this.eventSource;
-
- /// <summary>
- /// Gets this activity's unique identifier, or the default Guid if the
- /// event source was disabled when the activity was initialized.
- /// </summary>
- public Guid Id => this.activityId;
-
-#if false // don't expose RelatedActivityId unless there is a need.
- /// <summary>
- /// Gets the unique identifier of this activity's related (parent)
- /// activity.
- /// </summary>
- public Guid RelatedId
- {
- get { return this.relatedActivityId; }
- }
-#endif
-
- /// <summary>
- /// Writes a Start event with the specified name and data. If the start event is not active (because the provider
- /// is not on or keyword-level indicates the event is off, then the returned activity is simply the 'this' pointer
- /// and it is effectively like start did not get called.
- ///
- /// A new activityID GUID is generated and the returned
- /// EventSourceActivity remembers this activity and will mark every event (including the start stop and any writes)
- /// with this activityID. In addition the Start activity will log a 'relatedActivityID' that was the activity
- /// ID before the start event. This way event processors can form a linked list of all the activities that
- /// caused this one (directly or indirectly).
- /// </summary>
- /// <param name="eventName">
- /// The name to use for the event. It is strongly suggested that this name end in 'Start' (e.g. DownloadStart).
- /// If you do this, then the Stop() method will automatically replace the 'Start' suffix with a 'Stop' suffix.
- /// </param>
- /// <param name="options">Allow options (keywords, level) to be set for the write associated with this start
- /// These will also be used for the stop event.</param>
- /// <param name="data">The data to include in the event.</param>
- public EventSourceActivity Start<T>(string? eventName, EventSourceOptions options, T data)
- {
- return this.Start(eventName, ref options, ref data);
- }
- /// <summary>
- /// Shortcut version see Start(string eventName, EventSourceOptions options, T data) Options is empty (no keywords
- /// and level==Info) Data payload is empty.
- /// </summary>
- public EventSourceActivity Start(string? eventName)
- {
- EventSourceOptions options = default;
- EmptyStruct data = default;
- return this.Start(eventName, ref options, ref data);
- }
- /// <summary>
- /// Shortcut version see Start(string eventName, EventSourceOptions options, T data). Data payload is empty.
- /// </summary>
- public EventSourceActivity Start(string? eventName, EventSourceOptions options)
- {
- EmptyStruct data = default;
- return this.Start(eventName, ref options, ref data);
- }
- /// <summary>
- /// Shortcut version see Start(string eventName, EventSourceOptions options, T data) Options is empty (no keywords
- /// and level==Info)
- /// </summary>
- public EventSourceActivity Start<T>(string? eventName, T data)
- {
- EventSourceOptions options = default;
- return this.Start(eventName, ref options, ref data);
- }
-
- /// <summary>
- /// Writes a Stop event with the specified data, and sets the activity
- /// to the Stopped state. The name is determined by the eventName used in Start.
- /// If that Start event name is suffixed with 'Start' that is removed, and regardless
- /// 'Stop' is appended to the result to form the Stop event name.
- /// May only be called when the activity is in the Started state.
- /// </summary>
- /// <param name="data">The data to include in the event.</param>
- public void Stop<T>(T data)
- {
- this.Stop(null, ref data);
- }
- /// <summary>
- /// Used if you wish to use the non-default stop name (which is the start name with Start replace with 'Stop')
- /// This can be useful to indicate unusual ways of stopping (but it is still STRONGLY recommended that
- /// you start with the same prefix used for the start event and you end with the 'Stop' suffix.
- /// </summary>
- public void Stop<T>(string? eventName)
- {
- EmptyStruct data = default;
- this.Stop(eventName, ref data);
- }
- /// <summary>
- /// Used if you wish to use the non-default stop name (which is the start name with Start replace with 'Stop')
- /// This can be useful to indicate unusual ways of stopping (but it is still STRONGLY recommended that
- /// you start with the same prefix used for the start event and you end with the 'Stop' suffix.
- /// </summary>
- public void Stop<T>(string? eventName, T data)
- {
- this.Stop(eventName, ref data);
- }
-
- /// <summary>
- /// Writes an event associated with this activity to the eventSource associated with this activity.
- /// May only be called when the activity is in the Started state.
- /// </summary>
- /// <param name="eventName">
- /// The name to use for the event. If null, the name is determined from
- /// data's type.
- /// </param>
- /// <param name="options">
- /// The options to use for the event.
- /// </param>
- /// <param name="data">The data to include in the event.</param>
- public void Write<T>(string? eventName, EventSourceOptions options, T data)
- {
- this.Write(this.eventSource, eventName, ref options, ref data);
- }
- /// <summary>
- /// Writes an event associated with this activity.
- /// May only be called when the activity is in the Started state.
- /// </summary>
- /// <param name="eventName">
- /// The name to use for the event. If null, the name is determined from
- /// data's type.
- /// </param>
- /// <param name="data">The data to include in the event.</param>
- public void Write<T>(string? eventName, T data)
- {
- EventSourceOptions options = default;
- this.Write(this.eventSource, eventName, ref options, ref data);
- }
- /// <summary>
- /// Writes a trivial event associated with this activity.
- /// May only be called when the activity is in the Started state.
- /// </summary>
- /// <param name="eventName">
- /// The name to use for the event. Must not be null.
- /// </param>
- /// <param name="options">
- /// The options to use for the event.
- /// </param>
- public void Write(string? eventName, EventSourceOptions options)
- {
- EmptyStruct data = default;
- this.Write(this.eventSource, eventName, ref options, ref data);
- }
- /// <summary>
- /// Writes a trivial event associated with this activity.
- /// May only be called when the activity is in the Started state.
- /// </summary>
- /// <param name="eventName">
- /// The name to use for the event. Must not be null.
- /// </param>
- public void Write(string? eventName)
- {
- EventSourceOptions options = default;
- EmptyStruct data = default;
- this.Write(this.eventSource, eventName, ref options, ref data);
- }
- /// <summary>
- /// Writes an event to a arbitrary eventSource stamped with the activity ID of this activity.
- /// </summary>
- public void Write<T>(EventSource source, string? eventName, EventSourceOptions options, T data)
- {
- this.Write(source, eventName, ref options, ref data);
- }
-
- /// <summary>
- /// Releases any unmanaged resources associated with this object.
- /// If the activity is in the Started state, calls Stop().
- /// </summary>
- public void Dispose()
- {
- if (this.state == State.Started)
- {
- EmptyStruct data = default;
- this.Stop(null, ref data);
- }
- }
-
-#region private
- private EventSourceActivity Start<T>(string? eventName, ref EventSourceOptions options, ref T data)
- {
- if (this.state != State.Started)
- throw new InvalidOperationException();
-
- // If the source is not on at all, then we don't need to do anything and we can simply return ourselves.
- if (!this.eventSource.IsEnabled())
- return this;
-
- var newActivity = new EventSourceActivity(eventSource);
- if (!this.eventSource.IsEnabled(options.Level, options.Keywords))
- {
- // newActivity.relatedActivityId = this.Id;
- Guid relatedActivityId = this.Id;
- newActivity.activityId = Guid.NewGuid();
- newActivity.startStopOptions = options;
- newActivity.eventName = eventName;
- newActivity.startStopOptions.Opcode = EventOpcode.Start;
- this.eventSource.Write(eventName, ref newActivity.startStopOptions, ref newActivity.activityId, ref relatedActivityId, ref data);
- }
- else
- {
- // If we are not active, we don't set the eventName, which basically also turns off the Stop event as well.
- newActivity.activityId = this.Id;
- }
-
- return newActivity;
- }
-
- private void Write<T>(EventSource eventSource, string? eventName, ref EventSourceOptions options, ref T data)
- {
- if (this.state != State.Started)
- throw new InvalidOperationException(); // Write after stop.
- if (eventName == null)
- throw new ArgumentNullException();
-
- eventSource.Write(eventName, ref options, ref this.activityId, ref s_empty, ref data);
- }
-
- private void Stop<T>(string? eventName, ref T data)
- {
- if (this.state != State.Started)
- throw new InvalidOperationException();
-
- // If start was not fired, then stop isn't as well.
- if (!StartEventWasFired)
- return;
-
- Debug.Assert(this.eventName != null);
-
- this.state = State.Stopped;
- if (eventName == null)
- {
- eventName = this.eventName;
- if (eventName.EndsWith("Start"))
- eventName = eventName.Substring(0, eventName.Length - 5);
- eventName += "Stop";
- }
- this.startStopOptions.Opcode = EventOpcode.Stop;
- this.eventSource.Write(eventName, ref this.startStopOptions, ref this.activityId, ref s_empty, ref data);
- }
-
- private enum State
- {
- Started,
- Stopped
- }
-
- /// <summary>
- /// If eventName is non-null then we logged a start event
- /// </summary>
- private bool StartEventWasFired => eventName != null;
-
- private readonly EventSource eventSource;
- private EventSourceOptions startStopOptions;
- internal Guid activityId;
- // internal Guid relatedActivityId;
- private State state;
- private string? eventName;
-
- internal static Guid s_empty;
-#endregion
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceOptions.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceOptions.cs
deleted file mode 100644
index c6b675a420a..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceOptions.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Used when calling EventSource.Write.
- /// Optional overrides for event settings such as Level, Keywords, or Opcode.
- /// If overrides are not provided for a setting, default values will be used.
- /// </summary>
- public struct EventSourceOptions
- {
- internal EventKeywords keywords;
- internal EventTags tags;
- internal EventActivityOptions activityOptions;
- internal byte level;
- internal byte opcode;
- internal byte valuesSet;
-
- internal const byte keywordsSet = 0x1;
- internal const byte tagsSet = 0x2;
- internal const byte levelSet = 0x4;
- internal const byte opcodeSet = 0x8;
- internal const byte activityOptionsSet = 0x10;
-
- /// <summary>
- /// Gets or sets the level to use for the specified event. If this property
- /// is unset, the event's level will be 5 (Verbose).
- /// </summary>
- public EventLevel Level
- {
- get => (EventLevel)this.level;
- set
- {
- this.level = checked((byte)value);
- this.valuesSet |= levelSet;
- }
- }
-
- /// <summary>
- /// Gets or sets the opcode to use for the specified event. If this property
- /// is unset, the event's opcode will 0 (Info).
- /// </summary>
- public EventOpcode Opcode
- {
- get => (EventOpcode)this.opcode;
- set
- {
- this.opcode = checked((byte)value);
- this.valuesSet |= opcodeSet;
- }
- }
-
- internal bool IsOpcodeSet => (this.valuesSet & opcodeSet) != 0;
-
- /// <summary>
- /// Gets or sets the keywords to use for the specified event. If this
- /// property is unset, the event's keywords will be 0.
- /// </summary>
- public EventKeywords Keywords
- {
- get => this.keywords;
- set
- {
- this.keywords = value;
- this.valuesSet |= keywordsSet;
- }
- }
-
- /// <summary>
- /// Gets or sets the tags to use for the specified event. If this property is
- /// unset, the event's tags will be 0.
- /// </summary>
- public EventTags Tags
- {
- get => this.tags;
- set
- {
- this.tags = value;
- this.valuesSet |= tagsSet;
- }
- }
-
- /// <summary>
- /// Gets or sets the activity options for this specified events. If this property is
- /// unset, the event's activity options will be 0.
- /// </summary>
- public EventActivityOptions ActivityOptions
- {
- get => this.activityOptions;
- set
- {
- this.activityOptions = value;
- this.valuesSet |= activityOptionsSet;
- }
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
deleted file mode 100644
index c42e84afdc7..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
+++ /dev/null
@@ -1,230 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Text;
-
-#if ES_BUILD_STANDALONE
-using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Contains the information needed to generate tracelogging
- /// metadata for an event field.
- /// </summary>
- internal class FieldMetadata
- {
- /// <summary>
- /// Name of the field
- /// </summary>
- private readonly string name;
-
- /// <summary>
- /// The number of bytes in the UTF8 Encoding of 'name' INCLUDING a null terminator.
- /// </summary>
- private readonly int nameSize;
- private readonly EventFieldTags tags;
- private readonly byte[]? custom;
-
- /// <summary>
- /// ETW supports fixed sized arrays. If inType has the InTypeFixedCountFlag then this is the
- /// statically known count for the array. It is also used to encode the number of bytes of
- /// custom meta-data if InTypeCustomCountFlag set.
- /// </summary>
- private readonly ushort fixedCount;
-
- private byte inType;
- private byte outType;
-
- /// <summary>
- /// Scalar or variable-length array.
- /// </summary>
- public FieldMetadata(
- string name,
- TraceLoggingDataType type,
- EventFieldTags tags,
- bool variableCount)
- : this(
- name,
- type,
- tags,
- variableCount ? Statics.InTypeVariableCountFlag : (byte)0,
- 0,
- null)
- {
- }
-
- /// <summary>
- /// Fixed-length array.
- /// </summary>
- public FieldMetadata(
- string name,
- TraceLoggingDataType type,
- EventFieldTags tags,
- ushort fixedCount)
- : this(
- name,
- type,
- tags,
- Statics.InTypeFixedCountFlag,
- fixedCount,
- null)
- {
- }
-
- /// <summary>
- /// Custom serializer
- /// </summary>
- public FieldMetadata(
- string name,
- TraceLoggingDataType type,
- EventFieldTags tags,
- byte[]? custom)
- : this(
- name,
- type,
- tags,
- Statics.InTypeCustomCountFlag,
- checked((ushort)(custom == null ? 0 : custom.Length)),
- custom)
- {
- }
-
- private FieldMetadata(
- string name,
- TraceLoggingDataType dataType,
- EventFieldTags tags,
- byte countFlags,
- ushort fixedCount = 0,
- byte[]? custom = null)
- {
- if (name == null)
- {
- throw new ArgumentNullException(
- nameof(name),
- "This usually means that the object passed to Write is of a type that"
- + " does not support being used as the top-level object in an event,"
- + " e.g. a primitive or built-in type.");
- }
-
- Statics.CheckName(name);
- int coreType = (int)dataType & Statics.InTypeMask;
- this.name = name;
- this.nameSize = Encoding.UTF8.GetByteCount(this.name) + 1;
- this.inType = (byte)(coreType | countFlags);
- this.outType = (byte)(((int)dataType >> 8) & Statics.OutTypeMask);
- this.tags = tags;
- this.fixedCount = fixedCount;
- this.custom = custom;
-
- if (countFlags != 0)
- {
- if (coreType == (int)TraceLoggingDataType.Nil)
- {
- throw new NotSupportedException(SR.EventSource_NotSupportedArrayOfNil);
- }
- if (coreType == (int)TraceLoggingDataType.Binary)
- {
- throw new NotSupportedException(SR.EventSource_NotSupportedArrayOfBinary);
- }
- if (coreType == (int)TraceLoggingDataType.Utf16String ||
- coreType == (int)TraceLoggingDataType.MbcsString)
- {
- throw new NotSupportedException(SR.EventSource_NotSupportedArrayOfNullTerminatedString);
- }
- }
-
- if (((int)this.tags & 0xfffffff) != 0)
- {
- this.outType |= Statics.OutTypeChainFlag;
- }
-
- if (this.outType != 0)
- {
- this.inType |= Statics.InTypeChainFlag;
- }
- }
-
- public void IncrementStructFieldCount()
- {
- this.inType |= Statics.InTypeChainFlag;
- this.outType++;
- if ((this.outType & Statics.OutTypeMask) == 0)
- {
- throw new NotSupportedException(SR.EventSource_TooManyFields);
- }
- }
-
- /// <summary>
- /// This is the main routine for FieldMetaData. Basically it will serialize the data in
- /// this structure as TraceLogging style meta-data into the array 'metaArray' starting at
- /// 'pos' (pos is updated to reflect the bytes written).
- ///
- /// Note that 'metaData' can be null, in which case it only updates 'pos'. This is useful
- /// for a 'two pass' approach where you figure out how big to make the array, and then you
- /// fill it in.
- /// </summary>
- public void Encode(ref int pos, byte[]? metadata)
- {
- // Write out the null terminated UTF8 encoded name
- if (metadata != null)
- {
- Encoding.UTF8.GetBytes(this.name, 0, this.name.Length, metadata, pos);
- }
- pos += this.nameSize;
-
- // Write 1 byte for inType
- if (metadata != null)
- {
- metadata[pos] = this.inType;
- }
- pos++;
-
- // If InTypeChainFlag set, then write out the outType
- if (0 != (this.inType & Statics.InTypeChainFlag))
- {
- if (metadata != null)
- {
- metadata[pos] = this.outType;
- }
- pos++;
-
- // If OutTypeChainFlag set, then write out tags
- if (0 != (this.outType & Statics.OutTypeChainFlag))
- {
- Statics.EncodeTags((int)this.tags, ref pos, metadata);
- }
- }
-
- // If InTypeFixedCountFlag set, write out the fixedCount (2 bytes little endian)
- if (0 != (this.inType & Statics.InTypeFixedCountFlag))
- {
- if (metadata != null)
- {
- metadata[pos + 0] = unchecked((byte)this.fixedCount);
- metadata[pos + 1] = (byte)(this.fixedCount >> 8);
- }
- pos += 2;
-
- // If InTypeCustomCountFlag set, write out the blob of custom meta-data.
- if (Statics.InTypeCustomCountFlag == (this.inType & Statics.InTypeCountMask) &&
- this.fixedCount != 0)
- {
- if (metadata != null)
- {
- Debug.Assert(custom != null);
- Buffer.BlockCopy(custom, 0, metadata, pos, this.fixedCount);
- }
- pos += this.fixedCount;
- }
- }
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
deleted file mode 100644
index 3c5cf2541c1..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-using System.Collections.Generic;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: An implementation of TraceLoggingTypeInfo that works
- /// for arbitrary types. It writes all public instance properties of
- /// the type.
- /// </summary>
- internal sealed class InvokeTypeInfo : TraceLoggingTypeInfo
- {
- internal readonly PropertyAnalysis[]? properties;
-
- public InvokeTypeInfo(
- Type type,
- TypeAnalysis typeAnalysis)
- : base(
- type,
- typeAnalysis.name!,
- typeAnalysis.level,
- typeAnalysis.opcode,
- typeAnalysis.keywords,
- typeAnalysis.tags)
- {
- if (typeAnalysis.properties.Length != 0)
- this.properties = typeAnalysis.properties;
- }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- TraceLoggingMetadataCollector groupCollector = collector.AddGroup(name);
- if (this.properties != null)
- {
- foreach (PropertyAnalysis property in this.properties)
- {
- EventFieldFormat propertyFormat = EventFieldFormat.Default;
- EventFieldAttribute? propertyAttribute = property.fieldAttribute;
- if (propertyAttribute != null)
- {
- groupCollector.Tags = propertyAttribute.Tags;
- propertyFormat = propertyAttribute.Format;
- }
-
- property.typeInfo.WriteMetadata(
- groupCollector,
- property.name,
- propertyFormat);
- }
- }
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- if (this.properties != null)
- {
- foreach (PropertyAnalysis property in this.properties)
- {
- property.typeInfo.WriteData(collector, property.getter(value));
- }
- }
- }
-
- public override object? GetData(object? value)
- {
- if (this.properties != null)
- {
- var membersNames = new List<string>();
- var membersValues = new List<object?>();
- for (int i = 0; i < this.properties.Length; i++)
- {
- object? propertyValue = properties[i].propertyInfo.GetValue(value);
- membersNames.Add(properties[i].name);
- membersValues.Add(properties[i].typeInfo.GetData(propertyValue));
- }
- return new EventPayload(membersNames, membersValues);
- }
-
- return null;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs
deleted file mode 100644
index 17bf2eb2aed..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-using System.Collections.Generic;
-using System.Threading;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Stores the metadata and event identifier corresponding
- /// to a tracelogging event type+name+tags combination.
- /// </summary>
- internal sealed class NameInfo
- : ConcurrentSetItem<KeyValuePair<string, EventTags>, NameInfo>
- {
- /// <summary>
- /// Insure that eventIds strictly less than 'eventId' will not be
- /// used by the SelfDescribing events.
- /// </summary>
- internal static void ReserveEventIDsBelow(int eventId)
- {
- while (true)
- {
- int snapshot = lastIdentity;
- int newIdentity = (lastIdentity & ~0xFFFFFF) + eventId;
- newIdentity = Math.Max(newIdentity, snapshot); // Should be redundant. as we only create descriptors once.
- if (Interlocked.CompareExchange(ref lastIdentity, newIdentity, snapshot) == snapshot)
- break;
- }
- }
-
- private static int lastIdentity = Statics.TraceLoggingChannel << 24;
- internal readonly string name;
- internal readonly EventTags tags;
- internal readonly int identity;
- internal readonly byte[] nameMetadata;
-
- public NameInfo(string name, EventTags tags, int typeMetadataSize)
- {
- this.name = name;
- this.tags = tags & Statics.EventTagsMask;
- this.identity = Interlocked.Increment(ref lastIdentity);
-
- int tagsPos = 0;
- Statics.EncodeTags((int)this.tags, ref tagsPos, null);
-
- this.nameMetadata = Statics.MetadataForString(name, tagsPos, 0, typeMetadataSize);
-
- tagsPos = 2;
- Statics.EncodeTags((int)this.tags, ref tagsPos, this.nameMetadata);
- }
-
- public override int Compare(NameInfo other)
- {
- return this.Compare(other.name, other.tags);
- }
-
- public override int Compare(KeyValuePair<string, EventTags> key)
- {
- return this.Compare(key.Key, key.Value & Statics.EventTagsMask);
- }
-
- private int Compare(string otherName, EventTags otherTags)
- {
- int result = StringComparer.Ordinal.Compare(this.name, otherName);
- if (result == 0 && this.tags != otherTags)
- {
- result = this.tags < otherTags ? -1 : 1;
- }
- return result;
- }
-
-#if FEATURE_PERFTRACING
- public IntPtr GetOrCreateEventHandle(EventProvider provider, TraceLoggingEventHandleTable eventHandleTable, EventDescriptor descriptor, TraceLoggingEventTypes eventTypes)
- {
- IntPtr eventHandle;
- if ((eventHandle = eventHandleTable[descriptor.EventId]) == IntPtr.Zero)
- {
- lock (eventHandleTable)
- {
- if ((eventHandle = eventHandleTable[descriptor.EventId]) == IntPtr.Zero)
- {
- byte[]? metadataBlob = EventPipeMetadataGenerator.Instance.GenerateEventMetadata(
- descriptor.EventId,
- name,
- (EventKeywords)descriptor.Keywords,
- (EventLevel)descriptor.Level,
- descriptor.Version,
- eventTypes);
- uint metadataLength = (metadataBlob != null) ? (uint)metadataBlob.Length : 0;
-
- unsafe
- {
- fixed (byte* pMetadataBlob = metadataBlob)
- {
- // Define the event.
- eventHandle = provider.m_eventProvider.DefineEventHandle(
- (uint)descriptor.EventId,
- name,
- descriptor.Keywords,
- descriptor.Version,
- descriptor.Level,
- pMetadataBlob,
- metadataLength);
- }
- }
-
- // Cache the event handle.
- eventHandleTable.SetEventHandle(descriptor.EventId, eventHandle);
- }
- }
- }
-
- return eventHandle;
- }
-#endif
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyAnalysis.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyAnalysis.cs
deleted file mode 100644
index e7c2c08b275..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyAnalysis.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-using System.Reflection;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: stores the per-property information obtained by
- /// reflecting over a type.
- /// </summary>
- internal sealed class PropertyAnalysis
- {
- internal readonly string name;
- internal readonly PropertyInfo propertyInfo;
- internal readonly Func<PropertyValue, PropertyValue> getter;
- internal readonly TraceLoggingTypeInfo typeInfo;
- internal readonly EventFieldAttribute? fieldAttribute;
-
- public PropertyAnalysis(
- string name,
- PropertyInfo propertyInfo,
- TraceLoggingTypeInfo typeInfo,
- EventFieldAttribute? fieldAttribute)
- {
- this.name = name;
- this.propertyInfo = propertyInfo;
- this.getter = PropertyValue.GetPropertyGetter(propertyInfo);
- this.typeInfo = typeInfo;
- this.fieldAttribute = fieldAttribute;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs
deleted file mode 100644
index 645aab27244..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs
+++ /dev/null
@@ -1,272 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Holds property values of any type. For common value types, we have inline storage so that we don't need
- /// to box the values. For all other types, we store the value in a single object reference field.
- ///
- /// To get the value of a property quickly, use a delegate produced by <see cref="PropertyValue.GetPropertyGetter(PropertyInfo)"/>.
- /// </summary>
-#if ES_BUILD_PN
- [CLSCompliant(false)]
- public
-#else
- internal
-#endif
- readonly unsafe struct PropertyValue
- {
- /// <summary>
- /// Union of well-known value types, to avoid boxing those types.
- /// </summary>
- [StructLayout(LayoutKind.Explicit)]
- public struct Scalar
- {
- [FieldOffset(0)]
- public bool AsBoolean;
- [FieldOffset(0)]
- public byte AsByte;
- [FieldOffset(0)]
- public sbyte AsSByte;
- [FieldOffset(0)]
- public char AsChar;
- [FieldOffset(0)]
- public short AsInt16;
- [FieldOffset(0)]
- public ushort AsUInt16;
- [FieldOffset(0)]
- public int AsInt32;
- [FieldOffset(0)]
- public uint AsUInt32;
- [FieldOffset(0)]
- public long AsInt64;
- [FieldOffset(0)]
- public ulong AsUInt64;
- [FieldOffset(0)]
- public IntPtr AsIntPtr;
- [FieldOffset(0)]
- public UIntPtr AsUIntPtr;
- [FieldOffset(0)]
- public float AsSingle;
- [FieldOffset(0)]
- public double AsDouble;
- [FieldOffset(0)]
- public Guid AsGuid;
- [FieldOffset(0)]
- public DateTime AsDateTime;
- [FieldOffset(0)]
- public DateTimeOffset AsDateTimeOffset;
- [FieldOffset(0)]
- public TimeSpan AsTimeSpan;
- [FieldOffset(0)]
- public decimal AsDecimal;
- }
-
- // Anything not covered by the Scalar union gets stored in this reference.
- private readonly object? _reference;
- private readonly Scalar _scalar;
- private readonly int _scalarLength;
-
- private PropertyValue(object? value)
- {
- _reference = value;
- _scalar = default;
- _scalarLength = 0;
- }
-
- private PropertyValue(Scalar scalar, int scalarLength)
- {
- _reference = null;
- _scalar = scalar;
- _scalarLength = scalarLength;
- }
-
- private PropertyValue(bool value) : this(new Scalar() { AsBoolean = value }, sizeof(bool)) { }
- private PropertyValue(byte value) : this(new Scalar() { AsByte = value }, sizeof(byte)) { }
- private PropertyValue(sbyte value) : this(new Scalar() { AsSByte = value }, sizeof(sbyte)) { }
- private PropertyValue(char value) : this(new Scalar() { AsChar = value }, sizeof(char)) { }
- private PropertyValue(short value) : this(new Scalar() { AsInt16 = value }, sizeof(short)) { }
- private PropertyValue(ushort value) : this(new Scalar() { AsUInt16 = value }, sizeof(ushort)) { }
- private PropertyValue(int value) : this(new Scalar() { AsInt32 = value }, sizeof(int)) { }
- private PropertyValue(uint value) : this(new Scalar() { AsUInt32 = value }, sizeof(uint)) { }
- private PropertyValue(long value) : this(new Scalar() { AsInt64 = value }, sizeof(long)) { }
- private PropertyValue(ulong value) : this(new Scalar() { AsUInt64 = value }, sizeof(ulong)) { }
- private PropertyValue(IntPtr value) : this(new Scalar() { AsIntPtr = value }, sizeof(IntPtr)) { }
- private PropertyValue(UIntPtr value) : this(new Scalar() { AsUIntPtr = value }, sizeof(UIntPtr)) { }
- private PropertyValue(float value) : this(new Scalar() { AsSingle = value }, sizeof(float)) { }
- private PropertyValue(double value) : this(new Scalar() { AsDouble = value }, sizeof(double)) { }
- private PropertyValue(Guid value) : this(new Scalar() { AsGuid = value }, sizeof(Guid)) { }
- private PropertyValue(DateTime value) : this(new Scalar() { AsDateTime = value }, sizeof(DateTime)) { }
- private PropertyValue(DateTimeOffset value) : this(new Scalar() { AsDateTimeOffset = value }, sizeof(DateTimeOffset)) { }
- private PropertyValue(TimeSpan value) : this(new Scalar() { AsTimeSpan = value }, sizeof(TimeSpan)) { }
- private PropertyValue(decimal value) : this(new Scalar() { AsDecimal = value }, sizeof(decimal)) { }
-
- public static Func<object?, PropertyValue> GetFactory(Type type)
- {
- if (type == typeof(bool)) return value => new PropertyValue((bool)value!);
- if (type == typeof(byte)) return value => new PropertyValue((byte)value!);
- if (type == typeof(sbyte)) return value => new PropertyValue((sbyte)value!);
- if (type == typeof(char)) return value => new PropertyValue((char)value!);
- if (type == typeof(short)) return value => new PropertyValue((short)value!);
- if (type == typeof(ushort)) return value => new PropertyValue((ushort)value!);
- if (type == typeof(int)) return value => new PropertyValue((int)value!);
- if (type == typeof(uint)) return value => new PropertyValue((uint)value!);
- if (type == typeof(long)) return value => new PropertyValue((long)value!);
- if (type == typeof(ulong)) return value => new PropertyValue((ulong)value!);
- if (type == typeof(IntPtr)) return value => new PropertyValue((IntPtr)value!);
- if (type == typeof(UIntPtr)) return value => new PropertyValue((UIntPtr)value!);
- if (type == typeof(float)) return value => new PropertyValue((float)value!);
- if (type == typeof(double)) return value => new PropertyValue((double)value!);
- if (type == typeof(Guid)) return value => new PropertyValue((Guid)value!);
- if (type == typeof(DateTime)) return value => new PropertyValue((DateTime)value!);
- if (type == typeof(DateTimeOffset)) return value => new PropertyValue((DateTimeOffset)value!);
- if (type == typeof(TimeSpan)) return value => new PropertyValue((TimeSpan)value!);
- if (type == typeof(decimal)) return value => new PropertyValue((decimal)value!);
-
- return value => new PropertyValue(value);
- }
-
- public object? ReferenceValue
- {
- get
- {
- Debug.Assert(_scalarLength == 0, "This ReflectedValue refers to an unboxed value type, not a reference type or boxed value type.");
- return _reference;
- }
- }
-
- public Scalar ScalarValue
- {
- get
- {
- Debug.Assert(_scalarLength > 0, "This ReflectedValue refers to a reference type or boxed value type, not an unboxed value type");
- return _scalar;
- }
- }
-
- public int ScalarLength
- {
- get
- {
- Debug.Assert(_scalarLength > 0, "This ReflectedValue refers to a reference type or boxed value type, not an unboxed value type");
- return _scalarLength;
- }
- }
-
- /// <summary>
- /// Gets a delegate that gets the value of a given property.
- /// </summary>
- public static Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property)
- {
- if (property.DeclaringType!.GetTypeInfo().IsValueType)
- return GetBoxedValueTypePropertyGetter(property);
- else
- return GetReferenceTypePropertyGetter(property);
- }
-
- /// <summary>
- /// Gets a delegate that gets the value of a property of a value type. We unfortunately cannot avoid boxing the value type,
- /// without making this generic over the value type. That would result in a large number of generic instantiations, and furthermore
- /// does not work correctly on .NET Native (we cannot express the needed instantiations in an rd.xml file). We expect that user-defined
- /// value types will be rare, and in any case the boxing only happens for events that are actually enabled.
- /// </summary>
- private static Func<PropertyValue, PropertyValue> GetBoxedValueTypePropertyGetter(PropertyInfo property)
- {
- Type type = property.PropertyType;
-
- if (type.GetTypeInfo().IsEnum)
- type = Enum.GetUnderlyingType(type);
-
- Func<object?, PropertyValue> factory = GetFactory(type);
-
- return container => factory(property.GetValue(container.ReferenceValue));
- }
-
- /// <summary>
- /// For properties of reference types, we use a generic helper class to get the value. This enables us to use MethodInfo.CreateDelegate
- /// to build a fast getter. We can get away with this on .NET Native, because we really only need one runtime instantiation of the
- /// generic type, since it's only instantiated over reference types (and thus all instances are shared).
- /// </summary>
- /// <param name="property"></param>
- /// <returns></returns>
- private static Func<PropertyValue, PropertyValue> GetReferenceTypePropertyGetter(PropertyInfo property)
- {
- var helper = (TypeHelper)Activator.CreateInstance(typeof(ReferenceTypeHelper<>).MakeGenericType(property.DeclaringType!))!;
- return helper.GetPropertyGetter(property);
- }
-
-#if ES_BUILD_PN
- public
-#else
- private
-#endif
- abstract class TypeHelper
- {
- public abstract Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property);
-
- protected Delegate GetGetMethod(PropertyInfo property, Type propertyType)
- {
- return property.GetMethod!.CreateDelegate(typeof(Func<,>).MakeGenericType(property.DeclaringType!, propertyType));
- }
- }
-
-#if ES_BUILD_PN
- public
-#else
- private
-#endif
- sealed class ReferenceTypeHelper<TContainer> : TypeHelper where TContainer : class?
- {
- public override Func<PropertyValue, PropertyValue> GetPropertyGetter(PropertyInfo property)
- {
- Type type = property.PropertyType;
-
- if (!Statics.IsValueType(type))
- {
- var getter = (Func<TContainer, object?>)GetGetMethod(property, type);
- return container => new PropertyValue(getter((TContainer)container.ReferenceValue!));
- }
- else
- {
- if (type.GetTypeInfo().IsEnum)
- type = Enum.GetUnderlyingType(type);
-
- if (type == typeof(bool)) { var f = (Func<TContainer, bool>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(byte)) { var f = (Func<TContainer, byte>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(sbyte)) { var f = (Func<TContainer, sbyte>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(char)) { var f = (Func<TContainer, char>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(short)) { var f = (Func<TContainer, short>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(ushort)) { var f = (Func<TContainer, ushort>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(int)) { var f = (Func<TContainer, int>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(uint)) { var f = (Func<TContainer, uint>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(long)) { var f = (Func<TContainer, long>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(ulong)) { var f = (Func<TContainer, ulong>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(IntPtr)) { var f = (Func<TContainer, IntPtr>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(UIntPtr)) { var f = (Func<TContainer, UIntPtr>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(float)) { var f = (Func<TContainer, float>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(double)) { var f = (Func<TContainer, double>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(Guid)) { var f = (Func<TContainer, Guid>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(DateTime)) { var f = (Func<TContainer, DateTime>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(DateTimeOffset)) { var f = (Func<TContainer, DateTimeOffset>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(TimeSpan)) { var f = (Func<TContainer, TimeSpan>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
- if (type == typeof(decimal)) { var f = (Func<TContainer, decimal>)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); }
-
- return container => new PropertyValue(property.GetValue(container.ReferenceValue));
- }
- }
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleEventTypes.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleEventTypes.cs
deleted file mode 100644
index c85ec92febf..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleEventTypes.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Threading;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Contains the metadata needed to emit an event, optimized
- /// for events with one top-level compile-time-typed payload object.
- /// </summary>
- /// <typeparam name="T">
- /// Type of the top-level payload object. Should be EmptyStruct if the
- /// event has no payload.
- /// </typeparam>
- internal static class SimpleEventTypes<T>
- {
- private static TraceLoggingEventTypes? instance;
-
- public static TraceLoggingEventTypes Instance => instance ?? InitInstance();
-
- private static TraceLoggingEventTypes InitInstance()
- {
- var info = TraceLoggingTypeInfo.GetInstance(typeof(T), null);
- var newInstance = new TraceLoggingEventTypes(info.Name, info.Tags, new TraceLoggingTypeInfo[] { info });
- Interlocked.CompareExchange(ref instance, newInstance, null);
- Debug.Assert(instance != null);
- return instance;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
deleted file mode 100644
index 0525413ccd9..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
+++ /dev/null
@@ -1,299 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-#endif
-using System.Collections.Generic;
-using System.Reflection;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Type handler for empty or unsupported types.
- /// </summary>
- internal sealed class NullTypeInfo : TraceLoggingTypeInfo
- {
- public NullTypeInfo() : base(typeof(EmptyStruct)) { }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- collector.AddGroup(name);
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- return;
- }
-
- public override object? GetData(object? value)
- {
- return null;
- }
- }
-
- /// <summary>
- /// Type handler for simple scalar types.
- /// </summary>
- internal sealed class ScalarTypeInfo : TraceLoggingTypeInfo
- {
- private readonly Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc;
- private readonly TraceLoggingDataType nativeFormat;
-
- private ScalarTypeInfo(
- Type type,
- Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc,
- TraceLoggingDataType nativeFormat)
- : base(type)
- {
- this.formatFunc = formatFunc;
- this.nativeFormat = nativeFormat;
- }
-
- public override void WriteMetadata(TraceLoggingMetadataCollector collector, string? name, EventFieldFormat format)
- {
- collector.AddScalar(name!, formatFunc(format, nativeFormat));
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- collector.AddScalar(value);
- }
-
- public static TraceLoggingTypeInfo Boolean() { return new ScalarTypeInfo(typeof(bool), Statics.Format8, TraceLoggingDataType.Boolean8); }
- public static TraceLoggingTypeInfo Byte() { return new ScalarTypeInfo(typeof(byte), Statics.Format8, TraceLoggingDataType.UInt8); }
- public static TraceLoggingTypeInfo SByte() { return new ScalarTypeInfo(typeof(sbyte), Statics.Format8, TraceLoggingDataType.Int8); }
- public static TraceLoggingTypeInfo Char() { return new ScalarTypeInfo(typeof(char), Statics.Format16, TraceLoggingDataType.Char16); }
- public static TraceLoggingTypeInfo Int16() { return new ScalarTypeInfo(typeof(short), Statics.Format16, TraceLoggingDataType.Int16); }
- public static TraceLoggingTypeInfo UInt16() { return new ScalarTypeInfo(typeof(ushort), Statics.Format16, TraceLoggingDataType.UInt16); }
- public static TraceLoggingTypeInfo Int32() { return new ScalarTypeInfo(typeof(int), Statics.Format32, TraceLoggingDataType.Int32); }
- public static TraceLoggingTypeInfo UInt32() { return new ScalarTypeInfo(typeof(uint), Statics.Format32, TraceLoggingDataType.UInt32); }
- public static TraceLoggingTypeInfo Int64() { return new ScalarTypeInfo(typeof(long), Statics.Format64, TraceLoggingDataType.Int64); }
- public static TraceLoggingTypeInfo UInt64() { return new ScalarTypeInfo(typeof(ulong), Statics.Format64, TraceLoggingDataType.UInt64); }
- public static TraceLoggingTypeInfo IntPtr() { return new ScalarTypeInfo(typeof(IntPtr), Statics.FormatPtr, Statics.IntPtrType); }
- public static TraceLoggingTypeInfo UIntPtr() { return new ScalarTypeInfo(typeof(UIntPtr), Statics.FormatPtr, Statics.UIntPtrType); }
- public static TraceLoggingTypeInfo Single() { return new ScalarTypeInfo(typeof(float), Statics.Format32, TraceLoggingDataType.Float); }
- public static TraceLoggingTypeInfo Double() { return new ScalarTypeInfo(typeof(double), Statics.Format64, TraceLoggingDataType.Double); }
- public static TraceLoggingTypeInfo Guid() { return new ScalarTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid); }
- }
-
-
- /// <summary>
- /// Type handler for arrays of scalars
- /// </summary>
- internal sealed class ScalarArrayTypeInfo : TraceLoggingTypeInfo
- {
- private readonly Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc;
- private readonly TraceLoggingDataType nativeFormat;
- private readonly int elementSize;
-
- private ScalarArrayTypeInfo(
- Type type,
- Func<EventFieldFormat, TraceLoggingDataType, TraceLoggingDataType> formatFunc,
- TraceLoggingDataType nativeFormat,
- int elementSize)
- : base(type)
- {
- this.formatFunc = formatFunc;
- this.nativeFormat = nativeFormat;
- this.elementSize = elementSize;
- }
-
- public override void WriteMetadata(TraceLoggingMetadataCollector collector, string? name, EventFieldFormat format)
- {
- collector.AddArray(name!, formatFunc(format, nativeFormat));
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- collector.AddArray(value, elementSize);
- }
-
- public static TraceLoggingTypeInfo Boolean() { return new ScalarArrayTypeInfo(typeof(bool[]), Statics.Format8, TraceLoggingDataType.Boolean8, sizeof(bool)); }
- public static TraceLoggingTypeInfo Byte() { return new ScalarArrayTypeInfo(typeof(byte[]), Statics.Format8, TraceLoggingDataType.UInt8, sizeof(byte)); }
- public static TraceLoggingTypeInfo SByte() { return new ScalarArrayTypeInfo(typeof(sbyte[]), Statics.Format8, TraceLoggingDataType.Int8, sizeof(sbyte)); }
- public static TraceLoggingTypeInfo Char() { return new ScalarArrayTypeInfo(typeof(char[]), Statics.Format16, TraceLoggingDataType.Char16, sizeof(char)); }
- public static TraceLoggingTypeInfo Int16() { return new ScalarArrayTypeInfo(typeof(short[]), Statics.Format16, TraceLoggingDataType.Int16, sizeof(short)); }
- public static TraceLoggingTypeInfo UInt16() { return new ScalarArrayTypeInfo(typeof(ushort[]), Statics.Format16, TraceLoggingDataType.UInt16, sizeof(ushort)); }
- public static TraceLoggingTypeInfo Int32() { return new ScalarArrayTypeInfo(typeof(int[]), Statics.Format32, TraceLoggingDataType.Int32, sizeof(int)); }
- public static TraceLoggingTypeInfo UInt32() { return new ScalarArrayTypeInfo(typeof(uint[]), Statics.Format32, TraceLoggingDataType.UInt32, sizeof(uint)); }
- public static TraceLoggingTypeInfo Int64() { return new ScalarArrayTypeInfo(typeof(long[]), Statics.Format64, TraceLoggingDataType.Int64, sizeof(long)); }
- public static TraceLoggingTypeInfo UInt64() { return new ScalarArrayTypeInfo(typeof(ulong[]), Statics.Format64, TraceLoggingDataType.UInt64, sizeof(ulong)); }
- public static TraceLoggingTypeInfo IntPtr() { return new ScalarArrayTypeInfo(typeof(IntPtr[]), Statics.FormatPtr, Statics.IntPtrType, System.IntPtr.Size); }
- public static TraceLoggingTypeInfo UIntPtr() { return new ScalarArrayTypeInfo(typeof(UIntPtr[]), Statics.FormatPtr, Statics.UIntPtrType, System.IntPtr.Size); }
- public static TraceLoggingTypeInfo Single() { return new ScalarArrayTypeInfo(typeof(float[]), Statics.Format32, TraceLoggingDataType.Float, sizeof(float)); }
- public static TraceLoggingTypeInfo Double() { return new ScalarArrayTypeInfo(typeof(double[]), Statics.Format64, TraceLoggingDataType.Double, sizeof(double)); }
- public static unsafe TraceLoggingTypeInfo Guid() { return new ScalarArrayTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid, sizeof(Guid)); }
- }
-
- /// <summary>
- /// TraceLogging: Type handler for String.
- /// </summary>
- internal sealed class StringTypeInfo : TraceLoggingTypeInfo
- {
- public StringTypeInfo() : base(typeof(string)) { }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- collector.AddNullTerminatedString(name!, Statics.MakeDataType(TraceLoggingDataType.Utf16String, format));
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- collector.AddNullTerminatedString((string?)value.ReferenceValue);
- }
-
- public override object GetData(object? value)
- {
- if (value == null)
- {
- return "";
- }
-
- return value;
- }
- }
-
- /// <summary>
- /// TraceLogging: Type handler for DateTime.
- /// </summary>
- internal sealed class DateTimeTypeInfo : TraceLoggingTypeInfo
- {
- public DateTimeTypeInfo() : base(typeof(DateTime)) { }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- collector.AddScalar(name!, Statics.MakeDataType(TraceLoggingDataType.FileTime, format));
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- DateTime dateTime = value.ScalarValue.AsDateTime;
- const long UTCMinTicks = 504911232000000000;
- long dateTimeTicks = 0;
- // We cannot translate dates sooner than 1/1/1601 in UTC.
- // To avoid getting an ArgumentOutOfRangeException we compare with 1/1/1601 DateTime ticks
- if (dateTime.Ticks > UTCMinTicks)
- dateTimeTicks = dateTime.ToFileTimeUtc();
- collector.AddScalar(dateTimeTicks);
- }
- }
-
- /// <summary>
- /// TraceLogging: Type handler for DateTimeOffset.
- /// </summary>
- internal sealed class DateTimeOffsetTypeInfo : TraceLoggingTypeInfo
- {
- public DateTimeOffsetTypeInfo() : base(typeof(DateTimeOffset)) { }
-
- public override void WriteMetadata(TraceLoggingMetadataCollector collector, string? name, EventFieldFormat format)
- {
- TraceLoggingMetadataCollector group = collector.AddGroup(name);
- group.AddScalar("Ticks", Statics.MakeDataType(TraceLoggingDataType.FileTime, format));
- group.AddScalar("Offset", TraceLoggingDataType.Int64);
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- DateTimeOffset dateTimeOffset = value.ScalarValue.AsDateTimeOffset;
- long ticks = dateTimeOffset.Ticks;
- collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000);
- collector.AddScalar(dateTimeOffset.Offset.Ticks);
- }
- }
-
- /// <summary>
- /// TraceLogging: Type handler for TimeSpan.
- /// </summary>
- internal sealed class TimeSpanTypeInfo : TraceLoggingTypeInfo
- {
- public TimeSpanTypeInfo() : base(typeof(TimeSpan)) { }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- collector.AddScalar(name!, Statics.MakeDataType(TraceLoggingDataType.Int64, format));
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- collector.AddScalar(value.ScalarValue.AsTimeSpan.Ticks);
- }
- }
-
- /// <summary>
- /// TraceLogging: Type handler for decimal. (Note: not full-fidelity, exposed as Double.)
- /// </summary>
- internal sealed class DecimalTypeInfo : TraceLoggingTypeInfo
- {
- public DecimalTypeInfo() : base(typeof(decimal)) { }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- collector.AddScalar(name!, Statics.MakeDataType(TraceLoggingDataType.Double, format));
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- collector.AddScalar((double)value.ScalarValue.AsDecimal);
- }
- }
-
- /// <summary>
- /// TraceLogging: Type handler for Nullable.
- /// </summary>
- internal sealed class NullableTypeInfo : TraceLoggingTypeInfo
- {
- private readonly TraceLoggingTypeInfo valueInfo;
- private readonly Func<PropertyValue, PropertyValue> valueGetter;
-
- public NullableTypeInfo(Type type, List<Type> recursionCheck)
- : base(type)
- {
- Type[] typeArgs = type.GenericTypeArguments;
- Debug.Assert(typeArgs.Length == 1);
- this.valueInfo = TraceLoggingTypeInfo.GetInstance(typeArgs[0], recursionCheck);
- this.valueGetter = PropertyValue.GetPropertyGetter(type.GetTypeInfo().GetDeclaredProperty("Value")!);
- }
-
- public override void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format)
- {
- TraceLoggingMetadataCollector group = collector.AddGroup(name);
- group.AddScalar("HasValue", TraceLoggingDataType.Boolean8);
- this.valueInfo.WriteMetadata(group, "Value", format);
- }
-
- public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
- {
- // It's not currently possible to get the HasValue property of a nullable type through reflection when the
- // value is null. Instead, we simply check that the nullable is not null.
- bool hasValue = value.ReferenceValue != null;
- collector.AddScalar(hasValue);
- PropertyValue val = hasValue ? valueGetter(value) : valueInfo.PropertyValueFactory(Activator.CreateInstance(valueInfo.DataType));
- this.valueInfo.WriteData(collector, val);
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs
deleted file mode 100644
index 6d4dd919981..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs
+++ /dev/null
@@ -1,693 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
-#endif
-using System.Collections.Generic;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Text;
-using Microsoft.Reflection;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Constants and utility functions.
- /// </summary>
- internal static class Statics
- {
- #region Constants
-
- public const byte DefaultLevel = 5;
- public const byte TraceLoggingChannel = 0xb;
- public const byte InTypeMask = 31;
- public const byte InTypeFixedCountFlag = 32;
- public const byte InTypeVariableCountFlag = 64;
- public const byte InTypeCustomCountFlag = 96;
- public const byte InTypeCountMask = 96;
- public const byte InTypeChainFlag = 128;
- public const byte OutTypeMask = 127;
- public const byte OutTypeChainFlag = 128;
- public const EventTags EventTagsMask = (EventTags)0xfffffff;
-
- public static readonly TraceLoggingDataType IntPtrType = IntPtr.Size == 8
- ? TraceLoggingDataType.Int64
- : TraceLoggingDataType.Int32;
- public static readonly TraceLoggingDataType UIntPtrType = IntPtr.Size == 8
- ? TraceLoggingDataType.UInt64
- : TraceLoggingDataType.UInt32;
- public static readonly TraceLoggingDataType HexIntPtrType = IntPtr.Size == 8
- ? TraceLoggingDataType.HexInt64
- : TraceLoggingDataType.HexInt32;
-
- #endregion
-
- #region Metadata helpers
-
- /// <summary>
- /// A complete metadata chunk can be expressed as:
- /// length16 + prefix + null-terminated-utf8-name + suffix + additionalData.
- /// We assume that excludedData will be provided by some other means,
- /// but that its size is known. This function returns a blob containing
- /// length16 + prefix + name + suffix, with prefix and suffix initialized
- /// to 0's. The length16 value is initialized to the length of the returned
- /// blob plus additionalSize, so that the concatenation of the returned blob
- /// plus a blob of size additionalSize constitutes a valid metadata blob.
- /// </summary>
- /// <param name="name">
- /// The name to include in the blob.
- /// </param>
- /// <param name="prefixSize">
- /// Amount of space to reserve before name. For provider or field blobs, this
- /// should be 0. For event blobs, this is used for the tags field and will vary
- /// from 1 to 4, depending on how large the tags field needs to be.
- /// </param>
- /// <param name="suffixSize">
- /// Amount of space to reserve after name. For example, a provider blob with no
- /// traits would reserve 0 extra bytes, but a provider blob with a single GroupId
- /// field would reserve 19 extra bytes.
- /// </param>
- /// <param name="additionalSize">
- /// Amount of additional data in another blob. This value will be counted in the
- /// blob's length field, but will not be included in the returned byte[] object.
- /// The complete blob would then be the concatenation of the returned byte[] object
- /// with another byte[] object of length additionalSize.
- /// </param>
- /// <returns>
- /// A byte[] object with the length and name fields set, with room reserved for
- /// prefix and suffix. If additionalSize was 0, the byte[] object is a complete
- /// blob. Otherwise, another byte[] of size additionalSize must be concatenated
- /// with this one to form a complete blob.
- /// </returns>
- public static byte[] MetadataForString(
- string name,
- int prefixSize,
- int suffixSize,
- int additionalSize)
- {
- Statics.CheckName(name);
- int metadataSize = Encoding.UTF8.GetByteCount(name) + 3 + prefixSize + suffixSize;
- var metadata = new byte[metadataSize];
- ushort totalSize = checked((ushort)(metadataSize + additionalSize));
- metadata[0] = unchecked((byte)totalSize);
- metadata[1] = unchecked((byte)(totalSize >> 8));
- Encoding.UTF8.GetBytes(name, 0, name.Length, metadata, 2 + prefixSize);
- return metadata;
- }
-
- /// <summary>
- /// Serialize the low 28 bits of the tags value into the metadata stream,
- /// starting at the index given by pos. Updates pos. Writes 1 to 4 bytes,
- /// depending on the value of the tags variable. Usable for event tags and
- /// field tags.
- ///
- /// Note that 'metadata' can be null, in which case it only updates 'pos'.
- /// This is useful for a two pass approach where you figure out how big to
- /// make the array, and then you fill it in.
- /// </summary>
- public static void EncodeTags(int tags, ref int pos, byte[]? metadata)
- {
- // We transmit the low 28 bits of tags, high bits first, 7 bits at a time.
- int tagsLeft = tags & 0xfffffff;
- bool more;
- do
- {
- byte current = (byte)((tagsLeft >> 21) & 0x7f);
- more = (tagsLeft & 0x1fffff) != 0;
- current |= (byte)(more ? 0x80 : 0x00);
- tagsLeft <<= 7;
-
- if (metadata != null)
- {
- metadata[pos] = current;
- }
- pos++;
- }
- while (more);
- }
-
- public static byte Combine(
- int settingValue,
- byte defaultValue)
- {
- unchecked
- {
- return (byte)settingValue == settingValue
- ? (byte)settingValue
- : defaultValue;
- }
- }
-
- public static byte Combine(
- int settingValue1,
- int settingValue2,
- byte defaultValue)
- {
- unchecked
- {
- return (byte)settingValue1 == settingValue1
- ? (byte)settingValue1
- : (byte)settingValue2 == settingValue2
- ? (byte)settingValue2
- : defaultValue;
- }
- }
-
- public static int Combine(
- int settingValue1,
- int settingValue2)
- {
- unchecked
- {
- return (byte)settingValue1 == settingValue1
- ? settingValue1
- : settingValue2;
- }
- }
-
- public static void CheckName(string? name)
- {
- if (name != null && 0 <= name.IndexOf('\0'))
- {
- throw new ArgumentOutOfRangeException(nameof(name));
- }
- }
-
- public static bool ShouldOverrideFieldName(string fieldName)
- {
- return fieldName.Length <= 2 && fieldName[0] == '_';
- }
-
- public static TraceLoggingDataType MakeDataType(
- TraceLoggingDataType baseType,
- EventFieldFormat format)
- {
- return (TraceLoggingDataType)(((int)baseType & 0x1f) | ((int)format << 8));
- }
-
- /// <summary>
- /// Adjusts the native type based on format.
- /// - If format is default, return native.
- /// - If format is recognized, return the canonical type for that format.
- /// - Otherwise remove existing format from native and apply the requested format.
- /// </summary>
- public static TraceLoggingDataType Format8(
- EventFieldFormat format,
- TraceLoggingDataType native)
- {
- return format switch
- {
- EventFieldFormat.Default => native,
- EventFieldFormat.String => TraceLoggingDataType.Char8,
- EventFieldFormat.Boolean => TraceLoggingDataType.Boolean8,
- EventFieldFormat.Hexadecimal => TraceLoggingDataType.HexInt8,
-#if false
- EventSourceFieldFormat.Signed => TraceLoggingDataType.Int8,
- EventSourceFieldFormat.Unsigned => TraceLoggingDataType.UInt8,
-#endif
- _ => MakeDataType(native, format),
- };
- }
-
- /// <summary>
- /// Adjusts the native type based on format.
- /// - If format is default, return native.
- /// - If format is recognized, return the canonical type for that format.
- /// - Otherwise remove existing format from native and apply the requested format.
- /// </summary>
- public static TraceLoggingDataType Format16(
- EventFieldFormat format,
- TraceLoggingDataType native)
- {
- return format switch
- {
- EventFieldFormat.Default => native,
- EventFieldFormat.String => TraceLoggingDataType.Char16,
- EventFieldFormat.Hexadecimal => TraceLoggingDataType.HexInt16,
-#if false
- EventSourceFieldFormat.Port => TraceLoggingDataType.Port,
- EventSourceFieldFormat.Signed => TraceLoggingDataType.Int16,
- EventSourceFieldFormat.Unsigned => TraceLoggingDataType.UInt16,
-#endif
- _ => MakeDataType(native, format),
- };
- }
-
- /// <summary>
- /// Adjusts the native type based on format.
- /// - If format is default, return native.
- /// - If format is recognized, return the canonical type for that format.
- /// - Otherwise remove existing format from native and apply the requested format.
- /// </summary>
- public static TraceLoggingDataType Format32(
- EventFieldFormat format,
- TraceLoggingDataType native)
- {
- return format switch
- {
- EventFieldFormat.Default => native,
- EventFieldFormat.Boolean => TraceLoggingDataType.Boolean32,
- EventFieldFormat.Hexadecimal => TraceLoggingDataType.HexInt32,
-#if false
- EventSourceFieldFormat.Ipv4Address => TraceLoggingDataType.Ipv4Address,
- EventSourceFieldFormat.ProcessId => TraceLoggingDataType.ProcessId,
- EventSourceFieldFormat.ThreadId => TraceLoggingDataType.ThreadId,
- EventSourceFieldFormat.Win32Error => TraceLoggingDataType.Win32Error,
- EventSourceFieldFormat.NTStatus => TraceLoggingDataType.NTStatus,
-#endif
- EventFieldFormat.HResult => TraceLoggingDataType.HResult,
-#if false
- case EventSourceFieldFormat.Signed:
- return TraceLoggingDataType.Int32;
- case EventSourceFieldFormat.Unsigned:
- return TraceLoggingDataType.UInt32;
-#endif
- _ => MakeDataType(native, format),
- };
- }
-
- /// <summary>
- /// Adjusts the native type based on format.
- /// - If format is default, return native.
- /// - If format is recognized, return the canonical type for that format.
- /// - Otherwise remove existing format from native and apply the requested format.
- /// </summary>
- public static TraceLoggingDataType Format64(
- EventFieldFormat format,
- TraceLoggingDataType native)
- {
- return format switch
- {
- EventFieldFormat.Default => native,
- EventFieldFormat.Hexadecimal => TraceLoggingDataType.HexInt64,
-#if false
- EventSourceFieldFormat.FileTime => TraceLoggingDataType.FileTime,
- EventSourceFieldFormat.Signed => TraceLoggingDataType.Int64,
- EventSourceFieldFormat.Unsigned => TraceLoggingDataType.UInt64,
-#endif
- _ => MakeDataType(native, format),
- };
- }
-
- /// <summary>
- /// Adjusts the native type based on format.
- /// - If format is default, return native.
- /// - If format is recognized, return the canonical type for that format.
- /// - Otherwise remove existing format from native and apply the requested format.
- /// </summary>
- public static TraceLoggingDataType FormatPtr(
- EventFieldFormat format,
- TraceLoggingDataType native)
- {
- return format switch
- {
- EventFieldFormat.Default => native,
- EventFieldFormat.Hexadecimal => HexIntPtrType,
-#if false
- EventSourceFieldFormat.Signed => IntPtrType,
- EventSourceFieldFormat.Unsigned => UIntPtrType,
-#endif
- _ => MakeDataType(native, format),
- };
- }
-
- #endregion
-
- #region Reflection helpers
-
- /*
- All TraceLogging use of reflection APIs should go through wrappers here.
- This helps with portability, and it also makes it easier to audit what
- kinds of reflection operations are being done.
- */
-
- public static object? CreateInstance(Type type, params object?[]? parameters)
- {
- return Activator.CreateInstance(type, parameters);
- }
-
- public static bool IsValueType(Type type)
- {
- bool result = type.IsValueType();
- return result;
- }
-
- public static bool IsEnum(Type type)
- {
- bool result = type.IsEnum();
- return result;
- }
-
- public static IEnumerable<PropertyInfo> GetProperties(Type type)
- {
- IEnumerable<PropertyInfo> result = type.GetProperties();
- return result;
- }
-
- public static MethodInfo? GetGetMethod(PropertyInfo propInfo)
- {
- MethodInfo? result = propInfo.GetGetMethod();
- return result;
- }
-
- public static MethodInfo? GetDeclaredStaticMethod(Type declaringType, string name)
- {
- MethodInfo? result;
-#if (ES_BUILD_PCL || ES_BUILD_PN)
- result = declaringType.GetTypeInfo().GetDeclaredMethod(name);
-#else
- result = declaringType.GetMethod(
- name,
- BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic);
-#endif
- return result;
- }
-
- public static bool HasCustomAttribute(
- PropertyInfo propInfo,
- Type attributeType)
- {
- bool result;
-#if (ES_BUILD_PCL || ES_BUILD_PN)
- result = propInfo.IsDefined(attributeType);
-#else
- object[] attributes = propInfo.GetCustomAttributes(
- attributeType,
- false);
- result = attributes.Length != 0;
-#endif
- return result;
- }
-
- public static AttributeType? GetCustomAttribute<AttributeType>(PropertyInfo propInfo)
- where AttributeType : Attribute
- {
- AttributeType? result = null;
-#if (ES_BUILD_PCL || ES_BUILD_PN)
- foreach (var attrib in propInfo.GetCustomAttributes<AttributeType>(false))
- {
- result = attrib;
- break;
- }
-#else
- object[] attributes = propInfo.GetCustomAttributes(typeof(AttributeType), false);
- if (attributes.Length != 0)
- {
- result = (AttributeType)attributes[0];
- }
-#endif
- return result;
- }
-
- public static AttributeType? GetCustomAttribute<AttributeType>(Type type)
- where AttributeType : Attribute
- {
- AttributeType? result = null;
-#if (ES_BUILD_PCL || ES_BUILD_PN)
- foreach (var attrib in type.GetTypeInfo().GetCustomAttributes<AttributeType>(false))
- {
- result = attrib;
- break;
- }
-#else
- object[] attributes = type.GetCustomAttributes(typeof(AttributeType), false);
- if (attributes.Length != 0)
- {
- result = (AttributeType)attributes[0];
- }
-#endif
- return result;
- }
-
- public static Type[] GetGenericArguments(Type type)
- {
- return type.GetGenericArguments();
- }
-
- public static Type? FindEnumerableElementType(Type type)
- {
- Type? elementType = null;
-
- if (IsGenericMatch(type, typeof(IEnumerable<>)))
- {
- elementType = GetGenericArguments(type)[0];
- }
- else
- {
-#if (ES_BUILD_PCL || ES_BUILD_PN)
- IEnumerable<Type> ifaceTypes = type.GetTypeInfo().ImplementedInterfaces;
-#else
- Type[] ifaceTypes = type.FindInterfaces(IsGenericMatch, typeof(IEnumerable<>));
-#endif
-
- foreach (Type ifaceType in ifaceTypes)
- {
-#if (ES_BUILD_PCL || ES_BUILD_PN)
- if (!IsGenericMatch(ifaceType, typeof(IEnumerable<>)))
- {
- continue;
- }
-#endif
-
- if (elementType != null)
- {
- // ambiguous match. report no match at all.
- elementType = null;
- break;
- }
-
- elementType = GetGenericArguments(ifaceType)[0];
- }
- }
-
- return elementType;
- }
-
- public static bool IsGenericMatch(Type type, object? openType)
- {
- return type.IsGenericType() && type.GetGenericTypeDefinition() == (Type?)openType;
- }
-
- public static Delegate CreateDelegate(Type delegateType, MethodInfo methodInfo)
- {
- Delegate result;
-#if (ES_BUILD_PCL || ES_BUILD_PN)
- result = methodInfo.CreateDelegate(
- delegateType);
-#else
- result = Delegate.CreateDelegate(
- delegateType,
- methodInfo);
-#endif
- return result;
- }
-
- public static TraceLoggingTypeInfo CreateDefaultTypeInfo(
- Type dataType,
- List<Type> recursionCheck)
- {
- TraceLoggingTypeInfo result;
-
- if (recursionCheck.Contains(dataType))
- {
- throw new NotSupportedException(SR.EventSource_RecursiveTypeDefinition);
- }
-
- recursionCheck.Add(dataType);
-
- EventDataAttribute? eventAttrib = Statics.GetCustomAttribute<EventDataAttribute>(dataType);
- if (eventAttrib != null ||
- Statics.GetCustomAttribute<CompilerGeneratedAttribute>(dataType) != null ||
- IsGenericMatch(dataType, typeof(KeyValuePair<,>)))
- {
- var analysis = new TypeAnalysis(dataType, eventAttrib, recursionCheck);
- result = new InvokeTypeInfo(dataType, analysis);
- }
- else if (dataType.IsArray)
- {
- Type elementType = dataType.GetElementType()!;
- if (elementType == typeof(bool))
- {
- result = ScalarArrayTypeInfo.Boolean();
- }
- else if (elementType == typeof(byte))
- {
- result = ScalarArrayTypeInfo.Byte();
- }
- else if (elementType == typeof(sbyte))
- {
- result = ScalarArrayTypeInfo.SByte();
- }
- else if (elementType == typeof(short))
- {
- result = ScalarArrayTypeInfo.Int16();
- }
- else if (elementType == typeof(ushort))
- {
- result = ScalarArrayTypeInfo.UInt16();
- }
- else if (elementType == typeof(int))
- {
- result = ScalarArrayTypeInfo.Int32();
- }
- else if (elementType == typeof(uint))
- {
- result = ScalarArrayTypeInfo.UInt32();
- }
- else if (elementType == typeof(long))
- {
- result = ScalarArrayTypeInfo.Int64();
- }
- else if (elementType == typeof(ulong))
- {
- result = ScalarArrayTypeInfo.UInt64();
- }
- else if (elementType == typeof(char))
- {
- result = ScalarArrayTypeInfo.Char();
- }
- else if (elementType == typeof(double))
- {
- result = ScalarArrayTypeInfo.Double();
- }
- else if (elementType == typeof(float))
- {
- result = ScalarArrayTypeInfo.Single();
- }
- else if (elementType == typeof(IntPtr))
- {
- result = ScalarArrayTypeInfo.IntPtr();
- }
- else if (elementType == typeof(UIntPtr))
- {
- result = ScalarArrayTypeInfo.UIntPtr();
- }
- else if (elementType == typeof(Guid))
- {
- result = ScalarArrayTypeInfo.Guid();
- }
- else
- {
- result = new ArrayTypeInfo(dataType, TraceLoggingTypeInfo.GetInstance(elementType, recursionCheck));
- }
- }
- else
- {
- if (Statics.IsEnum(dataType))
- dataType = Enum.GetUnderlyingType(dataType);
-
- if (dataType == typeof(string))
- {
- result = new StringTypeInfo();
- }
- else if (dataType == typeof(bool))
- {
- result = ScalarTypeInfo.Boolean();
- }
- else if (dataType == typeof(byte))
- {
- result = ScalarTypeInfo.Byte();
- }
- else if (dataType == typeof(sbyte))
- {
- result = ScalarTypeInfo.SByte();
- }
- else if (dataType == typeof(short))
- {
- result = ScalarTypeInfo.Int16();
- }
- else if (dataType == typeof(ushort))
- {
- result = ScalarTypeInfo.UInt16();
- }
- else if (dataType == typeof(int))
- {
- result = ScalarTypeInfo.Int32();
- }
- else if (dataType == typeof(uint))
- {
- result = ScalarTypeInfo.UInt32();
- }
- else if (dataType == typeof(long))
- {
- result = ScalarTypeInfo.Int64();
- }
- else if (dataType == typeof(ulong))
- {
- result = ScalarTypeInfo.UInt64();
- }
- else if (dataType == typeof(char))
- {
- result = ScalarTypeInfo.Char();
- }
- else if (dataType == typeof(double))
- {
- result = ScalarTypeInfo.Double();
- }
- else if (dataType == typeof(float))
- {
- result = ScalarTypeInfo.Single();
- }
- else if (dataType == typeof(DateTime))
- {
- result = new DateTimeTypeInfo();
- }
- else if (dataType == typeof(decimal))
- {
- result = new DecimalTypeInfo();
- }
- else if (dataType == typeof(IntPtr))
- {
- result = ScalarTypeInfo.IntPtr();
- }
- else if (dataType == typeof(UIntPtr))
- {
- result = ScalarTypeInfo.UIntPtr();
- }
- else if (dataType == typeof(Guid))
- {
- result = ScalarTypeInfo.Guid();
- }
- else if (dataType == typeof(TimeSpan))
- {
- result = new TimeSpanTypeInfo();
- }
- else if (dataType == typeof(DateTimeOffset))
- {
- result = new DateTimeOffsetTypeInfo();
- }
- else if (dataType == typeof(EmptyStruct))
- {
- result = new NullTypeInfo();
- }
- else if (IsGenericMatch(dataType, typeof(Nullable<>)))
- {
- result = new NullableTypeInfo(dataType, recursionCheck);
- }
- else
- {
- Type? elementType = FindEnumerableElementType(dataType);
- if (elementType != null)
- {
- result = new EnumerableTypeInfo(dataType, TraceLoggingTypeInfo.GetInstance(elementType, recursionCheck));
- }
- else
- {
- throw new ArgumentException(SR.Format(SR.EventSource_NonCompliantTypeError, dataType.Name));
- }
- }
- }
-
- return result;
- }
-
- #endregion
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs
deleted file mode 100644
index a5b7621b647..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Used when implementing a custom TraceLoggingTypeInfo.
- /// The instance of this type is provided to the TypeInfo.WriteData method.
- /// All operations are forwarded to the current thread's DataCollector.
- /// Note that this abstraction would allow us to expose the custom
- /// serialization system to partially-trusted code. If we end up not
- /// making custom serialization public, or if we only expose it to
- /// full-trust code, this abstraction is unnecessary (though it probably
- /// doesn't hurt anything).
- /// </summary>
- internal unsafe class TraceLoggingDataCollector
- {
- internal static readonly TraceLoggingDataCollector Instance = new TraceLoggingDataCollector();
-
- private TraceLoggingDataCollector()
- {
- return;
- }
-
- /// <summary>
- /// Marks the start of a non-blittable array or enumerable.
- /// </summary>
- /// <returns>Bookmark to be passed to EndBufferedArray.</returns>
- public int BeginBufferedArray()
- {
- return DataCollector.ThreadInstance.BeginBufferedArray();
- }
-
- /// <summary>
- /// Marks the end of a non-blittable array or enumerable.
- /// </summary>
- /// <param name="bookmark">The value returned by BeginBufferedArray.</param>
- /// <param name="count">The number of items in the array.</param>
- public void EndBufferedArray(int bookmark, int count)
- {
- DataCollector.ThreadInstance.EndBufferedArray(bookmark, count);
- }
-
- /// <summary>
- /// Adds the start of a group to the event.
- /// This has no effect on the event payload, but is provided to allow
- /// WriteMetadata and WriteData implementations to have similar
- /// sequences of calls, allowing for easier verification of correctness.
- /// </summary>
- public TraceLoggingDataCollector AddGroup()
- {
- return this;
- }
-
- public void AddScalar(PropertyValue value)
- {
- PropertyValue.Scalar scalar = value.ScalarValue;
- DataCollector.ThreadInstance.AddScalar(&scalar, value.ScalarLength);
- }
-
- /// <summary>
- /// Adds an Int64 value to the event payload.
- /// </summary>
- /// <param name="value">Value to be added.</param>
- public void AddScalar(long value)
- {
- DataCollector.ThreadInstance.AddScalar(&value, sizeof(long));
- }
-
- /// <summary>
- /// Adds a Double value to the event payload.
- /// </summary>
- /// <param name="value">Value to be added.</param>
- public void AddScalar(double value)
- {
- DataCollector.ThreadInstance.AddScalar(&value, sizeof(double));
- }
-
- /// <summary>
- /// Adds a Boolean value to the event payload.
- /// </summary>
- /// <param name="value">Value to be added.</param>
- public void AddScalar(bool value)
- {
- DataCollector.ThreadInstance.AddScalar(&value, sizeof(bool));
- }
-
- /// <summary>
- /// Adds a null-terminated String value to the event payload.
- /// </summary>
- /// <param name="value">
- /// Value to be added. A null value is treated as a zero-length string.
- /// </param>
- public void AddNullTerminatedString(string? value)
- {
- DataCollector.ThreadInstance.AddNullTerminatedString(value);
- }
-
- /// <summary>
- /// Adds a counted String value to the event payload.
- /// </summary>
- /// <param name="value">
- /// Value to be added. A null value is treated as a zero-length string.
- /// </param>
- public void AddBinary(string? value)
- {
- DataCollector.ThreadInstance.AddBinary(value, value == null ? 0 : value.Length * 2);
- }
-
- public void AddArray(PropertyValue value, int elementSize)
- {
- Array? array = (Array?)value.ReferenceValue;
- DataCollector.ThreadInstance.AddArray(array, array == null ? 0 : array.Length, elementSize);
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataType.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataType.cs
deleted file mode 100644
index a71bf635756..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataType.cs
+++ /dev/null
@@ -1,351 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Used when implementing a custom TraceLoggingTypeInfo.
- /// These are passed to metadataCollector.Add to specify the low-level
- /// type of a field in the event payload. Note that a "formatted"
- /// TraceLoggingDataType consists of a core TraceLoggingDataType value
- /// (a TraceLoggingDataType with a value less than 32) plus an OutType.
- /// Any combination of TraceLoggingDataType + OutType is valid, but not
- /// all are useful. In particular, combinations not explicitly listed
- /// below are unlikely to be recognized by decoders, and will typically
- /// be decoded as the corresponding core type (i.e. the decoder will
- /// mask off any unrecognized OutType value).
- /// </summary>
- internal enum TraceLoggingDataType
- {
- /// <summary>
- /// Core type.
- /// Data type with no value (0-length payload).
- /// NOTE: arrays of Nil are illegal.
- /// NOTE: a fixed-length array of Nil is interpreted by the decoder as
- /// a struct (obsolete but retained for backwards-compatibility).
- /// </summary>
- Nil = 0,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes null-terminated Char16 string.
- /// Decoding treats as UTF-16LE string.
- /// </summary>
- Utf16String = 1,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes null-terminated Char8 string.
- /// Decoding treats as MBCS string.
- /// </summary>
- MbcsString = 2,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 8-bit value.
- /// Decoding treats as signed integer.
- /// </summary>
- Int8 = 3,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 8-bit value.
- /// Decoding treats as unsigned integer.
- /// </summary>
- UInt8 = 4,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 16-bit value.
- /// Decoding treats as signed integer.
- /// </summary>
- Int16 = 5,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 16-bit value.
- /// Decoding treats as unsigned integer.
- /// </summary>
- UInt16 = 6,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as signed integer.
- /// </summary>
- Int32 = 7,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as unsigned integer.
- /// </summary>
- UInt32 = 8,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 64-bit value.
- /// Decoding treats as signed integer.
- /// </summary>
- Int64 = 9,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 64-bit value.
- /// Decoding treats as unsigned integer.
- /// </summary>
- UInt64 = 10,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as Float.
- /// </summary>
- Float = 11,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 64-bit value.
- /// Decoding treats as Double.
- /// </summary>
- Double = 12,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as Boolean.
- /// </summary>
- Boolean32 = 13,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 16-bit bytecount followed by binary data.
- /// Decoding treats as binary data.
- /// </summary>
- Binary = 14,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 16-byte value.
- /// Decoding treats as GUID.
- /// </summary>
- Guid = 15,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 64-bit value.
- /// Decoding treats as FILETIME.
- /// </summary>
- FileTime = 17,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 16-byte value.
- /// Decoding treats as SYSTEMTIME.
- /// </summary>
- SystemTime = 18,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as hexadecimal unsigned integer.
- /// </summary>
- HexInt32 = 20,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 64-bit value.
- /// Decoding treats as hexadecimal unsigned integer.
- /// </summary>
- HexInt64 = 21,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 16-bit bytecount followed by Char16 data.
- /// Decoding treats as UTF-16LE string.
- /// </summary>
- CountedUtf16String = 22,
-
- /// <summary>
- /// Core type.
- /// Encoding assumes 16-bit bytecount followed by Char8 data.
- /// Decoding treats as MBCS string.
- /// </summary>
- CountedMbcsString = 23,
-
- /// <summary>
- /// Core type.
- /// Special case: Struct indicates that this field plus the
- /// subsequent N logical fields are to be considered as one logical
- /// field (i.e. a nested structure). The OutType is used to encode N.
- /// The maximum value for N is 127. This field has no payload by
- /// itself, but logically contains the payload of the following N
- /// fields. It is legal to have an array of Struct.
- /// </summary>
- Struct = 24,
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit value.
- /// Decoding treats as UTF-16LE character.
- /// </summary>
- Char16 = UInt16 + (EventFieldFormat.String << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 8-bit value.
- /// Decoding treats as character.
- /// </summary>
- Char8 = UInt8 + (EventFieldFormat.String << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 8-bit value.
- /// Decoding treats as Boolean.
- /// </summary>
- Boolean8 = UInt8 + (EventFieldFormat.Boolean << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 8-bit value.
- /// Decoding treats as hexadecimal unsigned integer.
- /// </summary>
- HexInt8 = UInt8 + (EventFieldFormat.Hexadecimal << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit value.
- /// Decoding treats as hexadecimal unsigned integer.
- /// </summary>
- HexInt16 = UInt16 + (EventFieldFormat.Hexadecimal << 8),
-
-#if false
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as process identifier.
- /// </summary>
- ProcessId = UInt32 + (EventSourceFieldFormat.ProcessId << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as thread identifier.
- /// </summary>
- ThreadId = UInt32 + (EventSourceFieldFormat.ThreadId << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit value.
- /// Decoding treats as IP port.
- /// </summary>
- Port = UInt16 + (EventSourceFieldFormat.Port << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as IPv4 address.
- /// </summary>
- Ipv4Address = UInt32 + (EventSourceFieldFormat.Ipv4Address << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit bytecount followed by binary data.
- /// Decoding treats as IPv6 address.
- /// </summary>
- Ipv6Address = Binary + (EventSourceFieldFormat.Ipv6Address << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit bytecount followed by binary data.
- /// Decoding treats as SOCKADDR.
- /// </summary>
- SocketAddress = Binary + (EventSourceFieldFormat.SocketAddress << 8),
-#endif
- /// <summary>
- /// Formatted type.
- /// Encoding assumes null-terminated Char16 string.
- /// Decoding treats as UTF-16LE XML string.
- /// </summary>
- Utf16Xml = Utf16String + (EventFieldFormat.Xml << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes null-terminated Char8 string.
- /// Decoding treats as MBCS XML string.
- /// </summary>
- MbcsXml = MbcsString + (EventFieldFormat.Xml << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit bytecount followed by Char16 data.
- /// Decoding treats as UTF-16LE XML.
- /// </summary>
- CountedUtf16Xml = CountedUtf16String + (EventFieldFormat.Xml << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit bytecount followed by Char8 data.
- /// Decoding treats as MBCS XML.
- /// </summary>
- CountedMbcsXml = CountedMbcsString + (EventFieldFormat.Xml << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes null-terminated Char16 string.
- /// Decoding treats as UTF-16LE JSON string.
- /// </summary>
- Utf16Json = Utf16String + (EventFieldFormat.Json << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes null-terminated Char8 string.
- /// Decoding treats as MBCS JSON string.
- /// </summary>
- MbcsJson = MbcsString + (EventFieldFormat.Json << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit bytecount followed by Char16 data.
- /// Decoding treats as UTF-16LE JSON.
- /// </summary>
- CountedUtf16Json = CountedUtf16String + (EventFieldFormat.Json << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 16-bit bytecount followed by Char8 data.
- /// Decoding treats as MBCS JSON.
- /// </summary>
- CountedMbcsJson = CountedMbcsString + (EventFieldFormat.Json << 8),
-#if false
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as Win32 error.
- /// </summary>
- Win32Error = UInt32 + (EventSourceFieldFormat.Win32Error << 8),
-
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as NTSTATUS.
- /// </summary>
- NTStatus = UInt32 + (EventSourceFieldFormat.NTStatus << 8),
-#endif
- /// <summary>
- /// Formatted type.
- /// Encoding assumes 32-bit value.
- /// Decoding treats as HRESULT.
- /// </summary>
- HResult = Int32 + (EventFieldFormat.HResult << 8)
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
deleted file mode 100644
index 3302018a214..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
+++ /dev/null
@@ -1,890 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
-// It is available from http://www.codeplex.com/hyperAddin
-
-#if PLATFORM_WINDOWS
-#define FEATURE_MANAGED_ETW
-#endif // PLATFORM_WINDOWS
-
-#if ES_BUILD_STANDALONE
-#define FEATURE_MANAGED_ETW_CHANNELS
-// #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
-#endif
-
-#if ES_BUILD_STANDALONE
-using System;
-using System.Diagnostics;
-using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
-using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
-#endif
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Runtime.InteropServices;
-using System.Text;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- public partial class EventSource
- {
-#if FEATURE_MANAGED_ETW
- private byte[] providerMetadata = null!;
-#endif
-
-#if FEATURE_PERFTRACING
- private readonly TraceLoggingEventHandleTable m_eventHandleTable = new TraceLoggingEventHandleTable();
-#endif
-
- /// <summary>
- /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
- /// </summary>
- /// <param name="eventSourceName">
- /// The name of the event source. Must not be null.
- /// </param>
- public EventSource(
- string eventSourceName)
- : this(eventSourceName, EventSourceSettings.EtwSelfDescribingEventFormat)
- { }
-
- /// <summary>
- /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
- /// </summary>
- /// <param name="eventSourceName">
- /// The name of the event source. Must not be null.
- /// </param>
- /// <param name="config">
- /// Configuration options for the EventSource as a whole.
- /// </param>
- public EventSource(
- string eventSourceName,
- EventSourceSettings config)
- : this(eventSourceName, config, null) { }
-
- /// <summary>
- /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
- ///
- /// Also specify a list of key-value pairs called traits (you must pass an even number of strings).
- /// The first string is the key and the second is the value. These are not interpreted by EventSource
- /// itself but may be interpreted the listeners. Can be fetched with GetTrait(string).
- /// </summary>
- /// <param name="eventSourceName">
- /// The name of the event source. Must not be null.
- /// </param>
- /// <param name="config">
- /// Configuration options for the EventSource as a whole.
- /// </param>
- /// <param name="traits">A collection of key-value strings (must be an even number).</param>
- public EventSource(
- string eventSourceName,
- EventSourceSettings config,
- params string[]? traits)
- : this(
- eventSourceName == null ? default : GenerateGuidFromName(eventSourceName.ToUpperInvariant()),
- eventSourceName!,
- config, traits)
- {
- if (eventSourceName == null)
- {
- throw new ArgumentNullException(nameof(eventSourceName));
- }
- }
-
- /// <summary>
- /// Writes an event with no fields and default options.
- /// (Native API: EventWriteTransfer)
- /// </summary>
- /// <param name="eventName">The name of the event.</param>
- public unsafe void Write(string? eventName)
- {
- if (!this.IsEnabled())
- {
- return;
- }
-
- EventSourceOptions options = default;
- this.WriteImpl(eventName, ref options, null, null, null, SimpleEventTypes<EmptyStruct>.Instance);
- }
-
- /// <summary>
- /// Writes an event with no fields.
- /// (Native API: EventWriteTransfer)
- /// </summary>
- /// <param name="eventName">The name of the event.</param>
- /// <param name="options">
- /// Options for the event, such as the level, keywords, and opcode. Unset
- /// options will be set to default values.
- /// </param>
- public unsafe void Write(string? eventName, EventSourceOptions options)
- {
- if (!this.IsEnabled())
- {
- return;
- }
-
- this.WriteImpl(eventName, ref options, null, null, null, SimpleEventTypes<EmptyStruct>.Instance);
- }
-
- /// <summary>
- /// Writes an event.
- /// (Native API: EventWriteTransfer)
- /// </summary>
- /// <typeparam name="T">
- /// The type that defines the event and its payload. This must be an
- /// anonymous type or a type with an [EventData] attribute.
- /// </typeparam>
- /// <param name="eventName">
- /// The name for the event. If null, the event name is automatically
- /// determined based on T, either from the Name property of T's EventData
- /// attribute or from typeof(T).Name.
- /// </param>
- /// <param name="data">
- /// The object containing the event payload data. The type T must be
- /// an anonymous type or a type with an [EventData] attribute. The
- /// public instance properties of data will be written recursively to
- /// create the fields of the event.
- /// </param>
- public unsafe void Write<T>(
- string? eventName,
- T data)
- {
- if (!this.IsEnabled())
- {
- return;
- }
-
- EventSourceOptions options = default;
- this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
- }
-
- /// <summary>
- /// Writes an event.
- /// (Native API: EventWriteTransfer)
- /// </summary>
- /// <typeparam name="T">
- /// The type that defines the event and its payload. This must be an
- /// anonymous type or a type with an [EventData] attribute.
- /// </typeparam>
- /// <param name="eventName">
- /// The name for the event. If null, the event name is automatically
- /// determined based on T, either from the Name property of T's EventData
- /// attribute or from typeof(T).Name.
- /// </param>
- /// <param name="options">
- /// Options for the event, such as the level, keywords, and opcode. Unset
- /// options will be set to default values.
- /// </param>
- /// <param name="data">
- /// The object containing the event payload data. The type T must be
- /// an anonymous type or a type with an [EventData] attribute. The
- /// public instance properties of data will be written recursively to
- /// create the fields of the event.
- /// </param>
- public unsafe void Write<T>(
- string? eventName,
- EventSourceOptions options,
- T data)
- {
- if (!this.IsEnabled())
- {
- return;
- }
-
- this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
- }
-
- /// <summary>
- /// Writes an event.
- /// This overload is for use with extension methods that wish to efficiently
- /// forward the options or data parameter without performing an extra copy.
- /// (Native API: EventWriteTransfer)
- /// </summary>
- /// <typeparam name="T">
- /// The type that defines the event and its payload. This must be an
- /// anonymous type or a type with an [EventData] attribute.
- /// </typeparam>
- /// <param name="eventName">
- /// The name for the event. If null, the event name is automatically
- /// determined based on T, either from the Name property of T's EventData
- /// attribute or from typeof(T).Name.
- /// </param>
- /// <param name="options">
- /// Options for the event, such as the level, keywords, and opcode. Unset
- /// options will be set to default values.
- /// </param>
- /// <param name="data">
- /// The object containing the event payload data. The type T must be
- /// an anonymous type or a type with an [EventData] attribute. The
- /// public instance properties of data will be written recursively to
- /// create the fields of the event.
- /// </param>
- public unsafe void Write<T>(
- string? eventName,
- ref EventSourceOptions options,
- ref T data)
- {
- if (!this.IsEnabled())
- {
- return;
- }
-
- this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
- }
-
- /// <summary>
- /// Writes an event.
- /// This overload is meant for clients that need to manipuate the activityId
- /// and related ActivityId for the event.
- /// </summary>
- /// <typeparam name="T">
- /// The type that defines the event and its payload. This must be an
- /// anonymous type or a type with an [EventData] attribute.
- /// </typeparam>
- /// <param name="eventName">
- /// The name for the event. If null, the event name is automatically
- /// determined based on T, either from the Name property of T's EventData
- /// attribute or from typeof(T).Name.
- /// </param>
- /// <param name="options">
- /// Options for the event, such as the level, keywords, and opcode. Unset
- /// options will be set to default values.
- /// </param>
- /// <param name="activityId">
- /// The GUID of the activity associated with this event.
- /// </param>
- /// <param name="relatedActivityId">
- /// The GUID of another activity that is related to this activity, or Guid.Empty
- /// if there is no related activity. Most commonly, the Start operation of a
- /// new activity specifies a parent activity as its related activity.
- /// </param>
- /// <param name="data">
- /// The object containing the event payload data. The type T must be
- /// an anonymous type or a type with an [EventData] attribute. The
- /// public instance properties of data will be written recursively to
- /// create the fields of the event.
- /// </param>
- public unsafe void Write<T>(
- string? eventName,
- ref EventSourceOptions options,
- ref Guid activityId,
- ref Guid relatedActivityId,
- ref T data)
- {
- if (!this.IsEnabled())
- {
- return;
- }
-
- fixed (Guid* pActivity = &activityId, pRelated = &relatedActivityId)
- {
- this.WriteImpl(
- eventName,
- ref options,
- data,
- pActivity,
- relatedActivityId == Guid.Empty ? null : pRelated,
- SimpleEventTypes<T>.Instance);
- }
- }
-
- /// <summary>
- /// Writes an extended event, where the values of the event are the
- /// combined properties of any number of values. This method is
- /// intended for use in advanced logging scenarios that support a
- /// dynamic set of event context providers.
- /// This method does a quick check on whether this event is enabled.
- /// </summary>
- /// <param name="eventName">
- /// The name for the event. If null, the name from eventTypes is used.
- /// (Note that providing the event name via the name parameter is slightly
- /// less efficient than using the name from eventTypes.)
- /// </param>
- /// <param name="options">
- /// Optional overrides for the event, such as the level, keyword, opcode,
- /// activityId, and relatedActivityId. Any settings not specified by options
- /// are obtained from eventTypes.
- /// </param>
- /// <param name="eventTypes">
- /// Information about the event and the types of the values in the event.
- /// Must not be null. Note that the eventTypes object should be created once and
- /// saved. It should not be recreated for each event.
- /// </param>
- /// <param name="activityID">
- /// A pointer to the activity ID GUID to log
- /// </param>
- /// <param name="childActivityID">
- /// A pointer to the child activity ID to log (can be null) </param>
- /// <param name="values">
- /// The values to include in the event. Must not be null. The number and types of
- /// the values must match the number and types of the fields described by the
- /// eventTypes parameter.
- /// </param>
- private unsafe void WriteMultiMerge(
- string? eventName,
- ref EventSourceOptions options,
- TraceLoggingEventTypes eventTypes,
- Guid* activityID,
- Guid* childActivityID,
- params object?[] values)
- {
- if (!this.IsEnabled())
- {
- return;
- }
- byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
- ? options.level
- : eventTypes.level;
- EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
- ? options.keywords
- : eventTypes.keywords;
-
- if (this.IsEnabled((EventLevel)level, keywords))
- {
- WriteMultiMergeInner(eventName, ref options, eventTypes, activityID, childActivityID, values);
- }
- }
-
- /// <summary>
- /// Writes an extended event, where the values of the event are the
- /// combined properties of any number of values. This method is
- /// intended for use in advanced logging scenarios that support a
- /// dynamic set of event context providers.
- /// Attention: This API does not check whether the event is enabled or not.
- /// Please use WriteMultiMerge to avoid spending CPU cycles for events that are
- /// not enabled.
- /// </summary>
- /// <param name="eventName">
- /// The name for the event. If null, the name from eventTypes is used.
- /// (Note that providing the event name via the name parameter is slightly
- /// less efficient than using the name from eventTypes.)
- /// </param>
- /// <param name="options">
- /// Optional overrides for the event, such as the level, keyword, opcode,
- /// activityId, and relatedActivityId. Any settings not specified by options
- /// are obtained from eventTypes.
- /// </param>
- /// <param name="eventTypes">
- /// Information about the event and the types of the values in the event.
- /// Must not be null. Note that the eventTypes object should be created once and
- /// saved. It should not be recreated for each event.
- /// </param>
- /// <param name="activityID">
- /// A pointer to the activity ID GUID to log
- /// </param>
- /// <param name="childActivityID">
- /// A pointer to the child activity ID to log (can be null)
- /// </param>
- /// <param name="values">
- /// The values to include in the event. Must not be null. The number and types of
- /// the values must match the number and types of the fields described by the
- /// eventTypes parameter.
- /// </param>
- private unsafe void WriteMultiMergeInner(
- string? eventName,
- ref EventSourceOptions options,
- TraceLoggingEventTypes eventTypes,
- Guid* activityID,
- Guid* childActivityID,
- params object?[] values)
- {
-#if FEATURE_MANAGED_ETW
- int identity = 0;
- byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
- ? options.level
- : eventTypes.level;
- byte opcode = (options.valuesSet & EventSourceOptions.opcodeSet) != 0
- ? options.opcode
- : eventTypes.opcode;
- EventTags tags = (options.valuesSet & EventSourceOptions.tagsSet) != 0
- ? options.tags
- : eventTypes.Tags;
- EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
- ? options.keywords
- : eventTypes.keywords;
-
- NameInfo nameInfo = eventTypes.GetNameInfo(eventName ?? eventTypes.Name, tags);
- if (nameInfo == null)
- {
- return;
- }
- identity = nameInfo.identity;
- EventDescriptor descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
-
-#if FEATURE_PERFTRACING
- IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_eventPipeProvider, m_eventHandleTable, descriptor, eventTypes);
- Debug.Assert(eventHandle != IntPtr.Zero);
-#else
- IntPtr eventHandle = IntPtr.Zero;
-#endif
-
- int pinCount = eventTypes.pinCount;
- byte* scratch = stackalloc byte[eventTypes.scratchSize];
- EventData* descriptors = stackalloc EventData[eventTypes.dataCount + 3];
- for (int i = 0; i < eventTypes.dataCount + 3; i++)
- descriptors[i] = default;
-
- GCHandle* pins = stackalloc GCHandle[pinCount];
- for (int i = 0; i < pinCount; i++)
- pins[i] = default;
-
- fixed (byte*
- pMetadata0 = this.providerMetadata,
- pMetadata1 = nameInfo.nameMetadata,
- pMetadata2 = eventTypes.typeMetadata)
- {
- descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
- descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
- descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
-
-#if (!ES_BUILD_PCL && !ES_BUILD_PN)
- System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
-#endif
- try
- {
- DataCollector.ThreadInstance.Enable(
- scratch,
- eventTypes.scratchSize,
- descriptors + 3,
- eventTypes.dataCount,
- pins,
- pinCount);
-
- for (int i = 0; i < eventTypes.typeInfos.Length; i++)
- {
- TraceLoggingTypeInfo info = eventTypes.typeInfos[i];
- info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(values[i]));
- }
-
- this.WriteEventRaw(
- eventName,
- ref descriptor,
- eventHandle,
- activityID,
- childActivityID,
- (int)(DataCollector.ThreadInstance.Finish() - descriptors),
- (IntPtr)descriptors);
- }
- finally
- {
- WriteCleanup(pins, pinCount);
- }
- }
-#endif // FEATURE_MANAGED_ETW
- }
-
- /// <summary>
- /// Writes an extended event, where the values of the event have already
- /// been serialized in "data".
- /// </summary>
- /// <param name="eventName">
- /// The name for the event. If null, the name from eventTypes is used.
- /// (Note that providing the event name via the name parameter is slightly
- /// less efficient than using the name from eventTypes.)
- /// </param>
- /// <param name="options">
- /// Optional overrides for the event, such as the level, keyword, opcode,
- /// activityId, and relatedActivityId. Any settings not specified by options
- /// are obtained from eventTypes.
- /// </param>
- /// <param name="eventTypes">
- /// Information about the event and the types of the values in the event.
- /// Must not be null. Note that the eventTypes object should be created once and
- /// saved. It should not be recreated for each event.
- /// </param>
- /// <param name="activityID">
- /// A pointer to the activity ID GUID to log
- /// </param>
- /// <param name="childActivityID">
- /// A pointer to the child activity ID to log (can be null)
- /// </param>
- /// <param name="data">
- /// The previously serialized values to include in the event. Must not be null.
- /// The number and types of the values must match the number and types of the
- /// fields described by the eventTypes parameter.
- /// </param>
- internal unsafe void WriteMultiMerge(
- string? eventName,
- ref EventSourceOptions options,
- TraceLoggingEventTypes eventTypes,
- Guid* activityID,
- Guid* childActivityID,
- EventData* data)
- {
-#if FEATURE_MANAGED_ETW
- if (!this.IsEnabled())
- {
- return;
- }
-
- fixed (EventSourceOptions* pOptions = &options)
- {
- EventDescriptor descriptor;
- NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
- if (nameInfo == null)
- {
- return;
- }
-
-#if FEATURE_PERFTRACING
- IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_eventPipeProvider, m_eventHandleTable, descriptor, eventTypes);
- Debug.Assert(eventHandle != IntPtr.Zero);
-#else
- IntPtr eventHandle = IntPtr.Zero;
-#endif
-
- // We make a descriptor for each EventData, and because we morph strings to counted strings
- // we may have 2 for each arg, so we allocate enough for this.
- int descriptorsLength = eventTypes.dataCount + eventTypes.typeInfos.Length * 2 + 3;
- EventData* descriptors = stackalloc EventData[descriptorsLength];
- for (int i = 0; i < descriptorsLength; i++)
- descriptors[i] = default;
-
- fixed (byte*
- pMetadata0 = this.providerMetadata,
- pMetadata1 = nameInfo.nameMetadata,
- pMetadata2 = eventTypes.typeMetadata)
- {
- descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
- descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
- descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
- int numDescrs = 3;
-
- for (int i = 0; i < eventTypes.typeInfos.Length; i++)
- {
- descriptors[numDescrs].m_Ptr = data[i].m_Ptr;
- descriptors[numDescrs].m_Size = data[i].m_Size;
-
- // old conventions for bool is 4 bytes, but meta-data assumes 1.
- if (data[i].m_Size == 4 && eventTypes.typeInfos[i].DataType == typeof(bool))
- descriptors[numDescrs].m_Size = 1;
-
- numDescrs++;
- }
-
- this.WriteEventRaw(
- eventName,
- ref descriptor,
- eventHandle,
- activityID,
- childActivityID,
- numDescrs,
- (IntPtr)descriptors);
- }
- }
-#endif // FEATURE_MANAGED_ETW
- }
-
- private unsafe void WriteImpl(
- string? eventName,
- ref EventSourceOptions options,
- object? data,
- Guid* pActivityId,
- Guid* pRelatedActivityId,
- TraceLoggingEventTypes eventTypes)
- {
- try
- {
- fixed (EventSourceOptions* pOptions = &options)
- {
- EventDescriptor descriptor;
- options.Opcode = options.IsOpcodeSet ? options.Opcode : GetOpcodeWithDefault(options.Opcode, eventName);
- NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
- if (nameInfo == null)
- {
- return;
- }
-
-#if FEATURE_PERFTRACING
- IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_eventPipeProvider, m_eventHandleTable, descriptor, eventTypes);
- Debug.Assert(eventHandle != IntPtr.Zero);
-#else
- IntPtr eventHandle = IntPtr.Zero;
-#endif
-
-#if FEATURE_MANAGED_ETW
- int pinCount = eventTypes.pinCount;
- byte* scratch = stackalloc byte[eventTypes.scratchSize];
- EventData* descriptors = stackalloc EventData[eventTypes.dataCount + 3];
- for (int i = 0; i < eventTypes.dataCount + 3; i++)
- descriptors[i] = default;
-
- GCHandle* pins = stackalloc GCHandle[pinCount];
- for (int i = 0; i < pinCount; i++)
- pins[i] = default;
-
- fixed (byte*
- pMetadata0 = this.providerMetadata,
- pMetadata1 = nameInfo.nameMetadata,
- pMetadata2 = eventTypes.typeMetadata)
- {
- descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
- descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
- descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
-#endif // FEATURE_MANAGED_ETW
-
-#if (!ES_BUILD_PCL && !ES_BUILD_PN)
- System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
-#endif
- EventOpcode opcode = (EventOpcode)descriptor.Opcode;
-
- Guid activityId = Guid.Empty;
- Guid relatedActivityId = Guid.Empty;
- if (pActivityId == null && pRelatedActivityId == null &&
- ((options.ActivityOptions & EventActivityOptions.Disable) == 0))
- {
- if (opcode == EventOpcode.Start)
- {
- Debug.Assert(eventName != null, "GetOpcodeWithDefault should not returned Start when eventName is null");
- m_activityTracker.OnStart(m_name, eventName, 0, ref activityId, ref relatedActivityId, options.ActivityOptions);
- }
- else if (opcode == EventOpcode.Stop)
- {
- Debug.Assert(eventName != null, "GetOpcodeWithDefault should not returned Stop when eventName is null");
- m_activityTracker.OnStop(m_name, eventName, 0, ref activityId);
- }
- if (activityId != Guid.Empty)
- pActivityId = &activityId;
- if (relatedActivityId != Guid.Empty)
- pRelatedActivityId = &relatedActivityId;
- }
-
- try
- {
-#if FEATURE_MANAGED_ETW
- DataCollector.ThreadInstance.Enable(
- scratch,
- eventTypes.scratchSize,
- descriptors + 3,
- eventTypes.dataCount,
- pins,
- pinCount);
-
- TraceLoggingTypeInfo info = eventTypes.typeInfos[0];
- info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(data));
-
- this.WriteEventRaw(
- eventName,
- ref descriptor,
- eventHandle,
- pActivityId,
- pRelatedActivityId,
- (int)(DataCollector.ThreadInstance.Finish() - descriptors),
- (IntPtr)descriptors);
-#endif // FEATURE_MANAGED_ETW
-
- // TODO enable filtering for listeners.
- if (m_Dispatchers != null)
- {
- var eventData = (EventPayload?)(eventTypes.typeInfos[0].GetData(data));
- WriteToAllListeners(eventName, ref descriptor, nameInfo.tags, pActivityId, pRelatedActivityId, eventData);
- }
- }
- catch (Exception ex)
- {
- if (ex is EventSourceException)
- throw;
- else
- ThrowEventSourceException(eventName, ex);
- }
-#if FEATURE_MANAGED_ETW
- finally
- {
- WriteCleanup(pins, pinCount);
- }
- }
-#endif // FEATURE_MANAGED_ETW
- }
- }
- catch (Exception ex)
- {
- if (ex is EventSourceException)
- throw;
- else
- ThrowEventSourceException(eventName, ex);
- }
- }
-
- private unsafe void WriteToAllListeners(string? eventName, ref EventDescriptor eventDescriptor, EventTags tags, Guid* pActivityId, Guid* pChildActivityId, EventPayload? payload)
- {
- EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
- eventCallbackArgs.EventName = eventName;
- eventCallbackArgs.m_level = (EventLevel)eventDescriptor.Level;
- eventCallbackArgs.m_keywords = (EventKeywords)eventDescriptor.Keywords;
- eventCallbackArgs.m_opcode = (EventOpcode)eventDescriptor.Opcode;
- eventCallbackArgs.m_tags = tags;
-
- // Self described events do not have an id attached. We mark it internally with -1.
- eventCallbackArgs.EventId = -1;
- if (pActivityId != null)
- eventCallbackArgs.ActivityId = *pActivityId;
- if (pChildActivityId != null)
- eventCallbackArgs.RelatedActivityId = *pChildActivityId;
-
- if (payload != null)
- {
- eventCallbackArgs.Payload = new ReadOnlyCollection<object?>((IList<object?>)payload.Values);
- eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>((IList<string>)payload.Keys);
- }
-
- DispatchToAllListeners(-1, eventCallbackArgs);
- }
-
-#if (!ES_BUILD_PCL && !ES_BUILD_PN)
- [System.Runtime.ConstrainedExecution.ReliabilityContract(
- System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState,
- System.Runtime.ConstrainedExecution.Cer.Success)]
-#endif
- [NonEvent]
- private static unsafe void WriteCleanup(GCHandle* pPins, int cPins)
- {
- DataCollector.ThreadInstance.Disable();
-
- for (int i = 0; i < cPins; i++)
- {
- if (pPins[i].IsAllocated)
- {
- pPins[i].Free();
- }
- }
- }
-
- private void InitializeProviderMetadata()
- {
-#if FEATURE_MANAGED_ETW
- if (m_traits != null)
- {
- List<byte> traitMetaData = new List<byte>(100);
- for (int i = 0; i < m_traits.Length - 1; i += 2)
- {
- if (m_traits[i].StartsWith("ETW_", StringComparison.Ordinal))
- {
- string etwTrait = m_traits[i].Substring(4);
- byte traitNum;
- if (!byte.TryParse(etwTrait, out traitNum))
- {
- if (etwTrait == "GROUP")
- {
- traitNum = 1;
- }
- else
- {
- throw new ArgumentException(SR.Format(SR.EventSource_UnknownEtwTrait, etwTrait), "traits");
- }
- }
- string value = m_traits[i + 1];
- int lenPos = traitMetaData.Count;
- traitMetaData.Add(0); // Emit size (to be filled in later)
- traitMetaData.Add(0);
- traitMetaData.Add(traitNum); // Emit Trait number
- int valueLen = AddValueToMetaData(traitMetaData, value) + 3; // Emit the value bytes +3 accounts for 3 bytes we emited above.
- traitMetaData[lenPos] = unchecked((byte)valueLen); // Fill in size
- traitMetaData[lenPos + 1] = unchecked((byte)(valueLen >> 8));
- }
- }
- providerMetadata = Statics.MetadataForString(this.Name, 0, traitMetaData.Count, 0);
- int startPos = providerMetadata.Length - traitMetaData.Count;
- foreach (byte b in traitMetaData)
- providerMetadata[startPos++] = b;
- }
- else
- providerMetadata = Statics.MetadataForString(this.Name, 0, 0, 0);
-#endif //FEATURE_MANAGED_ETW
- }
-
- private static int AddValueToMetaData(List<byte> metaData, string value)
- {
- if (value.Length == 0)
- return 0;
-
- int startPos = metaData.Count;
- char firstChar = value[0];
-
- if (firstChar == '@')
- metaData.AddRange(Encoding.UTF8.GetBytes(value.Substring(1)));
- else if (firstChar == '{')
- metaData.AddRange(new Guid(value).ToByteArray());
- else if (firstChar == '#')
- {
- for (int i = 1; i < value.Length; i++)
- {
- if (value[i] != ' ') // Skip spaces between bytes.
- {
- if (!(i + 1 < value.Length))
- {
- throw new ArgumentException(SR.EventSource_EvenHexDigits, "traits");
- }
- metaData.Add((byte)(HexDigit(value[i]) * 16 + HexDigit(value[i + 1])));
- i++;
- }
- }
- }
- else if ('A' <= firstChar || ' ' == firstChar) // Is it alphabetic or space (excludes digits and most punctuation).
- {
- metaData.AddRange(Encoding.UTF8.GetBytes(value));
- }
- else
- {
- throw new ArgumentException(SR.Format(SR.EventSource_IllegalValue, value), "traits");
- }
-
- return metaData.Count - startPos;
- }
-
- /// <summary>
- /// Returns a value 0-15 if 'c' is a hexadecimal digit. If it throws an argument exception.
- /// </summary>
- private static int HexDigit(char c)
- {
- if ('0' <= c && c <= '9')
- {
- return c - '0';
- }
- if ('a' <= c)
- {
- c = unchecked((char)(c - ('a' - 'A'))); // Convert to lower case
- }
- if ('A' <= c && c <= 'F')
- {
- return c - 'A' + 10;
- }
-
- throw new ArgumentException(SR.Format(SR.EventSource_BadHexDigit, c), "traits");
- }
-
- private NameInfo? UpdateDescriptor(
- string? name,
- TraceLoggingEventTypes eventInfo,
- ref EventSourceOptions options,
- out EventDescriptor descriptor)
- {
- NameInfo? nameInfo = null;
- int identity = 0;
- byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
- ? options.level
- : eventInfo.level;
- byte opcode = (options.valuesSet & EventSourceOptions.opcodeSet) != 0
- ? options.opcode
- : eventInfo.opcode;
- EventTags tags = (options.valuesSet & EventSourceOptions.tagsSet) != 0
- ? options.tags
- : eventInfo.Tags;
- EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
- ? options.keywords
- : eventInfo.keywords;
-
- if (this.IsEnabled((EventLevel)level, keywords))
- {
- nameInfo = eventInfo.GetNameInfo(name ?? eventInfo.Name, tags);
- identity = nameInfo.identity;
- }
-
- descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
- return nameInfo;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTraits.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTraits.cs
deleted file mode 100644
index e25ae7fdc23..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTraits.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Tags are flags that are not interpreted by EventSource but are passed along
- /// to the EventListener. The EventListener determines the semantics of the flags.
- /// </summary>
- [Flags]
- public enum EventTags
- {
- /// <summary>
- /// No special traits are added to the event.
- /// </summary>
- None = 0,
-
- /* Bits below 0x10000 are available for any use by the provider. */
- /* Bits at or above 0x10000 are reserved for definition by Microsoft. */
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
deleted file mode 100644
index 0bd29d645ce..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
+++ /dev/null
@@ -1,243 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-using System.Collections.Generic;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: Used when calling EventSource.WriteMultiMerge.
- /// Stores the type information to use when writing the event fields.
- /// </summary>
- public class TraceLoggingEventTypes
- {
- internal readonly TraceLoggingTypeInfo[] typeInfos;
-#if FEATURE_PERFTRACING
- internal readonly string[]? paramNames;
-#endif
- internal readonly string name;
- internal readonly EventTags tags;
- internal readonly byte level;
- internal readonly byte opcode;
- internal readonly EventKeywords keywords;
- internal readonly byte[] typeMetadata;
- internal readonly int scratchSize;
- internal readonly int dataCount;
- internal readonly int pinCount;
- private ConcurrentSet<KeyValuePair<string, EventTags>, NameInfo> nameInfos;
-
- /// <summary>
- /// Initializes a new instance of TraceLoggingEventTypes corresponding
- /// to the name, flags, and types provided. Always uses the default
- /// TypeInfo for each Type.
- /// </summary>
- /// <param name="name">
- /// The name to use when the name parameter passed to
- /// EventSource.Write is null. This value must not be null.
- /// </param>
- /// <param name="tags">
- /// Tags to add to the event if the tags are not set via options.
- /// </param>
- /// <param name="types">
- /// The types of the fields in the event. This value must not be null.
- /// </param>
- internal TraceLoggingEventTypes(
- string name,
- EventTags tags,
- params Type[] types)
- : this(tags, name, MakeArray(types))
- {
- }
-
- /// <summary>
- /// Returns a new instance of TraceLoggingEventInfo corresponding to the name,
- /// flags, and typeInfos provided.
- /// </summary>
- /// <param name="name">
- /// The name to use when the name parameter passed to
- /// EventSource.Write is null. This value must not be null.
- /// </param>
- /// <param name="tags">
- /// Tags to add to the event if the tags are not set via options.
- /// </param>
- /// <param name="typeInfos">
- /// The types of the fields in the event. This value must not be null.
- /// </param>
- /// <returns>
- /// An instance of TraceLoggingEventInfo with DefaultName set to the specified name
- /// and with the specified typeInfos.
- /// </returns>
- internal TraceLoggingEventTypes(
- string name,
- EventTags tags,
- params TraceLoggingTypeInfo[] typeInfos)
- : this(tags, name, MakeArray(typeInfos))
- {
- }
-
- internal TraceLoggingEventTypes(
- string name,
- EventTags tags,
- System.Reflection.ParameterInfo[] paramInfos)
- {
- if (name == null)
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- this.typeInfos = MakeArray(paramInfos);
-#if FEATURE_PERFTRACING
- this.paramNames = MakeParamNameArray(paramInfos);
-#endif
- this.name = name;
- this.tags = tags;
- this.level = Statics.DefaultLevel;
-
- var collector = new TraceLoggingMetadataCollector();
- for (int i = 0; i < typeInfos.Length; ++i)
- {
- TraceLoggingTypeInfo typeInfo = typeInfos[i];
- this.level = Statics.Combine((int)typeInfo.Level, this.level);
- this.opcode = Statics.Combine((int)typeInfo.Opcode, this.opcode);
- this.keywords |= typeInfo.Keywords;
- string? paramName = paramInfos[i].Name;
- if (Statics.ShouldOverrideFieldName(paramName!))
- {
- paramName = typeInfo.Name;
- }
- typeInfo.WriteMetadata(collector, paramName, EventFieldFormat.Default);
- }
-
- this.typeMetadata = collector.GetMetadata();
- this.scratchSize = collector.ScratchSize;
- this.dataCount = collector.DataCount;
- this.pinCount = collector.PinCount;
- }
-
- private TraceLoggingEventTypes(
- EventTags tags,
- string defaultName,
- TraceLoggingTypeInfo[] typeInfos)
- {
- if (defaultName == null)
- {
- throw new ArgumentNullException(nameof(defaultName));
- }
-
- this.typeInfos = typeInfos;
- this.name = defaultName;
- this.tags = tags;
- this.level = Statics.DefaultLevel;
-
- var collector = new TraceLoggingMetadataCollector();
- foreach (TraceLoggingTypeInfo typeInfo in typeInfos)
- {
- this.level = Statics.Combine((int)typeInfo.Level, this.level);
- this.opcode = Statics.Combine((int)typeInfo.Opcode, this.opcode);
- this.keywords |= typeInfo.Keywords;
- typeInfo.WriteMetadata(collector, null, EventFieldFormat.Default);
- }
-
- this.typeMetadata = collector.GetMetadata();
- this.scratchSize = collector.ScratchSize;
- this.dataCount = collector.DataCount;
- this.pinCount = collector.PinCount;
- }
-
- /// <summary>
- /// Gets the default name that will be used for events with this descriptor.
- /// </summary>
- internal string Name => this.name;
-
- /// <summary>
- /// Gets the default level that will be used for events with this descriptor.
- /// </summary>
- internal EventLevel Level => (EventLevel)this.level;
-
- /// <summary>
- /// Gets the default opcode that will be used for events with this descriptor.
- /// </summary>
- internal EventOpcode Opcode => (EventOpcode)this.opcode;
-
- /// <summary>
- /// Gets the default set of keywords that will added to events with this descriptor.
- /// </summary>
- internal EventKeywords Keywords => (EventKeywords)this.keywords;
-
- /// <summary>
- /// Gets the default tags that will be added events with this descriptor.
- /// </summary>
- internal EventTags Tags => this.tags;
-
- internal NameInfo GetNameInfo(string name, EventTags tags) =>
- this.nameInfos.TryGet(new KeyValuePair<string, EventTags>(name, tags)) ??
- this.nameInfos.GetOrAdd(new NameInfo(name, tags, this.typeMetadata.Length));
-
- private TraceLoggingTypeInfo[] MakeArray(System.Reflection.ParameterInfo[] paramInfos)
- {
- if (paramInfos == null)
- {
- throw new ArgumentNullException(nameof(paramInfos));
- }
-
- var recursionCheck = new List<Type>(paramInfos.Length);
- var result = new TraceLoggingTypeInfo[paramInfos.Length];
- for (int i = 0; i < paramInfos.Length; ++i)
- {
- result[i] = TraceLoggingTypeInfo.GetInstance(paramInfos[i].ParameterType, recursionCheck);
- }
-
- return result;
- }
-
- private static TraceLoggingTypeInfo[] MakeArray(Type[] types)
- {
- if (types == null)
- {
- throw new ArgumentNullException(nameof(types));
- }
-
- var recursionCheck = new List<Type>(types.Length);
- var result = new TraceLoggingTypeInfo[types.Length];
- for (int i = 0; i < types.Length; i++)
- {
- result[i] = TraceLoggingTypeInfo.GetInstance(types[i], recursionCheck);
- }
-
- return result;
- }
-
- private static TraceLoggingTypeInfo[] MakeArray(
- TraceLoggingTypeInfo[] typeInfos)
- {
- if (typeInfos == null)
- {
- throw new ArgumentNullException(nameof(typeInfos));
- }
-
- return (TraceLoggingTypeInfo[])typeInfos.Clone();
- }
-
-#if FEATURE_PERFTRACING
- private static string[] MakeParamNameArray(
- System.Reflection.ParameterInfo[] paramInfos)
- {
- string[] paramNames = new string[paramInfos.Length];
- for (int i = 0; i < paramNames.Length; i++)
- {
- paramNames[i] = paramInfos[i].Name!;
- }
-
- return paramNames;
- }
-#endif
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
deleted file mode 100644
index 4ab1d054932..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
+++ /dev/null
@@ -1,381 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
-#endif
-using System.Collections.Generic;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: used when implementing a custom TraceLoggingTypeInfo.
- /// An instance of this type is provided to the TypeInfo.WriteMetadata method.
- /// </summary>
- internal class TraceLoggingMetadataCollector
- {
- private readonly Impl impl;
- private readonly FieldMetadata? currentGroup;
- private int bufferedArrayFieldCount = int.MinValue;
-
- /// <summary>
- /// Creates a root-level collector.
- /// </summary>
- internal TraceLoggingMetadataCollector()
- {
- this.impl = new Impl();
- }
-
- /// <summary>
- /// Creates a collector for a group.
- /// </summary>
- /// <param name="other">Parent collector</param>
- /// <param name="group">The field that starts the group</param>
- private TraceLoggingMetadataCollector(
- TraceLoggingMetadataCollector other,
- FieldMetadata group)
- {
- this.impl = other.impl;
- this.currentGroup = group;
- }
-
- /// <summary>
- /// The field tags to be used for the next field.
- /// This will be reset to None each time a field is written.
- /// </summary>
- internal EventFieldTags Tags
- {
- get;
- set;
- }
-
- internal int ScratchSize => this.impl.scratchSize;
-
- internal int DataCount => this.impl.dataCount;
-
- internal int PinCount => this.impl.pinCount;
-
- private bool BeginningBufferedArray => this.bufferedArrayFieldCount == 0;
-
- /// <summary>
- /// Call this method to add a group to the event and to return
- /// a new metadata collector that can be used to add fields to the
- /// group. After all of the fields in the group have been written,
- /// switch back to the original metadata collector to add fields
- /// outside of the group.
- /// Special-case: if name is null, no group is created, and AddGroup
- /// returns the original metadata collector. This is useful when
- /// adding the top-level group for an event.
- /// Note: do not use the original metadata collector while the group's
- /// metadata collector is in use, and do not use the group's metadata
- /// collector after switching back to the original.
- /// </summary>
- /// <param name="name">
- /// The name of the group. If name is null, the call to AddGroup is a
- /// no-op (collector.AddGroup(null) returns collector).
- /// </param>
- /// <returns>
- /// A new metadata collector that can be used to add fields to the group.
- /// </returns>
- public TraceLoggingMetadataCollector AddGroup(string? name)
- {
- TraceLoggingMetadataCollector result = this;
-
- if (name != null || // Normal.
- this.BeginningBufferedArray) // Error, FieldMetadata's constructor will throw the appropriate exception.
- {
- var newGroup = new FieldMetadata(
- name!,
- TraceLoggingDataType.Struct,
- this.Tags,
- this.BeginningBufferedArray);
- this.AddField(newGroup);
- result = new TraceLoggingMetadataCollector(this, newGroup);
- }
-
- return result;
- }
-
- /// <summary>
- /// Adds a scalar field to an event.
- /// </summary>
- /// <param name="name">
- /// The name to use for the added field. This value must not be null.
- /// </param>
- /// <param name="type">
- /// The type code for the added field. This must be a fixed-size type
- /// (e.g. string types are not supported).
- /// </param>
- public void AddScalar(string name, TraceLoggingDataType type)
- {
- int size;
- switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
- {
- case TraceLoggingDataType.Int8:
- case TraceLoggingDataType.UInt8:
- case TraceLoggingDataType.Char8:
- size = 1;
- break;
- case TraceLoggingDataType.Int16:
- case TraceLoggingDataType.UInt16:
- case TraceLoggingDataType.Char16:
- size = 2;
- break;
- case TraceLoggingDataType.Int32:
- case TraceLoggingDataType.UInt32:
- case TraceLoggingDataType.HexInt32:
- case TraceLoggingDataType.Float:
- case TraceLoggingDataType.Boolean32:
- size = 4;
- break;
- case TraceLoggingDataType.Int64:
- case TraceLoggingDataType.UInt64:
- case TraceLoggingDataType.HexInt64:
- case TraceLoggingDataType.Double:
- case TraceLoggingDataType.FileTime:
- size = 8;
- break;
- case TraceLoggingDataType.Guid:
- case TraceLoggingDataType.SystemTime:
- size = 16;
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(type));
- }
-
- this.impl.AddScalar(size);
- this.AddField(new FieldMetadata(name, type, this.Tags, this.BeginningBufferedArray));
- }
-
- /// <summary>
- /// Adds a binary-format field to an event.
- /// Compatible with core types: Binary, CountedUtf16String, CountedMbcsString.
- /// Compatible with dataCollector methods: AddBinary(string), AddArray(Any8bitType[]).
- /// </summary>
- /// <param name="name">
- /// The name to use for the added field. This value must not be null.
- /// </param>
- /// <param name="type">
- /// The type code for the added field. This must be a Binary or CountedString type.
- /// </param>
- public void AddBinary(string name, TraceLoggingDataType type)
- {
- switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
- {
- case TraceLoggingDataType.Binary:
- case TraceLoggingDataType.CountedMbcsString:
- case TraceLoggingDataType.CountedUtf16String:
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(type));
- }
-
- this.impl.AddScalar(2);
- this.impl.AddNonscalar();
- this.AddField(new FieldMetadata(name, type, this.Tags, this.BeginningBufferedArray));
- }
-
- /// <summary>
- /// Adds a null-terminated string field to an event.
- /// Compatible with core types: Utf16String, MbcsString.
- /// Compatible with dataCollector method: AddNullTerminatedString(string).
- /// </summary>
- /// <param name="name">
- /// The name to use for the added field. This value must not be null.
- /// </param>
- /// <param name="type">
- /// The type code for the added field. This must be a null-terminated string type.
- /// </param>
- public void AddNullTerminatedString(string name, TraceLoggingDataType type)
- {
- switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
- {
- case TraceLoggingDataType.Utf16String:
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(type));
- }
-
- this.impl.AddNonscalar();
- this.AddField(new FieldMetadata(name, type, this.Tags, this.BeginningBufferedArray));
- }
-
- /// <summary>
- /// Adds an array field to an event.
- /// </summary>
- /// <param name="name">
- /// The name to use for the added field. This value must not be null.
- /// </param>
- /// <param name="type">
- /// The type code for the added field. This must be a fixed-size type.
- /// </param>
- public void AddArray(string name, TraceLoggingDataType type)
- {
- switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
- {
- case TraceLoggingDataType.Int8:
- case TraceLoggingDataType.UInt8:
- case TraceLoggingDataType.Int16:
- case TraceLoggingDataType.UInt16:
- case TraceLoggingDataType.Int32:
- case TraceLoggingDataType.UInt32:
- case TraceLoggingDataType.Int64:
- case TraceLoggingDataType.UInt64:
- case TraceLoggingDataType.Float:
- case TraceLoggingDataType.Double:
- case TraceLoggingDataType.Boolean32:
- case TraceLoggingDataType.Guid:
- case TraceLoggingDataType.FileTime:
- case TraceLoggingDataType.HexInt32:
- case TraceLoggingDataType.HexInt64:
- case TraceLoggingDataType.Char16:
- case TraceLoggingDataType.Char8:
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(type));
- }
-
- if (this.BeginningBufferedArray)
- {
- throw new NotSupportedException(SR.EventSource_NotSupportedNestedArraysEnums);
- }
-
- this.impl.AddScalar(2);
- this.impl.AddNonscalar();
- this.AddField(new FieldMetadata(name, type, this.Tags, true));
- }
-
- public void BeginBufferedArray()
- {
- if (this.bufferedArrayFieldCount >= 0)
- {
- throw new NotSupportedException(SR.EventSource_NotSupportedNestedArraysEnums);
- }
-
- this.bufferedArrayFieldCount = 0;
- this.impl.BeginBuffered();
- }
-
- public void EndBufferedArray()
- {
- if (this.bufferedArrayFieldCount != 1)
- {
- throw new InvalidOperationException(SR.EventSource_IncorrentlyAuthoredTypeInfo);
- }
-
- this.bufferedArrayFieldCount = int.MinValue;
- this.impl.EndBuffered();
- }
-
- /// <summary>
- /// Adds a custom-serialized field to an event.
- /// </summary>
- /// <param name="name">
- /// The name to use for the added field. This value must not be null.
- /// </param>
- /// <param name="type">The encoding type for the field.</param>
- /// <param name="metadata">Additional information needed to decode the field, if any.</param>
- public void AddCustom(string name, TraceLoggingDataType type, byte[] metadata)
- {
- if (this.BeginningBufferedArray)
- {
- throw new NotSupportedException(SR.EventSource_NotSupportedCustomSerializedData);
- }
-
- this.impl.AddScalar(2);
- this.impl.AddNonscalar();
- this.AddField(new FieldMetadata(
- name,
- type,
- this.Tags,
- metadata));
- }
-
- internal byte[] GetMetadata()
- {
- int size = this.impl.Encode(null);
- var metadata = new byte[size];
- this.impl.Encode(metadata);
- return metadata;
- }
-
- private void AddField(FieldMetadata fieldMetadata)
- {
- this.Tags = EventFieldTags.None;
- this.bufferedArrayFieldCount++;
- this.impl.fields.Add(fieldMetadata);
-
- if (this.currentGroup != null)
- {
- this.currentGroup.IncrementStructFieldCount();
- }
- }
-
- private class Impl
- {
- internal readonly List<FieldMetadata> fields = new List<FieldMetadata>();
- internal short scratchSize;
- internal sbyte dataCount;
- internal sbyte pinCount;
- private int bufferNesting;
- private bool scalar;
-
- public void AddScalar(int size)
- {
- if (this.bufferNesting == 0)
- {
- if (!this.scalar)
- {
- this.dataCount = checked((sbyte)(this.dataCount + 1));
- }
-
- this.scalar = true;
- this.scratchSize = checked((short)(this.scratchSize + size));
- }
- }
-
- public void AddNonscalar()
- {
- if (this.bufferNesting == 0)
- {
- this.scalar = false;
- this.pinCount = checked((sbyte)(this.pinCount + 1));
- this.dataCount = checked((sbyte)(this.dataCount + 1));
- }
- }
-
- public void BeginBuffered()
- {
- if (this.bufferNesting == 0)
- {
- this.AddNonscalar();
- }
-
- this.bufferNesting++;
- }
-
- public void EndBuffered()
- {
- this.bufferNesting--;
- }
-
- public int Encode(byte[]? metadata)
- {
- int size = 0;
-
- foreach (FieldMetadata field in this.fields)
- {
- field.Encode(ref size, metadata);
- }
-
- return size;
- }
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs
deleted file mode 100644
index a5de12342d1..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs
+++ /dev/null
@@ -1,179 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-using System.Collections.Generic;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: used when implementing a custom TraceLoggingTypeInfo.
- /// Non-generic base class for TraceLoggingTypeInfo&lt;DataType>. Do not derive
- /// from this class. Instead, derive from TraceLoggingTypeInfo&lt;DataType>.
- /// </summary>
- internal abstract class TraceLoggingTypeInfo
- {
- private readonly string name;
- private readonly EventKeywords keywords;
- private readonly EventLevel level = (EventLevel)(-1);
- private readonly EventOpcode opcode = (EventOpcode)(-1);
- private readonly EventTags tags;
- private readonly Type dataType;
- private readonly Func<object?, PropertyValue> propertyValueFactory;
-
- internal TraceLoggingTypeInfo(Type dataType)
- {
- if (dataType == null)
- {
- throw new ArgumentNullException(nameof(dataType));
- }
-
- this.name = dataType.Name;
- this.dataType = dataType;
- this.propertyValueFactory = PropertyValue.GetFactory(dataType);
- }
-
- internal TraceLoggingTypeInfo(
- Type dataType,
- string name,
- EventLevel level,
- EventOpcode opcode,
- EventKeywords keywords,
- EventTags tags)
- {
- if (dataType == null)
- {
- throw new ArgumentNullException(nameof(dataType));
- }
-
- if (name == null)
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- Statics.CheckName(name);
-
- this.name = name;
- this.keywords = keywords;
- this.level = level;
- this.opcode = opcode;
- this.tags = tags;
- this.dataType = dataType;
- this.propertyValueFactory = PropertyValue.GetFactory(dataType);
- }
-
- /// <summary>
- /// Gets the name to use for the event if this type is the top-level type,
- /// or the name to use for an implicitly-named field.
- /// Never null.
- /// </summary>
- public string Name => this.name;
-
- /// <summary>
- /// Gets the event level associated with this type. Any value in the range 0..255
- /// is an associated event level. Any value outside the range 0..255 is invalid and
- /// indicates that this type has no associated event level.
- /// </summary>
- public EventLevel Level => this.level;
-
- /// <summary>
- /// Gets the event opcode associated with this type. Any value in the range 0..255
- /// is an associated event opcode. Any value outside the range 0..255 is invalid and
- /// indicates that this type has no associated event opcode.
- /// </summary>
- public EventOpcode Opcode => this.opcode;
-
- /// <summary>
- /// Gets the keyword(s) associated with this type.
- /// </summary>
- public EventKeywords Keywords => this.keywords;
-
- /// <summary>
- /// Gets the event tags associated with this type.
- /// </summary>
- public EventTags Tags => this.tags;
-
- internal Type DataType => this.dataType;
-
- internal Func<object?, PropertyValue> PropertyValueFactory => this.propertyValueFactory;
-
- /// <summary>
- /// When overridden by a derived class, writes the metadata (schema) for
- /// this type. Note that the sequence of operations in WriteMetadata should be
- /// essentially identical to the sequence of operations in
- /// WriteData/WriteObjectData. Otherwise, the metadata and data will not match,
- /// which may cause trouble when decoding the event.
- /// </summary>
- /// <param name="collector">
- /// The object that collects metadata for this object's type. Metadata is written
- /// by calling methods on the collector object. Note that if the type contains
- /// sub-objects, the implementation of this method may need to call the
- /// WriteMetadata method for the type of the sub-object, e.g. by calling
- /// TraceLoggingTypeInfo&lt;SubType&gt;.Instance.WriteMetadata(...).
- /// </param>
- /// <param name="name">
- /// The name of the property that contains an object of this type, or null if this
- /// object is being written as a top-level object of an event. Typical usage
- /// is to pass this value to collector.AddGroup.
- /// </param>
- /// <param name="format">
- /// The format attribute for the field that contains an object of this type.
- /// </param>
- public abstract void WriteMetadata(
- TraceLoggingMetadataCollector collector,
- string? name,
- EventFieldFormat format);
-
- /// <summary>
- /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
- /// method.
- /// </summary>
- /// <param name="collector">
- /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
- /// method.
- /// </param>
- /// <param name="value">
- /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
- /// method.
- /// </param>
- public abstract void WriteData(
- TraceLoggingDataCollector collector,
- PropertyValue value);
-
- /// <summary>
- /// Fetches the event parameter data for internal serialization.
- /// </summary>
- /// <param name="value"></param>
- /// <returns></returns>
- public virtual object? GetData(object? value)
- {
- return value;
- }
-
- [ThreadStatic] // per-thread cache to avoid synchronization
- private static Dictionary<Type, TraceLoggingTypeInfo>? threadCache;
-
- public static TraceLoggingTypeInfo GetInstance(Type type, List<Type>? recursionCheck)
- {
- Dictionary<Type, TraceLoggingTypeInfo> cache = threadCache ??= new Dictionary<Type, TraceLoggingTypeInfo>();
-
- TraceLoggingTypeInfo? instance;
- if (!cache.TryGetValue(type, out instance))
- {
- recursionCheck ??= new List<Type>();
- int recursionCheckCount = recursionCheck.Count;
- instance = Statics.CreateDefaultTypeInfo(type, recursionCheck);
- cache[type] = instance;
- recursionCheck.RemoveRange(recursionCheckCount, recursionCheck.Count - recursionCheckCount);
- }
- return instance;
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs
deleted file mode 100644
index 571298623bd..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if ES_BUILD_STANDALONE
-using System;
-#endif
-using System.Collections.Generic;
-using System.Reflection;
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// TraceLogging: stores the per-type information obtained by reflecting over a type.
- /// </summary>
- internal sealed class TypeAnalysis
- {
- internal readonly PropertyAnalysis[] properties;
- internal readonly string? name;
- internal readonly EventKeywords keywords;
- internal readonly EventLevel level = (EventLevel)(-1);
- internal readonly EventOpcode opcode = (EventOpcode)(-1);
- internal readonly EventTags tags;
-
- public TypeAnalysis(
- Type dataType,
- EventDataAttribute? eventAttrib,
- List<Type> recursionCheck)
- {
- IEnumerable<PropertyInfo> propertyInfos = Statics.GetProperties(dataType);
- var propertyList = new List<PropertyAnalysis>();
-
- foreach (PropertyInfo propertyInfo in propertyInfos)
- {
- if (Statics.HasCustomAttribute(propertyInfo, typeof(EventIgnoreAttribute)))
- {
- continue;
- }
-
- if (!propertyInfo.CanRead ||
- propertyInfo.GetIndexParameters().Length != 0)
- {
- continue;
- }
-
- MethodInfo? getterInfo = Statics.GetGetMethod(propertyInfo);
- if (getterInfo == null)
- {
- continue;
- }
-
- if (getterInfo.IsStatic || !getterInfo.IsPublic)
- {
- continue;
- }
-
- Type propertyType = propertyInfo.PropertyType;
- var propertyTypeInfo = TraceLoggingTypeInfo.GetInstance(propertyType, recursionCheck);
- EventFieldAttribute? fieldAttribute = Statics.GetCustomAttribute<EventFieldAttribute>(propertyInfo);
-
- string propertyName =
- fieldAttribute != null && fieldAttribute.Name != null
- ? fieldAttribute.Name
- : Statics.ShouldOverrideFieldName(propertyInfo.Name)
- ? propertyTypeInfo.Name
- : propertyInfo.Name;
- propertyList.Add(new PropertyAnalysis(
- propertyName,
- propertyInfo,
- propertyTypeInfo,
- fieldAttribute));
- }
-
- this.properties = propertyList.ToArray();
-
- foreach (PropertyAnalysis property in this.properties)
- {
- TraceLoggingTypeInfo typeInfo = property.typeInfo;
- this.level = (EventLevel)Statics.Combine((int)typeInfo.Level, (int)this.level);
- this.opcode = (EventOpcode)Statics.Combine((int)typeInfo.Opcode, (int)this.opcode);
- this.keywords |= typeInfo.Keywords;
- this.tags |= typeInfo.Tags;
- }
-
- if (eventAttrib != null)
- {
- this.level = (EventLevel)Statics.Combine((int)eventAttrib.Level, (int)this.level);
- this.opcode = (EventOpcode)Statics.Combine((int)eventAttrib.Opcode, (int)this.opcode);
- this.keywords |= eventAttrib.Keywords;
- this.tags |= eventAttrib.Tags;
- this.name = eventAttrib.Name;
- }
-
- if (this.name == null)
- {
- this.name = dataType.Name;
- }
- }
- }
-}
diff --git a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/Winmeta.cs b/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/Winmeta.cs
deleted file mode 100644
index 03d86f8efab..00000000000
--- a/netcore/System.Private.CoreLib/shared/System/Diagnostics/Tracing/Winmeta.cs
+++ /dev/null
@@ -1,185 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*============================================================
-**
-**
-** Purpose:
-** Contains eventing constants defined by the Windows
-** environment.
-**
-============================================================*/
-
-#if ES_BUILD_STANDALONE
-#define FEATURE_MANAGED_ETW_CHANNELS
-using System;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// WindowsEventLevel. Custom values must be in the range from 16 through 255
- /// </summary>
- public enum EventLevel
- {
- /// <summary>
- /// Log always
- /// </summary>
- LogAlways = 0,
- /// <summary>
- /// Only critical errors
- /// </summary>
- Critical,
- /// <summary>
- /// All errors, including previous levels
- /// </summary>
- Error,
- /// <summary>
- /// All warnings, including previous levels
- /// </summary>
- Warning,
- /// <summary>
- /// All informational events, including previous levels
- /// </summary>
- Informational,
- /// <summary>
- /// All events, including previous levels
- /// </summary>
- Verbose
- }
- /// <summary>
- /// WindowsEventTask. Custom values must be in the range from 1 through 65534
- /// </summary>
- public enum EventTask
- {
- /// <summary>
- /// Undefined task
- /// </summary>
- None = 0
- }
- /// <summary>
- /// EventOpcode. Custom values must be in the range from 11 through 239
- /// </summary>
- public enum EventOpcode
- {
- /// <summary>
- /// An informational event
- /// </summary>
- Info = 0,
- /// <summary>
- /// An activity start event
- /// </summary>
- Start,
- /// <summary>
- /// An activity end event
- /// </summary>
- Stop,
- /// <summary>
- /// A trace collection start event
- /// </summary>
- DataCollectionStart,
- /// <summary>
- /// A trace collection end event
- /// </summary>
- DataCollectionStop,
- /// <summary>
- /// An extensional event
- /// </summary>
- Extension,
- /// <summary>
- /// A reply event
- /// </summary>
- Reply,
- /// <summary>
- /// An event representing the activity resuming from the suspension
- /// </summary>
- Resume,
- /// <summary>
- /// An event representing the activity is suspended, pending another activity's completion
- /// </summary>
- Suspend,
- /// <summary>
- /// An event representing the activity is transferred to another component, and can continue to work
- /// </summary>
- Send,
- /// <summary>
- /// An event representing receiving an activity transfer from another component
- /// </summary>
- Receive = 240
- }
-
- // Added for CLR V4
- /// <summary>
- /// EventChannel. Custom values must be in the range from 16 through 255. Currently only predefined values allowed.
- /// </summary>
- public enum EventChannel : byte
- {
- /// <summary>
- /// No channel
- /// </summary>
- None = 0,
- // Channels 1 - 15 are reserved...
- /// <summary>The admin channel</summary>
- Admin = 16,
- /// <summary>The operational channel</summary>
- Operational = 17,
- /// <summary>The analytic channel</summary>
- Analytic = 18,
- /// <summary>The debug channel</summary>
- Debug = 19,
- }
-
- /// <summary>
- /// EventOpcode
- /// </summary>
- [Flags]
- public enum EventKeywords : long
- {
- /// <summary>
- /// No events.
- /// </summary>
- None = 0x0,
- /// <summary>
- /// All Events
- /// </summary>
- All = ~0,
- /// <summary>
- /// Telemetry events
- /// </summary>
- MicrosoftTelemetry = 0x02000000000000,
- /// <summary>
- /// WDI context events
- /// </summary>
- WdiContext = 0x02000000000000,
- /// <summary>
- /// WDI diagnostic events
- /// </summary>
- WdiDiagnostic = 0x04000000000000,
- /// <summary>
- /// SQM events
- /// </summary>
- Sqm = 0x08000000000000,
- /// <summary>
- /// Failed security audits
- /// </summary>
- AuditFailure = 0x10000000000000,
- /// <summary>
- /// Successful security audits
- /// </summary>
- AuditSuccess = 0x20000000000000,
- /// <summary>
- /// Transfer events where the related Activity ID is a computed value and not a GUID
- /// N.B. The correct value for this field is 0x40000000000000.
- /// </summary>
- CorrelationHint = 0x10000000000000,
- /// <summary>
- /// Events raised using classic eventlog API
- /// </summary>
- EventLogClassic = 0x80000000000000
- }
-}