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)); } }
// @PublicExposureCandidate internal MetricAggregate GetCurrentAggregateUnsafe(MetricAggregationCycleKind aggregationCycleKind, DateTimeOffset dateTime) { IMetricSeriesAggregator aggregator = null; if (this.requiresPersistentAggregator) { aggregator = this.aggregatorPersistent; } else { switch (aggregationCycleKind) { case CycleKind.Default: aggregator = UnwrapAggregator(this.aggregatorDefault); break; case CycleKind.QuickPulse: aggregator = UnwrapAggregator(this.aggregatorQuickPulse); break; case CycleKind.Custom: aggregator = UnwrapAggregator(this.aggregatorCustom); break; default: throw new ArgumentException(Invariant($"Unexpected value of {nameof(aggregationCycleKind)}: {aggregationCycleKind}.")); } } dateTime = Util.RoundDownToSecond(dateTime); MetricAggregate aggregate = aggregator?.CreateAggregateUnsafe(dateTime); return(aggregate); }
// @PublicExposureCandidate internal void ResetAggregation(DateTimeOffset periodStart) { periodStart = Util.RoundDownToSecond(periodStart); if (this.requiresPersistentAggregator) { IMetricSeriesAggregator aggregator = this.aggregatorPersistent; aggregator?.Reset(periodStart); } else { { IMetricSeriesAggregator aggregator = UnwrapAggregator(this.aggregatorDefault); aggregator?.Reset(periodStart); } { IMetricSeriesAggregator aggregator = UnwrapAggregator(this.aggregatorQuickPulse); aggregator?.Reset(periodStart); } { IMetricSeriesAggregator aggregator = UnwrapAggregator(this.aggregatorCustom); aggregator?.Reset(periodStart); } } }
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 MetricAggregationManager() { DateTimeOffset now = DateTimeOffset.Now; DateTimeOffset timestamp = Util.RoundDownToSecond(now); _aggregatorsForDefault = new AggregatorCollection(timestamp, filter: null); _aggregatorsForPersistent = new AggregatorCollection(timestamp, filter: null); }