private unsafe void WriteToAllListeners(string eventName, ref EventDescriptor eventDescriptor, EventTags tags, Guid *pActivityId, EventPayload payload) { EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this); eventCallbackArgs.EventName = eventName; eventCallbackArgs.m_level = (EventLevel)eventDescriptor.Level; eventCallbackArgs.m_keywords = (EventKeywords)eventDescriptor.Keywords; eventCallbackArgs.m_opcode = (EventOpcode)eventDescriptor.Opcode; eventCallbackArgs.m_tags = tags; // 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); } DispatchToAllListeners(-1, pActivityId, eventCallbackArgs); }
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); }
/// <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="activityID"> /// A pointer to the activity ID GUID to log /// </param> /// <param name="childActivityID"> /// A pointer to the child activity ID to log (can be null) /// </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> private unsafe void WriteMultiMergeInner( string eventName, ref EventSourceOptions options, TraceLoggingEventTypes eventTypes, Guid *activityID, Guid *childActivityID, params object[] values) { #if FEATURE_MANAGED_ETW 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); #if FEATURE_PERFTRACING IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_eventPipeProvider, m_eventHandleMap, descriptor, eventTypes); Debug.Assert(eventHandle != IntPtr.Zero); #else IntPtr eventHandle = IntPtr.Zero; #endif var pinCount = eventTypes.pinCount; var scratch = stackalloc byte[eventTypes.scratchSize]; var descriptors = stackalloc EventData[eventTypes.dataCount + 3]; for (int i = 0; i < eventTypes.dataCount + 3; i++) { descriptors[i] = default; } var pins = stackalloc GCHandle[pinCount]; for (int i = 0; i < pinCount; i++) pins[i] = default; 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 && !ES_BUILD_PN) 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++) { var info = eventTypes.typeInfos[i]; info.WriteData(TraceLoggingDataCollector.Instance, info.PropertyValueFactory(values[i])); } this.WriteEventRaw( eventName, ref descriptor, eventHandle, activityID, childActivityID, (int)(DataCollector.ThreadInstance.Finish() - descriptors), (IntPtr)descriptors); } finally { this.WriteCleanup(pins, pinCount); } } #endif // FEATURE_MANAGED_ETW }
internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, Guid* activityID, Guid* childActivityID, params object[] eventPayload) { int status = 0; if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords)) { int argCount = 0; unsafe { argCount = eventPayload.Length; if (argCount > s_etwMaxNumberArguments) { s_returnCode = WriteEventErrorCode.TooManyArgs; return false; } uint totalEventSize = 0; int index; int refObjIndex = 0; List<int> refObjPosition = new List<int>(s_etwAPIMaxRefObjCount); List<object> dataRefObj = new List<object>(s_etwAPIMaxRefObjCount); EventData* userData = stackalloc EventData[2 * argCount]; EventData* userDataPtr = (EventData*)userData; byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize * 2 * 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. // Calculates the total size of the event by adding the data descriptor // size value set in EncodeObject method. // bool hasNonStringRefArgs = false; for (index = 0; index < eventPayload.Length; index++) { if (eventPayload[index] != null) { object supportedRefObj; supportedRefObj = EncodeObject(ref eventPayload[index], ref userDataPtr, ref currentBuffer, ref totalEventSize); if (supportedRefObj != null) { // EncodeObject advanced userDataPtr to the next empty slot int idx = (int)(userDataPtr - userData - 1); if (!(supportedRefObj is string)) { if (eventPayload.Length + idx + 1 - index > s_etwMaxNumberArguments) { s_returnCode = WriteEventErrorCode.TooManyArgs; return false; } hasNonStringRefArgs = true; } dataRefObj.Add(supportedRefObj); refObjPosition.Add(idx); refObjIndex++; } } else { s_returnCode = WriteEventErrorCode.NullInput; return false; } } // update argCount based on actual number of arguments written to 'userData' argCount = (int)(userDataPtr - userData); if (totalEventSize > s_traceEventMaximumSize) { s_returnCode = WriteEventErrorCode.EventTooBig; return false; } // the optimized path (using "fixed" instead of allocating pinned GCHandles if (!hasNonStringRefArgs && (refObjIndex < s_etwAPIMaxRefObjCount)) { // Fast path: at most 8 string arguments // ensure we have at least s_etwAPIMaxStringCount in dataString, so that // the "fixed" statement below works while (refObjIndex < s_etwAPIMaxRefObjCount) { dataRefObj.Add(null); ++refObjIndex; } // // now fix any string arguments and set the pointer on the data descriptor // fixed (char* v0 = (string)dataRefObj[0], v1 = (string)dataRefObj[1], v2 = (string)dataRefObj[2], v3 = (string)dataRefObj[3], v4 = (string)dataRefObj[4], v5 = (string)dataRefObj[5], v6 = (string)dataRefObj[6], v7 = (string)dataRefObj[7]) { userDataPtr = (EventData*)userData; if (dataRefObj[0] != null) { userDataPtr[refObjPosition[0]].Ptr = (ulong)v0; } if (dataRefObj[1] != null) { userDataPtr[refObjPosition[1]].Ptr = (ulong)v1; } if (dataRefObj[2] != null) { userDataPtr[refObjPosition[2]].Ptr = (ulong)v2; } if (dataRefObj[3] != null) { userDataPtr[refObjPosition[3]].Ptr = (ulong)v3; } if (dataRefObj[4] != null) { userDataPtr[refObjPosition[4]].Ptr = (ulong)v4; } if (dataRefObj[5] != null) { userDataPtr[refObjPosition[5]].Ptr = (ulong)v5; } if (dataRefObj[6] != null) { userDataPtr[refObjPosition[6]].Ptr = (ulong)v6; } if (dataRefObj[7] != null) { userDataPtr[refObjPosition[7]].Ptr = (ulong)v7; } status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, argCount, userData); } } else { // Slow path: use pinned handles userDataPtr = (EventData*)userData; GCHandle[] rgGCHandle = new GCHandle[refObjIndex]; for (int i = 0; i < refObjIndex; ++i) { // below we still use "fixed" to avoid taking dependency on the offset of the first field // in the object (the way we would need to if we used GCHandle.AddrOfPinnedObject) rgGCHandle[i] = GCHandle.Alloc(dataRefObj[i], GCHandleType.Pinned); if (dataRefObj[i] is string) { fixed (char* p = (string)dataRefObj[i]) userDataPtr[refObjPosition[i]].Ptr = (ulong)p; } else { fixed (byte* p = (byte[])dataRefObj[i]) userDataPtr[refObjPosition[i]].Ptr = (ulong)p; } } status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, argCount, userData); for (int i = 0; i < refObjIndex; ++i) { rgGCHandle[i].Free(); } } } } if (status != 0) { SetLastError((int)status); return false; } return true; }
internal unsafe bool WriteEventRaw( ref EventDescriptor eventDescriptor, Guid* activityID, Guid* relatedActivityID, int dataCount, IntPtr data) { int status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper( m_regHandle, ref eventDescriptor, activityID, relatedActivityID, dataCount, (EventData*)data); if (status != 0) { SetLastError(status); return false; } return true; }
internal unsafe protected bool WriteEvent(ref EventDescriptor eventDescriptor, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data) { if (childActivityID != null) { // activity transfers are supported only for events that specify the Send or Receive opcode Contract.Assert((EventOpcode)eventDescriptor.Opcode == EventOpcode.Send || (EventOpcode)eventDescriptor.Opcode == EventOpcode.Receive || (EventOpcode)eventDescriptor.Opcode == EventOpcode.Start || (EventOpcode)eventDescriptor.Opcode == EventOpcode.Stop); } int status = UnsafeNativeMethods.ManifestEtw.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, dataCount, (EventData*)data); if (status != 0) { SetLastError(status); return false; } return true; }