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
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
17 #if ES_BUILD_STANDALONE
19 using System
.Diagnostics
;
20 using Environment
= Microsoft
.Diagnostics
.Tracing
.Internal
.Environment
;
21 using EventDescriptor
= Microsoft
.Diagnostics
.Tracing
.EventDescriptor
;
23 using System
.Collections
.Generic
;
24 using System
.Collections
.ObjectModel
;
25 using System
.Runtime
.InteropServices
;
28 #if ES_BUILD_STANDALONE
29 namespace Microsoft
.Diagnostics
.Tracing
31 namespace System
.Diagnostics
.Tracing
34 public partial class EventSource
36 #if FEATURE_MANAGED_ETW
37 private byte[] providerMetadata
= null!;
40 #if FEATURE_PERFTRACING
41 private readonly TraceLoggingEventHandleTable m_eventHandleTable
= new TraceLoggingEventHandleTable();
45 /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
47 /// <param name="eventSourceName">
48 /// The name of the event source. Must not be null.
51 string eventSourceName
)
52 : this(eventSourceName
, EventSourceSettings
.EtwSelfDescribingEventFormat
)
56 /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
58 /// <param name="eventSourceName">
59 /// The name of the event source. Must not be null.
61 /// <param name="config">
62 /// Configuration options for the EventSource as a whole.
65 string eventSourceName
,
66 EventSourceSettings config
)
67 : this(eventSourceName
, config
, null) { }
70 /// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
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).
76 /// <param name="eventSourceName">
77 /// The name of the event source. Must not be null.
79 /// <param name="config">
80 /// Configuration options for the EventSource as a whole.
82 /// <param name="traits">A collection of key-value strings (must be an even number).</param>
84 string eventSourceName
,
85 EventSourceSettings config
,
86 params string[]? traits
)
88 eventSourceName
== null ? new Guid() : GenerateGuidFromName(eventSourceName
.ToUpperInvariant()),
92 if (eventSourceName
== null)
94 throw new ArgumentNullException(nameof(eventSourceName
));
99 /// Writes an event with no fields and default options.
100 /// (Native API: EventWriteTransfer)
102 /// <param name="eventName">The name of the event.</param>
103 public unsafe void Write(string? eventName
)
105 if (!this.IsEnabled())
110 var options
= new EventSourceOptions();
111 this.WriteImpl(eventName
, ref options
, null, null, null, SimpleEventTypes
<EmptyStruct
>.Instance
);
115 /// Writes an event with no fields.
116 /// (Native API: EventWriteTransfer)
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.
123 public unsafe void Write(string? eventName
, EventSourceOptions options
)
125 if (!this.IsEnabled())
130 this.WriteImpl(eventName
, ref options
, null, null, null, SimpleEventTypes
<EmptyStruct
>.Instance
);
135 /// (Native API: EventWriteTransfer)
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.
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.
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.
152 public unsafe void Write
<T
>(
156 if (!this.IsEnabled())
161 var options
= new EventSourceOptions();
162 this.WriteImpl(eventName
, ref options
, data
, null, null, SimpleEventTypes
<T
>.Instance
);
167 /// (Native API: EventWriteTransfer)
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.
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.
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.
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.
188 public unsafe void Write
<T
>(
190 EventSourceOptions options
,
193 if (!this.IsEnabled())
198 this.WriteImpl(eventName
, ref options
, data
, null, null, SimpleEventTypes
<T
>.Instance
);
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)
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.
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.
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.
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.
226 public unsafe void Write
<T
>(
228 ref EventSourceOptions options
,
231 if (!this.IsEnabled())
236 this.WriteImpl(eventName
, ref options
, data
, null, null, SimpleEventTypes
<T
>.Instance
);
241 /// This overload is meant for clients that need to manipuate the activityId
242 /// and related ActivityId for the event.
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.
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.
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.
257 /// <param name="activityId">
258 /// The GUID of the activity associated with this event.
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.
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.
271 public unsafe void Write
<T
>(
273 ref EventSourceOptions options
,
275 ref Guid relatedActivityId
,
278 if (!this.IsEnabled())
283 fixed (Guid
* pActivity
= &activityId
, pRelated
= &relatedActivityId
)
290 relatedActivityId
== Guid
.Empty
? null : pRelated
,
291 SimpleEventTypes
<T
>.Instance
);
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.
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.)
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.
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.
317 /// <param name="activityID">
318 /// A pointer to the activity ID GUID to log
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.
327 private unsafe void WriteMultiMerge(
329 ref EventSourceOptions options
,
330 TraceLoggingEventTypes eventTypes
,
332 Guid
* childActivityID
,
333 params object?[] values
)
335 if (!this.IsEnabled())
339 byte level
= (options
.valuesSet
& EventSourceOptions
.levelSet
) != 0
342 EventKeywords keywords
= (options
.valuesSet
& EventSourceOptions
.keywordsSet
) != 0
344 : eventTypes
.keywords
;
346 if (this.IsEnabled((EventLevel
)level
, keywords
))
348 WriteMultiMergeInner(eventName
, ref options
, eventTypes
, activityID
, childActivityID
, values
);
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
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.)
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.
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.
376 /// <param name="activityID">
377 /// A pointer to the activity ID GUID to log
379 /// <param name="childActivityID">
380 /// A pointer to the child activity ID to log (can be null)
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.
387 private unsafe void WriteMultiMergeInner(
389 ref EventSourceOptions options
,
390 TraceLoggingEventTypes eventTypes
,
392 Guid
* childActivityID
,
393 params object?[] values
)
395 #if FEATURE_MANAGED_ETW
397 byte level
= (options
.valuesSet
& EventSourceOptions
.levelSet
) != 0
400 byte opcode
= (options
.valuesSet
& EventSourceOptions
.opcodeSet
) != 0
403 EventTags tags
= (options
.valuesSet
& EventSourceOptions
.tagsSet
) != 0
406 EventKeywords keywords
= (options
.valuesSet
& EventSourceOptions
.keywordsSet
) != 0
408 : eventTypes
.keywords
;
410 NameInfo nameInfo
= eventTypes
.GetNameInfo(eventName
?? eventTypes
.Name
, tags
);
411 if (nameInfo
== null)
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
);
422 IntPtr eventHandle
= IntPtr
.Zero
;
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
++)
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();
449 DataCollector
.ThreadInstance
.Enable(
451 eventTypes
.scratchSize
,
453 eventTypes
.dataCount
,
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
]));
469 (int)(DataCollector
.ThreadInstance
.Finish() - descriptors
),
470 (IntPtr
)descriptors
);
474 WriteCleanup(pins
, pinCount
);
477 #endif // FEATURE_MANAGED_ETW
481 /// Writes an extended event, where the values of the event have already
482 /// been serialized in "data".
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.)
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.
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.
499 /// <param name="activityID">
500 /// A pointer to the activity ID GUID to log
502 /// <param name="childActivityID">
503 /// A pointer to the child activity ID to log (can be null)
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.
510 internal unsafe void WriteMultiMerge(
512 ref EventSourceOptions options
,
513 TraceLoggingEventTypes eventTypes
,
515 Guid
* childActivityID
,
518 #if FEATURE_MANAGED_ETW
519 if (!this.IsEnabled())
524 fixed (EventSourceOptions
* pOptions
= &options
)
526 EventDescriptor descriptor
;
527 NameInfo
? nameInfo
= this.UpdateDescriptor(eventName
, eventTypes
, ref options
, out descriptor
);
528 if (nameInfo
== null)
533 #if FEATURE_PERFTRACING
534 IntPtr eventHandle
= nameInfo
.GetOrCreateEventHandle(m_eventPipeProvider
, m_eventHandleTable
, descriptor
, eventTypes
);
535 Debug
.Assert(eventHandle
!= IntPtr
.Zero
);
537 IntPtr eventHandle
= IntPtr
.Zero
;
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;
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);
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;
576 (IntPtr
)descriptors
);
579 #endif // FEATURE_MANAGED_ETW
582 private unsafe void WriteImpl(
584 ref EventSourceOptions options
,
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)
602 #if FEATURE_PERFTRACING
603 IntPtr eventHandle
= nameInfo
.GetOrCreateEventHandle(m_eventPipeProvider
, m_eventHandleTable
, descriptor
, eventTypes
);
604 Debug
.Assert(eventHandle
!= IntPtr
.Zero
);
606 IntPtr eventHandle
= IntPtr
.Zero
;
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
++)
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();
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(
661 eventTypes
.scratchSize
,
663 eventTypes
.dataCount
,
667 TraceLoggingTypeInfo info
= eventTypes
.typeInfos
[0];
668 info
.WriteData(TraceLoggingDataCollector
.Instance
, info
.PropertyValueFactory(data
));
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
);
689 if (ex
is EventSourceException
)
692 ThrowEventSourceException(eventName
, ex
);
694 #if FEATURE_MANAGED_ETW
697 WriteCleanup(pins
, pinCount
);
700 #endif // FEATURE_MANAGED_ETW
705 if (ex
is EventSourceException
)
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
;
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
)]
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
)
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);
768 if (!byte.TryParse(etwTrait
, out traitNum
))
770 if (etwTrait
== "GROUP")
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
;
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)
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])));
826 else if ('A' <= firstChar
|| ' ' == firstChar
) // Is it alphabetic or space (excludes digits and most punctuation).
828 metaData
.AddRange(Encoding
.UTF8
.GetBytes(value));
832 throw new ArgumentException(SR
.Format(SR
.EventSource_IllegalValue
, value), "traits");
835 return metaData
.Count
- startPos
;
839 /// Returns a value 0-15 if 'c' is a hexadecimal digit. If it throws an argument exception.
841 private static int HexDigit(char c
)
843 if ('0' <= c
&& c
<= '9')
849 c
= unchecked((char)(c
- ('a' - 'A'))); // Convert to lower case
851 if ('A' <= c
&& c
<= 'F')
856 throw new ArgumentException(SR
.Format(SR
.EventSource_BadHexDigit
, c
), "traits");
859 private NameInfo
? UpdateDescriptor(
861 TraceLoggingEventTypes eventInfo
,
862 ref EventSourceOptions options
,
863 out EventDescriptor descriptor
)
865 NameInfo
? nameInfo
= null;
867 byte level
= (options
.valuesSet
& EventSourceOptions
.levelSet
) != 0
870 byte opcode
= (options
.valuesSet
& EventSourceOptions
.opcodeSet
) != 0
873 EventTags tags
= (options
.valuesSet
& EventSourceOptions
.tagsSet
) != 0
876 EventKeywords keywords
= (options
.valuesSet
& EventSourceOptions
.keywordsSet
) != 0
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
);