1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 using System
.Collections
.Generic
;
8 #if !ES_BUILD_AGAINST_DOTNET_V35
9 using Contract
= System
.Diagnostics
.Contracts
.Contract
;
11 using Contract
= Microsoft
.Diagnostics
.Contracts
.Internal
.Contract
;
14 #if ES_BUILD_STANDALONE
15 namespace Microsoft
.Diagnostics
.Tracing
17 namespace System
.Diagnostics
.Tracing
21 /// TraceLogging: used when implementing a custom TraceLoggingTypeInfo.
22 /// Non-generic base class for TraceLoggingTypeInfo<DataType>. Do not derive
23 /// from this class. Instead, derive from TraceLoggingTypeInfo<DataType>.
25 internal abstract class TraceLoggingTypeInfo
27 private readonly string name
;
28 private readonly EventKeywords keywords
;
29 private readonly EventLevel level
= (EventLevel
)(-1);
30 private readonly EventOpcode opcode
= (EventOpcode
)(-1);
31 private readonly EventTags tags
;
32 private readonly Type dataType
;
33 private readonly Func
<object?, PropertyValue
> propertyValueFactory
;
35 internal TraceLoggingTypeInfo(Type dataType
)
39 throw new ArgumentNullException(nameof(dataType
));
42 this.name
= dataType
.Name
;
43 this.dataType
= dataType
;
44 this.propertyValueFactory
= PropertyValue
.GetFactory(dataType
);
47 internal TraceLoggingTypeInfo(
52 EventKeywords keywords
,
57 throw new ArgumentNullException(nameof(dataType
));
62 throw new ArgumentNullException(nameof(name
));
65 Statics
.CheckName(name
);
68 this.keywords
= keywords
;
72 this.dataType
= dataType
;
73 this.propertyValueFactory
= PropertyValue
.GetFactory(dataType
);
77 /// Gets the name to use for the event if this type is the top-level type,
78 /// or the name to use for an implicitly-named field.
81 public string Name
=> this.name
;
84 /// Gets the event level associated with this type. Any value in the range 0..255
85 /// is an associated event level. Any value outside the range 0..255 is invalid and
86 /// indicates that this type has no associated event level.
88 public EventLevel Level
=> this.level
;
91 /// Gets the event opcode associated with this type. Any value in the range 0..255
92 /// is an associated event opcode. Any value outside the range 0..255 is invalid and
93 /// indicates that this type has no associated event opcode.
95 public EventOpcode Opcode
=> this.opcode
;
98 /// Gets the keyword(s) associated with this type.
100 public EventKeywords Keywords
=> this.keywords
;
103 /// Gets the event tags associated with this type.
105 public EventTags Tags
=> this.tags
;
107 internal Type DataType
=> this.dataType
;
109 internal Func
<object?, PropertyValue
> PropertyValueFactory
=> this.propertyValueFactory
;
112 /// When overridden by a derived class, writes the metadata (schema) for
113 /// this type. Note that the sequence of operations in WriteMetadata should be
114 /// essentially identical to the sequence of operations in
115 /// WriteData/WriteObjectData. Otherwise, the metadata and data will not match,
116 /// which may cause trouble when decoding the event.
118 /// <param name="collector">
119 /// The object that collects metadata for this object's type. Metadata is written
120 /// by calling methods on the collector object. Note that if the type contains
121 /// sub-objects, the implementation of this method may need to call the
122 /// WriteMetadata method for the type of the sub-object, e.g. by calling
123 /// TraceLoggingTypeInfo<SubType>.Instance.WriteMetadata(...).
125 /// <param name="name">
126 /// The name of the property that contains an object of this type, or null if this
127 /// object is being written as a top-level object of an event. Typical usage
128 /// is to pass this value to collector.AddGroup.
130 /// <param name="format">
131 /// The format attribute for the field that contains an object of this type.
133 public abstract void WriteMetadata(
134 TraceLoggingMetadataCollector collector
,
136 EventFieldFormat format
);
139 /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
142 /// <param name="collector">
143 /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
146 /// <param name="value">
147 /// Refer to TraceLoggingTypeInfo.WriteObjectData for information about this
150 public abstract void WriteData(
151 TraceLoggingDataCollector collector
,
152 PropertyValue
value);
155 /// Fetches the event parameter data for internal serialization.
157 /// <param name="value"></param>
158 /// <returns></returns>
159 public virtual object? GetData(object? value)
164 [ThreadStatic
] // per-thread cache to avoid synchronization
165 private static Dictionary
<Type
, TraceLoggingTypeInfo
>? threadCache
;
167 public static TraceLoggingTypeInfo
GetInstance(Type type
, List
<Type
>? recursionCheck
)
169 Dictionary
<Type
, TraceLoggingTypeInfo
> cache
= threadCache
?? (threadCache
= new Dictionary
<Type
, TraceLoggingTypeInfo
>());
171 TraceLoggingTypeInfo
? instance
;
172 if (!cache
.TryGetValue(type
, out instance
))
174 if (recursionCheck
== null)
175 recursionCheck
= new List
<Type
>();
176 int recursionCheckCount
= recursionCheck
.Count
;
177 instance
= Statics
.CreateDefaultTypeInfo(type
, recursionCheck
);
178 cache
[type
] = instance
;
179 recursionCheck
.RemoveRange(recursionCheckCount
, recursionCheck
.Count
- recursionCheckCount
);