/// <summary> /// Froms the etw event. /// </summary> /// <param name="etwMetricData">The etw metric data.</param> /// <returns>The diagnostic heartbeat.</returns> public static unsafe IDiagnosticHeartbeat FromEtwEvent(NativeMethods.EventRecord *etwMetricData) { var heartbeat = new DiagnosticHeartbeat(); var pointerInPayload = etwMetricData->UserData; heartbeat.InstanceName = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); var uptimeSec = *((int *)pointerInPayload); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(int)); heartbeat.UptimeInSec = uptimeSec; var etwEventsDropped = *((int *)pointerInPayload); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(int)); heartbeat.EtwEventsDroppedCount = etwEventsDropped; var etwEventsLost = *((int *)pointerInPayload); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(int)); heartbeat.EtwEventsLostCount = etwEventsLost; var aggregatedMetricsDropped = *((int *)pointerInPayload); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(int)); heartbeat.AggregatedMetricsDroppedCount = aggregatedMetricsDropped; var isNearingEtwLimit = *((byte *)pointerInPayload); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(byte)); heartbeat.IsNearingEtwQueueLimit = isNearingEtwLimit != 0; var isNearingAggregationLimit = *((byte *)pointerInPayload); heartbeat.IsNearingAggregationQueueLimit = isNearingAggregationLimit != 0; return(heartbeat); }
/// <summary> /// Converts content of the ETW event to <see cref="LocalRawMetric"/>. /// </summary> /// <param name="etwMetricData">Object containing information about metric data sample.</param> /// <returns>A <see cref="LocalRawMetric"/> object representing metric sample data.</returns> /// <exception cref="ArgumentException">Throw when information contained in metricDataRecord is in incorrect format.</exception> internal static unsafe LocalRawMetric ConvertToMetricData(NativeMethods.EventRecord *etwMetricData) { try { // Read ETW event time and use as metric time var etwTimeUtc = DateTime.FromFileTimeUtc(etwMetricData->EventHeader.TimeStamp); IntPtr pointerInPayload = etwMetricData->UserData; // Get number of dimensions ushort dimensionsCount = *((ushort *)pointerInPayload); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(ushort)); // Shift 6 bytes as this space is reserved for alignment pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(ushort) + sizeof(uint)); // If time was reported with metric, use it long timestamp = *((long *)pointerInPayload); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(long)); var metricTimeUtc = timestamp == 0 ? etwTimeUtc : DateTime.FromFileTimeUtc(timestamp); // Metric sample value which is either value or delta double doubleMetricSampleValue = 0; long metricSampleValue = 0; if (etwMetricData->EventHeader.Id == PlatformMetricEtwOperationCode) { doubleMetricSampleValue = *((double *)pointerInPayload); } else { metricSampleValue = *((long *)pointerInPayload); } pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(long)); // Read monitoring account, metric namespace and name var monitoringAccount = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); var metricNameSpace = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); var metricName = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); var dimensionNames = new List <string>(); for (int i = 0; i < dimensionsCount; ++i) { dimensionNames.Add(EtwPayloadManipulationUtils.ReadString(ref pointerInPayload)); } var dimensionValues = new List <string>(); for (int i = 0; i < dimensionsCount; ++i) { dimensionValues.Add(EtwPayloadManipulationUtils.ReadString(ref pointerInPayload)); } var dimensions = new Dictionary <string, string>(); for (int i = 0; i < dimensionsCount; ++i) { dimensions[dimensionNames[i]] = dimensionValues[i]; } return(new LocalRawMetric { IsPlatformMetric = etwMetricData->EventHeader.Id == PlatformMetricEtwOperationCode, MetricTimeUtc = metricTimeUtc, MetricLongValue = (ulong)metricSampleValue, MetricDoubleValue = doubleMetricSampleValue, MonitoringAccount = monitoringAccount, MetricNamespace = metricNameSpace, MetricName = metricName, Dimensions = dimensions }); } catch (Exception e) { Logger.Log( LoggerLevel.Error, LogId, "ConvertToMetricData", "Failed to read raw metric daat from the ETW event payload.", e); throw; } }
/// <summary> /// Converts content of the ETW event published by ME to a <see cref="LocalAggregatedMetric"/> /// </summary> /// <param name="etwMetricData">Object containing information about metric data sample.</param> /// <returns>A MetricData object representing a locally aggregated metric.</returns> internal static unsafe LocalAggregatedMetric ConvertToMetricData(NativeMethods.EventRecord *etwMetricData) { var metricData = new LocalAggregatedMetric(); IntPtr pointerInPayload = etwMetricData->UserData; metricData.MonitoringAccount = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); metricData.MetricNamespace = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); metricData.MetricName = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); long timestamp = *((long *)pointerInPayload); metricData.MetricTimeUtc = DateTime.FromFileTimeUtc(timestamp); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(long)); // Read the dimension name and values and split them out. var dimensionNames = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); var dimensionValues = EtwPayloadManipulationUtils.ReadString(ref pointerInPayload); if (!string.IsNullOrWhiteSpace(dimensionNames) && !string.IsNullOrWhiteSpace(dimensionValues)) { var splitDimensionNames = dimensionNames.Split(EtwListSeparatorChar, StringSplitOptions.None); var splitDimensionValues = dimensionValues.Split(EtwListSeparatorChar, StringSplitOptions.None); // Expected that both lengths be the same since they are written this way. for (var x = 0; x < splitDimensionNames.Length && x < splitDimensionValues.Length; ++x) { metricData.dimensions[splitDimensionNames[x]] = splitDimensionValues[x]; } } var scalingFactor = *((float *)pointerInPayload); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(float)); metricData.ScalingFactor = scalingFactor; var samplingTypes = (SamplingTypes)(*((int *)pointerInPayload)); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(int)); if ((samplingTypes & SamplingTypes.Min) != 0) { metricData.Min = *((ulong *)pointerInPayload); metricData.ScaledMin = metricData.Min / scalingFactor; } pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(ulong)); if ((samplingTypes & SamplingTypes.Max) != 0) { metricData.Max = *((ulong *)pointerInPayload); metricData.ScaledMax = metricData.Max / scalingFactor; } pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(ulong)); if ((samplingTypes & SamplingTypes.Sum) != 0) { metricData.Sum = *((ulong *)pointerInPayload); metricData.ScaledSum = metricData.Sum / scalingFactor; } pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(ulong)); pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(float)); if ((samplingTypes & SamplingTypes.Count) != 0) { metricData.Count = *((uint *)pointerInPayload); } pointerInPayload = EtwPayloadManipulationUtils.Shift(pointerInPayload, sizeof(uint)); return(metricData); }