/WCFWebApi/src/Microsoft.Server.Common/Microsoft/Server/Common/Diagnostics/DiagnosticEventProvider.cs
C# | 883 lines | 676 code | 73 blank | 134 comment | 149 complexity | aaed747b6a03d0f41415c779f1b6d62d MD5 | raw file
Possible License(s): CC-BY-SA-3.0, Apache-2.0
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
-
- namespace Microsoft.Server.Common.Diagnostics
- {
- using System;
- using System.Diagnostics.CodeAnalysis;
- using System.Globalization;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Security.Permissions;
- using System.Threading;
- using Microsoft.Server.Common.Interop;
-
- // This is a class defined based on CLR's internal implementation of ETW provider
- // This class should be replaced with CLR's version (whenever avaialble) that exposes callback functionality
- [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
- public class DiagnosticsEventProvider : IDisposable
- {
- [SecurityCritical]
- [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of UnsafeNativeMethods.EtwEnableCallback")]
- UnsafeNativeMethods.EtwEnableCallback etwCallback; // Trace Callback function
-
- long traceRegistrationHandle; // Trace Registration Handle
- byte currentTraceLevel; // Tracing Level
- long anyKeywordMask; // Trace Enable Flags
- long allKeywordMask; // Match all keyword
- bool isProviderEnabled; // Enabled flag from Trace callback
- Guid providerId; // Control Guid
- int isDisposed; // when 1, provider has unregister
-
- [ThreadStatic]
- static WriteEventErrorCode errorCode; // The last return code stored from a WriteEvent call
-
- const int basicTypeAllocationBufferSize = 16;
- const int etwMaxNumberArguments = 32;
- const int etwAPIMaxStringCount = 8;
- const int maxEventDataDescriptors = 128;
- const int traceEventMaximumSize = 65482;
- const int traceEventMaximumStringSize = 32724;
- const int WindowsVistaMajorNumber = 6;
-
- [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
- public enum WriteEventErrorCode : int
- {
- NoError,
- NoFreeBuffers,
- EventTooBig
- }
-
- /// <summary>
- /// Constructs a new EventProvider. This causes the class to be registered with the OS
- /// if an ETW controller turns on the logging then logging will start.
- /// </summary>
- /// <param name="providerGuid">The GUID that identifies this provider to the system.</param>
- [SecurityCritical]
- [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
- [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", Justification = "Use of guid here is acceptable.")]
- protected DiagnosticsEventProvider(Guid providerGuid)
- {
- this.providerId = providerGuid;
- EtwRegister();
- }
-
- /// <summary>
- /// This method registers the controlGuid of this class with ETW.
- /// We need to be running on Vista or above. If not a
- /// PlatformNotSupported exception will be thrown.
- /// If for some reason the ETW EtwRegister call failed
- /// a NotSupported exception will be thrown.
- /// </summary>
- [SecurityCritical]
- [SuppressMessage("Reliability", "Reliability102:WrapExceptionsRule",
- Justification = "Don't trace exceptions thrown from the initialization API.")]
- unsafe void EtwRegister()
- {
- this.etwCallback = new UnsafeNativeMethods.EtwEnableCallback(EtwEnableCallBack);
- uint etwRegistrationStatus = UnsafeNativeMethods.EventRegister(ref this.providerId, this.etwCallback, null, ref this.traceRegistrationHandle);
- if (etwRegistrationStatus != 0)
- {
- throw new InvalidOperationException(SR.EtwRegistrationFailed(etwRegistrationStatus.ToString("x", CultureInfo.CurrentCulture)));
- }
- }
-
- //
- // implement Dispose Pattern to early deregister from ETW instead of waiting for
- // the finalizer to call deregistration.
- // Once the user is done with the provider it needs to call Close() or Dispose()
- // If neither are called the finalizer will unregister the provider anyway
- //
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- [System.Security.SecuritySafeCritical]
- protected virtual void Dispose(bool disposing)
- {
- if ((this.isDisposed != 1) && (Interlocked.Exchange(ref this.isDisposed, 1) == 0))
- {
- this.isProviderEnabled = false;
- Deregister();
- }
- }
-
- /// <summary>
- /// This method deregisters the controlGuid of this class with ETW.
- /// </summary>
- public virtual void Close()
- {
- Dispose();
- }
-
- ~DiagnosticsEventProvider()
- {
- Dispose(false);
- }
-
- /// <summary>
- /// This method un-registers from ETW.
- /// </summary>
- [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")]
- [SecurityCritical]
- unsafe void Deregister()
- {
- // Unregister from ETW using the RegHandle saved from
- // the register call.
- if (this.traceRegistrationHandle != 0)
- {
- UnsafeNativeMethods.EventUnregister(this.traceRegistrationHandle);
- this.traceRegistrationHandle = 0;
- }
- }
-
- [SecurityCritical]
- unsafe void EtwEnableCallBack(
- [In] ref System.Guid sourceId,
- [In] int isEnabled,
- [In] byte setLevel,
- [In] long anyKeyword,
- [In] long allKeyword,
- [In] void* filterData,
- [In] void* callbackContext
- )
- {
- this.isProviderEnabled = (isEnabled != 0);
- this.currentTraceLevel = setLevel;
- this.anyKeywordMask = anyKeyword;
- this.allKeywordMask = allKeyword;
- OnControllerCommand();
- }
-
- protected virtual void OnControllerCommand() { }
-
- /// <summary>
- /// IsEnabled, method used to test if provider is enabled
- /// </summary>
- public bool IsEnabled()
- {
- return this.isProviderEnabled;
- }
-
- /// <summary>
- /// IsEnabled, method used to test if event is enabled
- /// </summary>
- /// <param name="level">
- /// Level to test
- /// </param>
- /// <param name="keywords">
- /// Keyword to test
- /// </param>
- public bool IsEnabled(byte level, long keywords)
- {
- if (this.isProviderEnabled)
- {
- if ((level <= this.currentTraceLevel) ||
- (this.currentTraceLevel == 0)) // This also covers the case of Level == 0.
- {
- // Check if Keyword is enabled
- if ((keywords == 0) ||
- (((keywords & this.anyKeywordMask) != 0) &&
- ((keywords & this.allKeywordMask) == this.allKeywordMask)))
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
- public static WriteEventErrorCode GetLastWriteEventError()
- {
- return errorCode;
- }
-
- //
- // Helper function to set the last error on the thread
- //
- static void SetLastError(int error)
- {
- switch (error)
- {
- case UnsafeNativeMethods.ERROR_ARITHMETIC_OVERFLOW:
- case UnsafeNativeMethods.ERROR_MORE_DATA:
- errorCode = WriteEventErrorCode.EventTooBig;
- break;
- case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY:
- errorCode = WriteEventErrorCode.NoFreeBuffers;
- break;
- }
- }
-
- /// <summary>
- /// This routine is used by WriteEvent to unbox the object type and
- /// to fill the passed in ETW data descriptor.
- /// </summary>
- /// <param name="data">argument to be decoded</param>
- /// <param name="dataDescriptor">pointer to the descriptor to be filled</param>
- /// <param name="dataBuffer">storage buffer for storing user data, needed because cant get the address of the object</param>
- /// <returns>null if the object is a basic type other than string. String otherwise</returns>
-
- [SecurityCritical]
- static unsafe string EncodeObject(ref object data, UnsafeNativeMethods.EventData* dataDescriptor, byte* dataBuffer)
- {
- dataDescriptor->Reserved = 0;
-
- string sRet = data as string;
- if (sRet != null)
- {
- dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);
- return sRet;
- }
-
- if (data is IntPtr)
- {
- dataDescriptor->Size = (uint)sizeof(IntPtr);
- IntPtr* intptrPtr = (IntPtr*)dataBuffer;
- *intptrPtr = (IntPtr)data;
- dataDescriptor->DataPointer = (ulong)intptrPtr;
- }
- else if (data is int)
- {
- dataDescriptor->Size = (uint)sizeof(int);
- int* intptrPtr = (int*)dataBuffer;
- *intptrPtr = (int)data;
- dataDescriptor->DataPointer = (ulong)intptrPtr;
- }
- else if (data is long)
- {
- dataDescriptor->Size = (uint)sizeof(long);
- long* longptr = (long*)dataBuffer;
- *longptr = (long)data;
- dataDescriptor->DataPointer = (ulong)longptr;
- }
- else if (data is uint)
- {
- dataDescriptor->Size = (uint)sizeof(uint);
- uint* uintptr = (uint*)dataBuffer;
- *uintptr = (uint)data;
- dataDescriptor->DataPointer = (ulong)uintptr;
- }
- else if (data is UInt64)
- {
- dataDescriptor->Size = (uint)sizeof(ulong);
- UInt64* ulongptr = (ulong*)dataBuffer;
- *ulongptr = (ulong)data;
- dataDescriptor->DataPointer = (ulong)ulongptr;
- }
- else if (data is char)
- {
- dataDescriptor->Size = (uint)sizeof(char);
- char* charptr = (char*)dataBuffer;
- *charptr = (char)data;
- dataDescriptor->DataPointer = (ulong)charptr;
- }
- else if (data is byte)
- {
- dataDescriptor->Size = (uint)sizeof(byte);
- byte* byteptr = (byte*)dataBuffer;
- *byteptr = (byte)data;
- dataDescriptor->DataPointer = (ulong)byteptr;
- }
- else if (data is short)
- {
- dataDescriptor->Size = (uint)sizeof(short);
- short* shortptr = (short*)dataBuffer;
- *shortptr = (short)data;
- dataDescriptor->DataPointer = (ulong)shortptr;
- }
- else if (data is sbyte)
- {
- dataDescriptor->Size = (uint)sizeof(sbyte);
- sbyte* sbyteptr = (sbyte*)dataBuffer;
- *sbyteptr = (sbyte)data;
- dataDescriptor->DataPointer = (ulong)sbyteptr;
- }
- else if (data is ushort)
- {
- dataDescriptor->Size = (uint)sizeof(ushort);
- ushort* ushortptr = (ushort*)dataBuffer;
- *ushortptr = (ushort)data;
- dataDescriptor->DataPointer = (ulong)ushortptr;
- }
- else if (data is float)
- {
- dataDescriptor->Size = (uint)sizeof(float);
- float* floatptr = (float*)dataBuffer;
- *floatptr = (float)data;
- dataDescriptor->DataPointer = (ulong)floatptr;
- }
- else if (data is double)
- {
- dataDescriptor->Size = (uint)sizeof(double);
- double* doubleptr = (double*)dataBuffer;
- *doubleptr = (double)data;
- dataDescriptor->DataPointer = (ulong)doubleptr;
- }
- else if (data is bool)
- {
- dataDescriptor->Size = (uint)sizeof(bool);
- bool* boolptr = (bool*)dataBuffer;
- *boolptr = (bool)data;
- dataDescriptor->DataPointer = (ulong)boolptr;
- }
- else if (data is Guid)
- {
- dataDescriptor->Size = (uint)sizeof(Guid);
- Guid* guidptr = (Guid*)dataBuffer;
- *guidptr = (Guid)data;
- dataDescriptor->DataPointer = (ulong)guidptr;
- }
- else if (data is decimal)
- {
- dataDescriptor->Size = (uint)sizeof(decimal);
- decimal* decimalptr = (decimal*)dataBuffer;
- *decimalptr = (decimal)data;
- dataDescriptor->DataPointer = (ulong)decimalptr;
- }
- else if (data is Boolean)
- {
- dataDescriptor->Size = (uint)sizeof(Boolean);
- Boolean* booleanptr = (Boolean*)dataBuffer;
- *booleanptr = (Boolean)data;
- dataDescriptor->DataPointer = (ulong)booleanptr;
- }
- else
- {
- // Everything else is a just a string
- sRet = data.ToString();
- dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);
- return sRet;
- }
-
- return null;
- }
-
- /// <summary>
- /// WriteMessageEvent, method to write a string with level and Keyword
- /// </summary>
- /// <param name="level">
- /// Level to test
- /// </param>
- /// <param name="Keyword">
- /// Keyword to test
- /// </param>
- [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
- [SecurityCritical]
- public bool WriteMessageEvent(EventTraceActivity eventTraceActivity, string eventMessage, byte eventLevel, long eventKeywords)
- {
- int status = 0;
-
- if (eventMessage == null)
- {
- throw Fx.Exception.AsError(new ArgumentNullException("eventMessage"));
- }
-
- if (eventTraceActivity != null)
- {
- SetActivityId(ref eventTraceActivity.ActivityId);
- }
-
- if (IsEnabled(eventLevel, eventKeywords))
- {
- if (eventMessage.Length > traceEventMaximumStringSize)
- {
- errorCode = WriteEventErrorCode.EventTooBig;
- return false;
- }
- unsafe
- {
- fixed (char* pdata = eventMessage)
- {
- status = (int)UnsafeNativeMethods.EventWriteString(this.traceRegistrationHandle, eventLevel, eventKeywords, pdata);
- }
-
- if (status != 0)
- {
- SetLastError(status);
- return false;
- }
- }
- }
- return true;
- }
-
- /// <summary>
- /// WriteMessageEvent, method to write a string with level=0 and Keyword=0
- /// </summary>
- /// <param name="eventMessage">
- /// Message to log
- /// </param>
- [SecurityCritical]
- [Fx.Tag.SecurityNote(Critical = "Accesses security critical code WriteMessageEvent")]
- public bool WriteMessageEvent(EventTraceActivity eventTraceActivity, string eventMessage)
- {
- return WriteMessageEvent(eventTraceActivity, eventMessage, 0, 0);
- }
-
- /// <summary>
- /// WriteEvent, method to write a parameters with event schema properties
- /// </summary>
- /// <param name="EventDescriptor">
- /// Event Descriptor for this event.
- /// </param>
- [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
- [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Ported from WCF")]
- [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
- [SecurityCritical]
- public bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, params object[] eventPayload)
- {
- uint status = 0;
-
- if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
- {
- int argCount = 0;
-
- if (eventTraceActivity != null)
- {
- SetActivityId(ref eventTraceActivity.ActivityId);
- }
-
- unsafe
- {
- if ((eventPayload == null)
- || (eventPayload.Length == 0)
- || (eventPayload.Length == 1))
- {
- string dataString = null;
- UnsafeNativeMethods.EventData userData;
-
- byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize]; // Assume a max of 16 chars for non-string argument
-
- userData.Size = 0;
- if ((eventPayload != null) && (eventPayload.Length != 0))
- {
- //
- // Figure out the type and fill the data descriptor
- //
- dataString = EncodeObject(ref eventPayload[0], &userData, dataBuffer);
- argCount = 1;
- }
-
- if (userData.Size > traceEventMaximumSize)
- {
- //
- // Maximum size of the event payload plus header is 64k
- //
- errorCode = WriteEventErrorCode.EventTooBig;
- return false;
- }
-
- if (dataString != null)
- {
- fixed (char* pdata = dataString)
- {
- userData.DataPointer = (ulong)pdata;
- status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, &userData);
- }
- }
- else
- {
- if (argCount == 0)
- {
- status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, 0, null);
- }
- else
- {
- status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, &userData);
- }
-
- }
- }
- else
- {
-
- argCount = eventPayload.Length;
-
- if (argCount > etwMaxNumberArguments)
- {
- //
- //too many arguments to log
- //
- throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
- SR.EtwMaxNumberArgumentsExceeded(etwMaxNumberArguments)));
- }
-
- uint totalEventSize = 0;
- int index;
- int stringIndex = 0;
- int[] stringPosition = new int[etwAPIMaxStringCount];
- string[] dataString = new string[etwAPIMaxStringCount];
- UnsafeNativeMethods.EventData* userData = stackalloc UnsafeNativeMethods.EventData[argCount];
- UnsafeNativeMethods.EventData* userDataPtr = (UnsafeNativeMethods.EventData*)userData;
- byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize * argCount]; // Assume 16 chars for non-string argument
- byte* currentBuffer = dataBuffer;
-
- //
- // The loop below goes through all the arguments and fills in the data
- // descriptors. For strings save the location in the dataString array.
- // Caculates the total size of the event by adding the data descriptor
- // size value set in EncodeObjec method.
- //
- for (index = 0; index < eventPayload.Length; index++)
- {
- if (eventPayload[index] != null)
- {
- string isString;
- isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer);
- currentBuffer += basicTypeAllocationBufferSize;
- totalEventSize += userDataPtr->Size;
- userDataPtr++;
- if (isString != null)
- {
- if (stringIndex < etwAPIMaxStringCount)
- {
- dataString[stringIndex] = isString;
- stringPosition[stringIndex] = index;
- stringIndex++;
- }
- else
- {
- throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
- SR.EtwAPIMaxStringCountExceeded(etwAPIMaxStringCount)));
- }
- }
- }
- }
-
- if (totalEventSize > traceEventMaximumSize)
- {
- errorCode = WriteEventErrorCode.EventTooBig;
- return false;
- }
-
- //
- // now fix any string arguments and set the pointer on the data descriptor
- //
- fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3],
- v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7])
- {
- userDataPtr = (UnsafeNativeMethods.EventData*)userData;
- if (dataString[0] != null)
- {
- userDataPtr[stringPosition[0]].DataPointer = (ulong)v0;
- }
- if (dataString[1] != null)
- {
- userDataPtr[stringPosition[1]].DataPointer = (ulong)v1;
- }
- if (dataString[2] != null)
- {
- userDataPtr[stringPosition[2]].DataPointer = (ulong)v2;
- }
- if (dataString[3] != null)
- {
- userDataPtr[stringPosition[3]].DataPointer = (ulong)v3;
- }
- if (dataString[4] != null)
- {
- userDataPtr[stringPosition[4]].DataPointer = (ulong)v4;
- }
- if (dataString[5] != null)
- {
- userDataPtr[stringPosition[5]].DataPointer = (ulong)v5;
- }
- if (dataString[6] != null)
- {
- userDataPtr[stringPosition[6]].DataPointer = (ulong)v6;
- }
- if (dataString[7] != null)
- {
- userDataPtr[stringPosition[7]].DataPointer = (ulong)v7;
- }
-
- status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, userData);
- }
-
- }
- }
- }
-
- if (status != 0)
- {
- SetLastError((int)status);
- return false;
- }
-
- return true;
- }
-
- /// <summary>
- /// WriteEvent, method to write a string with event schema properties
- /// </summary>
- /// <param name="EventDescriptor">
- /// Event Descriptor for this event.
- /// </param>
- /// <param name="data">
- /// string to log.
- /// </param>
- [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
- [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
- [SecurityCritical]
- public bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, string data)
- {
- uint status = 0;
- //check all strings for null
- data = (data ?? string.Empty);
-
- if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
- {
- if (data.Length > traceEventMaximumStringSize)
- {
- errorCode = WriteEventErrorCode.EventTooBig;
- return false;
- }
-
- if (eventTraceActivity != null)
- {
- SetActivityId(ref eventTraceActivity.ActivityId);
- }
-
- UnsafeNativeMethods.EventData userData;
-
- userData.Size = (uint)((data.Length + 1) * 2);
- userData.Reserved = 0;
-
- unsafe
- {
- fixed (char* pdata = data)
- {
- userData.DataPointer = (ulong)pdata;
- status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, 1, &userData);
- }
- }
- }
-
- if (status != 0)
- {
- SetLastError((int)status);
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// WriteEvent, method to be used by generated code on a derived class
- /// </summary>
- /// <param name="EventDescriptor">
- /// Event Descriptor for this event.
- /// </param>
- /// <param name="count">
- /// number of event descriptors
- /// </param>
- /// <param name="data">
- /// pointer do the event data
- /// </param>
- [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
- [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
- [SecurityCritical]
- internal protected bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, int dataCount, IntPtr data)
- {
- uint status = 0;
-
- if (eventTraceActivity != null)
- {
- SetActivityId(ref eventTraceActivity.ActivityId);
- }
-
- unsafe
- {
- status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)dataCount, (UnsafeNativeMethods.EventData*)data);
- }
- if (status != 0)
- {
- SetLastError((int)status);
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// WriteTransferEvent, method to write a parameters with event schema properties
- /// </summary>
- /// <param name="eventDescriptor">
- /// Event Descriptor for this event.
- /// </param>
- [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
- [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Ported from WCF")]
- [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
- [SecurityCritical]
- public bool WriteTransferEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, Guid relatedActivityId, params object[] eventPayload)
- {
- // ActivityId is required when writing transfer event
- if (eventTraceActivity == null)
- {
- Fx.Assert(false, "eventTraceActivity should not be null for WriteTransferEvent");
- eventTraceActivity = EventTraceActivity.Empty;
- }
-
- uint status = 0;
- if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
- {
- unsafe
- {
- if ((eventPayload != null) && (eventPayload.Length != 0))
- {
- int argCount = eventPayload.Length;
- if (argCount > etwMaxNumberArguments)
- {
- //
- //too many arguments to log
- //
- throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
- SR.EtwMaxNumberArgumentsExceeded(etwMaxNumberArguments)));
- }
-
- uint totalEventSize = 0;
- int index;
- int stringIndex = 0;
- int[] stringPosition = new int[etwAPIMaxStringCount]; //used to keep the position of strings in the eventPayload parameter
- string[] dataString = new string[etwAPIMaxStringCount]; // string arrays from the eventPayload parameter
- UnsafeNativeMethods.EventData* userData = stackalloc UnsafeNativeMethods.EventData[argCount]; // allocation for the data descriptors
- UnsafeNativeMethods.EventData* userDataPtr = (UnsafeNativeMethods.EventData*)userData;
- byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize * argCount]; // 16 byte for unboxing non-string argument
- byte* currentBuffer = dataBuffer;
-
- //
- // The loop below goes through all the arguments and fills in the data
- // descriptors. For strings save the location in the dataString array.
- // Caculates the total size of the event by adding the data descriptor
- // size value set in EncodeObjec method.
- //
- for (index = 0; index < eventPayload.Length; index++)
- {
- if (eventPayload[index] != null)
- {
- string isString;
- isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer);
- currentBuffer += basicTypeAllocationBufferSize;
- totalEventSize += userDataPtr->Size;
- userDataPtr++;
- if (isString != null)
- {
- if (stringIndex < etwAPIMaxStringCount)
- {
- dataString[stringIndex] = isString;
- stringPosition[stringIndex] = index;
- stringIndex++;
- }
- else
- {
- throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
- SR.EtwAPIMaxStringCountExceeded(etwAPIMaxStringCount)));
- }
- }
- }
- }
-
- if (totalEventSize > traceEventMaximumSize)
- {
- errorCode = WriteEventErrorCode.EventTooBig;
- return false;
- }
-
- fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3],
- v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7])
- {
- userDataPtr = (UnsafeNativeMethods.EventData*)userData;
- if (dataString[0] != null)
- {
- userDataPtr[stringPosition[0]].DataPointer = (ulong)v0;
- }
- if (dataString[1] != null)
- {
- userDataPtr[stringPosition[1]].DataPointer = (ulong)v1;
- }
- if (dataString[2] != null)
- {
- userDataPtr[stringPosition[2]].DataPointer = (ulong)v2;
- }
- if (dataString[3] != null)
- {
- userDataPtr[stringPosition[3]].DataPointer = (ulong)v3;
- }
- if (dataString[4] != null)
- {
- userDataPtr[stringPosition[4]].DataPointer = (ulong)v4;
- }
- if (dataString[5] != null)
- {
- userDataPtr[stringPosition[5]].DataPointer = (ulong)v5;
- }
- if (dataString[6] != null)
- {
- userDataPtr[stringPosition[6]].DataPointer = (ulong)v6;
- }
- if (dataString[7] != null)
- {
- userDataPtr[stringPosition[7]].DataPointer = (ulong)v7;
- }
-
- status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, (uint)argCount, userData);
- }
- }
- else
- {
- status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, 0, null);
- }
- }
- }
-
- if (status != 0)
- {
- SetLastError((int)status);
- return false;
- }
-
- return true;
- }
-
- [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
- [SecurityCritical]
- [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
- protected bool WriteTransferEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, Guid relatedActivityId, int dataCount, IntPtr data)
- {
- // ActivityId is required when writing transfer event
- if (eventTraceActivity == null)
- {
- throw Fx.Exception.ArgumentNull("eventTraceActivity");
- }
-
- uint status = 0;
- unsafe
- {
- status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle,
- ref eventDescriptor,
- ref eventTraceActivity.ActivityId,
- ref relatedActivityId,
- (uint)dataCount,
- (UnsafeNativeMethods.EventData*)data);
- }
-
- if (status != 0)
- {
- SetLastError((int)status);
- return false;
- }
- return true;
- }
-
- [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "Microsoft.Server.Common.Interop.UnsafeNativeMethods.EventActivityIdControl(System.Int32,System.Guid@)", Justification = "Ported code from")]
- [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
- [SecurityCritical]
- public static void SetActivityId(ref Guid id)
- {
- UnsafeNativeMethods.EventActivityIdControl((int)ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref id);
- }
- }
- }