summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging')
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ArrayTypeInfo.cs62
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ConcurrentSet.cs125
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ConcurrentSetItem.cs23
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/DataCollector.cs309
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EmptyStruct.cs15
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumHelper.cs44
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumerableTypeInfo.cs64
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventDataAttribute.cs144
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldAttribute.cs73
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldFormat.cs128
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventIgnoreAttribute.cs23
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventPayload.cs147
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceActivity.cs319
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceOptions.cs128
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/FieldMetadata.cs229
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/InvokeTypeInfo.cs116
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/NameInfo.cs61
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAccessor.cs156
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAnalysis.cs35
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleEventTypes.cs48
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleTypeInfos.cs1046
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/Statics.cs829
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataCollector.cs394
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataType.cs347
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventSource.cs842
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTraits.cs26
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTypes.cs260
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingMetadataCollector.cs368
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo.cs178
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo_T.cs160
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TypeAnalysis.cs101
31 files changed, 6800 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ArrayTypeInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ArrayTypeInfo.cs
new file mode 100644
index 0000000000..1b7772246c
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ArrayTypeInfo.cs
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Collections.Generic;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+ internal sealed class ArrayTypeInfo<ElementType>
+ : TraceLoggingTypeInfo<ElementType[]>
+ {
+ private readonly TraceLoggingTypeInfo<ElementType> elementInfo;
+
+ public ArrayTypeInfo(TraceLoggingTypeInfo<ElementType> elementInfo)
+ {
+ 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,
+ ref ElementType[] value)
+ {
+ var bookmark = collector.BeginBufferedArray();
+
+ var count = 0;
+ if (value != null)
+ {
+ count = value.Length;
+ for (int i = 0; i < value.Length; i++)
+ {
+ this.elementInfo.WriteData(collector, ref value[i]);
+ }
+ }
+
+ collector.EndBufferedArray(bookmark, count);
+ }
+
+ public override object GetData(object value)
+ {
+ var array = (ElementType[])value;
+ var serializedArray = new object[array.Length];
+ for (int i = 0; i < array.Length; i++)
+ {
+ serializedArray[i] = this.elementInfo.GetData(array[i]);
+ }
+ return serializedArray;
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ConcurrentSet.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ConcurrentSet.cs
new file mode 100644
index 0000000000..b07d671f5a
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ConcurrentSet.cs
@@ -0,0 +1,125 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using Interlocked = System.Threading.Interlocked;
+
+#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;
+ var oldItems = this.items;
+
+ if (oldItems != null)
+ {
+ var lo = 0;
+ var 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;
+ var oldItems = this.items;
+ ItemType[] newItems;
+
+ Retry:
+
+ if (oldItems == null)
+ {
+ newItems = new ItemType[] { newItem };
+ }
+ else
+ {
+ var lo = 0;
+ var 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, 0, newItems, 0, 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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ConcurrentSetItem.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ConcurrentSetItem.cs
new file mode 100644
index 0000000000..322f664303
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/ConcurrentSetItem.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/DataCollector.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/DataCollector.cs
new file mode 100644
index 0000000000..7166297e8a
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/DataCollector.cs
@@ -0,0 +1,309 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+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>
+ [SecurityCritical]
+ 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 = new DataCollector();
+ }
+
+ /// <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)
+ {
+ var scratchOld = this.scratch;
+ var scratchNew = scratchOld + size;
+ if (this.scratchEnd < scratchNew)
+ {
+ throw new IndexOutOfRangeException(Environment.GetResourceString("EventSource_AddScalarOutOfRange"));
+ }
+
+ this.ScalarsBegin();
+ this.scratch = scratchNew;
+
+ for (int i = 0; i != size; i++)
+ {
+ scratchOld[i] = pb[i];
+ }
+ }
+ else
+ {
+ var oldPos = this.bufferPos;
+ this.bufferPos = checked(this.bufferPos + size);
+ this.EnsureBuffer();
+ 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
+ {
+ var oldPos = this.bufferPos;
+ this.bufferPos = checked(this.bufferPos + size);
+ this.EnsureBuffer();
+ fixed (void* p = value)
+ {
+ Marshal.Copy((IntPtr)p, this.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;
+ }
+
+ var 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
+ {
+ var oldPos = this.bufferPos;
+ this.bufferPos = checked(this.bufferPos + size);
+ this.EnsureBuffer();
+ 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();
+ 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 += 1;
+ }
+
+ /// <summary>
+ /// Marks the end of dynamically-buffered data.
+ /// </summary>
+ internal void EndBuffered()
+ {
+ this.bufferNesting -= 1;
+
+ if (this.bufferNesting == 0)
+ {
+ this.EnsureBuffer();
+ this.PinArray(this.buffer, this.bufferPos);
+ this.buffer = null;
+ this.bufferPos = 0;
+ }
+ }
+
+ private void EnsureBuffer()
+ {
+ var required = this.bufferPos;
+ if (this.buffer == null || this.buffer.Length < required)
+ {
+ this.GrowBuffer(required);
+ }
+ }
+
+ private void EnsureBuffer(int additionalSize)
+ {
+ var required = this.bufferPos + additionalSize;
+ if (this.buffer == null || this.buffer.Length < required)
+ {
+ this.GrowBuffer(required);
+ }
+ }
+
+ private void GrowBuffer(int required)
+ {
+ var 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)
+ {
+ var pinsTemp = this.pins;
+ if (this.pinsEnd <= pinsTemp)
+ {
+ throw new IndexOutOfRangeException(Environment.GetResourceString("EventSource_PinArrayOutOfRange"));
+ }
+
+ var datasTemp = this.datas;
+ if (this.datasEnd <= datasTemp)
+ {
+ throw new IndexOutOfRangeException(Environment.GetResourceString("EventSource_DataDescriptorsOutOfRange"));
+ }
+
+ this.pins = pinsTemp + 1;
+ this.datas = datasTemp + 1;
+
+ *pinsTemp = GCHandle.Alloc(value, GCHandleType.Pinned);
+ datasTemp->m_Ptr = (long)(ulong)(UIntPtr)(void*)pinsTemp->AddrOfPinnedObject();
+ datasTemp->m_Size = size;
+ }
+
+ private void ScalarsBegin()
+ {
+ if (!this.writingScalars)
+ {
+ var datasTemp = this.datas;
+ if (this.datasEnd <= datasTemp)
+ {
+ throw new IndexOutOfRangeException(Environment.GetResourceString("EventSource_DataDescriptorsOutOfRange"));
+ }
+
+ datasTemp->m_Ptr = (long)(ulong)(UIntPtr)this.scratch;
+ this.writingScalars = true;
+ }
+ }
+
+ private void ScalarsEnd()
+ {
+ if (this.writingScalars)
+ {
+ var datasTemp = this.datas;
+ datasTemp->m_Size = checked((int)(this.scratch - (byte*)datasTemp->m_Ptr));
+ this.datas = datasTemp + 1;
+ this.writingScalars = false;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EmptyStruct.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EmptyStruct.cs
new file mode 100644
index 0000000000..829020ac23
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EmptyStruct.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license 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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumHelper.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumHelper.cs
new file mode 100644
index 0000000000..db6317ee51
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumHelper.cs
@@ -0,0 +1,44 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+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>
+ {
+ private delegate UnderlyingType Transformer<ValueType>(ValueType value);
+
+ private static readonly MethodInfo IdentityInfo =
+ Statics.GetDeclaredStaticMethod(typeof(EnumHelper<UnderlyingType>), "Identity");
+
+ public static UnderlyingType Cast<ValueType>(ValueType value)
+ {
+ return Caster<ValueType>.Instance(value);
+ }
+
+ internal static UnderlyingType Identity(UnderlyingType value)
+ {
+ return value;
+ }
+
+ private static class Caster<ValueType>
+ {
+ public static readonly Transformer<ValueType> Instance =
+ (Transformer<ValueType>)Statics.CreateDelegate(
+ typeof(Transformer<ValueType>),
+ IdentityInfo);
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumerableTypeInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumerableTypeInfo.cs
new file mode 100644
index 0000000000..5ff6c07889
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EnumerableTypeInfo.cs
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Collections.Generic;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+ internal sealed class EnumerableTypeInfo<IterableType, ElementType>
+ : TraceLoggingTypeInfo<IterableType>
+ where IterableType : IEnumerable<ElementType>
+ {
+ private readonly TraceLoggingTypeInfo<ElementType> elementInfo;
+
+ public EnumerableTypeInfo(TraceLoggingTypeInfo<ElementType> elementInfo)
+ {
+ 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,
+ ref IterableType value)
+ {
+ var bookmark = collector.BeginBufferedArray();
+
+ var count = 0;
+ if (value != null)
+ {
+ foreach (var element in value)
+ {
+ var el = element;
+ this.elementInfo.WriteData(collector, ref el);
+ count++;
+ }
+ }
+
+ collector.EndBufferedArray(bookmark, count);
+ }
+
+ public override object GetData(object value)
+ {
+ var iterType = (IterableType)value;
+ List<object> serializedEnumerable = new List<object>();
+ foreach (var element in iterType)
+ {
+ serializedEnumerable.Add(elementInfo.GetData(element));
+ }
+ return serializedEnumerable.ToArray();
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventDataAttribute.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventDataAttribute.cs
new file mode 100644
index 0000000000..905bf5ac1c
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventDataAttribute.cs
@@ -0,0 +1,144 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#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 { return 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 { return 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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldAttribute.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldAttribute.cs
new file mode 100644
index 0000000000..0b896b7fcf
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldAttribute.cs
@@ -0,0 +1,73 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#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.
+ /// </summary>
+ internal string Name
+ {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets a field formatting hint.
+ /// </summary>
+ public EventFieldFormat Format
+ {
+ get;
+ set;
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldFormat.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldFormat.cs
new file mode 100644
index 0000000000..0505d6af63
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventFieldFormat.cs
@@ -0,0 +1,128 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license 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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventIgnoreAttribute.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventIgnoreAttribute.cs
new file mode 100644
index 0000000000..367693f0cd
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventIgnoreAttribute.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventPayload.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventPayload.cs
new file mode 100644
index 0000000000..3240a8d738
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventPayload.cs
@@ -0,0 +1,147 @@
+using System.Collections.Generic;
+using System.Collections;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#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)
+ {
+ Contract.Assert(payloadNames.Count == payloadValues.Count);
+
+ m_names = payloadNames;
+ m_values = payloadValues;
+ }
+
+ public ICollection<string> Keys { get { return m_names; } }
+ public ICollection<object> Values { get { return m_values; } }
+
+ public object this[string key]
+ {
+ get
+ {
+ if (key == null)
+ throw new System.ArgumentNullException("key");
+
+ int position = 0;
+ foreach(var name in m_names)
+ {
+ if (name == key)
+ {
+ return m_values[position];
+ }
+ position++;
+ }
+
+ throw new System.Collections.Generic.KeyNotFoundException();
+ }
+ 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("key");
+
+ foreach (var item in m_names)
+ {
+ if (item == key)
+ return true;
+ }
+ return false;
+ }
+
+ public int Count { get { return m_names.Count; } }
+
+ public bool IsReadOnly { get { return true; } }
+
+ public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
+ {
+ throw new System.NotSupportedException();
+ }
+
+ 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, out object value)
+ {
+ if (key == null)
+ throw new System.ArgumentNullException("key");
+
+ int position = 0;
+ foreach (var name in m_names)
+ {
+ if (name == key)
+ {
+ value = m_values[position];
+ return true;
+ }
+ position++;
+ }
+
+ value = default(object);
+ return false;
+ }
+
+ #region private
+ private List<string> m_names;
+ private List<object> m_values;
+ #endregion
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceActivity.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceActivity.cs
new file mode 100644
index 0000000000..2114707d69
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceActivity.cs
@@ -0,0 +1,319 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#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("eventSource");
+ Contract.EndContractBlock();
+
+ this.eventSource = eventSource;
+ }
+
+ /// <summary>
+ /// You can make an activity out of just an EventSource.
+ /// </summary>
+ public static implicit operator EventSourceActivity(EventSource eventSource) { return new EventSourceActivity(eventSource); }
+
+ /* Properties */
+ /// <summary>
+ /// Gets the event source to which this activity writes events.
+ /// </summary>
+ public EventSource EventSource
+ {
+ get { return 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
+ {
+ get { return 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 indiates the event is off, then the returned activity is simply the 'this' poitner
+ /// and it is effectively like the Start d
+ ///
+ /// 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)
+ {
+ var options = new EventSourceOptions();
+ var data = new EmptyStruct();
+ 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)
+ {
+ var data = new EmptyStruct();
+ 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)
+ {
+ var options = new EventSourceOptions();
+ 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 stoping (but it is still STRONGLY recommeded 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)
+ {
+ var data = new EmptyStruct();
+ 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 stoping (but it is still STRONGLY recommeded 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 associted 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)
+ {
+ var options = new EventSourceOptions();
+ 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)
+ {
+ var data = new EmptyStruct();
+ 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)
+ {
+ var options = new EventSourceOptions();
+ var data = new EmptyStruct();
+ 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)
+ {
+ var data = new EmptyStruct();
+ 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;
+
+ this.state = State.Stopped;
+ if (eventName == null)
+ {
+ eventName = this.eventName;
+ if (eventName.EndsWith("Start"))
+ eventName = eventName.Substring(0, eventName.Length - 5);
+ eventName = 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 { get { return eventName != null; }}
+
+ private readonly EventSource eventSource;
+ private EventSourceOptions startStopOptions;
+ internal Guid activityId;
+ // internal Guid relatedActivityId;
+ private State state;
+ private string eventName;
+
+ static internal Guid s_empty;
+ #endregion
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceOptions.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceOptions.cs
new file mode 100644
index 0000000000..5b12ea9098
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/EventSourceOptions.cs
@@ -0,0 +1,128 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#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
+ {
+ return (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
+ {
+ return (EventOpcode)this.opcode;
+ }
+
+ set
+ {
+ this.opcode = checked((byte)value);
+ this.valuesSet |= opcodeSet;
+ }
+ }
+
+ internal bool IsOpcodeSet
+ {
+ get
+ {
+ return (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
+ {
+ return 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
+ {
+ return 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
+ {
+ return this.activityOptions;
+ }
+ set
+ {
+ this.activityOptions = value;
+ this.valuesSet |= activityOptionsSet;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/FieldMetadata.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/FieldMetadata.cs
new file mode 100644
index 0000000000..8dbe604767
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/FieldMetadata.cs
@@ -0,0 +1,229 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using Encoding = System.Text.Encoding;
+
+#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)
+ {
+ return;
+ }
+
+ /// <summary>
+ /// Fixed-length array.
+ /// </summary>
+ public FieldMetadata(
+ string name,
+ TraceLoggingDataType type,
+ EventFieldTags tags,
+ ushort fixedCount)
+ : this(
+ name,
+ type,
+ tags,
+ Statics.InTypeFixedCountFlag,
+ fixedCount,
+ null)
+ {
+ return;
+ }
+
+ /// <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)
+ {
+ return;
+ }
+
+ private FieldMetadata(
+ string name,
+ TraceLoggingDataType dataType,
+ EventFieldTags tags,
+ byte countFlags,
+ ushort fixedCount = 0,
+ byte[] custom = null)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException(
+ "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);
+ var 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(Environment.GetResourceString("EventSource_NotSupportedArrayOfNil"));
+ }
+ if (coreType == (int)TraceLoggingDataType.Binary)
+ {
+ throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedArrayOfBinary"));
+ }
+#if !BROKEN_UNTIL_M3
+ if (coreType == (int)TraceLoggingDataType.Utf16String ||
+ coreType == (int)TraceLoggingDataType.MbcsString)
+ {
+ throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedArrayOfNullTerminatedString"));
+ }
+#endif
+ }
+
+ 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(Environment.GetResourceString("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 += 1;
+
+ // If InTypeChainFlag set, then write out the outType
+ if (0 != (this.inType & Statics.InTypeChainFlag))
+ {
+ if (metadata != null)
+ {
+ metadata[pos] = this.outType;
+ }
+ pos += 1;
+
+ // 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)
+ {
+ Buffer.BlockCopy(this.custom, 0, metadata, pos, this.fixedCount);
+ }
+ pos += this.fixedCount;
+ }
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/InvokeTypeInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/InvokeTypeInfo.cs
new file mode 100644
index 0000000000..ec4196efa5
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/InvokeTypeInfo.cs
@@ -0,0 +1,116 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+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. Implemented using Delegate.CreateDelegate(property.Getter).
+ /// </summary>
+ /// <typeparam name="ContainerType">
+ /// Type from which to read values.
+ /// </typeparam>
+ internal sealed class InvokeTypeInfo<ContainerType>
+ : TraceLoggingTypeInfo<ContainerType>
+ {
+ private readonly PropertyAnalysis[] properties;
+ private readonly PropertyAccessor<ContainerType>[] accessors;
+
+ public InvokeTypeInfo(
+ TypeAnalysis typeAnalysis)
+ : base(
+ typeAnalysis.name,
+ typeAnalysis.level,
+ typeAnalysis.opcode,
+ typeAnalysis.keywords,
+ typeAnalysis.tags)
+ {
+ if (typeAnalysis.properties.Length != 0)
+ {
+ this.properties = typeAnalysis.properties;
+ this.accessors = new PropertyAccessor<ContainerType>[this.properties.Length];
+ for (int i = 0; i < this.accessors.Length; i++)
+ {
+ this.accessors[i] = PropertyAccessor<ContainerType>.Create(this.properties[i]);
+ }
+ }
+ }
+
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ var groupCollector = collector.AddGroup(name);
+ if (this.properties != null)
+ {
+ foreach (var property in this.properties)
+ {
+ var propertyFormat = EventFieldFormat.Default;
+ var 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,
+ ref ContainerType value)
+ {
+ if (this.accessors != null)
+ {
+ foreach (var accessor in this.accessors)
+ {
+ accessor.Write(collector, ref value);
+ }
+ }
+ }
+
+ public override object GetData(object value)
+ {
+ if (this.properties != null)
+ {
+ var membersNames = new List<string>();
+ var memebersValues = new List<object>();
+ for (int i = 0; i < this.properties.Length; i++)
+ {
+ var propertyValue = accessors[i].GetData((ContainerType)value);
+ membersNames.Add(properties[i].name);
+ memebersValues.Add(properties[i].typeInfo.GetData(propertyValue));
+ }
+ return new EventPayload(membersNames, memebersValues);
+ }
+
+ return null;
+ }
+
+ public override void WriteObjectData(
+ TraceLoggingDataCollector collector,
+ object valueObj)
+ {
+ if (this.accessors != null)
+ {
+ var value = valueObj == null
+ ? default(ContainerType)
+ : (ContainerType)valueObj;
+ this.WriteData(collector, ref value);
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/NameInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/NameInfo.cs
new file mode 100644
index 0000000000..1820443092
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/NameInfo.cs
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Collections.Generic;
+using Interlocked = System.Threading.Interlocked;
+
+#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>
+ {
+ 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;
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAccessor.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAccessor.cs
new file mode 100644
index 0000000000..7fb7802435
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAccessor.cs
@@ -0,0 +1,156 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Reflection;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+ /// <summary>
+ /// TraceLogging: Each PropertyAccessor instance encapsulates the information
+ /// needed to read a particular property from an instance of ContainerType
+ /// and write the value to a DataCollector. Used by InvokeTypeInfo.
+ /// </summary>
+ /// <typeparam name="ContainerType">
+ /// The type of the object from which properties are read.
+ /// </typeparam>
+ internal abstract class PropertyAccessor<ContainerType>
+ {
+ public abstract void Write(TraceLoggingDataCollector collector, ref ContainerType value);
+ public abstract object GetData(ContainerType value);
+
+ public static PropertyAccessor<ContainerType> Create(PropertyAnalysis property)
+ {
+ // Due to current Project N limitations on handling generic instantiations with
+ // 2 generic parameters we have to explicitly create the instantiations that we consider
+ // important to EventSource performance (we have considered int, long, string for the moment).
+ // Everything else is handled by NonGenericPropertyWriter that ends up boxing the container object.
+ var retType = property.getterInfo.ReturnType;
+ if (!Statics.IsValueType(typeof(ContainerType)))
+ {
+ if (retType == typeof(int))
+ return new ClassPropertyWriter<ContainerType, int>(property);
+ else if (retType == typeof(long))
+ return new ClassPropertyWriter<ContainerType, long>(property);
+ else if (retType == typeof(string))
+ return new ClassPropertyWriter<ContainerType, string>(property);
+ }
+ else
+ {
+ // Handle the case if it is a struct (DD 1027919)
+ }
+
+ // Otherwise use the boxing one.
+ return new NonGenericProperytWriter<ContainerType>(property);
+ }
+ }
+
+ /// <summary>
+ /// The type specific version of the property writers uses generics in a way
+ /// that Project N can't handle at the moment. To avoid this we simply
+ /// use reflection completely.
+ /// </summary>
+ internal class NonGenericProperytWriter<ContainerType> : PropertyAccessor<ContainerType>
+ {
+ public NonGenericProperytWriter(PropertyAnalysis property)
+ {
+ getterInfo = property.getterInfo;
+ typeInfo = property.typeInfo;
+ }
+
+ public override void Write(TraceLoggingDataCollector collector, ref ContainerType container)
+ {
+ object value = container == null
+ ? null
+ : getterInfo.Invoke((object)container, null);
+ this.typeInfo.WriteObjectData(collector, value);
+ }
+
+ public override object GetData(ContainerType container)
+ {
+ return container == null
+ ? default(ValueType)
+ : getterInfo.Invoke((object)container, null);
+ }
+
+ private readonly TraceLoggingTypeInfo typeInfo;
+ private readonly MethodInfo getterInfo;
+ }
+
+ /// <summary>
+ /// Implementation of PropertyAccessor for use when ContainerType is a
+ /// value type.
+ /// </summary>
+ /// <typeparam name="ContainerType">The type of the object from which properties are read.</typeparam>
+ /// <typeparam name="ValueType">Type of the property being read.</typeparam>
+ internal class StructPropertyWriter<ContainerType, ValueType>
+ : PropertyAccessor<ContainerType>
+ {
+ private delegate ValueType Getter(ref ContainerType container);
+ private readonly TraceLoggingTypeInfo<ValueType> valueTypeInfo;
+ private readonly Getter getter;
+
+ public StructPropertyWriter(PropertyAnalysis property)
+ {
+ this.valueTypeInfo = (TraceLoggingTypeInfo<ValueType>)property.typeInfo;
+ this.getter = (Getter)Statics.CreateDelegate(
+ typeof(Getter),
+ property.getterInfo);
+ }
+
+ public override void Write(TraceLoggingDataCollector collector, ref ContainerType container)
+ {
+ var value = container == null
+ ? default(ValueType)
+ : getter(ref container);
+ this.valueTypeInfo.WriteData(collector, ref value);
+ }
+
+ public override object GetData(ContainerType container)
+ {
+ return container == null
+ ? default(ValueType)
+ : getter(ref container);
+ }
+ }
+
+ /// <summary>
+ /// Implementation of PropertyAccessor for use when ContainerType is a
+ /// reference type.
+ /// </summary>
+ /// <typeparam name="ContainerType">The type of the object from which properties are read.</typeparam>
+ /// <typeparam name="ValueType">Type of the property being read.</typeparam>
+ internal class ClassPropertyWriter<ContainerType, ValueType>
+ : PropertyAccessor<ContainerType>
+ {
+ private delegate ValueType Getter(ContainerType container);
+ private readonly TraceLoggingTypeInfo<ValueType> valueTypeInfo;
+ private readonly Getter getter;
+
+ public ClassPropertyWriter(PropertyAnalysis property)
+ {
+ this.valueTypeInfo = (TraceLoggingTypeInfo<ValueType>)property.typeInfo;
+ this.getter = (Getter)Statics.CreateDelegate(
+ typeof(Getter),
+ property.getterInfo);
+ }
+
+ public override void Write(TraceLoggingDataCollector collector, ref ContainerType container)
+ {
+ var value = container == null
+ ? default(ValueType)
+ : getter(container);
+ this.valueTypeInfo.WriteData(collector, ref value);
+ }
+
+ public override object GetData(ContainerType container)
+ {
+ return container == null
+ ? default(ValueType)
+ : getter(container);
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAnalysis.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAnalysis.cs
new file mode 100644
index 0000000000..523d6830ef
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/PropertyAnalysis.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+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 MethodInfo getterInfo;
+ internal readonly TraceLoggingTypeInfo typeInfo;
+ internal readonly EventFieldAttribute fieldAttribute;
+
+ public PropertyAnalysis(
+ string name,
+ MethodInfo getterInfo,
+ TraceLoggingTypeInfo typeInfo,
+ EventFieldAttribute fieldAttribute)
+ {
+ this.name = name;
+ this.getterInfo = getterInfo;
+ this.typeInfo = typeInfo;
+ this.fieldAttribute = fieldAttribute;
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleEventTypes.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleEventTypes.cs
new file mode 100644
index 0000000000..9685885879
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleEventTypes.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using Interlocked = System.Threading.Interlocked;
+
+#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 class SimpleEventTypes<T>
+ : TraceLoggingEventTypes
+ {
+ private static SimpleEventTypes<T> instance;
+
+ internal readonly TraceLoggingTypeInfo<T> typeInfo;
+
+ private SimpleEventTypes(TraceLoggingTypeInfo<T> typeInfo)
+ : base(
+ typeInfo.Name,
+ typeInfo.Tags,
+ new TraceLoggingTypeInfo[] { typeInfo })
+ {
+ this.typeInfo = typeInfo;
+ }
+
+ public static SimpleEventTypes<T> Instance
+ {
+ get { return instance ?? InitInstance(); }
+ }
+
+ private static SimpleEventTypes<T> InitInstance()
+ {
+ var newInstance = new SimpleEventTypes<T>(TraceLoggingTypeInfo<T>.Instance);
+ Interlocked.CompareExchange(ref instance, newInstance, null);
+ return instance;
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleTypeInfos.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleTypeInfos.cs
new file mode 100644
index 0000000000..87798d8878
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/SimpleTypeInfos.cs
@@ -0,0 +1,1046 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Collections.Generic;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+ #region NullTypeInfo
+
+ /// <summary>
+ /// TraceLogging: Type handler for empty or unsupported types.
+ /// </summary>
+ /// <typeparam name="DataType">The type to handle.</typeparam>
+ internal sealed class NullTypeInfo<DataType>
+ : TraceLoggingTypeInfo<DataType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddGroup(name);
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref DataType value)
+ {
+ return;
+ }
+
+ public override object GetData(object value)
+ {
+ return null;
+ }
+ }
+
+ #endregion
+
+ #region Primitive scalars
+
+ /// <summary>
+ /// TraceLogging: Type handler for Boolean.
+ /// </summary>
+ internal sealed class BooleanTypeInfo
+ : TraceLoggingTypeInfo<Boolean>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.Boolean8));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Boolean value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Byte.
+ /// </summary>
+ internal sealed class ByteTypeInfo
+ : TraceLoggingTypeInfo<Byte>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.UInt8));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Byte value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for SByte.
+ /// </summary>
+ internal sealed class SByteTypeInfo
+ : TraceLoggingTypeInfo<SByte>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.Int8));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref SByte value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Int16.
+ /// </summary>
+ internal sealed class Int16TypeInfo
+ : TraceLoggingTypeInfo<Int16>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.Int16));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Int16 value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for UInt16.
+ /// </summary>
+ internal sealed class UInt16TypeInfo
+ : TraceLoggingTypeInfo<UInt16>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.UInt16));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref UInt16 value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Int32.
+ /// </summary>
+ internal sealed class Int32TypeInfo
+ : TraceLoggingTypeInfo<Int32>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.Int32));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Int32 value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for UInt32.
+ /// </summary>
+ internal sealed class UInt32TypeInfo
+ : TraceLoggingTypeInfo<UInt32>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.UInt32));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref UInt32 value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Int64.
+ /// </summary>
+ internal sealed class Int64TypeInfo
+ : TraceLoggingTypeInfo<Int64>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.Int64));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Int64 value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for UInt64.
+ /// </summary>
+ internal sealed class UInt64TypeInfo
+ : TraceLoggingTypeInfo<UInt64>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.UInt64));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref UInt64 value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for IntPtr.
+ /// </summary>
+ internal sealed class IntPtrTypeInfo
+ : TraceLoggingTypeInfo<IntPtr>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.FormatPtr(format, Statics.IntPtrType));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref IntPtr value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for UIntPtr.
+ /// </summary>
+ internal sealed class UIntPtrTypeInfo
+ : TraceLoggingTypeInfo<UIntPtr>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.FormatPtr(format, Statics.UIntPtrType));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref UIntPtr value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Double.
+ /// </summary>
+ internal sealed class DoubleTypeInfo
+ : TraceLoggingTypeInfo<Double>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.Double));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Double value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Single.
+ /// </summary>
+ internal sealed class SingleTypeInfo
+ : TraceLoggingTypeInfo<Single>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.Float));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Single value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Char.
+ /// </summary>
+ internal sealed class CharTypeInfo
+ : TraceLoggingTypeInfo<Char>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.Char16));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Char value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ #endregion
+
+ #region Primitive arrays
+
+ /// <summary>
+ /// TraceLogging: Type handler for Boolean[].
+ /// </summary>
+ internal sealed class BooleanArrayTypeInfo
+ : TraceLoggingTypeInfo<Boolean[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format8(format, TraceLoggingDataType.Boolean8));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Boolean[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Byte[].
+ /// </summary>
+ internal sealed class ByteArrayTypeInfo
+ : TraceLoggingTypeInfo<Byte[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ switch (format)
+ {
+ default:
+ collector.AddBinary(name, Statics.MakeDataType(TraceLoggingDataType.Binary, format));
+ break;
+ case EventFieldFormat.String:
+ collector.AddBinary(name, TraceLoggingDataType.CountedMbcsString);
+ break;
+ case EventFieldFormat.Xml:
+ collector.AddBinary(name, TraceLoggingDataType.CountedMbcsXml);
+ break;
+ case EventFieldFormat.Json:
+ collector.AddBinary(name, TraceLoggingDataType.CountedMbcsJson);
+ break;
+ case EventFieldFormat.Boolean:
+ collector.AddArray(name, TraceLoggingDataType.Boolean8);
+ break;
+ case EventFieldFormat.Hexadecimal:
+ collector.AddArray(name, TraceLoggingDataType.HexInt8);
+ break;
+#if false
+ case EventSourceFieldFormat.Signed:
+ collector.AddArray(name, TraceLoggingDataType.Int8);
+ break;
+ case EventSourceFieldFormat.Unsigned:
+ collector.AddArray(name, TraceLoggingDataType.UInt8);
+ break;
+#endif
+ }
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Byte[] value)
+ {
+ collector.AddBinary(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for SByte[].
+ /// </summary>
+ internal sealed class SByteArrayTypeInfo
+ : TraceLoggingTypeInfo<SByte[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format8(format, TraceLoggingDataType.Int8));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref SByte[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Int16[].
+ /// </summary>
+ internal sealed class Int16ArrayTypeInfo
+ : TraceLoggingTypeInfo<Int16[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format16(format, TraceLoggingDataType.Int16));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Int16[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for UInt16[].
+ /// </summary>
+ internal sealed class UInt16ArrayTypeInfo
+ : TraceLoggingTypeInfo<UInt16[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format16(format, TraceLoggingDataType.UInt16));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref UInt16[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Int32[].
+ /// </summary>
+ internal sealed class Int32ArrayTypeInfo
+ : TraceLoggingTypeInfo<Int32[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format32(format, TraceLoggingDataType.Int32));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Int32[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for UInt32[].
+ /// </summary>
+ internal sealed class UInt32ArrayTypeInfo
+ : TraceLoggingTypeInfo<UInt32[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format32(format, TraceLoggingDataType.UInt32));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref UInt32[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Int64[].
+ /// </summary>
+ internal sealed class Int64ArrayTypeInfo
+ : TraceLoggingTypeInfo<Int64[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format64(format, TraceLoggingDataType.Int64));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Int64[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for UInt64[].
+ /// </summary>
+ internal sealed class UInt64ArrayTypeInfo
+ : TraceLoggingTypeInfo<UInt64[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format64(format, TraceLoggingDataType.UInt64));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref UInt64[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for IntPtr[].
+ /// </summary>
+ internal sealed class IntPtrArrayTypeInfo
+ : TraceLoggingTypeInfo<IntPtr[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.FormatPtr(format, Statics.IntPtrType));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref IntPtr[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for UIntPtr[].
+ /// </summary>
+ internal sealed class UIntPtrArrayTypeInfo
+ : TraceLoggingTypeInfo<UIntPtr[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.FormatPtr(format, Statics.UIntPtrType));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref UIntPtr[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Char[].
+ /// </summary>
+ internal sealed class CharArrayTypeInfo
+ : TraceLoggingTypeInfo<Char[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format16(format, TraceLoggingDataType.Char16));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Char[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Double[].
+ /// </summary>
+ internal sealed class DoubleArrayTypeInfo
+ : TraceLoggingTypeInfo<Double[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format64(format, TraceLoggingDataType.Double));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Double[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Single[].
+ /// </summary>
+ internal sealed class SingleArrayTypeInfo
+ : TraceLoggingTypeInfo<Single[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.Format32(format, TraceLoggingDataType.Float));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Single[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ #endregion
+
+ #region Enum scalars
+
+ internal sealed class EnumByteTypeInfo<EnumType>
+ : TraceLoggingTypeInfo<EnumType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.UInt8));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value)
+ {
+ collector.AddScalar(EnumHelper<Byte>.Cast(value));
+ }
+
+ public override object GetData(object value)
+ {
+ return (Byte)value;
+ }
+ }
+
+ internal sealed class EnumSByteTypeInfo<EnumType>
+ : TraceLoggingTypeInfo<EnumType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format8(format, TraceLoggingDataType.Int8));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value)
+ {
+ collector.AddScalar(EnumHelper<SByte>.Cast(value));
+ }
+
+ public override object GetData(object value)
+ {
+ return (SByte)value;
+ }
+ }
+
+ internal sealed class EnumInt16TypeInfo<EnumType>
+ : TraceLoggingTypeInfo<EnumType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.Int16));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value)
+ {
+ collector.AddScalar(EnumHelper<Int16>.Cast(value));
+ }
+
+ public override object GetData(object value)
+ {
+ return (Int16)value;
+ }
+ }
+
+ internal sealed class EnumUInt16TypeInfo<EnumType>
+ : TraceLoggingTypeInfo<EnumType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format16(format, TraceLoggingDataType.UInt16));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value)
+ {
+ collector.AddScalar(EnumHelper<UInt16>.Cast(value));
+ }
+
+ public override object GetData(object value)
+ {
+ return (UInt16)value;
+ }
+ }
+
+ internal sealed class EnumInt32TypeInfo<EnumType>
+ : TraceLoggingTypeInfo<EnumType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.Int32));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value)
+ {
+ collector.AddScalar(EnumHelper<Int32>.Cast(value));
+ }
+
+ public override object GetData(object value)
+ {
+ return (Int32)value;
+ }
+ }
+
+ internal sealed class EnumUInt32TypeInfo<EnumType>
+ : TraceLoggingTypeInfo<EnumType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format32(format, TraceLoggingDataType.UInt32));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value)
+ {
+ collector.AddScalar(EnumHelper<UInt32>.Cast(value));
+ }
+
+ public override object GetData(object value)
+ {
+ return (UInt32)value;
+ }
+ }
+
+ internal sealed class EnumInt64TypeInfo<EnumType>
+ : TraceLoggingTypeInfo<EnumType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.Int64));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value)
+ {
+ collector.AddScalar(EnumHelper<Int64>.Cast(value));
+ }
+
+ public override object GetData(object value)
+ {
+ return (Int64)value;
+ }
+ }
+
+ internal sealed class EnumUInt64TypeInfo<EnumType>
+ : TraceLoggingTypeInfo<EnumType>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.Format64(format, TraceLoggingDataType.UInt64));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref EnumType value)
+ {
+ collector.AddScalar(EnumHelper<UInt64>.Cast(value));
+ }
+
+ public override object GetData(object value)
+ {
+ return (UInt64)value;
+ }
+ }
+
+ #endregion
+
+ #region Other built-in types
+
+ /// <summary>
+ /// TraceLogging: Type handler for String.
+ /// </summary>
+ internal sealed class StringTypeInfo
+ : TraceLoggingTypeInfo<String>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddBinary(name, Statics.MakeDataType(TraceLoggingDataType.CountedUtf16String, format));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref String value)
+ {
+ collector.AddBinary(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Guid.
+ /// </summary>
+ internal sealed class GuidTypeInfo
+ : TraceLoggingTypeInfo<Guid>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Guid, format));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Guid value)
+ {
+ collector.AddScalar(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Guid[].
+ /// </summary>
+ internal sealed class GuidArrayTypeInfo
+ : TraceLoggingTypeInfo<Guid[]>
+ {
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ collector.AddArray(name, Statics.MakeDataType(TraceLoggingDataType.Guid, format));
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref Guid[] value)
+ {
+ collector.AddArray(value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for DateTime.
+ /// </summary>
+ internal sealed class DateTimeTypeInfo
+ : TraceLoggingTypeInfo<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, ref DateTime value)
+ {
+ var ticks = value.Ticks;
+ collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for DateTimeOffset.
+ /// </summary>
+ internal sealed class DateTimeOffsetTypeInfo
+ : TraceLoggingTypeInfo<DateTimeOffset>
+ {
+ public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format)
+ {
+ var group = collector.AddGroup(name);
+ group.AddScalar("Ticks", Statics.MakeDataType(TraceLoggingDataType.FileTime, format));
+ group.AddScalar("Offset", TraceLoggingDataType.Int64);
+ }
+
+ public override void WriteData(TraceLoggingDataCollector collector, ref DateTimeOffset value)
+ {
+ var ticks = value.Ticks;
+ collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000);
+ collector.AddScalar(value.Offset.Ticks);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for TimeSpan.
+ /// </summary>
+ internal sealed class TimeSpanTypeInfo
+ : TraceLoggingTypeInfo<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, ref TimeSpan value)
+ {
+ collector.AddScalar(value.Ticks);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Decimal. (Note: not full-fidelity, exposed as Double.)
+ /// </summary>
+ internal sealed class DecimalTypeInfo
+ : TraceLoggingTypeInfo<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, ref decimal value)
+ {
+ collector.AddScalar((double)value);
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for KeyValuePair.
+ /// </summary>
+ /// <typeparam name="K">Type of the KeyValuePair's Key property.</typeparam>
+ /// <typeparam name="V">Type of the KeyValuePair's Value property.</typeparam>
+ internal sealed class KeyValuePairTypeInfo<K, V>
+ : TraceLoggingTypeInfo<KeyValuePair<K, V>>
+ {
+ private readonly TraceLoggingTypeInfo<K> keyInfo;
+ private readonly TraceLoggingTypeInfo<V> valueInfo;
+
+ public KeyValuePairTypeInfo(List<Type> recursionCheck)
+ {
+ this.keyInfo = TraceLoggingTypeInfo<K>.GetInstance(recursionCheck);
+ this.valueInfo = TraceLoggingTypeInfo<V>.GetInstance(recursionCheck);
+ }
+
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ var group = collector.AddGroup(name);
+ this.keyInfo.WriteMetadata(group, "Key", EventFieldFormat.Default);
+ this.valueInfo.WriteMetadata(group, "Value", format);
+ }
+
+ public override void WriteData(
+ TraceLoggingDataCollector collector,
+ ref KeyValuePair<K, V> value)
+ {
+ var key = value.Key;
+ var val = value.Value;
+ this.keyInfo.WriteData(collector, ref key);
+ this.valueInfo.WriteData(collector, ref val);
+ }
+
+ public override object GetData(object value)
+ {
+ var serializedType = new Dictionary<string, object>();
+ var keyValuePair = (KeyValuePair<K, V>) value;
+ serializedType.Add("Key", this.keyInfo.GetData(keyValuePair.Key));
+ serializedType.Add("Value", this.valueInfo.GetData(keyValuePair.Value));
+ return serializedType;
+ }
+ }
+
+ /// <summary>
+ /// TraceLogging: Type handler for Nullable.
+ /// </summary>
+ /// <typeparam name="T">Type of the Nullable's Value property.</typeparam>
+ internal sealed class NullableTypeInfo<T>
+ : TraceLoggingTypeInfo<Nullable<T>>
+ where T : struct
+ {
+ private readonly TraceLoggingTypeInfo<T> valueInfo;
+
+ public NullableTypeInfo(List<Type> recursionCheck)
+ {
+ this.valueInfo = TraceLoggingTypeInfo<T>.GetInstance(recursionCheck);
+ }
+
+ public override void WriteMetadata(
+ TraceLoggingMetadataCollector collector,
+ string name,
+ EventFieldFormat format)
+ {
+ var group = collector.AddGroup(name);
+ group.AddScalar("HasValue", TraceLoggingDataType.Boolean8);
+ this.valueInfo.WriteMetadata(group, "Value", format);
+ }
+
+ public override void WriteData(
+ TraceLoggingDataCollector collector,
+ ref Nullable<T> value)
+ {
+ var hasValue = value.HasValue;
+ collector.AddScalar(hasValue);
+ var val = hasValue ? value.Value : default(T);
+ this.valueInfo.WriteData(collector, ref val);
+ }
+ }
+
+ #endregion
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/Statics.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/Statics.cs
new file mode 100644
index 0000000000..5239c31402
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/Statics.cs
@@ -0,0 +1,829 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using Encoding = System.Text.Encoding;
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+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.
+ var tagsLeft = tags & 0xfffffff;
+ bool more;
+ do
+ {
+ byte current = (byte)((tagsLeft >> 21) & 0x7f);
+ more = (tagsLeft & 0x1fffff) != 0;
+ current |= (byte)(more ? 0x80 : 0x00);
+ tagsLeft = tagsLeft << 7;
+
+ if (metadata != null)
+ {
+ metadata[pos] = current;
+ }
+ pos += 1;
+ }
+ 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("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)
+ {
+ switch (format)
+ {
+ case EventFieldFormat.Default:
+ return native;
+ case EventFieldFormat.String:
+ return TraceLoggingDataType.Char8;
+ case EventFieldFormat.Boolean:
+ return TraceLoggingDataType.Boolean8;
+ case EventFieldFormat.Hexadecimal:
+ return TraceLoggingDataType.HexInt8;
+#if false
+ case EventSourceFieldFormat.Signed:
+ return TraceLoggingDataType.Int8;
+ case EventSourceFieldFormat.Unsigned:
+ return TraceLoggingDataType.UInt8;
+#endif
+ default:
+ return 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)
+ {
+ switch (format)
+ {
+ case EventFieldFormat.Default:
+ return native;
+ case EventFieldFormat.String:
+ return TraceLoggingDataType.Char16;
+ case EventFieldFormat.Hexadecimal:
+ return TraceLoggingDataType.HexInt16;
+#if false
+ case EventSourceFieldFormat.Port:
+ return TraceLoggingDataType.Port;
+ case EventSourceFieldFormat.Signed:
+ return TraceLoggingDataType.Int16;
+ case EventSourceFieldFormat.Unsigned:
+ return TraceLoggingDataType.UInt16;
+#endif
+ default:
+ return 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)
+ {
+ switch (format)
+ {
+ case EventFieldFormat.Default:
+ return native;
+ case EventFieldFormat.Boolean:
+ return TraceLoggingDataType.Boolean32;
+ case EventFieldFormat.Hexadecimal:
+ return TraceLoggingDataType.HexInt32;
+#if false
+ case EventSourceFieldFormat.Ipv4Address:
+ return TraceLoggingDataType.Ipv4Address;
+ case EventSourceFieldFormat.ProcessId:
+ return TraceLoggingDataType.ProcessId;
+ case EventSourceFieldFormat.ThreadId:
+ return TraceLoggingDataType.ThreadId;
+ case EventSourceFieldFormat.Win32Error:
+ return TraceLoggingDataType.Win32Error;
+ case EventSourceFieldFormat.NTStatus:
+ return TraceLoggingDataType.NTStatus;
+#endif
+ case EventFieldFormat.HResult:
+ return TraceLoggingDataType.HResult;
+#if false
+ case EventSourceFieldFormat.Signed:
+ return TraceLoggingDataType.Int32;
+ case EventSourceFieldFormat.Unsigned:
+ return TraceLoggingDataType.UInt32;
+#endif
+ default:
+ return 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)
+ {
+ switch (format)
+ {
+ case EventFieldFormat.Default:
+ return native;
+ case EventFieldFormat.Hexadecimal:
+ return TraceLoggingDataType.HexInt64;
+#if false
+ case EventSourceFieldFormat.FileTime:
+ return TraceLoggingDataType.FileTime;
+ case EventSourceFieldFormat.Signed:
+ return TraceLoggingDataType.Int64;
+ case EventSourceFieldFormat.Unsigned:
+ return TraceLoggingDataType.UInt64;
+#endif
+ default:
+ return 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)
+ {
+ switch (format)
+ {
+ case EventFieldFormat.Default:
+ return native;
+ case EventFieldFormat.Hexadecimal:
+ return HexIntPtrType;
+#if false
+ case EventSourceFieldFormat.Signed:
+ return IntPtrType;
+ case EventSourceFieldFormat.Unsigned:
+ return UIntPtrType;
+#endif
+ default:
+ return 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;
+#if ES_BUILD_PCL
+ result = type.GetTypeInfo().IsValueType;
+#else
+ result = type.IsValueType;
+#endif
+ return result;
+ }
+
+ public static bool IsEnum(Type type)
+ {
+ bool result;
+#if ES_BUILD_PCL
+ result = type.GetTypeInfo().IsEnum;
+#else
+ result = type.IsEnum;
+#endif
+ return result;
+ }
+
+ public static IEnumerable<PropertyInfo> GetProperties(Type type)
+ {
+ IEnumerable<PropertyInfo> result;
+#if ES_BUILD_PCL
+ result = type.GetRuntimeProperties();
+#else
+ result = type.GetProperties();
+#endif
+ return result;
+ }
+
+ public static MethodInfo GetGetMethod(PropertyInfo propInfo)
+ {
+ MethodInfo result;
+#if ES_BUILD_PCL
+ result = propInfo.GetMethod;
+#else
+ result = propInfo.GetGetMethod();
+#endif
+ return result;
+ }
+
+ public static MethodInfo GetDeclaredStaticMethod(Type declaringType, string name)
+ {
+ MethodInfo result;
+#if ES_BUILD_PCL
+ 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
+ result = propInfo.IsDefined(attributeType);
+#else
+ var 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
+ foreach (var attrib in propInfo.GetCustomAttributes<AttributeType>(false))
+ {
+ result = attrib;
+ break;
+ }
+#else
+ var 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
+ foreach (var attrib in type.GetTypeInfo().GetCustomAttributes<AttributeType>(false))
+ {
+ result = attrib;
+ break;
+ }
+#else
+ var attributes = type.GetCustomAttributes(typeof(AttributeType), false);
+ if (attributes.Length != 0)
+ {
+ result = (AttributeType)attributes[0];
+ }
+#endif
+ return result;
+ }
+
+ public static Type[] GetGenericArguments(Type type)
+ {
+#if ES_BUILD_PCL
+ return type.GenericTypeArguments;
+#else
+ return type.GetGenericArguments();
+#endif
+ }
+
+ public static Type FindEnumerableElementType(Type type)
+ {
+ Type elementType = null;
+
+ if (IsGenericMatch(type, typeof(IEnumerable<>)))
+ {
+ elementType = GetGenericArguments(type)[0];
+ }
+ else
+ {
+#if ES_BUILD_PCL
+ var ifaceTypes = type.GetTypeInfo().ImplementedInterfaces;
+#else
+ var ifaceTypes = type.FindInterfaces(IsGenericMatch, typeof(IEnumerable<>));
+#endif
+
+ foreach (var ifaceType in ifaceTypes)
+ {
+#if ES_BUILD_PCL
+ 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)
+ {
+ bool isGeneric;
+#if ES_BUILD_PCL
+ isGeneric = type.IsConstructedGenericType;
+#else
+ isGeneric = type.IsGenericType;
+#endif
+ return isGeneric && type.GetGenericTypeDefinition() == (Type)openType;
+ }
+
+ public static Delegate CreateDelegate(Type delegateType, MethodInfo methodInfo)
+ {
+ Delegate result;
+#if ES_BUILD_PCL
+ result = methodInfo.CreateDelegate(
+ delegateType);
+#else
+ result = Delegate.CreateDelegate(
+ delegateType,
+ methodInfo);
+#endif
+ return result;
+ }
+
+ public static TraceLoggingTypeInfo GetTypeInfoInstance(Type dataType, List<Type> recursionCheck)
+ {
+ TraceLoggingTypeInfo result;
+
+ if (dataType == typeof(Int32))
+ {
+ result = TraceLoggingTypeInfo<Int32>.Instance;
+ }
+ else if (dataType == typeof(Int64))
+ {
+ result = TraceLoggingTypeInfo<Int64>.Instance;
+ }
+ else if (dataType == typeof(String))
+ {
+ result = TraceLoggingTypeInfo<String>.Instance;
+ }
+ else
+ {
+ var getInstanceInfo = Statics.GetDeclaredStaticMethod(
+ typeof(TraceLoggingTypeInfo<>).MakeGenericType(dataType),
+ "GetInstance");
+ var typeInfoObj = getInstanceInfo.Invoke(null, new object[] { recursionCheck });
+ result = (TraceLoggingTypeInfo)typeInfoObj;
+ }
+
+ return result;
+ }
+
+ public static TraceLoggingTypeInfo<DataType> CreateDefaultTypeInfo<DataType>(
+ List<Type> recursionCheck)
+ {
+ TraceLoggingTypeInfo result;
+ var dataType = typeof(DataType);
+
+ if (recursionCheck.Contains(dataType))
+ {
+ throw new NotSupportedException(Environment.GetResourceString("EventSource_RecursiveTypeDefinition"));
+ }
+
+ recursionCheck.Add(dataType);
+
+ var eventAttrib = Statics.GetCustomAttribute<EventDataAttribute>(dataType);
+ if (eventAttrib != null ||
+ Statics.GetCustomAttribute<CompilerGeneratedAttribute>(dataType) != null)
+ {
+ var analysis = new TypeAnalysis(dataType, eventAttrib, recursionCheck);
+ result = new InvokeTypeInfo<DataType>(analysis);
+ }
+ else if (dataType.IsArray)
+ {
+ var elementType = dataType.GetElementType();
+ if (elementType == typeof(Boolean))
+ {
+ result = new BooleanArrayTypeInfo();
+ }
+ else if (elementType == typeof(Byte))
+ {
+ result = new ByteArrayTypeInfo();
+ }
+ else if (elementType == typeof(SByte))
+ {
+ result = new SByteArrayTypeInfo();
+ }
+ else if (elementType == typeof(Int16))
+ {
+ result = new Int16ArrayTypeInfo();
+ }
+ else if (elementType == typeof(UInt16))
+ {
+ result = new UInt16ArrayTypeInfo();
+ }
+ else if (elementType == typeof(Int32))
+ {
+ result = new Int32ArrayTypeInfo();
+ }
+ else if (elementType == typeof(UInt32))
+ {
+ result = new UInt32ArrayTypeInfo();
+ }
+ else if (elementType == typeof(Int64))
+ {
+ result = new Int64ArrayTypeInfo();
+ }
+ else if (elementType == typeof(UInt64))
+ {
+ result = new UInt64ArrayTypeInfo();
+ }
+ else if (elementType == typeof(Char))
+ {
+ result = new CharArrayTypeInfo();
+ }
+ else if (elementType == typeof(Double))
+ {
+ result = new DoubleArrayTypeInfo();
+ }
+ else if (elementType == typeof(Single))
+ {
+ result = new SingleArrayTypeInfo();
+ }
+ else if (elementType == typeof(IntPtr))
+ {
+ result = new IntPtrArrayTypeInfo();
+ }
+ else if (elementType == typeof(UIntPtr))
+ {
+ result = new UIntPtrArrayTypeInfo();
+ }
+ else if (elementType == typeof(Guid))
+ {
+ result = new GuidArrayTypeInfo();
+ }
+ else
+ {
+ result = (TraceLoggingTypeInfo<DataType>)CreateInstance(
+ typeof(ArrayTypeInfo<>).MakeGenericType(elementType),
+ GetTypeInfoInstance(elementType, recursionCheck));
+ }
+ }
+ else if (Statics.IsEnum(dataType))
+ {
+ var underlyingType = Enum.GetUnderlyingType(dataType);
+ if (underlyingType == typeof(Int32))
+ {
+ result = new EnumInt32TypeInfo<DataType>();
+ }
+ else if (underlyingType == typeof(UInt32))
+ {
+ result = new EnumUInt32TypeInfo<DataType>();
+ }
+ else if (underlyingType == typeof(Byte))
+ {
+ result = new EnumByteTypeInfo<DataType>();
+ }
+ else if (underlyingType == typeof(SByte))
+ {
+ result = new EnumSByteTypeInfo<DataType>();
+ }
+ else if (underlyingType == typeof(Int16))
+ {
+ result = new EnumInt16TypeInfo<DataType>();
+ }
+ else if (underlyingType == typeof(UInt16))
+ {
+ result = new EnumUInt16TypeInfo<DataType>();
+ }
+ else if (underlyingType == typeof(Int64))
+ {
+ result = new EnumInt64TypeInfo<DataType>();
+ }
+ else if (underlyingType == typeof(UInt64))
+ {
+ result = new EnumUInt64TypeInfo<DataType>();
+ }
+ else
+ {
+ // Unexpected
+ throw new NotSupportedException(Environment.GetResourceString("EventSource_NotSupportedEnumType", dataType.Name, underlyingType.Name));
+ }
+ }
+ else if (dataType == typeof(String))
+ {
+ result = new StringTypeInfo();
+ }
+ else if (dataType == typeof(Boolean))
+ {
+ result = new BooleanTypeInfo();
+ }
+ else if (dataType == typeof(Byte))
+ {
+ result = new ByteTypeInfo();
+ }
+ else if (dataType == typeof(SByte))
+ {
+ result = new SByteTypeInfo();
+ }
+ else if (dataType == typeof(Int16))
+ {
+ result = new Int16TypeInfo();
+ }
+ else if (dataType == typeof(UInt16))
+ {
+ result = new UInt16TypeInfo();
+ }
+ else if (dataType == typeof(Int32))
+ {
+ result = new Int32TypeInfo();
+ }
+ else if (dataType == typeof(UInt32))
+ {
+ result = new UInt32TypeInfo();
+ }
+ else if (dataType == typeof(Int64))
+ {
+ result = new Int64TypeInfo();
+ }
+ else if (dataType == typeof(UInt64))
+ {
+ result = new UInt64TypeInfo();
+ }
+ else if (dataType == typeof(Char))
+ {
+ result = new CharTypeInfo();
+ }
+ else if (dataType == typeof(Double))
+ {
+ result = new DoubleTypeInfo();
+ }
+ else if (dataType == typeof(Single))
+ {
+ result = new SingleTypeInfo();
+ }
+ else if (dataType == typeof(DateTime))
+ {
+ result = new DateTimeTypeInfo();
+ }
+ else if (dataType == typeof(Decimal))
+ {
+ result = new DecimalTypeInfo();
+ }
+ else if (dataType == typeof(IntPtr))
+ {
+ result = new IntPtrTypeInfo();
+ }
+ else if (dataType == typeof(UIntPtr))
+ {
+ result = new UIntPtrTypeInfo();
+ }
+ else if (dataType == typeof(Guid))
+ {
+ result = new GuidTypeInfo();
+ }
+ else if (dataType == typeof(TimeSpan))
+ {
+ result = new TimeSpanTypeInfo();
+ }
+ else if (dataType == typeof(DateTimeOffset))
+ {
+ result = new DateTimeOffsetTypeInfo();
+ }
+ else if (dataType == typeof(EmptyStruct))
+ {
+ result = new NullTypeInfo<EmptyStruct>();
+ }
+ else if (IsGenericMatch(dataType, typeof(KeyValuePair<,>)))
+ {
+ var args = GetGenericArguments(dataType);
+ result = (TraceLoggingTypeInfo<DataType>)CreateInstance(
+ typeof(KeyValuePairTypeInfo<,>).MakeGenericType(args[0], args[1]),
+ recursionCheck);
+ }
+ else if (IsGenericMatch(dataType, typeof(Nullable<>)))
+ {
+ var args = GetGenericArguments(dataType);
+ result = (TraceLoggingTypeInfo<DataType>)CreateInstance(
+ typeof(NullableTypeInfo<>).MakeGenericType(args[0]),
+ recursionCheck);
+ }
+ else
+ {
+ var elementType = FindEnumerableElementType(dataType);
+ if (elementType != null)
+ {
+ result = (TraceLoggingTypeInfo<DataType>)CreateInstance(
+ typeof(EnumerableTypeInfo<,>).MakeGenericType(dataType, elementType),
+ GetTypeInfoInstance(elementType, recursionCheck));
+ }
+ else
+ {
+ throw new ArgumentException(Environment.GetResourceString("EventSource_NonCompliantTypeError", dataType.Name));
+ }
+ }
+
+ return (TraceLoggingTypeInfo<DataType>)result;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataCollector.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataCollector.cs
new file mode 100644
index 0000000000..4b8158c0d7
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataCollector.cs
@@ -0,0 +1,394 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Security;
+
+#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>
+ [SecuritySafeCritical]
+ 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;
+ }
+
+ /// <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 an SByte value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ //[CLSCompliant(false)]
+ public void AddScalar(sbyte value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(sbyte));
+ }
+
+ /// <summary>
+ /// Adds a Byte value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ public void AddScalar(byte value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(byte));
+ }
+
+ /// <summary>
+ /// Adds an Int16 value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ public void AddScalar(short value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(short));
+ }
+
+ /// <summary>
+ /// Adds a UInt16 value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ //[CLSCompliant(false)]
+ public void AddScalar(ushort value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(ushort));
+ }
+
+ /// <summary>
+ /// Adds an Int32 value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ public void AddScalar(int value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(int));
+ }
+
+ /// <summary>
+ /// Adds a UInt32 value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ //[CLSCompliant(false)]
+ public void AddScalar(uint value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(uint));
+ }
+
+ /// <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 UInt64 value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ //[CLSCompliant(false)]
+ public void AddScalar(ulong value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(ulong));
+ }
+
+ /// <summary>
+ /// Adds an IntPtr value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ public void AddScalar(IntPtr value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, IntPtr.Size);
+ }
+
+ /// <summary>
+ /// Adds a UIntPtr value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ //[CLSCompliant(false)]
+ public void AddScalar(UIntPtr value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, UIntPtr.Size);
+ }
+
+ /// <summary>
+ /// Adds a Single value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ public void AddScalar(float value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(float));
+ }
+
+ /// <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 Char value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ public void AddScalar(char value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, sizeof(char));
+ }
+
+ /// <summary>
+ /// Adds a Guid value to the event payload.
+ /// </summary>
+ /// <param name="value">Value to be added.</param>
+ public void AddScalar(Guid value)
+ {
+ DataCollector.ThreadInstance.AddScalar(&value, 16);
+ }
+
+ /// <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);
+ }
+
+ /// <summary>
+ /// Adds an array of Byte values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddBinary(byte[] value)
+ {
+ DataCollector.ThreadInstance.AddBinary(value, value == null ? 0 : value.Length);
+ }
+
+ /// <summary>
+ /// Adds an array of Boolean values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(bool[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(bool));
+ }
+
+ /// <summary>
+ /// Adds an array of SByte values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ //[CLSCompliant(false)]
+ public void AddArray(sbyte[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(sbyte));
+ }
+
+ /// <summary>
+ /// Adds an array of Int16 values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(short[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(short));
+ }
+
+ /// <summary>
+ /// Adds an array of UInt16 values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ //[CLSCompliant(false)]
+ public void AddArray(ushort[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(ushort));
+ }
+
+ /// <summary>
+ /// Adds an array of Int32 values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(int[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(int));
+ }
+
+ /// <summary>
+ /// Adds an array of UInt32 values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ //[CLSCompliant(false)]
+ public void AddArray(uint[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(uint));
+ }
+
+ /// <summary>
+ /// Adds an array of Int64 values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(long[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(long));
+ }
+
+ /// <summary>
+ /// Adds an array of UInt64 values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ //[CLSCompliant(false)]
+ public void AddArray(ulong[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(ulong));
+ }
+
+ /// <summary>
+ /// Adds an array of IntPtr values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(IntPtr[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, IntPtr.Size);
+ }
+
+ /// <summary>
+ /// Adds an array of UIntPtr values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ //[CLSCompliant(false)]
+ public void AddArray(UIntPtr[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, UIntPtr.Size);
+ }
+
+ /// <summary>
+ /// Adds an array of Single values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(float[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(float));
+ }
+
+ /// <summary>
+ /// Adds an array of Double values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(double[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(double));
+ }
+
+ /// <summary>
+ /// Adds an array of Char values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(char[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(char));
+ }
+
+ /// <summary>
+ /// Adds an array of Guid values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddArray(Guid[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, 16);
+ }
+
+ /// <summary>
+ /// Adds an array of Byte values to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length array.
+ /// </param>
+ public void AddCustom(byte[] value)
+ {
+ DataCollector.ThreadInstance.AddArray(value, value == null ? 0 : value.Length, sizeof(byte));
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataType.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataType.cs
new file mode 100644
index 0000000000..8e218ba9bf
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingDataType.cs
@@ -0,0 +1,347 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#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 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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventSource.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventSource.cs
new file mode 100644
index 0000000000..7eea8dfaca
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventSource.cs
@@ -0,0 +1,842 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license 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
+#define FEATURE_MANAGED_ETW
+
+#if !ES_BUILD_STANDALONE
+#define FEATURE_ACTIVITYSAMPLING
+#endif
+
+#if ES_BUILD_STANDALONE
+#define FEATURE_MANAGED_ETW_CHANNELS
+// #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
+#endif
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+#endif
+
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Collections.ObjectModel;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+using System.Collections.Generic;
+using System.Text;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+using System.Collections.Generic;
+using System.Text;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+ public partial class EventSource
+ {
+ private byte[] providerMetadata;
+
+ /// <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 interprated 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 ? new Guid() : GenerateGuidFromName(eventSourceName.ToUpperInvariant()),
+ eventSourceName,
+ config, traits)
+ {
+ if (eventSourceName == null)
+ {
+ throw new ArgumentNullException("eventSourceName");
+ }
+ Contract.EndContractBlock();
+ }
+
+ /// <summary>
+ /// Writes an event with no fields and default options.
+ /// (Native API: EventWriteTransfer)
+ /// </summary>
+ /// <param name="eventName">The name of the event. Must not be null.</param>
+ [SecuritySafeCritical]
+ public unsafe void Write(string eventName)
+ {
+ if (eventName == null)
+ {
+ throw new ArgumentNullException("eventName");
+ }
+
+ Contract.EndContractBlock();
+
+ if (!this.IsEnabled())
+ {
+ return;
+ }
+
+ var options = new EventSourceOptions();
+ var data = new EmptyStruct();
+ this.WriteImpl(eventName, ref options, ref data, null, null);
+ }
+
+ /// <summary>
+ /// Writes an event with no fields.
+ /// (Native API: EventWriteTransfer)
+ /// </summary>
+ /// <param name="eventName">The name of the event. Must not be null.</param>
+ /// <param name="options">
+ /// Options for the event, such as the level, keywords, and opcode. Unset
+ /// options will be set to default values.
+ /// </param>
+ [SecuritySafeCritical]
+ public unsafe void Write(string eventName, EventSourceOptions options)
+ {
+ if (eventName == null)
+ {
+ throw new ArgumentNullException("eventName");
+ }
+
+ Contract.EndContractBlock();
+
+ if (!this.IsEnabled())
+ {
+ return;
+ }
+
+ var data = new EmptyStruct();
+ this.WriteImpl(eventName, ref options, ref data, null, null);
+ }
+
+ /// <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>
+ [SecuritySafeCritical]
+ public unsafe void Write<T>(
+ string eventName,
+ T data)
+ {
+ if (!this.IsEnabled())
+ {
+ return;
+ }
+
+ var options = new EventSourceOptions();
+ this.WriteImpl(eventName, ref options, ref data, null, null);
+ }
+
+ /// <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>
+ [SecuritySafeCritical]
+ public unsafe void Write<T>(
+ string eventName,
+ EventSourceOptions options,
+ T data)
+ {
+ if (!this.IsEnabled())
+ {
+ return;
+ }
+
+ this.WriteImpl(eventName, ref options, ref data, null, null);
+ }
+
+ /// <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>
+ [SecuritySafeCritical]
+ public unsafe void Write<T>(
+ string eventName,
+ ref EventSourceOptions options,
+ ref T data)
+ {
+ if (!this.IsEnabled())
+ {
+ return;
+ }
+
+ this.WriteImpl(eventName, ref options, ref data, null, null);
+ }
+
+ /// <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>
+ [SecuritySafeCritical]
+ 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,
+ ref data,
+ pActivity,
+ relatedActivityId == Guid.Empty ? null : pRelated);
+ }
+ }
+
+ /// <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="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>
+ [SecuritySafeCritical]
+ 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="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>
+ [SecuritySafeCritical]
+ private unsafe void WriteMultiMergeInner(
+ string eventName,
+ ref EventSourceOptions options,
+ TraceLoggingEventTypes eventTypes,
+ Guid* activityID,
+ Guid* childActivityID,
+ params object[] values)
+ {
+ 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;
+
+ var nameInfo = eventTypes.GetNameInfo(eventName ?? eventTypes.Name, tags);
+ if (nameInfo == null)
+ {
+ return;
+ }
+ identity = nameInfo.identity;
+ EventDescriptor descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
+
+ var pinCount = eventTypes.pinCount;
+ var scratch = stackalloc byte[eventTypes.scratchSize];
+ var descriptors = stackalloc EventData[eventTypes.dataCount + 3];
+ var pins = stackalloc GCHandle[pinCount];
+
+ 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
+ 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++)
+ {
+ eventTypes.typeInfos[i].WriteObjectData(TraceLoggingDataCollector.Instance, values[i]);
+ }
+
+ this.WriteEventRaw(
+ ref descriptor,
+ activityID,
+ childActivityID,
+ (int)(DataCollector.ThreadInstance.Finish() - descriptors),
+ (IntPtr)descriptors);
+ }
+ finally
+ {
+ this.WriteCleanup(pins, pinCount);
+ }
+ }
+
+ }
+
+ /// <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="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>
+ [SecuritySafeCritical]
+ internal unsafe void WriteMultiMerge(
+ string eventName,
+ ref EventSourceOptions options,
+ TraceLoggingEventTypes eventTypes,
+ Guid* activityID,
+ Guid* childActivityID,
+ EventData* data)
+ {
+ if (!this.IsEnabled())
+ {
+ return;
+ }
+
+ fixed (EventSourceOptions* pOptions = &options)
+ {
+ EventDescriptor descriptor;
+ var nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
+ if (nameInfo == null)
+ {
+ return;
+ }
+
+ // 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.
+ var descriptors = stackalloc EventData[eventTypes.dataCount + eventTypes.typeInfos.Length * 2 + 3];
+
+ 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++)
+ {
+ // Until M3, we need to morph strings to a counted representation
+ // When TDH supports null terminated strings, we can remove this.
+ if (eventTypes.typeInfos[i].DataType == typeof(string))
+ {
+ // Write out the size of the string
+ descriptors[numDescrs].m_Ptr = (long)&descriptors[numDescrs + 1].m_Size;
+ descriptors[numDescrs].m_Size = 2;
+ numDescrs++;
+
+ descriptors[numDescrs].m_Ptr = data[i].m_Ptr;
+ descriptors[numDescrs].m_Size = data[i].m_Size - 2; // Remove the null terminator
+ numDescrs++;
+ }
+ else
+ {
+ 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(
+ ref descriptor,
+ activityID,
+ childActivityID,
+ numDescrs,
+ (IntPtr)descriptors);
+ }
+ }
+ }
+
+ [SecuritySafeCritical]
+ private unsafe void WriteImpl<T>(
+ string eventName,
+ ref EventSourceOptions options,
+ ref T data,
+ Guid* pActivityId,
+ Guid* pRelatedActivityId)
+ {
+ try
+ {
+ var eventTypes = SimpleEventTypes<T>.Instance;
+
+ fixed (EventSourceOptions* pOptions = &options)
+ {
+ EventDescriptor descriptor;
+ options.Opcode = options.IsOpcodeSet ? options.Opcode : GetOpcodeWithDefault(options.Opcode, eventName);
+ var nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
+ if (nameInfo == null)
+ {
+ return;
+ }
+
+ var pinCount = eventTypes.pinCount;
+ var scratch = stackalloc byte[eventTypes.scratchSize];
+ var descriptors = stackalloc EventData[eventTypes.dataCount + 3];
+ var pins = stackalloc GCHandle[pinCount];
+
+ 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
+ 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)
+ {
+ m_activityTracker.OnStart(m_name, eventName, 0, ref activityId, ref relatedActivityId, options.ActivityOptions);
+ }
+ else if (opcode == EventOpcode.Stop)
+ {
+ m_activityTracker.OnStop(m_name, eventName, 0, ref activityId);
+ }
+ if (activityId != Guid.Empty)
+ pActivityId = &activityId;
+ if (relatedActivityId != Guid.Empty)
+ pRelatedActivityId = &relatedActivityId;
+ }
+
+ try
+ {
+ DataCollector.ThreadInstance.Enable(
+ scratch,
+ eventTypes.scratchSize,
+ descriptors + 3,
+ eventTypes.dataCount,
+ pins,
+ pinCount);
+
+ eventTypes.typeInfo.WriteData(TraceLoggingDataCollector.Instance, ref data);
+
+ this.WriteEventRaw(
+ ref descriptor,
+ pActivityId,
+ pRelatedActivityId,
+ (int)(DataCollector.ThreadInstance.Finish() - descriptors),
+ (IntPtr)descriptors);
+
+ // TODO enable filtering for listners.
+ if (m_Dispatchers != null)
+ {
+ var eventData = (EventPayload)(eventTypes.typeInfo.GetData(data));
+ WriteToAllListeners(eventName, pActivityId, eventData);
+ }
+
+ }
+ catch(Exception ex)
+ {
+ if (ex is EventSourceException)
+ throw;
+ else
+ ThrowEventSourceException(ex);
+ }
+ finally
+ {
+ this.WriteCleanup(pins, pinCount);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (ex is EventSourceException)
+ throw;
+ else
+ ThrowEventSourceException(ex);
+ }
+ }
+
+ [SecurityCritical]
+ private unsafe void WriteToAllListeners(string eventName, Guid* pActivityId, EventPayload payload)
+ {
+ EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
+ eventCallbackArgs.EventName = eventName;
+
+ // Self described events do not have an id attached. We mark it internally with -1.
+ eventCallbackArgs.EventId = -1;
+ if (pActivityId != null)
+ eventCallbackArgs.RelatedActivityId = *pActivityId;
+
+ if (payload != null)
+ {
+ eventCallbackArgs.Payload = new ReadOnlyCollection<object>((IList<object>)payload.Values);
+ eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>((IList<string>)payload.Keys);
+ }
+
+ DisptachToAllListeners(-1, pActivityId, eventCallbackArgs);
+ }
+
+#if !ES_BUILD_PCL
+ [System.Runtime.ConstrainedExecution.ReliabilityContract(
+ System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState,
+ System.Runtime.ConstrainedExecution.Cer.Success)]
+#endif
+ [SecurityCritical]
+ [NonEvent]
+ private unsafe void WriteCleanup(GCHandle* pPins, int cPins)
+ {
+ DataCollector.ThreadInstance.Disable();
+
+ for (int i = 0; i != cPins; i++)
+ {
+ if (IntPtr.Zero != (IntPtr)pPins[i])
+ {
+ pPins[i].Free();
+ }
+ }
+ }
+
+ private void InitializeProviderMetadata()
+ {
+ 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_"))
+ {
+ string etwTrait = m_traits[i].Substring(4);
+ byte traitNum;
+ if (!byte.TryParse(etwTrait, out traitNum))
+ {
+ if (etwTrait == "GROUP")
+ traitNum = 1;
+ else
+ throw new ArgumentException(Environment.GetResourceString("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
+ var 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 (var b in traitMetaData)
+ providerMetadata[startPos++] = b;
+ }
+ else
+ providerMetadata = Statics.MetadataForString(this.Name, 0, 0, 0);
+ }
+
+ 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] != ' ') // Skp spaces between bytes.
+ {
+ if (!(i + 1 < value.Length))
+ throw new ArgumentException(Environment.GetResourceString("EvenHexDigits"), "traits");
+ metaData.Add((byte)(HexDigit(value[i]) * 16 + HexDigit(value[i + 1])));
+ i++;
+ }
+ }
+ }
+ else if (' ' <= firstChar) // Is it alphabetic (excludes digits and most punctuation.
+ metaData.AddRange(Encoding.UTF8.GetBytes(value));
+ else
+ throw new ArgumentException(Environment.GetResourceString("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(Environment.GetResourceString("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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTraits.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTraits.cs
new file mode 100644
index 0000000000..6c5a5793bb
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTraits.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#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/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTypes.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTypes.cs
new file mode 100644
index 0000000000..8e2732b0ff
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingEventTypes.cs
@@ -0,0 +1,260 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Collections.Generic;
+using Interlocked = System.Threading.Interlocked;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#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>
+ internal class TraceLoggingEventTypes
+ {
+ internal readonly TraceLoggingTypeInfo[] typeInfos;
+ 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))
+ {
+ return;
+ }
+
+ /// <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))
+ {
+ return;
+ }
+
+ internal TraceLoggingEventTypes(
+ string name,
+ EventTags tags,
+ System.Reflection.ParameterInfo[] paramInfos)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ Contract.EndContractBlock();
+
+ this.typeInfos = MakeArray(paramInfos);
+ this.name = name;
+ this.tags = tags;
+ this.level = Statics.DefaultLevel;
+
+ var collector = new TraceLoggingMetadataCollector();
+ for (int i = 0; i < typeInfos.Length; ++i)
+ {
+ var 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;
+ var 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("defaultName");
+ }
+
+ Contract.EndContractBlock();
+
+ this.typeInfos = typeInfos;
+ this.name = defaultName;
+ this.tags = tags;
+ this.level = Statics.DefaultLevel;
+
+ var collector = new TraceLoggingMetadataCollector();
+ foreach (var 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
+ {
+ get { return this.name; }
+ }
+
+ /// <summary>
+ /// Gets the default level that will be used for events with this descriptor.
+ /// </summary>
+ internal EventLevel Level
+ {
+ get { return (EventLevel)this.level; }
+ }
+
+ /// <summary>
+ /// Gets the default opcode that will be used for events with this descriptor.
+ /// </summary>
+ internal EventOpcode Opcode
+ {
+ get { return (EventOpcode)this.opcode; }
+ }
+
+ /// <summary>
+ /// Gets the default set of keywords that will added to events with this descriptor.
+ /// </summary>
+ internal EventKeywords Keywords
+ {
+ get { return (EventKeywords)this.keywords; }
+ }
+
+ /// <summary>
+ /// Gets the default tags that will be added events with this descriptor.
+ /// </summary>
+ internal EventTags Tags
+ {
+ get { return this.tags; }
+ }
+
+ internal NameInfo GetNameInfo(string name, EventTags tags)
+ {
+ var ret = this.nameInfos.TryGet(new KeyValuePair<string, EventTags>(name, tags));
+ if (ret == null)
+ {
+ ret = this.nameInfos.GetOrAdd(new NameInfo(name, tags, this.typeMetadata.Length));
+ }
+
+ return ret;
+ }
+
+ private TraceLoggingTypeInfo[] MakeArray(System.Reflection.ParameterInfo[] paramInfos)
+ {
+ if (paramInfos == null)
+ {
+ throw new ArgumentNullException("paramInfos");
+ }
+
+ Contract.EndContractBlock();
+
+ var recursionCheck = new List<Type>(paramInfos.Length);
+ var result = new TraceLoggingTypeInfo[paramInfos.Length];
+ for (int i = 0; i < paramInfos.Length; ++i)
+ {
+ result[i] = Statics.GetTypeInfoInstance(paramInfos[i].ParameterType, recursionCheck);
+ }
+
+ return result;
+ }
+
+ private static TraceLoggingTypeInfo[] MakeArray(Type[] types)
+ {
+ if (types == null)
+ {
+ throw new ArgumentNullException("types");
+ }
+
+ Contract.EndContractBlock();
+
+ var recursionCheck = new List<Type>(types.Length);
+ var result = new TraceLoggingTypeInfo[types.Length];
+ for (int i = 0; i < types.Length; i++)
+ {
+ result[i] = Statics.GetTypeInfoInstance(types[i], recursionCheck);
+ }
+
+ return result;
+ }
+
+ private static TraceLoggingTypeInfo[] MakeArray(
+ TraceLoggingTypeInfo[] typeInfos)
+ {
+ if (typeInfos == null)
+ {
+ throw new ArgumentNullException("typeInfos");
+ }
+
+ Contract.EndContractBlock();
+
+ return (TraceLoggingTypeInfo[])typeInfos.Clone(); ;
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingMetadataCollector.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingMetadataCollector.cs
new file mode 100644
index 0000000000..1101439d66
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingMetadataCollector.cs
@@ -0,0 +1,368 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Collections.Generic;
+
+#if ES_BUILD_STANDALONE
+using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
+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
+ {
+ get { return this.impl.scratchSize; }
+ }
+
+ internal int DataCount
+ {
+ get { return this.impl.dataCount; }
+ }
+
+ internal int PinCount
+ {
+ get { return this.impl.pinCount; }
+ }
+
+ private bool BeginningBufferedArray
+ {
+ get { return 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,
+ 0,
+ 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("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("type");
+ }
+
+ this.impl.AddScalar(2);
+ 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
+ /// or a string type. In the case of a string type, this adds an array
+ /// of characters, not an array of strings.
+ /// </param>
+ public void AddArray(string name, TraceLoggingDataType type)
+ {
+ switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
+ {
+ case TraceLoggingDataType.Utf16String:
+ case TraceLoggingDataType.MbcsString:
+ 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("type");
+ }
+
+ if (this.BeginningBufferedArray)
+ {
+ throw new NotSupportedException(Environment.GetResourceString("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(Environment.GetResourceString("EventSource_NotSupportedNestedArraysEnums"));
+ }
+
+ this.bufferedArrayFieldCount = 0;
+ this.impl.BeginBuffered();
+ }
+
+ public void EndBufferedArray()
+ {
+ if (this.bufferedArrayFieldCount != 1)
+ {
+ throw new InvalidOperationException(Environment.GetResourceString("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(Environment.GetResourceString("EventSource_NotSupportedCustomSerializedData"));
+ }
+
+ this.impl.AddScalar(2);
+ this.impl.AddNonscalar();
+ this.AddField(new FieldMetadata(
+ name,
+ type,
+ this.Tags,
+ metadata));
+ }
+
+ internal byte[] GetMetadata()
+ {
+ var 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 (var field in this.fields)
+ {
+ field.Encode(ref size, metadata);
+ }
+
+ return size;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo.cs
new file mode 100644
index 0000000000..326af51c10
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo.cs
@@ -0,0 +1,178 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#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;
+
+ internal TraceLoggingTypeInfo(Type dataType)
+ {
+ if (dataType == null)
+ {
+ throw new ArgumentNullException("dataType");
+ }
+
+ Contract.EndContractBlock();
+
+ this.name = dataType.Name;
+ this.dataType = dataType;
+ }
+
+ internal TraceLoggingTypeInfo(
+ Type dataType,
+ string name,
+ EventLevel level,
+ EventOpcode opcode,
+ EventKeywords keywords,
+ EventTags tags)
+ {
+ if (dataType == null)
+ {
+ throw new ArgumentNullException("dataType");
+ }
+
+ if (name == null)
+ {
+ throw new ArgumentNullException("eventName");
+ }
+
+ Contract.EndContractBlock();
+
+ Statics.CheckName(name);
+
+ this.name = name;
+ this.keywords = keywords;
+ this.level = level;
+ this.opcode = opcode;
+ this.tags = tags;
+ this.dataType = 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
+ {
+ get { return 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
+ {
+ get { return 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
+ {
+ get { return this.opcode; }
+ }
+
+ /// <summary>
+ /// Gets the keyword(s) associated with this type.
+ /// </summary>
+ public EventKeywords Keywords
+ {
+ get { return this.keywords; }
+ }
+
+ /// <summary>
+ /// Gets the event tags associated with this type.
+ /// </summary>
+ public EventTags Tags
+ {
+ get { return this.tags; }
+ }
+
+ internal Type DataType
+ {
+ get { return this.dataType; }
+ }
+
+ /// <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 WriteObjectData(
+ TraceLoggingDataCollector collector,
+ object 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;
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo_T.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo_T.cs
new file mode 100644
index 0000000000..b93aab9d65
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TraceLoggingTypeInfo_T.cs
@@ -0,0 +1,160 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+using System.Collections.Generic;
+using Interlocked = System.Threading.Interlocked;
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
+namespace System.Diagnostics.Tracing
+#endif
+{
+ /// <summary>
+ /// TraceLogging: used when implementing a custom TraceLoggingTypeInfo.
+ /// Implementations of this type provide the behaviors that TraceLogging
+ /// uses to turn objects into event data. TraceLogging provides default
+ /// implementations of this type, but custom implementations can be used
+ /// when the default TraceLogging implementation is insufficient.
+ /// </summary>
+ /// <typeparam name="DataType">
+ /// The type of object that is handled by this implementation.
+ /// </typeparam>
+ internal abstract class TraceLoggingTypeInfo<DataType>
+ : TraceLoggingTypeInfo
+ {
+ private static TraceLoggingTypeInfo<DataType> instance;
+
+ /// <summary>
+ /// Initializes a new instance of the TraceLoggingTypeInfo class with
+ /// default settings. Uses typeof(DataType).Name for EventName and FieldName.
+ /// Marks Level and Opcode as unset. Sets Keywords and Traits to 0.
+ /// </summary>
+ protected TraceLoggingTypeInfo()
+ : base(typeof(DataType))
+ {
+ return;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the TraceLoggingTypeInfo class, using
+ /// the specified values for the EventName, Level, Opcode, Keywords,
+ /// FieldName, and Traits properties.
+ /// </summary>
+ /// <param name="name">
+ /// The value for the Name property. Must not contain '\0' characters.
+ /// Must not be null.
+ /// </param>
+ /// <param name="level">
+ /// The value for the Level property, or -1 to mark Level as unset.
+ /// </param>
+ /// <param name="opcode">
+ /// The value for the Opcode property, or -1 to mark Opcode as unset.
+ /// </param>
+ /// <param name="keywords">
+ /// The value for the Keywords property.
+ /// </param>
+ /// <param name="tags">
+ /// The value for the Tags property.
+ /// </param>
+ protected TraceLoggingTypeInfo(
+ string name,
+ EventLevel level,
+ EventOpcode opcode,
+ EventKeywords keywords,
+ EventTags tags)
+ : base(
+ typeof(DataType),
+ name,
+ level,
+ opcode,
+ keywords,
+ tags)
+ {
+ return;
+ }
+
+ /// <summary>
+ /// Gets the type info that will be used for handling instances of
+ /// DataType. If the instance has not already been set, this will
+ /// call TrySetInstance(automaticSerializer) to set one, where
+ /// automaticSerializer is the value returned from CreateDefault(),
+ /// or a do-nothing serializer if CreateDefault() fails.
+ /// </summary>
+ public static TraceLoggingTypeInfo<DataType> Instance
+ {
+ get
+ {
+ return instance ?? InitInstance();
+ }
+ }
+
+ /// <summary>
+ /// When overridden by a derived class, writes the data (fields) for an instance
+ /// of DataType. Note that the sequence of operations in WriteData should be
+ /// essentially identical to the sequence of operations in WriteMetadata. Otherwise,
+ /// the metadata and data will not match, which may cause trouble when decoding the
+ /// event.
+ /// </summary>
+ /// <param name="collector">
+ /// The object that collects the data for the instance. Data 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 WriteData method
+ /// for the sub-object, e.g. by calling
+ /// TraceLoggingTypeInfo&lt;SubType&gt;.Instance.WriteData(...).
+ /// </param>
+ /// <param name="value">
+ /// The value for which data is to be written.
+ /// </param>
+ public abstract void WriteData(
+ TraceLoggingDataCollector collector,
+ ref DataType value);
+
+ /// <summary>
+ /// When overridden in a derived class, writes the data (fields) for an instance
+ /// of DataType. The default implementation of WriteObjectData calls
+ /// WriteData(collector, (DataType)value). Normally, you will override WriteData
+ /// and not WriteObjectData. However, if your implementation of WriteData has to
+ /// cast the value to object, it may be more efficient to reverse this calling
+ /// pattern, i.e. to implement WriteObjectData, and then implement WriteData as a
+ /// call to WriteObjectData.
+ /// </summary>
+ /// <param name="collector">
+ /// The object that collects the data for the instance. Data 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 WriteData method
+ /// for the sub-object, e.g. by calling
+ /// TraceLoggingTypeInfo&lt;SubType&gt;.Instance.WriteData(...).
+ /// </param>
+ /// <param name="value">
+ /// The value for which data is to be written. Note that this value may be null
+ /// (even for value types) if the property from which the value was read is
+ /// missing or null.
+ /// </param>
+ public override void WriteObjectData(
+ TraceLoggingDataCollector collector,
+ object value)
+ {
+ var val = value == null ? default(DataType) : (DataType)value;
+ this.WriteData(collector, ref val);
+ }
+
+ internal static TraceLoggingTypeInfo<DataType> GetInstance(List<Type> recursionCheck)
+ {
+ if (instance == null)
+ {
+ var recursionCheckCount = recursionCheck.Count;
+ var newInstance = Statics.CreateDefaultTypeInfo<DataType>(recursionCheck);
+ Interlocked.CompareExchange(ref instance, newInstance, null);
+ recursionCheck.RemoveRange(recursionCheckCount, recursionCheck.Count - recursionCheckCount);
+ }
+
+ return instance;
+ }
+
+ private static TraceLoggingTypeInfo<DataType> InitInstance()
+ {
+ return GetInstance(new List<Type>());
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TypeAnalysis.cs b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TypeAnalysis.cs
new file mode 100644
index 0000000000..404fdadc31
--- /dev/null
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/TraceLogging/TypeAnalysis.cs
@@ -0,0 +1,101 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
+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)
+ {
+ var propertyInfos = Statics.GetProperties(dataType);
+ var propertyList = new List<PropertyAnalysis>();
+
+ foreach (var 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;
+ }
+
+ var propertyType = propertyInfo.PropertyType;
+ var propertyTypeInfo = Statics.GetTypeInfoInstance(propertyType, recursionCheck);
+ var 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,
+ getterInfo,
+ propertyTypeInfo,
+ fieldAttribute));
+ }
+
+ this.properties = propertyList.ToArray();
+
+ foreach (var property in this.properties)
+ {
+ var 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;
+ }
+ }
+ }
+}