public void DefaultState() { DateTimeOffset dto = new DateTimeOffset(2017, 10, 2, 17, 5, 0, TimeSpan.FromHours(-7)); var aggregationManager = new MetricAggregationManager(); var measurementMetric = new MetricSeries( aggregationManager, "Measurement Metric", null, new MetricSeriesConfigurationForMeasurement(restrictToUInt32Values: false)); var accumulatorMetric = new MetricSeries( aggregationManager, "Accumulator Metric", null, new MetricSeriesConfigurationForAccumulator(restrictToUInt32Values: false)); measurementMetric.TrackValue(1); accumulatorMetric.TrackValue(2); AggregationPeriodSummary defaultPeriod = aggregationManager.StartOrCycleAggregators(MetricAggregationCycleKind.Default, dto, futureFilter: null); Assert.IsNotNull(defaultPeriod); Assert.IsNotNull(defaultPeriod.NonpersistentAggregates); Assert.IsNotNull(defaultPeriod.PersistentAggregates); Assert.AreEqual(1, defaultPeriod.NonpersistentAggregates.Count); Assert.AreEqual("Measurement Metric", (defaultPeriod.NonpersistentAggregates[0]).MetricId); Assert.AreEqual(1, defaultPeriod.NonpersistentAggregates[0].Data["Count"]); Assert.AreEqual(1.0, defaultPeriod.NonpersistentAggregates[0].Data["Sum"]); Assert.AreEqual(1, defaultPeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", defaultPeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, defaultPeriod.PersistentAggregates[0].Data["Sum"]); AggregationPeriodSummary customPeriod = aggregationManager.StartOrCycleAggregators(MetricAggregationCycleKind.Custom, dto, futureFilter: null); Assert.IsNotNull(customPeriod); Assert.IsNotNull(customPeriod.NonpersistentAggregates); Assert.IsNotNull(customPeriod.PersistentAggregates); Assert.AreEqual(0, customPeriod.NonpersistentAggregates.Count); Assert.AreEqual(1, customPeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", customPeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, customPeriod.PersistentAggregates[0].Data["Sum"]); AggregationPeriodSummary quickpulsePeriod = aggregationManager.StartOrCycleAggregators(MetricAggregationCycleKind.QuickPulse, dto, futureFilter: null); Assert.IsNotNull(quickpulsePeriod); Assert.IsNotNull(quickpulsePeriod.NonpersistentAggregates); Assert.IsNotNull(quickpulsePeriod.PersistentAggregates); Assert.AreEqual(0, quickpulsePeriod.NonpersistentAggregates.Count); Assert.AreEqual(1, quickpulsePeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", quickpulsePeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, quickpulsePeriod.PersistentAggregates[0].Data["Sum"]); }
public void FetchAndTrackMetrics() { // We know that GetNextCycleTargetTime(..) tries to snap cycles to 1 second into each minute. // But the timer wakes us up *approxumately* at that time. If we are within a few seconds of that time, we will snap exactly to that time. // If we are further away, we will just snap to a whole second. That way downstream systems do not need to worry about sub-second resolution. DateTimeOffset now = DateTimeOffset.Now; if (new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, now.Offset) <= now && new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, 4, now.Offset) >= now) { now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, 1, now.Offset); } else { now = Util.RoundDownToSecond(now); } AggregationPeriodSummary aggregates = this.aggregationManager.StartOrCycleAggregators( MetricAggregationCycleKind.Default, futureFilter: null, tactTimestamp: now); if (aggregates != null) { Task fireAndForget = Task.Run(() => this.metricManager.TrackMetricAggregates(aggregates, flush: false)); } }
/// <summary>@ToDo: Complete documentation before stable release. {134}</summary> public void Flush() { DateTimeOffset now = DateTimeOffset.Now; AggregationPeriodSummary aggregates = this.aggregationManager.StartOrCycleAggregators(MetricAggregationCycleKind.Default, futureFilter: null, tactTimestamp: now); this.TrackMetricAggregates(aggregates, flush: true); }
internal void Flush(bool flushDownstreamPipeline) { DateTimeOffset now = DateTimeOffset.Now; AggregationPeriodSummary aggregates = this.aggregationManager.StartOrCycleAggregators(MetricAggregationCycleKind.Default, futureFilter: null, tactTimestamp: now); this.TrackMetricAggregates(aggregates, flushDownstreamPipeline); }
private AggregationPeriodSummary CycleAggregators( ref AggregatorCollection aggregators, DateTimeOffset tactTimestamp, IMetricSeriesFilter futureFilter, bool stopAggregators) { if (aggregators == _aggregatorsForPersistent) { throw new InvalidOperationException("Invernal SDK bug. Please report. Cannot cycle persistent aggregators."); } tactTimestamp = Util.RoundDownToSecond(tactTimestamp); // For non-persistent aggregators: create empty holder for the next aggregation period and swap for the previous holder: AggregatorCollection prevAggregators; if (stopAggregators) { prevAggregators = Interlocked.Exchange(ref aggregators, null); } else { AggregatorCollection nextAggregators = new AggregatorCollection(tactTimestamp, futureFilter); prevAggregators = Interlocked.Exchange(ref aggregators, nextAggregators); } List <MetricAggregate> persistentValsAggregations = GetPersistentAggregations(tactTimestamp, prevAggregators?.Filter); List <MetricAggregate> nonpersistentAggregations = GetNonpersistentAggregations(tactTimestamp, prevAggregators); var summary = new AggregationPeriodSummary(persistentValsAggregations, nonpersistentAggregations); return(summary); }
internal void TrackMetricAggregates(AggregationPeriodSummary aggregates, bool flush) { int nonpersistentAggregatesCount = (aggregates?.NonpersistentAggregates == null) ? 0 : aggregates.NonpersistentAggregates.Count; int persistentAggregatesCount = (aggregates?.PersistentAggregates == null) ? 0 : aggregates.PersistentAggregates.Count; int totalAggregatesCount = nonpersistentAggregatesCount + persistentAggregatesCount; if (totalAggregatesCount == 0) { return; } Task[] trackTasks = new Task[totalAggregatesCount]; int taskIndex = 0; if (nonpersistentAggregatesCount != 0) { foreach (MetricAggregate telemetryItem in aggregates.NonpersistentAggregates) { if (telemetryItem != null) { Task trackTask = this.telemetryPipeline.TrackAsync(telemetryItem, CancellationToken.None); trackTasks[taskIndex++] = trackTask; } } } if (aggregates.PersistentAggregates != null && aggregates.PersistentAggregates.Count != 0) { foreach (MetricAggregate telemetryItem in aggregates.PersistentAggregates) { if (telemetryItem != null) { Task trackTask = this.telemetryPipeline.TrackAsync(telemetryItem, CancellationToken.None); trackTasks[taskIndex++] = trackTask; } } } Task.WaitAll(trackTasks); if (flush) { Task flushTask = this.telemetryPipeline.FlushAsync(CancellationToken.None); flushTask.Wait(); } }
internal void TrackMetricAggregates(AggregationPeriodSummary aggregates, bool flush) { int?nonpersistentAggregatesCount = aggregates?.NonpersistentAggregates?.Count; int?persistentAggregatesCount = aggregates?.PersistentAggregates?.Count; int totalAggregatesCount = (nonpersistentAggregatesCount ?? 0) + (persistentAggregatesCount ?? 0); if (totalAggregatesCount == 0) { return; } Task[] trackTasks = new Task[totalAggregatesCount]; int taskIndex = 0; if (nonpersistentAggregatesCount != 0) { foreach (MetricAggregate telemetryItem in aggregates.NonpersistentAggregates) { if (telemetryItem != null) { Task trackTask = this.telemetryPipeline.TrackAsync(telemetryItem, CancellationToken.None); trackTasks[taskIndex++] = trackTask; } } } if (aggregates.PersistentAggregates != null && aggregates.PersistentAggregates.Count != 0) { foreach (MetricAggregate telemetryItem in aggregates.PersistentAggregates) { if (telemetryItem != null) { Task trackTask = this.telemetryPipeline.TrackAsync(telemetryItem, CancellationToken.None); trackTasks[taskIndex++] = trackTask; } } } CoreEventSource.Log.MetricManagerCreatedTasks(trackTasks.Length); Task.WaitAll(trackTasks); if (flush) { Task flushTask = this.telemetryPipeline.FlushAsync(CancellationToken.None); flushTask.Wait(); } }
public void StopAggregators() { DateTimeOffset dto = new DateTimeOffset(2017, 10, 2, 17, 5, 0, TimeSpan.FromHours(-7)); var aggregationManager = new MetricAggregationManager(); var measurementMetric = new MetricSeries( aggregationManager, "Measurement Metric", null, new MetricSeriesConfigurationForMeasurement(restrictToUInt32Values: false)); var accumulatorMetric = new MetricSeries( aggregationManager, "Accumulator Metric", null, new MetricSeriesConfigurationForAccumulator(restrictToUInt32Values: false)); // Cannot stop default: Assert.ThrowsException <ArgumentException>(() => aggregationManager.StopAggregators(MetricAggregationCycleKind.Default, dto)); // Stop cycles that never started: AggregationPeriodSummary customPeriod = aggregationManager.StopAggregators(MetricAggregationCycleKind.Custom, dto); Assert.IsNotNull(customPeriod); Assert.IsNotNull(customPeriod.NonpersistentAggregates); Assert.IsNotNull(customPeriod.PersistentAggregates); Assert.AreEqual(0, customPeriod.NonpersistentAggregates.Count); Assert.AreEqual(0, customPeriod.PersistentAggregates.Count); AggregationPeriodSummary quickpulsePeriod = aggregationManager.StopAggregators(MetricAggregationCycleKind.QuickPulse, dto); Assert.IsNotNull(quickpulsePeriod); Assert.IsNotNull(quickpulsePeriod.NonpersistentAggregates); Assert.IsNotNull(quickpulsePeriod.PersistentAggregates); Assert.AreEqual(0, quickpulsePeriod.NonpersistentAggregates.Count); Assert.AreEqual(0, quickpulsePeriod.PersistentAggregates.Count); // Track a value. Stop cycles that never started again. Observe that persistent cycle was active by default: measurementMetric.TrackValue(1); accumulatorMetric.TrackValue(2); customPeriod = aggregationManager.StopAggregators(MetricAggregationCycleKind.Custom, dto); Assert.IsNotNull(customPeriod); Assert.IsNotNull(customPeriod.NonpersistentAggregates); Assert.IsNotNull(customPeriod.PersistentAggregates); Assert.AreEqual(0, customPeriod.NonpersistentAggregates.Count); Assert.AreEqual(1, customPeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", customPeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, customPeriod.PersistentAggregates[0].Data["Sum"]); quickpulsePeriod = aggregationManager.StopAggregators(MetricAggregationCycleKind.QuickPulse, dto); Assert.IsNotNull(quickpulsePeriod); Assert.IsNotNull(quickpulsePeriod.NonpersistentAggregates); Assert.IsNotNull(quickpulsePeriod.PersistentAggregates); Assert.AreEqual(0, quickpulsePeriod.NonpersistentAggregates.Count); Assert.AreEqual(1, quickpulsePeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", quickpulsePeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, quickpulsePeriod.PersistentAggregates[0].Data["Sum"]); // Now start cycles, track values and stop them again. Observe that values were tracked: aggregationManager.StartOrCycleAggregators(MetricAggregationCycleKind.Custom, dto, futureFilter: null); aggregationManager.StartOrCycleAggregators(MetricAggregationCycleKind.QuickPulse, dto, futureFilter: null); measurementMetric.TrackValue(3); accumulatorMetric.TrackValue(4); customPeriod = aggregationManager.StopAggregators(MetricAggregationCycleKind.Custom, dto); Assert.IsNotNull(customPeriod); Assert.IsNotNull(customPeriod.NonpersistentAggregates); Assert.IsNotNull(customPeriod.PersistentAggregates); Assert.AreEqual(1, customPeriod.NonpersistentAggregates.Count); Assert.AreEqual("Measurement Metric", customPeriod.NonpersistentAggregates[0].MetricId); Assert.AreEqual(1, customPeriod.NonpersistentAggregates[0].Data["Count"]); Assert.AreEqual(3.0, customPeriod.NonpersistentAggregates[0].Data["Sum"]); Assert.AreEqual(1, customPeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", customPeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(6.0, customPeriod.PersistentAggregates[0].Data["Sum"]); quickpulsePeriod = aggregationManager.StopAggregators(MetricAggregationCycleKind.QuickPulse, dto); Assert.IsNotNull(quickpulsePeriod); Assert.IsNotNull(quickpulsePeriod.NonpersistentAggregates); Assert.IsNotNull(quickpulsePeriod.PersistentAggregates); Assert.AreEqual(1, quickpulsePeriod.NonpersistentAggregates.Count); Assert.AreEqual("Measurement Metric", quickpulsePeriod.NonpersistentAggregates[0].MetricId); Assert.AreEqual(1, quickpulsePeriod.NonpersistentAggregates[0].Data["Count"]); Assert.AreEqual(3.0, quickpulsePeriod.NonpersistentAggregates[0].Data["Sum"]); Assert.AreEqual(1, quickpulsePeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", quickpulsePeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(6.0, quickpulsePeriod.PersistentAggregates[0].Data["Sum"]); measurementMetric.TrackValue(5); accumulatorMetric.TrackValue(6); quickpulsePeriod = aggregationManager.StopAggregators(MetricAggregationCycleKind.Custom, dto); Assert.IsNotNull(quickpulsePeriod); Assert.IsNotNull(quickpulsePeriod.NonpersistentAggregates); Assert.IsNotNull(quickpulsePeriod.PersistentAggregates); Assert.AreEqual(0, quickpulsePeriod.NonpersistentAggregates.Count); Assert.AreEqual(1, customPeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", customPeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(6.0, customPeriod.PersistentAggregates[0].Data["Sum"]); quickpulsePeriod = aggregationManager.StopAggregators(MetricAggregationCycleKind.QuickPulse, dto); Assert.IsNotNull(quickpulsePeriod); Assert.IsNotNull(quickpulsePeriod.NonpersistentAggregates); Assert.IsNotNull(quickpulsePeriod.PersistentAggregates); Assert.AreEqual(0, quickpulsePeriod.NonpersistentAggregates.Count); Assert.AreEqual(1, quickpulsePeriod.PersistentAggregates.Count); Assert.AreEqual("Accumulator Metric", quickpulsePeriod.PersistentAggregates[0].MetricId); Assert.AreEqual(12.0, quickpulsePeriod.PersistentAggregates[0].Data["Sum"]); }
private static void StartOrCycleAggregatorsTest(MetricAggregationCycleKind cycleKind, bool supportsSettingFilters) { DateTimeOffset dto = new DateTimeOffset(2017, 10, 2, 17, 5, 0, TimeSpan.FromHours(-7)); var aggregationManager = new MetricAggregationManager(); var measurementMetric = new MetricSeries( aggregationManager, "Measurement Metric", null, new MetricSeriesConfigurationForMeasurement(restrictToUInt32Values: false)); var accumulatorMetric = new MetricSeries( aggregationManager, "Accumulator Metric", null, new MetricSeriesConfigurationForAccumulator(restrictToUInt32Values: false)); // Cycle once, get nothing: AggregationPeriodSummary period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(0, period.NonpersistentAggregates.Count); Assert.AreEqual(0, period.PersistentAggregates.Count); // Record something, cycle, check for it: measurementMetric.TrackValue(1); accumulatorMetric.TrackValue(2); period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(1, period.NonpersistentAggregates.Count); Assert.AreEqual(1, period.PersistentAggregates.Count); Assert.IsNotNull(period.NonpersistentAggregates[0]); Assert.IsNotNull(period.PersistentAggregates[0]); Assert.AreEqual("Measurement Metric", period.NonpersistentAggregates[0].MetricId); Assert.AreEqual(1, period.NonpersistentAggregates[0].Data["Count"]); Assert.AreEqual(1.0, period.NonpersistentAggregates[0].Data["Sum"]); Assert.AreEqual("Accumulator Metric", period.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, period.PersistentAggregates[0].Data["Sum"]); // Now we should be empty again for non-persistent. Persistent stays: period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(0, period.NonpersistentAggregates.Count); Assert.AreEqual(1, period.PersistentAggregates.Count); Assert.IsNotNull(period.PersistentAggregates[0]); Assert.AreEqual("Accumulator Metric", period.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, period.PersistentAggregates[0].Data["Sum"]); // Now set a deny filter. Track. Expect to get nothng. // Note: for persistent, values tracked under Deny filter should persist for the future, for non-persistent they are just discarded. if (false == supportsSettingFilters) { Assert.ThrowsException <ArgumentException>(() => aggregationManager.StartOrCycleAggregators( cycleKind, dto, futureFilter: new AcceptAllFilter())); } else { period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: new DenyAllFilter()); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); measurementMetric.TrackValue(3); accumulatorMetric.TrackValue(4); period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(0, period.NonpersistentAggregates.Count); Assert.AreEqual(0, period.PersistentAggregates.Count); period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(0, period.NonpersistentAggregates.Count); Assert.AreEqual(1, period.PersistentAggregates.Count); Assert.IsNotNull(period.PersistentAggregates[0]); Assert.AreEqual("Accumulator Metric", period.PersistentAggregates[0].MetricId); Assert.AreEqual(6.0, period.PersistentAggregates[0].Data["Sum"]); // Validate that deny filter was removed: measurementMetric.TrackValue(5); accumulatorMetric.TrackValue(6); period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(1, period.NonpersistentAggregates.Count); Assert.AreEqual(1, period.PersistentAggregates.Count); Assert.IsNotNull(period.PersistentAggregates[0]); Assert.IsNotNull(period.NonpersistentAggregates[0]); Assert.AreEqual("Accumulator Metric", period.PersistentAggregates[0].MetricId); Assert.AreEqual(12.0, period.PersistentAggregates[0].Data["Sum"]); Assert.AreEqual("Measurement Metric", period.NonpersistentAggregates[0].MetricId); Assert.AreEqual(5.0, period.NonpersistentAggregates[0].Data["Sum"]); } }
private void RecordNormalMetric(TelemetryConfiguration telemetryPipeline) { MetricSeries durationMeric = telemetryPipeline.GetMetricManager().CreateNewSeries( "Test Metrics", "Item Add duration", new MetricSeriesConfigurationForMeasurement(restrictToUInt32Values: false)); MockContainerDataStructure dataStructure = new MockContainerDataStructure((c) => TimeSpan.FromSeconds(c)); DateTimeOffset experimentStart = new DateTimeOffset(2017, 9, 14, 0, 0, 0, TimeSpan.Zero); // Stop the default minute-ly cycle so that it does not interfere with our virtual time debugging: Task fireAndForget = telemetryPipeline.GetMetricManager().StopDefaultAggregationCycleAsync(); telemetryPipeline.GetMetricManager().StartOrCycleAggregators(CycleKind.Custom, experimentStart, futureFilter: null); const int ExperimentLengthSecs = 60 * 10; const int IntervalLengthSecs = 60; int totalSecs = 0; int intervalSecs = 0; int itemsThisTime = 0; const int maxItemsAtATime = 4; int operationsCount = 0; while (totalSecs < ExperimentLengthSecs) { itemsThisTime = (itemsThisTime + 1) % maxItemsAtATime; int addItemCount = 1 + (itemsThisTime + 1) % maxItemsAtATime; int removeItemCount = 1 + itemsThisTime % maxItemsAtATime; Trace.WriteLine($"{totalSecs})"); Trace.WriteLine(addItemCount); Trace.WriteLine(removeItemCount); Trace.WriteLine(""); TimeSpan duration; dataStructure.AddItems(addItemCount, out duration); operationsCount++; int durationSecs = (int)duration.TotalSeconds; durationMeric.TrackValue(durationSecs); totalSecs += durationSecs; intervalSecs += durationSecs; dataStructure.RemoveItems(removeItemCount, out duration); operationsCount++; durationSecs = (int)duration.TotalSeconds; durationMeric.TrackValue(durationSecs); totalSecs += durationSecs; intervalSecs += durationSecs; if (intervalSecs >= IntervalLengthSecs) { AggregationPeriodSummary aggregatedMetrics = telemetryPipeline.GetMetricManager().StartOrCycleAggregators( CycleKind.Custom, experimentStart.AddSeconds(totalSecs), futureFilter: null); Assert.IsNotNull(aggregatedMetrics); IReadOnlyList <MetricAggregate> aggregates = aggregatedMetrics.NonpersistentAggregates; Assert.IsNotNull(aggregates); Assert.AreEqual(1, aggregates.Count); MetricAggregate aggregate = aggregates[0]; Assert.IsNotNull(aggregates); Assert.AreEqual(1.0, aggregate.Data["Min"]); Assert.AreEqual(4.0, aggregate.Data["Max"]); Assert.AreEqual(operationsCount, aggregate.Data["Count"]); Assert.AreEqual("Item Add duration", aggregate.MetricId); Assert.IsNotNull(aggregate.Dimensions); Assert.AreEqual(0, aggregate.Dimensions.Count); Assert.AreEqual((double)intervalSecs, aggregate.Data["Sum"]); Assert.AreEqual(experimentStart.AddSeconds(totalSecs - intervalSecs), aggregate.AggregationPeriodStart); intervalSecs %= IntervalLengthSecs; operationsCount = 0; Assert.AreEqual(0, intervalSecs, "For the above to work, the number of wirtual secs must exactly fit into IntervalLengthSecs."); } } { AggregationPeriodSummary aggregatedMetrics = telemetryPipeline.GetMetricManager().StartOrCycleAggregators( CycleKind.Custom, experimentStart.AddSeconds(totalSecs), futureFilter: null); Assert.IsNotNull(aggregatedMetrics); IReadOnlyList <MetricAggregate> aggregates = aggregatedMetrics.NonpersistentAggregates; Assert.IsNotNull(aggregates); Assert.AreEqual(0, aggregates.Count); } { durationMeric.TrackValue("7"); durationMeric.TrackValue("8"); durationMeric.TrackValue("9.0"); totalSecs += 24; } { AggregationPeriodSummary aggregatedMetrics = telemetryPipeline.GetMetricManager().StopAggregators( CycleKind.Custom, experimentStart.AddSeconds(totalSecs)); Assert.IsNotNull(aggregatedMetrics); IReadOnlyList <MetricAggregate> aggregates = aggregatedMetrics.NonpersistentAggregates; Assert.IsNotNull(aggregates); MetricAggregate aggregate = aggregates[0]; Assert.IsNotNull(aggregates); Assert.AreEqual(7.0, aggregate.Data["Min"]); Assert.AreEqual(9.0, aggregate.Data["Max"]); Assert.AreEqual(3, aggregate.Data["Count"]); Assert.AreEqual("Item Add duration", aggregate.MetricId); Assert.IsNotNull(aggregate.Dimensions); Assert.AreEqual(0, aggregate.Dimensions.Count); Assert.AreEqual(24.0, aggregate.Data["Sum"]); Assert.AreEqual(experimentStart.AddSeconds(totalSecs - 24), aggregate.AggregationPeriodStart); } }