internal static void FlushImpl() { foreach (KeyValuePair <int, AggregationSet> aggregationSetPair in aggregationSets) { if (disposing) { return; } AggregationSet aggregationSet = aggregationSetPair.Value; ConcurrentDictionary <int, MetricsBag> aggregations = aggregationSet.RemoveAggregations(); var periodStartTime = DateTimeOffset.Now.Subtract(AggregateMetricsTelemetryModule.FlushInterval); foreach (MetricsBag metricsBag in aggregations.Values) { if (disposing) { return; } int registrationKey = aggregationSet.Key; string p1Name = null; string p2Name = null; string p3Name = null; var percentileCalculation = PercentileCalculation.DoNotCalculate; AggregateMetricProperties metricProperties; if (metricRegistrations.TryGetValue(registrationKey, out metricProperties)) { if (metricProperties.P1Name != null) { p1Name = metricProperties.P1Name; } if (metricProperties.P2Name != null) { p2Name = metricProperties.P2Name; } if (metricProperties.P3Name != null) { p3Name = metricProperties.P3Name; } percentileCalculation = metricProperties.PercentileCalculation; } AggregationResult aggregation = metricsBag.CalculateAggregation(percentileCalculation); var metric = new MetricTelemetry(aggregationSet.Name, aggregation.Sum) { Timestamp = periodStartTime, Count = aggregation.Count, Min = aggregation.Min, Max = aggregation.Max, StandardDeviation = aggregation.StdDev }; metric.Context.GetInternalContext().SdkVersion = sdkVersion; metric.AddProperties(metricsBag, p1Name, p2Name, p3Name); if (percentileCalculation != PercentileCalculation.DoNotCalculate) { metric.Properties.Add(Constants.P50Name, aggregation.P50.ToString(CultureInfo.InvariantCulture)); MetricTelemetry p50Metric = metric.CreateDerivedMetric(Constants.P50Name, aggregation.P50); p50Metric.AddProperties(metricsBag, p1Name, p2Name, p3Name); aggregationSet.TelemetryClient.TrackMetric(p50Metric); metric.Properties.Add(Constants.P75Name, aggregation.P75.ToString(CultureInfo.InvariantCulture)); MetricTelemetry p75Metric = metric.CreateDerivedMetric(Constants.P75Name, aggregation.P75); p75Metric.AddProperties(metricsBag, p1Name, p2Name, p3Name); aggregationSet.TelemetryClient.TrackMetric(p75Metric); metric.Properties.Add(Constants.P90Name, aggregation.P90.ToString(CultureInfo.InvariantCulture)); MetricTelemetry p90Metric = metric.CreateDerivedMetric(Constants.P90Name, aggregation.P90); p90Metric.AddProperties(metricsBag, p1Name, p2Name, p3Name); aggregationSet.TelemetryClient.TrackMetric(p90Metric); metric.Properties.Add(Constants.P95Name, aggregation.P95.ToString(CultureInfo.InvariantCulture)); MetricTelemetry p95Metric = metric.CreateDerivedMetric(Constants.P95Name, aggregation.P95); p95Metric.AddProperties(metricsBag, p1Name, p2Name, p3Name); aggregationSet.TelemetryClient.TrackMetric(p95Metric); metric.Properties.Add(Constants.P99Name, aggregation.P99.ToString(CultureInfo.InvariantCulture)); MetricTelemetry p99Metric = metric.CreateDerivedMetric(Constants.P99Name, aggregation.P99); p99Metric.AddProperties(metricsBag, p1Name, p2Name, p3Name); aggregationSet.TelemetryClient.TrackMetric(p99Metric); } aggregationSet.TelemetryClient.TrackMetric(metric); } } }
internal AggregationResult CalculateAggregation(PercentileCalculation percentileCalculation = PercentileCalculation.DoNotCalculate) { if (this.Count == 0) { return(new AggregationResult()); } // Use sorted enumerables if we need percentiles. IEnumerable <double> values; if (percentileCalculation == PercentileCalculation.OrderByLargest) { values = this.OrderBy(i => i); } else if (percentileCalculation == PercentileCalculation.OrderBySmallest) { values = this.OrderByDescending(i => i); } else { values = this; } double first = values.First(); double sum = 0; double min = first; double max = first; int p50Index = 0; int p75Index = 0; int p90Index = 0; int p95Index = 0; int p99Index = 0; bool shouldCalculatePercentile = percentileCalculation != PercentileCalculation.DoNotCalculate; if (shouldCalculatePercentile) { p50Index = this.GetPercentileNearestIndex(50); p75Index = this.GetPercentileNearestIndex(75); p90Index = this.GetPercentileNearestIndex(90); p95Index = this.GetPercentileNearestIndex(95); p99Index = this.GetPercentileNearestIndex(99); } var aggregation = new AggregationResult() { Count = this.Count }; int valueIndex = 0; foreach (double value in values) { if (value < min) { min = value; } else if (value > max) { max = value; } sum += value; if (shouldCalculatePercentile) { // Note: This only works if sample size >= 100 (which we enforce with Constants.PercentileMinimumCount). if (valueIndex == p50Index) { aggregation.P50 = value; } else if (valueIndex == p75Index) { aggregation.P75 = value; } else if (valueIndex == p90Index) { aggregation.P90 = value; } else if (valueIndex == p95Index) { aggregation.P95 = value; } else if (valueIndex == p99Index) { aggregation.P99 = value; } } valueIndex++; } aggregation.Sum = sum; aggregation.Min = min; aggregation.Max = max; aggregation.StdDev = Math.Sqrt(this.Average(v => Math.Pow(v - aggregation.Average, 2))); return(aggregation); }