More Corelib cleanup (dotnet/coreclr#26872)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Diagnostics / Tracing / TraceLogging / TraceLoggingEventSource.cs
blob9cc14967c060078ea4c90f00a7aadb26d282d2f7
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
6 // It is available from http://www.codeplex.com/hyperAddin
8 #if PLATFORM_WINDOWS
9 #define FEATURE_MANAGED_ETW
10 #endif // PLATFORM_WINDOWS
12 #if ES_BUILD_STANDALONE
13 #define FEATURE_MANAGED_ETW_CHANNELS
14 // #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
15 #endif
17 #if ES_BUILD_STANDALONE
18 using System;
19 using System.Diagnostics;
20 using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
21 using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
22 #endif
23 using System.Collections.Generic;
24 using System.Collections.ObjectModel;
25 using System.Runtime.InteropServices;
26 using System.Text;
28 #if ES_BUILD_STANDALONE
29 namespace Microsoft.Diagnostics.Tracing
30 #else
31 namespace System.Diagnostics.Tracing
32 #endif
34 public partial class EventSource
36 #if FEATURE_MANAGED_ETW
37 private byte[] providerMetadata = null!;
38 #endif
40 #if FEATURE_PERFTRACING
41 private readonly TraceLoggingEventHandleTable m_eventHandleTable = new TraceLoggingEventHandleTable();
42 #endif
44 /// <summary>
45 /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
46 /// </summary>
47 /// <param name="eventSourceName">
48 /// The name of the event source. Must not be null.
49 /// </param>
50 public EventSource(
51 string eventSourceName)
52 : this(eventSourceName, EventSourceSettings.EtwSelfDescribingEventFormat)
53 { }
55 /// <summary>
56 /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
57 /// </summary>
58 /// <param name="eventSourceName">
59 /// The name of the event source. Must not be null.
60 /// </param>
61 /// <param name="config">
62 /// Configuration options for the EventSource as a whole.
63 /// </param>
64 public EventSource(
65 string eventSourceName,
66 EventSourceSettings config)
67 : this(eventSourceName, config, null) { }
69 /// <summary>
70 /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
71 ///
72 /// Also specify a list of key-value pairs called traits (you must pass an even number of strings).
73 /// The first string is the key and the second is the value. These are not interpreted by EventSource
74 /// itself but may be interpreted the listeners. Can be fetched with GetTrait(string).
75 /// </summary>
76 /// <param name="eventSourceName">
77 /// The name of the event source. Must not be null.
78 /// </param>
79 /// <param name="config">
80 /// Configuration options for the EventSource as a whole.
81 /// </param>
82 /// <param name="traits">A collection of key-value strings (must be an even number).</param>
83 public EventSource(
84 string eventSourceName,
85 EventSourceSettings config,
86 params string[]? traits)
87 : this(
88 eventSourceName == null ? new Guid() : GenerateGuidFromName(eventSourceName.ToUpperInvariant()),
89 eventSourceName!,
90 config, traits)
92 if (eventSourceName == null)
94 throw new ArgumentNullException(nameof(eventSourceName));
98 /// <summary>
99 /// Writes an event with no fields and default options.
100 /// (Native API: EventWriteTransfer)
101 /// </summary>
102 /// <param name="eventName">The name of the event.</param>
103 public unsafe void Write(string? eventName)
105 if (!this.IsEnabled())
107 return;
110 var options = new EventSourceOptions();
111 this.WriteImpl(eventName, ref options, null, null, null, SimpleEventTypes<EmptyStruct>.Instance);
114 /// <summary>
115 /// Writes an event with no fields.
116 /// (Native API: EventWriteTransfer)
117 /// </summary>
118 /// <param name="eventName">The name of the event.</param>
119 /// <param name="options">
120 /// Options for the event, such as the level, keywords, and opcode. Unset
121 /// options will be set to default values.
122 /// </param>
123 public unsafe void Write(string? eventName, EventSourceOptions options)
125 if (!this.IsEnabled())
127 return;
130 this.WriteImpl(eventName, ref options, null, null, null, SimpleEventTypes<EmptyStruct>.Instance);
133 /// <summary>
134 /// Writes an event.
135 /// (Native API: EventWriteTransfer)
136 /// </summary>
137 /// <typeparam name="T">
138 /// The type that defines the event and its payload. This must be an
139 /// anonymous type or a type with an [EventData] attribute.
140 /// </typeparam>
141 /// <param name="eventName">
142 /// The name for the event. If null, the event name is automatically
143 /// determined based on T, either from the Name property of T's EventData
144 /// attribute or from typeof(T).Name.
145 /// </param>
146 /// <param name="data">
147 /// The object containing the event payload data. The type T must be
148 /// an anonymous type or a type with an [EventData] attribute. The
149 /// public instance properties of data will be written recursively to
150 /// create the fields of the event.
151 /// </param>
152 public unsafe void Write<T>(
153 string? eventName,
154 T data)
156 if (!this.IsEnabled())
158 return;
161 var options = new EventSourceOptions();
162 this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
165 /// <summary>
166 /// Writes an event.
167 /// (Native API: EventWriteTransfer)
168 /// </summary>
169 /// <typeparam name="T">
170 /// The type that defines the event and its payload. This must be an
171 /// anonymous type or a type with an [EventData] attribute.
172 /// </typeparam>
173 /// <param name="eventName">
174 /// The name for the event. If null, the event name is automatically
175 /// determined based on T, either from the Name property of T's EventData
176 /// attribute or from typeof(T).Name.
177 /// </param>
178 /// <param name="options">
179 /// Options for the event, such as the level, keywords, and opcode. Unset
180 /// options will be set to default values.
181 /// </param>
182 /// <param name="data">
183 /// The object containing the event payload data. The type T must be
184 /// an anonymous type or a type with an [EventData] attribute. The
185 /// public instance properties of data will be written recursively to
186 /// create the fields of the event.
187 /// </param>
188 public unsafe void Write<T>(
189 string? eventName,
190 EventSourceOptions options,
191 T data)
193 if (!this.IsEnabled())
195 return;
198 this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
201 /// <summary>
202 /// Writes an event.
203 /// This overload is for use with extension methods that wish to efficiently
204 /// forward the options or data parameter without performing an extra copy.
205 /// (Native API: EventWriteTransfer)
206 /// </summary>
207 /// <typeparam name="T">
208 /// The type that defines the event and its payload. This must be an
209 /// anonymous type or a type with an [EventData] attribute.
210 /// </typeparam>
211 /// <param name="eventName">
212 /// The name for the event. If null, the event name is automatically
213 /// determined based on T, either from the Name property of T's EventData
214 /// attribute or from typeof(T).Name.
215 /// </param>
216 /// <param name="options">
217 /// Options for the event, such as the level, keywords, and opcode. Unset
218 /// options will be set to default values.
219 /// </param>
220 /// <param name="data">
221 /// The object containing the event payload data. The type T must be
222 /// an anonymous type or a type with an [EventData] attribute. The
223 /// public instance properties of data will be written recursively to
224 /// create the fields of the event.
225 /// </param>
226 public unsafe void Write<T>(
227 string? eventName,
228 ref EventSourceOptions options,
229 ref T data)
231 if (!this.IsEnabled())
233 return;
236 this.WriteImpl(eventName, ref options, data, null, null, SimpleEventTypes<T>.Instance);
239 /// <summary>
240 /// Writes an event.
241 /// This overload is meant for clients that need to manipuate the activityId
242 /// and related ActivityId for the event.
243 /// </summary>
244 /// <typeparam name="T">
245 /// The type that defines the event and its payload. This must be an
246 /// anonymous type or a type with an [EventData] attribute.
247 /// </typeparam>
248 /// <param name="eventName">
249 /// The name for the event. If null, the event name is automatically
250 /// determined based on T, either from the Name property of T's EventData
251 /// attribute or from typeof(T).Name.
252 /// </param>
253 /// <param name="options">
254 /// Options for the event, such as the level, keywords, and opcode. Unset
255 /// options will be set to default values.
256 /// </param>
257 /// <param name="activityId">
258 /// The GUID of the activity associated with this event.
259 /// </param>
260 /// <param name="relatedActivityId">
261 /// The GUID of another activity that is related to this activity, or Guid.Empty
262 /// if there is no related activity. Most commonly, the Start operation of a
263 /// new activity specifies a parent activity as its related activity.
264 /// </param>
265 /// <param name="data">
266 /// The object containing the event payload data. The type T must be
267 /// an anonymous type or a type with an [EventData] attribute. The
268 /// public instance properties of data will be written recursively to
269 /// create the fields of the event.
270 /// </param>
271 public unsafe void Write<T>(
272 string? eventName,
273 ref EventSourceOptions options,
274 ref Guid activityId,
275 ref Guid relatedActivityId,
276 ref T data)
278 if (!this.IsEnabled())
280 return;
283 fixed (Guid* pActivity = &activityId, pRelated = &relatedActivityId)
285 this.WriteImpl(
286 eventName,
287 ref options,
288 data,
289 pActivity,
290 relatedActivityId == Guid.Empty ? null : pRelated,
291 SimpleEventTypes<T>.Instance);
295 /// <summary>
296 /// Writes an extended event, where the values of the event are the
297 /// combined properties of any number of values. This method is
298 /// intended for use in advanced logging scenarios that support a
299 /// dynamic set of event context providers.
300 /// This method does a quick check on whether this event is enabled.
301 /// </summary>
302 /// <param name="eventName">
303 /// The name for the event. If null, the name from eventTypes is used.
304 /// (Note that providing the event name via the name parameter is slightly
305 /// less efficient than using the name from eventTypes.)
306 /// </param>
307 /// <param name="options">
308 /// Optional overrides for the event, such as the level, keyword, opcode,
309 /// activityId, and relatedActivityId. Any settings not specified by options
310 /// are obtained from eventTypes.
311 /// </param>
312 /// <param name="eventTypes">
313 /// Information about the event and the types of the values in the event.
314 /// Must not be null. Note that the eventTypes object should be created once and
315 /// saved. It should not be recreated for each event.
316 /// </param>
317 /// <param name="activityID">
318 /// A pointer to the activity ID GUID to log
319 /// </param>
320 /// <param name="childActivityID">
321 /// A pointer to the child activity ID to log (can be null) </param>
322 /// <param name="values">
323 /// The values to include in the event. Must not be null. The number and types of
324 /// the values must match the number and types of the fields described by the
325 /// eventTypes parameter.
326 /// </param>
327 private unsafe void WriteMultiMerge(
328 string? eventName,
329 ref EventSourceOptions options,
330 TraceLoggingEventTypes eventTypes,
331 Guid* activityID,
332 Guid* childActivityID,
333 params object?[] values)
335 if (!this.IsEnabled())
337 return;
339 byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
340 ? options.level
341 : eventTypes.level;
342 EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
343 ? options.keywords
344 : eventTypes.keywords;
346 if (this.IsEnabled((EventLevel)level, keywords))
348 WriteMultiMergeInner(eventName, ref options, eventTypes, activityID, childActivityID, values);
352 /// <summary>
353 /// Writes an extended event, where the values of the event are the
354 /// combined properties of any number of values. This method is
355 /// intended for use in advanced logging scenarios that support a
356 /// dynamic set of event context providers.
357 /// Attention: This API does not check whether the event is enabled or not.
358 /// Please use WriteMultiMerge to avoid spending CPU cycles for events that are
359 /// not enabled.
360 /// </summary>
361 /// <param name="eventName">
362 /// The name for the event. If null, the name from eventTypes is used.
363 /// (Note that providing the event name via the name parameter is slightly
364 /// less efficient than using the name from eventTypes.)
365 /// </param>
366 /// <param name="options">
367 /// Optional overrides for the event, such as the level, keyword, opcode,
368 /// activityId, and relatedActivityId. Any settings not specified by options
369 /// are obtained from eventTypes.
370 /// </param>
371 /// <param name="eventTypes">
372 /// Information about the event and the types of the values in the event.
373 /// Must not be null. Note that the eventTypes object should be created once and
374 /// saved. It should not be recreated for each event.
375 /// </param>
376 /// <param name="activityID">
377 /// A pointer to the activity ID GUID to log
378 /// </param>
379 /// <param name="childActivityID">
380 /// A pointer to the child activity ID to log (can be null)
381 /// </param>
382 /// <param name="values">
383 /// The values to include in the event. Must not be null. The number and types of
384 /// the values must match the number and types of the fields described by the
385 /// eventTypes parameter.
386 /// </param>
387 private unsafe void WriteMultiMergeInner(
388 string? eventName,
389 ref EventSourceOptions options,
390 TraceLoggingEventTypes eventTypes,
391 Guid* activityID,
392 Guid* childActivityID,
393 params object?[] values)
395 #if FEATURE_MANAGED_ETW
396 int identity = 0;
397 byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
398 ? options.level
399 : eventTypes.level;
400 byte opcode = (options.valuesSet & EventSourceOptions.opcodeSet) != 0
401 ? options.opcode
402 : eventTypes.opcode;
403 EventTags tags = (options.valuesSet & EventSourceOptions.tagsSet) != 0
404 ? options.tags
405 : eventTypes.Tags;
406 EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
407 ? options.keywords
408 : eventTypes.keywords;
410 NameInfo nameInfo = eventTypes.GetNameInfo(eventName ?? eventTypes.Name, tags);
411 if (nameInfo == null)
413 return;
415 identity = nameInfo.identity;
416 EventDescriptor descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
418 #if FEATURE_PERFTRACING
419 IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_eventPipeProvider, m_eventHandleTable, descriptor, eventTypes);
420 Debug.Assert(eventHandle != IntPtr.Zero);
421 #else
422 IntPtr eventHandle = IntPtr.Zero;
423 #endif
425 int pinCount = eventTypes.pinCount;
426 byte* scratch = stackalloc byte[eventTypes.scratchSize];
427 EventData* descriptors = stackalloc EventData[eventTypes.dataCount + 3];
428 for (int i = 0; i < eventTypes.dataCount + 3; i++)
429 descriptors[i] = default;
431 GCHandle* pins = stackalloc GCHandle[pinCount];
432 for (int i = 0; i < pinCount; i++)
433 pins[i] = default;
435 fixed (byte*
436 pMetadata0 = this.providerMetadata,
437 pMetadata1 = nameInfo.nameMetadata,
438 pMetadata2 = eventTypes.typeMetadata)
440 descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
441 descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
442 descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
444 #if (!ES_BUILD_PCL && !ES_BUILD_PN)
445 System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
446 #endif
449 DataCollector.ThreadInstance.Enable(
450 scratch,
451 eventTypes.scratchSize,
452 descriptors + 3,
453 eventTypes.dataCount,
454 pins,
455 pinCount);
457 for (int i = 0; i < eventTypes.typeInfos.Length; i++)
459 TraceLoggingTypeInfo info = eventTypes.typeInfos[i];
460 info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(values[i]));
463 this.WriteEventRaw(
464 eventName,
465 ref descriptor,
466 eventHandle,
467 activityID,
468 childActivityID,
469 (int)(DataCollector.ThreadInstance.Finish() - descriptors),
470 (IntPtr)descriptors);
472 finally
474 WriteCleanup(pins, pinCount);
477 #endif // FEATURE_MANAGED_ETW
480 /// <summary>
481 /// Writes an extended event, where the values of the event have already
482 /// been serialized in "data".
483 /// </summary>
484 /// <param name="eventName">
485 /// The name for the event. If null, the name from eventTypes is used.
486 /// (Note that providing the event name via the name parameter is slightly
487 /// less efficient than using the name from eventTypes.)
488 /// </param>
489 /// <param name="options">
490 /// Optional overrides for the event, such as the level, keyword, opcode,
491 /// activityId, and relatedActivityId. Any settings not specified by options
492 /// are obtained from eventTypes.
493 /// </param>
494 /// <param name="eventTypes">
495 /// Information about the event and the types of the values in the event.
496 /// Must not be null. Note that the eventTypes object should be created once and
497 /// saved. It should not be recreated for each event.
498 /// </param>
499 /// <param name="activityID">
500 /// A pointer to the activity ID GUID to log
501 /// </param>
502 /// <param name="childActivityID">
503 /// A pointer to the child activity ID to log (can be null)
504 /// </param>
505 /// <param name="data">
506 /// The previously serialized values to include in the event. Must not be null.
507 /// The number and types of the values must match the number and types of the
508 /// fields described by the eventTypes parameter.
509 /// </param>
510 internal unsafe void WriteMultiMerge(
511 string? eventName,
512 ref EventSourceOptions options,
513 TraceLoggingEventTypes eventTypes,
514 Guid* activityID,
515 Guid* childActivityID,
516 EventData* data)
518 #if FEATURE_MANAGED_ETW
519 if (!this.IsEnabled())
521 return;
524 fixed (EventSourceOptions* pOptions = &options)
526 EventDescriptor descriptor;
527 NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
528 if (nameInfo == null)
530 return;
533 #if FEATURE_PERFTRACING
534 IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_eventPipeProvider, m_eventHandleTable, descriptor, eventTypes);
535 Debug.Assert(eventHandle != IntPtr.Zero);
536 #else
537 IntPtr eventHandle = IntPtr.Zero;
538 #endif
540 // We make a descriptor for each EventData, and because we morph strings to counted strings
541 // we may have 2 for each arg, so we allocate enough for this.
542 int descriptorsLength = eventTypes.dataCount + eventTypes.typeInfos.Length * 2 + 3;
543 EventData* descriptors = stackalloc EventData[descriptorsLength];
544 for (int i = 0; i < descriptorsLength; i++)
545 descriptors[i] = default;
547 fixed (byte*
548 pMetadata0 = this.providerMetadata,
549 pMetadata1 = nameInfo.nameMetadata,
550 pMetadata2 = eventTypes.typeMetadata)
552 descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
553 descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
554 descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
555 int numDescrs = 3;
557 for (int i = 0; i < eventTypes.typeInfos.Length; i++)
559 descriptors[numDescrs].m_Ptr = data[i].m_Ptr;
560 descriptors[numDescrs].m_Size = data[i].m_Size;
562 // old conventions for bool is 4 bytes, but meta-data assumes 1.
563 if (data[i].m_Size == 4 && eventTypes.typeInfos[i].DataType == typeof(bool))
564 descriptors[numDescrs].m_Size = 1;
566 numDescrs++;
569 this.WriteEventRaw(
570 eventName,
571 ref descriptor,
572 eventHandle,
573 activityID,
574 childActivityID,
575 numDescrs,
576 (IntPtr)descriptors);
579 #endif // FEATURE_MANAGED_ETW
582 private unsafe void WriteImpl(
583 string? eventName,
584 ref EventSourceOptions options,
585 object? data,
586 Guid* pActivityId,
587 Guid* pRelatedActivityId,
588 TraceLoggingEventTypes eventTypes)
592 fixed (EventSourceOptions* pOptions = &options)
594 EventDescriptor descriptor;
595 options.Opcode = options.IsOpcodeSet ? options.Opcode : GetOpcodeWithDefault(options.Opcode, eventName);
596 NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
597 if (nameInfo == null)
599 return;
602 #if FEATURE_PERFTRACING
603 IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_eventPipeProvider, m_eventHandleTable, descriptor, eventTypes);
604 Debug.Assert(eventHandle != IntPtr.Zero);
605 #else
606 IntPtr eventHandle = IntPtr.Zero;
607 #endif
609 #if FEATURE_MANAGED_ETW
610 int pinCount = eventTypes.pinCount;
611 byte* scratch = stackalloc byte[eventTypes.scratchSize];
612 EventData* descriptors = stackalloc EventData[eventTypes.dataCount + 3];
613 for (int i = 0; i < eventTypes.dataCount + 3; i++)
614 descriptors[i] = default;
616 GCHandle* pins = stackalloc GCHandle[pinCount];
617 for (int i = 0; i < pinCount; i++)
618 pins[i] = default;
620 fixed (byte*
621 pMetadata0 = this.providerMetadata,
622 pMetadata1 = nameInfo.nameMetadata,
623 pMetadata2 = eventTypes.typeMetadata)
625 descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
626 descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
627 descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
628 #endif // FEATURE_MANAGED_ETW
630 #if (!ES_BUILD_PCL && !ES_BUILD_PN)
631 System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
632 #endif
633 EventOpcode opcode = (EventOpcode)descriptor.Opcode;
635 Guid activityId = Guid.Empty;
636 Guid relatedActivityId = Guid.Empty;
637 if (pActivityId == null && pRelatedActivityId == null &&
638 ((options.ActivityOptions & EventActivityOptions.Disable) == 0))
640 if (opcode == EventOpcode.Start)
642 Debug.Assert(eventName != null, "GetOpcodeWithDefault should not returned Start when eventName is null");
643 m_activityTracker.OnStart(m_name, eventName, 0, ref activityId, ref relatedActivityId, options.ActivityOptions);
645 else if (opcode == EventOpcode.Stop)
647 Debug.Assert(eventName != null, "GetOpcodeWithDefault should not returned Stop when eventName is null");
648 m_activityTracker.OnStop(m_name, eventName, 0, ref activityId);
650 if (activityId != Guid.Empty)
651 pActivityId = &activityId;
652 if (relatedActivityId != Guid.Empty)
653 pRelatedActivityId = &relatedActivityId;
658 #if FEATURE_MANAGED_ETW
659 DataCollector.ThreadInstance.Enable(
660 scratch,
661 eventTypes.scratchSize,
662 descriptors + 3,
663 eventTypes.dataCount,
664 pins,
665 pinCount);
667 TraceLoggingTypeInfo info = eventTypes.typeInfos[0];
668 info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(data));
670 this.WriteEventRaw(
671 eventName,
672 ref descriptor,
673 eventHandle,
674 pActivityId,
675 pRelatedActivityId,
676 (int)(DataCollector.ThreadInstance.Finish() - descriptors),
677 (IntPtr)descriptors);
678 #endif // FEATURE_MANAGED_ETW
680 // TODO enable filtering for listeners.
681 if (m_Dispatchers != null)
683 var eventData = (EventPayload?)(eventTypes.typeInfos[0].GetData(data));
684 WriteToAllListeners(eventName, ref descriptor, nameInfo.tags, pActivityId, pRelatedActivityId, eventData);
687 catch (Exception ex)
689 if (ex is EventSourceException)
690 throw;
691 else
692 ThrowEventSourceException(eventName, ex);
694 #if FEATURE_MANAGED_ETW
695 finally
697 WriteCleanup(pins, pinCount);
700 #endif // FEATURE_MANAGED_ETW
703 catch (Exception ex)
705 if (ex is EventSourceException)
706 throw;
707 else
708 ThrowEventSourceException(eventName, ex);
712 private unsafe void WriteToAllListeners(string? eventName, ref EventDescriptor eventDescriptor, EventTags tags, Guid* pActivityId, Guid* pChildActivityId, EventPayload? payload)
714 EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
715 eventCallbackArgs.EventName = eventName;
716 eventCallbackArgs.m_level = (EventLevel)eventDescriptor.Level;
717 eventCallbackArgs.m_keywords = (EventKeywords)eventDescriptor.Keywords;
718 eventCallbackArgs.m_opcode = (EventOpcode)eventDescriptor.Opcode;
719 eventCallbackArgs.m_tags = tags;
721 // Self described events do not have an id attached. We mark it internally with -1.
722 eventCallbackArgs.EventId = -1;
723 if (pActivityId != null)
724 eventCallbackArgs.ActivityId = *pActivityId;
725 if (pChildActivityId != null)
726 eventCallbackArgs.RelatedActivityId = *pChildActivityId;
728 if (payload != null)
730 eventCallbackArgs.Payload = new ReadOnlyCollection<object?>((IList<object?>)payload.Values);
731 eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>((IList<string>)payload.Keys);
734 DispatchToAllListeners(-1, eventCallbackArgs);
737 #if (!ES_BUILD_PCL && !ES_BUILD_PN)
738 [System.Runtime.ConstrainedExecution.ReliabilityContract(
739 System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState,
740 System.Runtime.ConstrainedExecution.Cer.Success)]
741 #endif
742 [NonEvent]
743 private static unsafe void WriteCleanup(GCHandle* pPins, int cPins)
745 DataCollector.ThreadInstance.Disable();
747 for (int i = 0; i < cPins; i++)
749 if (pPins[i].IsAllocated)
751 pPins[i].Free();
756 private void InitializeProviderMetadata()
758 #if FEATURE_MANAGED_ETW
759 if (m_traits != null)
761 List<byte> traitMetaData = new List<byte>(100);
762 for (int i = 0; i < m_traits.Length - 1; i += 2)
764 if (m_traits[i].StartsWith("ETW_", StringComparison.Ordinal))
766 string etwTrait = m_traits[i].Substring(4);
767 byte traitNum;
768 if (!byte.TryParse(etwTrait, out traitNum))
770 if (etwTrait == "GROUP")
772 traitNum = 1;
774 else
776 throw new ArgumentException(SR.Format(SR.EventSource_UnknownEtwTrait, etwTrait), "traits");
779 string value = m_traits[i + 1];
780 int lenPos = traitMetaData.Count;
781 traitMetaData.Add(0); // Emit size (to be filled in later)
782 traitMetaData.Add(0);
783 traitMetaData.Add(traitNum); // Emit Trait number
784 int valueLen = AddValueToMetaData(traitMetaData, value) + 3; // Emit the value bytes +3 accounts for 3 bytes we emited above.
785 traitMetaData[lenPos] = unchecked((byte)valueLen); // Fill in size
786 traitMetaData[lenPos + 1] = unchecked((byte)(valueLen >> 8));
789 providerMetadata = Statics.MetadataForString(this.Name, 0, traitMetaData.Count, 0);
790 int startPos = providerMetadata.Length - traitMetaData.Count;
791 foreach (byte b in traitMetaData)
792 providerMetadata[startPos++] = b;
794 else
795 providerMetadata = Statics.MetadataForString(this.Name, 0, 0, 0);
796 #endif //FEATURE_MANAGED_ETW
799 private static int AddValueToMetaData(List<byte> metaData, string value)
801 if (value.Length == 0)
802 return 0;
804 int startPos = metaData.Count;
805 char firstChar = value[0];
807 if (firstChar == '@')
808 metaData.AddRange(Encoding.UTF8.GetBytes(value.Substring(1)));
809 else if (firstChar == '{')
810 metaData.AddRange(new Guid(value).ToByteArray());
811 else if (firstChar == '#')
813 for (int i = 1; i < value.Length; i++)
815 if (value[i] != ' ') // Skip spaces between bytes.
817 if (!(i + 1 < value.Length))
819 throw new ArgumentException(SR.EventSource_EvenHexDigits, "traits");
821 metaData.Add((byte)(HexDigit(value[i]) * 16 + HexDigit(value[i + 1])));
822 i++;
826 else if ('A' <= firstChar || ' ' == firstChar) // Is it alphabetic or space (excludes digits and most punctuation).
828 metaData.AddRange(Encoding.UTF8.GetBytes(value));
830 else
832 throw new ArgumentException(SR.Format(SR.EventSource_IllegalValue, value), "traits");
835 return metaData.Count - startPos;
838 /// <summary>
839 /// Returns a value 0-15 if 'c' is a hexadecimal digit. If it throws an argument exception.
840 /// </summary>
841 private static int HexDigit(char c)
843 if ('0' <= c && c <= '9')
845 return c - '0';
847 if ('a' <= c)
849 c = unchecked((char)(c - ('a' - 'A'))); // Convert to lower case
851 if ('A' <= c && c <= 'F')
853 return c - 'A' + 10;
856 throw new ArgumentException(SR.Format(SR.EventSource_BadHexDigit, c), "traits");
859 private NameInfo? UpdateDescriptor(
860 string? name,
861 TraceLoggingEventTypes eventInfo,
862 ref EventSourceOptions options,
863 out EventDescriptor descriptor)
865 NameInfo? nameInfo = null;
866 int identity = 0;
867 byte level = (options.valuesSet & EventSourceOptions.levelSet) != 0
868 ? options.level
869 : eventInfo.level;
870 byte opcode = (options.valuesSet & EventSourceOptions.opcodeSet) != 0
871 ? options.opcode
872 : eventInfo.opcode;
873 EventTags tags = (options.valuesSet & EventSourceOptions.tagsSet) != 0
874 ? options.tags
875 : eventInfo.Tags;
876 EventKeywords keywords = (options.valuesSet & EventSourceOptions.keywordsSet) != 0
877 ? options.keywords
878 : eventInfo.keywords;
880 if (this.IsEnabled((EventLevel)level, keywords))
882 nameInfo = eventInfo.GetNameInfo(name ?? eventInfo.Name, tags);
883 identity = nameInfo.identity;
886 descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
887 return nameInfo;