// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;
#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
{
///
/// TraceLogging: Type handler for empty or unsupported types.
///
internal sealed class NullTypeInfo : TraceLoggingTypeInfo
{
public NullTypeInfo() : base(typeof(EmptyStruct)) { }
public override void WriteMetadata(
TraceLoggingMetadataCollector collector,
string name,
EventFieldFormat format)
{
collector.AddGroup(name);
}
public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
{
return;
}
public override object GetData(object value)
{
return null;
}
}
///
/// Type handler for simple scalar types.
///
sealed class ScalarTypeInfo : TraceLoggingTypeInfo
{
Func formatFunc;
TraceLoggingDataType nativeFormat;
private ScalarTypeInfo(
Type type,
Func formatFunc,
TraceLoggingDataType nativeFormat)
: base(type)
{
this.formatFunc = formatFunc;
this.nativeFormat = nativeFormat;
}
public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format)
{
collector.AddScalar(name, formatFunc(format, nativeFormat));
}
public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
{
collector.AddScalar(value);
}
public static TraceLoggingTypeInfo Boolean() { return new ScalarTypeInfo(typeof(Boolean), Statics.Format8, TraceLoggingDataType.Boolean8); }
public static TraceLoggingTypeInfo Byte() { return new ScalarTypeInfo(typeof(Byte), Statics.Format8, TraceLoggingDataType.UInt8); }
public static TraceLoggingTypeInfo SByte() { return new ScalarTypeInfo(typeof(SByte), Statics.Format8, TraceLoggingDataType.Int8); }
public static TraceLoggingTypeInfo Char() { return new ScalarTypeInfo(typeof(Char), Statics.Format16, TraceLoggingDataType.Char16); }
public static TraceLoggingTypeInfo Int16() { return new ScalarTypeInfo(typeof(Int16), Statics.Format16, TraceLoggingDataType.Int16); }
public static TraceLoggingTypeInfo UInt16() { return new ScalarTypeInfo(typeof(UInt16), Statics.Format16, TraceLoggingDataType.UInt16); }
public static TraceLoggingTypeInfo Int32() { return new ScalarTypeInfo(typeof(Int32), Statics.Format32, TraceLoggingDataType.Int32); }
public static TraceLoggingTypeInfo UInt32() { return new ScalarTypeInfo(typeof(UInt32), Statics.Format32, TraceLoggingDataType.UInt32); }
public static TraceLoggingTypeInfo Int64() { return new ScalarTypeInfo(typeof(Int64), Statics.Format64, TraceLoggingDataType.Int64); }
public static TraceLoggingTypeInfo UInt64() { return new ScalarTypeInfo(typeof(UInt64), Statics.Format64, TraceLoggingDataType.UInt64); }
public static TraceLoggingTypeInfo IntPtr() { return new ScalarTypeInfo(typeof(IntPtr), Statics.FormatPtr, Statics.IntPtrType); }
public static TraceLoggingTypeInfo UIntPtr() { return new ScalarTypeInfo(typeof(UIntPtr), Statics.FormatPtr, Statics.UIntPtrType); }
public static TraceLoggingTypeInfo Single() { return new ScalarTypeInfo(typeof(Single), Statics.Format32, TraceLoggingDataType.Float); }
public static TraceLoggingTypeInfo Double() { return new ScalarTypeInfo(typeof(Double), Statics.Format64, TraceLoggingDataType.Double); }
public static TraceLoggingTypeInfo Guid() { return new ScalarTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid); }
}
///
/// Type handler for arrays of scalars
///
internal sealed class ScalarArrayTypeInfo : TraceLoggingTypeInfo
{
Func formatFunc;
TraceLoggingDataType nativeFormat;
int elementSize;
private ScalarArrayTypeInfo(
Type type,
Func formatFunc,
TraceLoggingDataType nativeFormat,
int elementSize)
: base(type)
{
this.formatFunc = formatFunc;
this.nativeFormat = nativeFormat;
this.elementSize = elementSize;
}
public override void WriteMetadata(TraceLoggingMetadataCollector collector, string name, EventFieldFormat format)
{
collector.AddArray(name, formatFunc(format, nativeFormat));
}
public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
{
collector.AddArray(value, elementSize);
}
public static TraceLoggingTypeInfo Boolean() { return new ScalarArrayTypeInfo(typeof(Boolean[]), Statics.Format8, TraceLoggingDataType.Boolean8, sizeof(Boolean)); }
public static TraceLoggingTypeInfo Byte() { return new ScalarArrayTypeInfo(typeof(Byte[]), Statics.Format8, TraceLoggingDataType.UInt8, sizeof(Byte)); }
public static TraceLoggingTypeInfo SByte() { return new ScalarArrayTypeInfo(typeof(SByte[]), Statics.Format8, TraceLoggingDataType.Int8, sizeof(SByte)); }
public static TraceLoggingTypeInfo Char() { return new ScalarArrayTypeInfo(typeof(Char[]), Statics.Format16, TraceLoggingDataType.Char16, sizeof(Char)); }
public static TraceLoggingTypeInfo Int16() { return new ScalarArrayTypeInfo(typeof(Int16[]), Statics.Format16, TraceLoggingDataType.Int16, sizeof(Int16)); }
public static TraceLoggingTypeInfo UInt16() { return new ScalarArrayTypeInfo(typeof(UInt16[]), Statics.Format16, TraceLoggingDataType.UInt16, sizeof(UInt16)); }
public static TraceLoggingTypeInfo Int32() { return new ScalarArrayTypeInfo(typeof(Int32[]), Statics.Format32, TraceLoggingDataType.Int32, sizeof(Int32)); }
public static TraceLoggingTypeInfo UInt32() { return new ScalarArrayTypeInfo(typeof(UInt32[]), Statics.Format32, TraceLoggingDataType.UInt32, sizeof(UInt32)); }
public static TraceLoggingTypeInfo Int64() { return new ScalarArrayTypeInfo(typeof(Int64[]), Statics.Format64, TraceLoggingDataType.Int64, sizeof(Int64)); }
public static TraceLoggingTypeInfo UInt64() { return new ScalarArrayTypeInfo(typeof(UInt64[]), Statics.Format64, TraceLoggingDataType.UInt64, sizeof(UInt64)); }
public static TraceLoggingTypeInfo IntPtr() { return new ScalarArrayTypeInfo(typeof(IntPtr[]), Statics.FormatPtr, Statics.IntPtrType, System.IntPtr.Size); }
public static TraceLoggingTypeInfo UIntPtr() { return new ScalarArrayTypeInfo(typeof(UIntPtr[]), Statics.FormatPtr, Statics.UIntPtrType, System.IntPtr.Size); }
public static TraceLoggingTypeInfo Single() { return new ScalarArrayTypeInfo(typeof(Single[]), Statics.Format32, TraceLoggingDataType.Float, sizeof(Single)); }
public static TraceLoggingTypeInfo Double() { return new ScalarArrayTypeInfo(typeof(Double[]), Statics.Format64, TraceLoggingDataType.Double, sizeof(Double)); }
public unsafe static TraceLoggingTypeInfo Guid() { return new ScalarArrayTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid, sizeof(Guid)); }
}
///
/// TraceLogging: Type handler for String.
///
internal sealed class StringTypeInfo : TraceLoggingTypeInfo
{
public StringTypeInfo() : base(typeof(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, PropertyValue value)
{
collector.AddBinary((string)value.ReferenceValue);
}
public override object GetData(object value)
{
if(value == null)
{
return "";
}
return value;
}
}
///
/// TraceLogging: Type handler for DateTime.
///
internal sealed class DateTimeTypeInfo : TraceLoggingTypeInfo
{
public DateTimeTypeInfo() : base(typeof(DateTime)) { }
public override void WriteMetadata(
TraceLoggingMetadataCollector collector,
string name,
EventFieldFormat format)
{
collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.FileTime, format));
}
public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
{
var ticks = value.ScalarValue.AsDateTime.Ticks;
collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000);
}
}
///
/// TraceLogging: Type handler for DateTimeOffset.
///
internal sealed class DateTimeOffsetTypeInfo : TraceLoggingTypeInfo
{
public DateTimeOffsetTypeInfo() : base(typeof(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, PropertyValue value)
{
var dateTimeOffset = value.ScalarValue.AsDateTimeOffset;
var ticks = dateTimeOffset.Ticks;
collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000);
collector.AddScalar(dateTimeOffset.Offset.Ticks);
}
}
///
/// TraceLogging: Type handler for TimeSpan.
///
internal sealed class TimeSpanTypeInfo : TraceLoggingTypeInfo
{
public TimeSpanTypeInfo() : base(typeof(TimeSpan)) { }
public override void WriteMetadata(
TraceLoggingMetadataCollector collector,
string name,
EventFieldFormat format)
{
collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Int64, format));
}
public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
{
collector.AddScalar(value.ScalarValue.AsTimeSpan.Ticks);
}
}
///
/// TraceLogging: Type handler for Decimal. (Note: not full-fidelity, exposed as Double.)
///
internal sealed class DecimalTypeInfo : TraceLoggingTypeInfo
{
public DecimalTypeInfo() : base(typeof(Decimal)) { }
public override void WriteMetadata(
TraceLoggingMetadataCollector collector,
string name,
EventFieldFormat format)
{
collector.AddScalar(name, Statics.MakeDataType(TraceLoggingDataType.Double, format));
}
public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
{
collector.AddScalar((double)value.ScalarValue.AsDecimal);
}
}
///
/// TraceLogging: Type handler for Nullable.
///
internal sealed class NullableTypeInfo : TraceLoggingTypeInfo
{
private readonly TraceLoggingTypeInfo valueInfo;
private readonly Func hasValueGetter;
private readonly Func valueGetter;
public NullableTypeInfo(Type type, List recursionCheck)
: base(type)
{
var typeArgs = type.GenericTypeArguments;
Debug.Assert(typeArgs.Length == 1);
this.valueInfo = TraceLoggingTypeInfo.GetInstance(typeArgs[0], recursionCheck);
this.hasValueGetter = PropertyValue.GetPropertyGetter(type.GetTypeInfo().GetDeclaredProperty("HasValue"));
this.valueGetter = PropertyValue.GetPropertyGetter(type.GetTypeInfo().GetDeclaredProperty("Value"));
}
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, PropertyValue value)
{
var hasValue = hasValueGetter(value);
collector.AddScalar(hasValue);
var val = hasValue.ScalarValue.AsBoolean ? valueGetter(value) : valueInfo.PropertyValueFactory(Activator.CreateInstance(valueInfo.DataType));
this.valueInfo.WriteData(collector, val);
}
}
}