From df8fd7b46d32be9249c2c5a892f8518699884de4 Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Thu, 3 Jun 2021 14:02:23 -0700 Subject: [PATCH 1/9] Define *Metric types and aggregators --- examples/Console/TestMetrics.cs | 34 ++++- .../Metrics/Aggregator/LastValueAggregator.cs | 85 ----------- .../Metrics/Aggregator/SumAggregator.cs | 119 --------------- src/OpenTelemetry/Metrics/AggregatorStore.cs | 129 ++++++++++------ .../Metrics/{ => DataPoint}/DataPoint.cs | 0 .../Metrics/{ => DataPoint}/DataPoint{T}.cs | 9 ++ .../Metrics/{ => DataPoint}/IDataPoint.cs | 0 src/OpenTelemetry/Metrics/InstrumentState.cs | 1 + .../Metrics/MeterProviderBuilderSdk.cs | 4 +- src/OpenTelemetry/Metrics/MeterProviderSdk.cs | 51 +++---- .../GaugeMetricAggregator.cs | 108 ++++++++++++++ .../MetricAggregators/HistogramBucket.cs | 25 ++++ .../HistogramMetricAggregator.cs | 97 ++++++++++++ .../IGaugeMetric.cs} | 19 +-- .../MetricAggregators/IHistogramMetric.cs | 33 ++++ .../IMetric.cs} | 21 ++- .../MetricAggregators/IMetricBuilder.cs | 28 ++++ .../Metrics/MetricAggregators/ISumMetric.cs | 31 ++++ .../MetricAggregators/ISummaryMetric.cs | 29 ++++ .../MetricAggregators/SumMetricAggregator.cs | 141 ++++++++++++++++++ .../SummaryMetricAggregator.cs | 112 ++++++++++++++ .../MetricAggregators/ValueAtQuantile.cs | 24 +++ .../Metrics/Processors/AggregateProcessor.cs | 51 ------- .../Processors/MetricConsoleExporter.cs | 19 ++- .../Metrics/Processors/MetricItem.cs | 5 +- test/Benchmarks/Metrics/MetricsBenchmarks.cs | 38 ++--- .../Metrics/MetricAPITest.cs | 2 +- 27 files changed, 838 insertions(+), 377 deletions(-) delete mode 100644 src/OpenTelemetry/Metrics/Aggregator/LastValueAggregator.cs delete mode 100644 src/OpenTelemetry/Metrics/Aggregator/SumAggregator.cs rename src/OpenTelemetry/Metrics/{ => DataPoint}/DataPoint.cs (100%) rename src/OpenTelemetry/Metrics/{ => DataPoint}/DataPoint{T}.cs (84%) rename src/OpenTelemetry/Metrics/{ => DataPoint}/IDataPoint.cs (100%) create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/HistogramBucket.cs create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs rename src/OpenTelemetry/Metrics/{Metric.cs => MetricAggregators/IGaugeMetric.cs} (62%) create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/IHistogramMetric.cs rename src/OpenTelemetry/Metrics/{Aggregator.cs => MetricAggregators/IMetric.cs} (66%) create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/IMetricBuilder.cs create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/ISummaryMetric.cs create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs create mode 100644 src/OpenTelemetry/Metrics/MetricAggregators/ValueAtQuantile.cs delete mode 100644 src/OpenTelemetry/Metrics/Processors/AggregateProcessor.cs diff --git a/examples/Console/TestMetrics.cs b/examples/Console/TestMetrics.cs index 259ca4c3d69..45d1011c4bf 100644 --- a/examples/Console/TestMetrics.cs +++ b/examples/Console/TestMetrics.cs @@ -34,14 +34,18 @@ internal static object Run(MetricsOptions options, ref bool prompt) .AddSource("TestMeter") // All instruments from this meter are enabled. .SetObservationPeriod(options.ObservationPeriodMilliseconds) .SetCollectionPeriod(options.CollectionPeriodMilliseconds) - .AddProcessor(new TagEnrichmentProcessor("newAttrib", "newAttribValue")) - .AddExportProcessor(new MetricConsoleExporter()) + .AddProcessor(new TagEnrichmentProcessor("resource", "here")) + .AddExportProcessor(new MetricConsoleExporter("A")) + .SetCollectionPeriod(5 * options.CollectionPeriodMilliseconds) + .AddExportProcessor(new MetricConsoleExporter("B")) .Build(); using var meter = new Meter("TestMeter", "0.0.1"); var counter = meter.CreateCounter("counter1"); + var histogram = meter.CreateHistogram("histogram"); + if (options.RunObservable ?? true) { var observableCounter = meter.CreateObservableGauge("CurrentMemoryUsage", () => @@ -76,6 +80,26 @@ internal static object Run(MetricsOptions options, ref bool prompt) break; } + histogram.Record(10); + + histogram.Record( + 100, + new KeyValuePair("tag1", "value1")); + + histogram.Record( + 200, + new KeyValuePair("tag1", "value2"), + new KeyValuePair("tag2", "value2")); + + histogram.Record( + 100, + new KeyValuePair("tag1", "value1")); + + histogram.Record( + 200, + new KeyValuePair("tag2", "value2"), + new KeyValuePair("tag1", "value2")); + counter.Add(10); counter.Add( @@ -102,6 +126,12 @@ internal static object Run(MetricsOptions options, ref bool prompt) } cts.CancelAfter(options.RunTime); + System.Console.WriteLine($"Wait for {options.RunTime} milliseconds."); + while (!cts.IsCancellationRequested) + { + Task.Delay(1000).Wait(); + } + Task.WaitAll(tasks.ToArray()); if (prompt) diff --git a/src/OpenTelemetry/Metrics/Aggregator/LastValueAggregator.cs b/src/OpenTelemetry/Metrics/Aggregator/LastValueAggregator.cs deleted file mode 100644 index 757dd99150e..00000000000 --- a/src/OpenTelemetry/Metrics/Aggregator/LastValueAggregator.cs +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System; -using System.Collections.Generic; -using System.Diagnostics.Metrics; -using System.Linq; - -namespace OpenTelemetry.Metrics -{ - internal class LastValueAggregator : Aggregator - { - private readonly Instrument instrument; - private readonly KeyValuePair[] tags; - - private readonly object lockUpdate = new object(); - private int count = 0; - private DataPoint lastDataPoint; - - internal LastValueAggregator(Instrument instrument, string[] names, object[] values) - { - this.instrument = instrument; - - if (names.Length != values.Length) - { - throw new ArgumentException($"Length of {nameof(names)} and {nameof(values)} must match."); - } - - this.tags = new KeyValuePair[names.Length]; - for (int i = 0; i < names.Length; i++) - { - this.tags[i] = new KeyValuePair(names[i], values[i]); - } - } - - internal override void Update(DateTimeOffset dt, T value) - where T : struct - { - lock (this.lockUpdate) - { - this.count++; - this.lastDataPoint = DataPoint.CreateDataPoint(dt, value, this.tags); - } - } - - internal override IEnumerable Collect() - { - // TODO: Need to determine how to convert to Metric - - if (this.count == 0) - { - return Enumerable.Empty(); - } - - DataPoint lastValue; - lock (this.lockUpdate) - { - lastValue = this.lastDataPoint; - this.count = 0; - } - - var metrics = new Metric[] - { - new Metric( - $"{this.instrument.Meter.Name}:{this.instrument.Name}:LastValue", - lastValue), - }; - - return metrics; - } - } -} diff --git a/src/OpenTelemetry/Metrics/Aggregator/SumAggregator.cs b/src/OpenTelemetry/Metrics/Aggregator/SumAggregator.cs deleted file mode 100644 index 4fc75ccce70..00000000000 --- a/src/OpenTelemetry/Metrics/Aggregator/SumAggregator.cs +++ /dev/null @@ -1,119 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System; -using System.Collections.Generic; -using System.Diagnostics.Metrics; -using System.Linq; - -namespace OpenTelemetry.Metrics -{ - internal class SumAggregator : Aggregator - { - private readonly Instrument instrument; - private readonly KeyValuePair[] tags; - private readonly object lockUpdate = new object(); - private Type valueType; - private long sum = 0; - private double dsum = 0; - private long count = 0; - - internal SumAggregator(Instrument instrument, string[] names, object[] values) - { - this.instrument = instrument; - - if (names.Length != values.Length) - { - throw new ArgumentException("Length of names[] and values[] must match."); - } - - this.tags = new KeyValuePair[names.Length]; - for (int i = 0; i < names.Length; i++) - { - this.tags[i] = new KeyValuePair(names[i], values[i]); - } - } - - internal override void Update(DateTimeOffset dt, T value) - where T : struct - { - lock (this.lockUpdate) - { - this.count++; - this.valueType = typeof(T); - - // TODO: Need to handle DataPoint appropriately - - if (typeof(T) == typeof(int)) - { - this.sum += (int)(object)value; - } - else if (typeof(T) == typeof(double)) - { - this.dsum += (double)(object)value; - } - else - { - throw new Exception("Unsupported Type"); - } - } - } - - internal override IEnumerable Collect() - { - // TODO: Need to determine how to convert to Metric - - if (this.count == 0) - { - return Enumerable.Empty(); - } - - var dt = MeterProviderSdk.GetDateTimeOffset(); - - IDataPoint datapointSum; - IDataPoint datapointCount; - lock (this.lockUpdate) - { - datapointCount = new DataPoint(dt, (int)this.count, this.tags); - - if (this.valueType == typeof(int)) - { - datapointSum = new DataPoint(dt, (int)this.sum, this.tags); - this.sum = 0; - } - else if (this.valueType == typeof(double)) - { - datapointSum = new DataPoint(dt, (double)this.dsum, this.tags); - this.dsum = 0; - } - else - { - throw new Exception("Unsupported Type"); - } - - this.count = 0; - } - - var metrics = new Metric[] - { - new Metric($"{this.instrument.Meter.Name}:{this.instrument.Name}:Count", datapointCount), - new Metric($"{this.instrument.Meter.Name}:{this.instrument.Name}:Sum", datapointSum), - }; - - return metrics; - } - } -} diff --git a/src/OpenTelemetry/Metrics/AggregatorStore.cs b/src/OpenTelemetry/Metrics/AggregatorStore.cs index 9f3fe9a7870..9fe058228c9 100644 --- a/src/OpenTelemetry/Metrics/AggregatorStore.cs +++ b/src/OpenTelemetry/Metrics/AggregatorStore.cs @@ -15,9 +15,9 @@ // using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.Metrics; +using System.Linq; namespace OpenTelemetry.Metrics { @@ -31,54 +31,80 @@ internal class AggregatorStore private readonly object lockKeyValue2MetricAggs = new object(); - // Two-Level lookup. TagKeys x [ TagValues x Aggregators ] - private readonly Dictionary> keyValue2MetricAggs = - new Dictionary>(new StringArrayEqualityComparer()); + // Two-Level lookup. TagKeys x [ TagValues x Metrics ] + private readonly Dictionary> keyValue2MetricAggs = + new Dictionary>(new StringArrayEqualityComparer()); - private Aggregator[] tag0Aggregators = null; + private MetricAgg[] tag0Metrics = null; + + private IEnumerable timePeriods; internal AggregatorStore(MeterProviderSdk sdk, Instrument instrument) { this.sdk = sdk; this.instrument = instrument; - foreach (var processor in this.sdk.AggregateProcessors) - { - processor.Register(this); - } + this.timePeriods = this.sdk.ExportProcessors.Select(k => k.Value).Distinct(); } - internal Aggregator[] GetDefaultAggregator(string[] seqKey, object[] seqVal) + internal MetricAgg[] MapToMetrics(string[] seqKey, object[] seqVal) { - // TODO: Figure out default aggregator/s based on Instrument and configs + var metricpairs = new List(); + + var name = $"{this.instrument.Meter.Name}:{this.instrument.Name}"; - if (!this.instrument.IsObservable) + var tags = new KeyValuePair[seqKey.Length]; + for (int i = 0; i < seqKey.Length; i++) { - return new Aggregator[] - { - new SumAggregator(this.instrument, seqKey, seqVal), - new LastValueAggregator(this.instrument, seqKey, seqVal), - }; + tags[i] = new KeyValuePair(seqKey[i], seqVal[i]); } - return new Aggregator[] + var dt = DateTimeOffset.UtcNow; + + foreach (var timeperiod in this.timePeriods) { - new LastValueAggregator(this.instrument, seqKey, seqVal), - }; + // TODO: Need to map each instrument to metrics (based on View API) + + if (this.instrument.GetType().Name.Contains("Counter")) + { + metricpairs.Add(new MetricAgg(timeperiod, new SumMetricAggregator(name, dt, tags, false, true))); + metricpairs.Add(new MetricAgg(timeperiod, new SumMetricAggregator(name, dt, tags, true, true))); + metricpairs.Add(new MetricAgg(timeperiod, new SummaryMetricAggregator(name, dt, tags, false))); + } + else if (this.instrument.GetType().Name.Contains("Gauge")) + { + metricpairs.Add(new MetricAgg(timeperiod, new GaugeMetricAggregator(name, dt, tags, false))); + metricpairs.Add(new MetricAgg(timeperiod, new SummaryMetricAggregator(name, dt, tags, false))); + } + else if (this.instrument.GetType().Name.Contains("Histogram")) + { + metricpairs.Add(new MetricAgg(timeperiod, new HistogramMetricAggregator(name, dt, tags, false))); + } + else + { + metricpairs.Add(new MetricAgg(timeperiod, new GaugeMetricAggregator(name, dt, tags, false))); + metricpairs.Add(new MetricAgg(timeperiod, new SumMetricAggregator(name, dt, tags, false, true))); + metricpairs.Add(new MetricAgg(timeperiod, new SumMetricAggregator(name, dt, tags, true, true))); + metricpairs.Add(new MetricAgg(timeperiod, new SummaryMetricAggregator(name, dt, tags, false))); + metricpairs.Add(new MetricAgg(timeperiod, new HistogramMetricAggregator(name, dt, tags, false))); + } + } + + return metricpairs.ToArray(); } - internal Aggregator[] FindAggregators(ReadOnlySpan> tags) + internal MetricAgg[] FindMetricAggregators(ReadOnlySpan> tags) { int len = tags.Length; if (len == 0) { - if (this.tag0Aggregators == null) + if (this.tag0Metrics == null) { - this.tag0Aggregators = this.GetDefaultAggregator(AggregatorStore.EmptySeqKey, AggregatorStore.EmptySeqValue); + this.tag0Metrics = this.MapToMetrics(AggregatorStore.EmptySeqKey, AggregatorStore.EmptySeqValue); } - return this.tag0Aggregators; + return this.tag0Metrics; } var storage = ThreadStaticStorage.GetStorage(); @@ -90,14 +116,14 @@ internal Aggregator[] FindAggregators(ReadOnlySpan> Array.Sort(tagKey, tagValue); } - Aggregator[] aggregators; + MetricAgg[] metrics; lock (this.lockKeyValue2MetricAggs) { string[] seqKey = null; // GetOrAdd by TagKey at 1st Level of 2-level dictionary structure. - // Get back a Dictionary of [ Values x Aggregators[] ]. + // Get back a Dictionary of [ Values x Metrics[] ]. if (!this.keyValue2MetricAggs.TryGetValue(tagKey, out var value2metrics)) { // Note: We are using storage from ThreadStatic, so need to make a deep copy for Dictionary storage. @@ -105,13 +131,13 @@ internal Aggregator[] FindAggregators(ReadOnlySpan> seqKey = new string[len]; tagKey.CopyTo(seqKey, 0); - value2metrics = new Dictionary(new ObjectArrayEqualityComparer()); + value2metrics = new Dictionary(new ObjectArrayEqualityComparer()); this.keyValue2MetricAggs.Add(seqKey, value2metrics); } // GetOrAdd by TagValue at 2st Level of 2-level dictionary structure. - // Get back Aggregators[]. - if (!value2metrics.TryGetValue(tagValue, out aggregators)) + // Get back Metrics[]. + if (!value2metrics.TryGetValue(tagValue, out metrics)) { // Note: We are using storage from ThreadStatic, so need to make a deep copy for Dictionary storage. @@ -124,13 +150,13 @@ internal Aggregator[] FindAggregators(ReadOnlySpan> var seqVal = new object[len]; tagValue.CopyTo(seqVal, 0); - aggregators = this.GetDefaultAggregator(seqKey, seqVal); + metrics = this.MapToMetrics(seqKey, seqVal); - value2metrics.Add(seqVal, aggregators); + value2metrics.Add(seqVal, metrics); } } - return aggregators; + return metrics; } internal void Update(DateTimeOffset dt, T value, ReadOnlySpan> tags) @@ -141,34 +167,51 @@ internal void Update(DateTimeOffset dt, T value, ReadOnlySpan Collect() + internal List Collect(int periodMilliseconds) { - var aggs = new List(); + var collectedMetrics = new List(); + + var dt = DateTimeOffset.UtcNow; foreach (var keys in this.keyValue2MetricAggs) { foreach (var values in keys.Value) { - aggs.AddRange(values.Value); + foreach (var metric in values.Value) + { + if (metric.TimePeriod == periodMilliseconds) + { + var m = metric.Metric.Collect(dt); + if (m != null) + { + collectedMetrics.Add(m); + } + } + } } } - var metrics = new List(); + return collectedMetrics; + } + + internal class MetricAgg + { + internal int TimePeriod; + internal IMetricBuilder Metric; - foreach (var aggregator in aggs) + internal MetricAgg(int timePeriod, IMetricBuilder metric) { - metrics.AddRange(aggregator.Collect()); + this.TimePeriod = timePeriod; + this.Metric = metric; } - - return metrics; } } } diff --git a/src/OpenTelemetry/Metrics/DataPoint.cs b/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs similarity index 100% rename from src/OpenTelemetry/Metrics/DataPoint.cs rename to src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs diff --git a/src/OpenTelemetry/Metrics/DataPoint{T}.cs b/src/OpenTelemetry/Metrics/DataPoint/DataPoint{T}.cs similarity index 84% rename from src/OpenTelemetry/Metrics/DataPoint{T}.cs rename to src/OpenTelemetry/Metrics/DataPoint/DataPoint{T}.cs index cc19d1a33b1..60a10145db6 100644 --- a/src/OpenTelemetry/Metrics/DataPoint{T}.cs +++ b/src/OpenTelemetry/Metrics/DataPoint/DataPoint{T}.cs @@ -23,12 +23,21 @@ namespace OpenTelemetry.Metrics internal readonly struct DataPoint : IDataPoint where T : struct { + private static readonly KeyValuePair[] EmptyTag = new KeyValuePair[0]; + private readonly T value; private readonly DateTimeOffset timestamp; private readonly KeyValuePair[] tags; + internal DataPoint(DateTimeOffset timestamp, T value) + { + this.timestamp = timestamp; + this.value = value; + this.tags = DataPoint.EmptyTag; + } + internal DataPoint(DateTimeOffset timestamp, T value, KeyValuePair[] tags) { this.timestamp = timestamp; diff --git a/src/OpenTelemetry/Metrics/IDataPoint.cs b/src/OpenTelemetry/Metrics/DataPoint/IDataPoint.cs similarity index 100% rename from src/OpenTelemetry/Metrics/IDataPoint.cs rename to src/OpenTelemetry/Metrics/DataPoint/IDataPoint.cs diff --git a/src/OpenTelemetry/Metrics/InstrumentState.cs b/src/OpenTelemetry/Metrics/InstrumentState.cs index 997faa38649..7a3722f5998 100644 --- a/src/OpenTelemetry/Metrics/InstrumentState.cs +++ b/src/OpenTelemetry/Metrics/InstrumentState.cs @@ -28,6 +28,7 @@ internal class InstrumentState internal InstrumentState(MeterProviderSdk sdk, Instrument instrument) { this.store = new AggregatorStore(sdk, instrument); + sdk.AggregatorStores.TryAdd(this.store, true); } internal void Update(DateTimeOffset dt, T value, ReadOnlySpan> tags) diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs index 289b1f45a55..5d574f4cc90 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs @@ -31,7 +31,7 @@ internal MeterProviderBuilderSdk() internal List MeasurementProcessors { get; } = new List(); - internal List ExportProcessors { get; } = new List(); + internal List> ExportProcessors { get; } = new List>(); public override MeterProviderBuilder AddSource(params string[] names) { @@ -73,7 +73,7 @@ internal MeterProviderBuilderSdk AddMeasurementProcessor(MeasurementProcessor pr internal MeterProviderBuilderSdk AddExporter(MetricProcessor processor) { - this.ExportProcessors.Add(processor); + this.ExportProcessors.Add(new KeyValuePair(processor, this.collectionPeriodMilliseconds)); return this; } diff --git a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs index ad546cf01c0..7e42cd4082f 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs @@ -15,8 +15,10 @@ // using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.Metrics; +using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -26,12 +28,14 @@ namespace OpenTelemetry.Metrics public class MeterProviderSdk : MeterProvider { + internal readonly ConcurrentDictionary AggregatorStores = new ConcurrentDictionary(); + private static int lastTick = -1; private static DateTimeOffset lastTimestamp = DateTimeOffset.MinValue; private readonly CancellationTokenSource cts = new CancellationTokenSource(); private readonly Task observerTask; - private readonly Task collectorTask; + private readonly List collectorTasks = new List(); private readonly MeterListener listener; private readonly object lockInstrumentStates = new object(); @@ -42,7 +46,7 @@ internal MeterProviderSdk( int observationPeriodMilliseconds, int collectionPeriodMilliseconds, MeasurementProcessor[] measurementProcessors, - MetricProcessor[] metricExportProcessors) + KeyValuePair[] metricExportProcessors) { this.ObservationPeriodMilliseconds = observationPeriodMilliseconds; this.CollectionPeriodMilliseconds = collectionPeriodMilliseconds; @@ -51,8 +55,6 @@ internal MeterProviderSdk( this.MeasurementProcessors.AddRange(measurementProcessors); - this.AggregateProcessors.Add(new AggregateProcessor()); - this.ExportProcessors.AddRange(metricExportProcessors); // Setup Listener @@ -96,7 +98,13 @@ internal MeterProviderSdk( var token = this.cts.Token; this.observerTask = Task.Run(async () => await this.ObserverTask(token)); - this.collectorTask = Task.Run(async () => await this.CollectorTask(token)); + + // Group Export processors by their collectionPeriod. + var groups = this.ExportProcessors.GroupBy(k => k.Value, v => v.Key); + foreach (var group in groups) + { + this.collectorTasks.Add(Task.Run(async () => await this.CollectorTask(token, group.Key, group.ToArray()))); + } } internal int ObservationPeriodMilliseconds { get; } = 1000; @@ -105,11 +113,9 @@ internal MeterProviderSdk( internal List MeasurementProcessors { get; } = new List(); - internal List AggregateProcessors { get; } = new List(); - internal List MetricProcessors { get; } = new List(); - internal List ExportProcessors { get; } = new List(); + internal List> ExportProcessors { get; } = new List>(); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static DateTimeOffset GetDateTimeOffset() @@ -155,18 +161,12 @@ internal void MeasurementRecorded(Instrument instrument, T value, ReadOnlySpa var val = value; // Run Pre Aggregator Processors - foreach (var processor in this.MeasurementProcessors) { processor.OnEnd(measurementItem, ref dt, ref val, ref tags); } - // Run Aggregator Processors - - foreach (var processor in this.AggregateProcessors) - { - processor.OnEnd(measurementItem, ref dt, ref val, ref tags); - } + instrumentState.Update(dt, val, tags); } protected override void Dispose(bool disposing) @@ -177,9 +177,10 @@ protected override void Dispose(bool disposing) this.observerTask.Wait(); - this.collectorTask.Wait(); - - this.Collect(); + foreach (var collectorTask in this.collectorTasks) + { + collectorTask.Wait(); + } } private async Task ObserverTask(CancellationToken token) @@ -198,29 +199,29 @@ private async Task ObserverTask(CancellationToken token) } } - private async Task CollectorTask(CancellationToken token) + private async Task CollectorTask(CancellationToken token, int collectionPeriodMilliseconds, MetricProcessor[] processors) { while (!token.IsCancellationRequested) { try { - await Task.Delay(this.CollectionPeriodMilliseconds, token); + await Task.Delay(collectionPeriodMilliseconds, token); } catch (TaskCanceledException) { } - this.Collect(); + this.Collect(collectionPeriodMilliseconds, processors); } } - private void Collect() + private void Collect(int collectionPeriodMilliseconds, MetricProcessor[] processors) { var metricItem = new MetricItem(); - foreach (var processor in this.AggregateProcessors) + foreach (var kv in this.AggregatorStores) { - var metrics = processor.Collect(); + var metrics = kv.Key.Collect(collectionPeriodMilliseconds); metricItem.Metrics.AddRange(metrics); } @@ -229,7 +230,7 @@ private void Collect() processor.OnEnd(metricItem); } - foreach (var processor in this.ExportProcessors) + foreach (var processor in processors) { processor.OnEnd(metricItem); } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs new file mode 100644 index 00000000000..2c14aaf39ae --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs @@ -0,0 +1,108 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal class GaugeMetricAggregator : IGaugeMetric, IMetricBuilder + { + private readonly object lockUpdate = new object(); + private Type valueType; + private int intValue; + private double doubleValue; + + internal GaugeMetricAggregator(string name, DateTimeOffset startTimeExclusive, KeyValuePair[] attributes, bool isDelta) + { + this.Name = name; + this.StartTimeExclusive = startTimeExclusive; + this.EndTimeInclusive = startTimeExclusive; + this.Attributes = attributes; + this.IsDeltaTemporality = isDelta; + } + + public string Name { get; private set; } + + public DateTimeOffset StartTimeExclusive { get; private set; } + + public DateTimeOffset EndTimeInclusive { get; private set; } + + public KeyValuePair[] Attributes { get; private set; } + + public bool IsDeltaTemporality { get; } + + public IEnumerable Exemplars { get; private set; } = new List(); + + public IDataPoint LastValue + { + get + { + if (this.valueType == typeof(int)) + { + return DataPoint.CreateDataPoint(this.EndTimeInclusive, this.intValue, this.Attributes); + } + else if (this.valueType == typeof(double)) + { + return DataPoint.CreateDataPoint(this.EndTimeInclusive, this.doubleValue, this.Attributes); + } + else + { + throw new Exception("Unsupported Type"); + } + } + } + + public void Update(DateTimeOffset dt, T value) + where T : struct + { + lock (this.lockUpdate) + { + this.EndTimeInclusive = dt; + this.valueType = typeof(T); + if (typeof(T) == typeof(int)) + { + this.intValue = (int)(object)value; + } + else if (typeof(T) == typeof(double)) + { + this.doubleValue = (double)(object)value; + } + } + } + + public IMetric Collect(DateTimeOffset dt) + { + var cloneItem = new GaugeMetricAggregator(this.Name, this.StartTimeExclusive, this.Attributes, this.IsDeltaTemporality); + + lock (this.lockUpdate) + { + cloneItem.Exemplars = this.Exemplars; + cloneItem.EndTimeInclusive = dt; + cloneItem.valueType = this.valueType; + cloneItem.intValue = this.intValue; + cloneItem.doubleValue = this.doubleValue; + } + + return cloneItem; + } + + public string ToDisplayString() + { + return $"Last={this.LastValue.Value}"; + } + } +} diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/HistogramBucket.cs b/src/OpenTelemetry/Metrics/MetricAggregators/HistogramBucket.cs new file mode 100644 index 00000000000..4c972d7e6ea --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/HistogramBucket.cs @@ -0,0 +1,25 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Metrics +{ + internal struct HistogramBucket + { + internal double LowBoundary; + internal double HighBoundary; + internal long Count; + } +} diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs new file mode 100644 index 00000000000..4d92ccb640a --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs @@ -0,0 +1,97 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal class HistogramMetricAggregator : IHistogramMetric, IMetricBuilder + { + private readonly object lockUpdate = new object(); + private List buckets = new List(); + + internal HistogramMetricAggregator(string name, DateTimeOffset startTimeExclusive, KeyValuePair[] attributes, bool isDelta) + { + this.Name = name; + this.StartTimeExclusive = startTimeExclusive; + this.EndTimeInclusive = startTimeExclusive; + this.Attributes = attributes; + this.IsDeltaTemporality = isDelta; + } + + public string Name { get; private set; } + + public DateTimeOffset StartTimeExclusive { get; private set; } + + public DateTimeOffset EndTimeInclusive { get; private set; } + + public KeyValuePair[] Attributes { get; private set; } + + public bool IsDeltaTemporality { get; } + + public IEnumerable Exemplars { get; private set; } = new List(); + + public long PopulationCount { get; private set; } + + public double PopulationSum { get; private set; } + + public IEnumerable Buckets => this.buckets; + + public void Update(DateTimeOffset dt, T value) + where T : struct + { + // TODO: Implement Histogram! + + lock (this.lockUpdate) + { + this.EndTimeInclusive = dt; + this.PopulationCount++; + } + } + + public IMetric Collect(DateTimeOffset dt) + { + if (this.PopulationCount == 0) + { + // TODO: Output stale markers + return null; + } + + var cloneItem = new HistogramMetricAggregator(this.Name, this.StartTimeExclusive, this.Attributes, this.IsDeltaTemporality); + + lock (this.lockUpdate) + { + cloneItem.Exemplars = this.Exemplars; + cloneItem.EndTimeInclusive = dt; + cloneItem.PopulationCount = this.PopulationCount; + cloneItem.PopulationSum = this.PopulationSum; + cloneItem.buckets = this.buckets; + + this.StartTimeExclusive = dt; + this.PopulationCount = 0; + this.PopulationSum = 0; + } + + return cloneItem; + } + + public string ToDisplayString() + { + return $"Count={this.PopulationCount},Sum={this.PopulationSum}"; + } + } +} diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs similarity index 62% rename from src/OpenTelemetry/Metrics/Metric.cs rename to src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs index c3b89808386..8b3621c1921 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,23 +14,16 @@ // limitations under the License. // -using System; using System.Collections.Generic; -using System.Diagnostics.Metrics; namespace OpenTelemetry.Metrics { - // TODO: Need to determine what a Metric actually contains - - internal struct Metric + internal interface IGaugeMetric : IMetric { - internal readonly string Name; - internal IDataPoint Point; + bool IsDeltaTemporality { get; } + + IEnumerable Exemplars { get; } - internal Metric(string name, IDataPoint point) - { - this.Name = name; - this.Point = point; - } + IDataPoint LastValue { get; } } } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/IHistogramMetric.cs b/src/OpenTelemetry/Metrics/MetricAggregators/IHistogramMetric.cs new file mode 100644 index 00000000000..475250bf1da --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/IHistogramMetric.cs @@ -0,0 +1,33 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal interface IHistogramMetric : IMetric + { + bool IsDeltaTemporality { get; } + + IEnumerable Exemplars { get; } + + long PopulationCount { get; } + + double PopulationSum { get; } + + IEnumerable Buckets { get; } + } +} diff --git a/src/OpenTelemetry/Metrics/Aggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/IMetric.cs similarity index 66% rename from src/OpenTelemetry/Metrics/Aggregator.cs rename to src/OpenTelemetry/Metrics/MetricAggregators/IMetric.cs index 471bb67bc22..e8d7d56dc18 100644 --- a/src/OpenTelemetry/Metrics/Aggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/IMetric.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,20 +16,19 @@ using System; using System.Collections.Generic; -using System.Linq; namespace OpenTelemetry.Metrics { - internal abstract class Aggregator + internal interface IMetric { - internal virtual void Update(DateTimeOffset dt, T value) - where T : struct - { - } + string Name { get; } - internal virtual IEnumerable Collect() - { - return Enumerable.Empty(); - } + DateTimeOffset StartTimeExclusive { get; } + + DateTimeOffset EndTimeInclusive { get; } + + KeyValuePair[] Attributes { get; } + + string ToDisplayString(); } } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/IMetricBuilder.cs b/src/OpenTelemetry/Metrics/MetricAggregators/IMetricBuilder.cs new file mode 100644 index 00000000000..ddf1e97cbac --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/IMetricBuilder.cs @@ -0,0 +1,28 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; + +namespace OpenTelemetry.Metrics +{ + internal interface IMetricBuilder + { + void Update(DateTimeOffset dt, T value) + where T : struct; + + IMetric Collect(DateTimeOffset dt); + } +} diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs b/src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs new file mode 100644 index 00000000000..f95fdd8ed4e --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs @@ -0,0 +1,31 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal interface ISumMetric : IMetric + { + bool IsDeltaTemporality { get; } + + bool IsMonotonic { get; } + + IEnumerable Exemplars { get; } + + object Sum { get; } + } +} diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/ISummaryMetric.cs b/src/OpenTelemetry/Metrics/MetricAggregators/ISummaryMetric.cs new file mode 100644 index 00000000000..f36f23171be --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/ISummaryMetric.cs @@ -0,0 +1,29 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal interface ISummaryMetric : IMetric + { + long PopulationCount { get; } + + double PopulationSum { get; } + + IEnumerable Quantiles { get; } + } +} diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs new file mode 100644 index 00000000000..7a13c306bcf --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs @@ -0,0 +1,141 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal class SumMetricAggregator : ISumMetric, IMetricBuilder + { + private readonly object lockUpdate = new object(); + private Type valueType; + private long sum = 0; + private double dsum = 0; + private long count = 0; + + internal SumMetricAggregator(string name, DateTimeOffset startTimeExclusive, KeyValuePair[] attributes, bool isDelta, bool isMonotonic) + { + this.Name = name; + this.StartTimeExclusive = startTimeExclusive; + this.EndTimeInclusive = startTimeExclusive; + this.Attributes = attributes; + this.IsDeltaTemporality = isDelta; + this.IsMonotonic = isMonotonic; + } + + public string Name { get; private set; } + + public DateTimeOffset StartTimeExclusive { get; private set; } + + public DateTimeOffset EndTimeInclusive { get; private set; } + + public KeyValuePair[] Attributes { get; private set; } + + public bool IsDeltaTemporality { get; } + + public bool IsMonotonic { get; } + + public IEnumerable Exemplars { get; private set; } = new List(); + + public object Sum + { + get + { + if (this.valueType == typeof(int)) + { + return this.sum; + } + else if (this.valueType == typeof(double)) + { + return this.dsum; + } + + return "Unknown"; + } + } + + public void Update(DateTimeOffset dt, T value) + where T : struct + { + lock (this.lockUpdate) + { + this.EndTimeInclusive = dt; + + this.valueType = typeof(T); + + if (typeof(T) == typeof(int)) + { + var val = (int)(object)value; + + if (this.IsMonotonic && val < 0) + { + return; + } + + this.sum += val; + this.count++; + } + else if (typeof(T) == typeof(double)) + { + var val = (double)(object)value; + + if (this.IsMonotonic && val < 0) + { + return; + } + + this.dsum += val; + this.count++; + } + else + { + throw new Exception("Unsupported Type"); + } + } + } + + public IMetric Collect(DateTimeOffset dt) + { + var cloneItem = new SumMetricAggregator(this.Name, this.StartTimeExclusive, this.Attributes, this.IsDeltaTemporality, this.IsMonotonic); + + lock (this.lockUpdate) + { + cloneItem.Exemplars = this.Exemplars; + cloneItem.EndTimeInclusive = dt; + cloneItem.valueType = this.valueType; + cloneItem.count = this.count; + cloneItem.sum = this.sum; + cloneItem.dsum = this.dsum; + + if (this.IsDeltaTemporality) + { + this.StartTimeExclusive = dt; + this.count = 0; + this.sum = 0; + this.dsum = 0; + } + } + + return cloneItem; + } + + public string ToDisplayString() + { + return $"Delta={this.IsDeltaTemporality},Count={this.count},Sum={this.Sum}"; + } + } +} diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs new file mode 100644 index 00000000000..cd34f553e4a --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs @@ -0,0 +1,112 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal class SummaryMetricAggregator : ISummaryMetric, IMetricBuilder + { + internal readonly bool IsMonotonic; + private readonly object lockUpdate = new object(); + + private List quantiles = new List(); + + internal SummaryMetricAggregator(string name, DateTimeOffset startTimeExclusive, KeyValuePair[] attributes, bool isMonotonic) + { + this.Name = name; + this.StartTimeExclusive = startTimeExclusive; + this.EndTimeInclusive = startTimeExclusive; + this.Attributes = attributes; + this.IsMonotonic = isMonotonic; + } + + public string Name { get; private set; } + + public DateTimeOffset StartTimeExclusive { get; private set; } + + public DateTimeOffset EndTimeInclusive { get; private set; } + + public KeyValuePair[] Attributes { get; private set; } + + public long PopulationCount { get; private set; } + + public double PopulationSum { get; private set; } + + public IEnumerable Quantiles => this.quantiles; + + public void Update(DateTimeOffset dt, T value) + where T : struct + { + // TODO: Implement Summary! + + lock (this.lockUpdate) + { + this.EndTimeInclusive = dt; + + if (typeof(T) == typeof(int)) + { + var val = (int)(object)value; + if (val > 0 || !this.IsMonotonic) + { + this.PopulationSum += (double)val; + } + } + else if (typeof(T) == typeof(double)) + { + var val = (double)(object)value; + if (val > 0 || !this.IsMonotonic) + { + this.PopulationSum += (double)val; + } + } + + this.PopulationCount++; + } + } + + public IMetric Collect(DateTimeOffset dt) + { + if (this.PopulationCount == 0) + { + // TODO: Output stale markers + return null; + } + + var cloneItem = new SummaryMetricAggregator(this.Name, this.StartTimeExclusive, this.Attributes, this.IsMonotonic); + + lock (this.lockUpdate) + { + cloneItem.EndTimeInclusive = dt; + cloneItem.PopulationCount = this.PopulationCount; + cloneItem.PopulationSum = this.PopulationSum; + cloneItem.quantiles = this.quantiles; + + this.StartTimeExclusive = dt; + this.PopulationCount = 0; + this.PopulationSum = 0; + } + + return cloneItem; + } + + public string ToDisplayString() + { + return $"Count={this.PopulationCount},Sum={this.PopulationSum}"; + } + } +} diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/ValueAtQuantile.cs b/src/OpenTelemetry/Metrics/MetricAggregators/ValueAtQuantile.cs new file mode 100644 index 00000000000..7b757cbd2df --- /dev/null +++ b/src/OpenTelemetry/Metrics/MetricAggregators/ValueAtQuantile.cs @@ -0,0 +1,24 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Metrics +{ + internal struct ValueAtQuantile + { + internal double Quantile; + internal double Value; + } +} diff --git a/src/OpenTelemetry/Metrics/Processors/AggregateProcessor.cs b/src/OpenTelemetry/Metrics/Processors/AggregateProcessor.cs deleted file mode 100644 index 9e905e2aaab..00000000000 --- a/src/OpenTelemetry/Metrics/Processors/AggregateProcessor.cs +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics.Metrics; - -namespace OpenTelemetry.Metrics -{ - internal class AggregateProcessor : MeasurementProcessor - { - internal ConcurrentDictionary AggregatorStores { get; } = new ConcurrentDictionary(); - - internal override void OnEnd(MeasurementItem measurementItem, ref DateTimeOffset dt, ref T value, ref ReadOnlySpan> tags) - where T : struct - { - measurementItem.State.Update(dt, value, tags); - } - - internal void Register(AggregatorStore store) - { - this.AggregatorStores.TryAdd(store, true); - } - - internal IEnumerable Collect() - { - var metrics = new List(); - - foreach (var kv in this.AggregatorStores) - { - metrics.AddRange(kv.Key.Collect()); - } - - return metrics.ToArray(); - } - } -} diff --git a/src/OpenTelemetry/Metrics/Processors/MetricConsoleExporter.cs b/src/OpenTelemetry/Metrics/Processors/MetricConsoleExporter.cs index 4555b396c93..fe718669850 100644 --- a/src/OpenTelemetry/Metrics/Processors/MetricConsoleExporter.cs +++ b/src/OpenTelemetry/Metrics/Processors/MetricConsoleExporter.cs @@ -21,13 +21,26 @@ namespace OpenTelemetry.Metrics { public class MetricConsoleExporter : MetricProcessor { + private string name; + + public MetricConsoleExporter(string name) + { + this.name = name; + } + public override void OnEnd(MetricItem data) { foreach (var metric in data.Metrics) { - var tags = metric.Point?.Tags.ToArray().Select(k => $"{k.Key}={k.Value?.ToString()}"); - var msg = $"{metric.Name}[{string.Join(";", tags)}] = {metric.Point?.Value.ToString()}"; - Console.WriteLine($"Export: {msg}"); + var tags = metric.Attributes.ToArray().Select(k => $"{k.Key}={k.Value?.ToString()}"); + + var kind = metric.GetType().Name; + var value = metric.ToDisplayString(); + + string time = $"{metric.StartTimeExclusive.ToLocalTime().ToString("HH:mm:ss.fff")} {metric.EndTimeInclusive.ToLocalTime().ToString("HH:mm:ss.fff")}"; + + var msg = $"Export[{this.name}] {time} {metric.Name} [{string.Join(";", tags)}] {kind} {value}"; + Console.WriteLine(msg); } } } diff --git a/src/OpenTelemetry/Metrics/Processors/MetricItem.cs b/src/OpenTelemetry/Metrics/Processors/MetricItem.cs index c317321ee60..1f06d33e0de 100644 --- a/src/OpenTelemetry/Metrics/Processors/MetricItem.cs +++ b/src/OpenTelemetry/Metrics/Processors/MetricItem.cs @@ -14,16 +14,13 @@ // limitations under the License. // -using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics.Metrics; namespace OpenTelemetry.Metrics { public class MetricItem { - internal List Metrics = new List(); + internal List Metrics = new List(); internal MetricItem() { diff --git a/test/Benchmarks/Metrics/MetricsBenchmarks.cs b/test/Benchmarks/Metrics/MetricsBenchmarks.cs index 634b62bddb1..b0d7f2a8bcc 100644 --- a/test/Benchmarks/Metrics/MetricsBenchmarks.cs +++ b/test/Benchmarks/Metrics/MetricsBenchmarks.cs @@ -27,16 +27,17 @@ [Host] : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT DefaultJob : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT -| Method | WithSDK | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | -|-------------------------- |-------- |-----------:|-----------:|-----------:|-------:|------:|------:|----------:| -| CounterHotPath | False | 13.291 ns | 0.0867 ns | 0.0769 ns | - | - | - | - | -| CounterWith1LabelsHotPath | False | 8.777 ns | 0.1995 ns | 0.2523 ns | - | - | - | - | -| CounterWith3LabelsHotPath | False | 22.326 ns | 0.1740 ns | 0.1453 ns | - | - | - | - | -| CounterWith5LabelsHotPath | False | 31.854 ns | 0.5290 ns | 0.4949 ns | 0.0249 | - | - | 104 B | -| CounterHotPath | True | 111.240 ns | 2.0913 ns | 1.7464 ns | - | - | - | - | -| CounterWith1LabelsHotPath | True | 170.970 ns | 3.4123 ns | 3.1919 ns | - | - | - | - | -| CounterWith3LabelsHotPath | True | 478.776 ns | 2.8576 ns | 2.3862 ns | - | - | - | - | -| CounterWith5LabelsHotPath | True | 614.775 ns | 11.6086 ns | 12.4211 ns | 0.0553 | - | - | 232 B | + +| Method | WithSDK | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | +|-------------------------- |-------- |-----------:|-----------:|----------:|-------:|------:|------:|----------:| +| CounterHotPath | False | 15.126 ns | 0.3228 ns | 0.3965 ns | - | - | - | - | +| CounterWith1LabelsHotPath | False | 9.766 ns | 0.2268 ns | 0.3530 ns | - | - | - | - | +| CounterWith3LabelsHotPath | False | 25.240 ns | 0.2876 ns | 0.2690 ns | - | - | - | - | +| CounterWith5LabelsHotPath | False | 37.929 ns | 0.7512 ns | 0.5865 ns | 0.0249 | - | - | 104 B | +| CounterHotPath | True | 44.790 ns | 0.9101 ns | 1.3621 ns | - | - | - | - | +| CounterWith1LabelsHotPath | True | 115.023 ns | 2.1001 ns | 1.9644 ns | - | - | - | - | +| CounterWith3LabelsHotPath | True | 436.527 ns | 6.5121 ns | 5.7728 ns | - | - | - | - | +| CounterWith5LabelsHotPath | True | 586.498 ns | 11.4783 ns | 9.5849 ns | 0.0553 | - | - | 232 B | BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19043 @@ -44,16 +45,17 @@ [Host] : .NET Framework 4.8 (4.8.4360.0), X64 RyuJIT DefaultJob : .NET Framework 4.8 (4.8.4360.0), X64 RyuJIT + | Method | WithSDK | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | |-------------------------- |-------- |------------:|----------:|----------:|-------:|------:|------:|----------:| -| CounterHotPath | False | 21.66 ns | 0.304 ns | 0.270 ns | - | - | - | - | -| CounterWith1LabelsHotPath | False | 26.03 ns | 0.154 ns | 0.136 ns | - | - | - | - | -| CounterWith3LabelsHotPath | False | 42.22 ns | 0.252 ns | 0.223 ns | - | - | - | - | -| CounterWith5LabelsHotPath | False | 46.35 ns | 0.890 ns | 0.953 ns | 0.0249 | - | - | 104 B | -| CounterHotPath | True | 143.95 ns | 1.215 ns | 1.014 ns | - | - | - | - | -| CounterWith1LabelsHotPath | True | 224.92 ns | 4.491 ns | 8.760 ns | - | - | - | - | -| CounterWith3LabelsHotPath | True | 905.84 ns | 6.651 ns | 5.193 ns | - | - | - | - | -| CounterWith5LabelsHotPath | True | 1,898.68 ns | 35.805 ns | 36.770 ns | 0.0553 | - | - | 233 B | +| CounterHotPath | False | 23.53 ns | 0.480 ns | 0.401 ns | - | - | - | - | +| CounterWith1LabelsHotPath | False | 28.70 ns | 0.592 ns | 0.770 ns | - | - | - | - | +| CounterWith3LabelsHotPath | False | 46.27 ns | 0.942 ns | 1.157 ns | - | - | - | - | +| CounterWith5LabelsHotPath | False | 51.66 ns | 1.060 ns | 1.857 ns | 0.0249 | - | - | 104 B | +| CounterHotPath | True | 70.44 ns | 1.029 ns | 0.912 ns | - | - | - | - | +| CounterWith1LabelsHotPath | True | 151.92 ns | 3.067 ns | 3.651 ns | - | - | - | - | +| CounterWith3LabelsHotPath | True | 876.20 ns | 15.920 ns | 14.892 ns | - | - | - | - | +| CounterWith5LabelsHotPath | True | 1,973.64 ns | 38.393 ns | 45.705 ns | 0.0534 | - | - | 233 B | */ namespace Benchmarks.Metrics diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index 080e9a922fc..f2295bc74e3 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -33,7 +33,7 @@ public void SimpleTest() .SetObservationPeriod(300) .SetCollectionPeriod(1000) .AddProcessor(new TagEnrichmentProcessor("newAttrib", "newAttribValue")) - .AddExportProcessor(new MetricConsoleExporter()) + .AddExportProcessor(new MetricConsoleExporter("Test")) .Build(); using var meter = new Meter("BasicAllTest", "0.0.1"); From b3baba96a8a58744eebcdcd243846579225d44e1 Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Thu, 3 Jun 2021 16:05:58 -0700 Subject: [PATCH 2/9] Refactor to use SetDefaultCollectionPeriod and overload for AddExportProcessor() --- examples/Console/TestMetrics.cs | 5 ++-- .../Metrics/MeterProviderBuilderExtensions.cs | 23 ++++++++++++++++--- .../Metrics/MeterProviderBuilderSdk.cs | 8 ++++++- test/Benchmarks/Metrics/MetricsBenchmarks.cs | 2 +- .../Metrics/MetricAPITest.cs | 2 +- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/examples/Console/TestMetrics.cs b/examples/Console/TestMetrics.cs index 45d1011c4bf..98f2383dd73 100644 --- a/examples/Console/TestMetrics.cs +++ b/examples/Console/TestMetrics.cs @@ -32,12 +32,11 @@ internal static object Run(MetricsOptions options, ref bool prompt) using var provider = Sdk.CreateMeterProviderBuilder() .AddSource("TestMeter") // All instruments from this meter are enabled. + .SetDefaultCollectionPeriod(options.CollectionPeriodMilliseconds) .SetObservationPeriod(options.ObservationPeriodMilliseconds) - .SetCollectionPeriod(options.CollectionPeriodMilliseconds) .AddProcessor(new TagEnrichmentProcessor("resource", "here")) .AddExportProcessor(new MetricConsoleExporter("A")) - .SetCollectionPeriod(5 * options.CollectionPeriodMilliseconds) - .AddExportProcessor(new MetricConsoleExporter("B")) + .AddExportProcessor(new MetricConsoleExporter("B"), 5 * options.CollectionPeriodMilliseconds) .Build(); using var meter = new Meter("TestMeter", "0.0.1"); diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs index 3eaea341b47..86259abbf33 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs @@ -38,16 +38,16 @@ public static MeterProviderBuilder SetObservationPeriod(this MeterProviderBuilde } /// - /// Sets collection period. + /// Sets default collection period. /// /// . /// Perion in milliseconds. /// . - public static MeterProviderBuilder SetCollectionPeriod(this MeterProviderBuilder meterProviderBuilder, int periodMilliseconds) + public static MeterProviderBuilder SetDefaultCollectionPeriod(this MeterProviderBuilder meterProviderBuilder, int periodMilliseconds) { if (meterProviderBuilder is MeterProviderBuilderSdk meterProviderBuilderSdk) { - return meterProviderBuilderSdk.SetCollectionPeriod(periodMilliseconds); + return meterProviderBuilderSdk.SetDefaultCollectionPeriod(periodMilliseconds); } return meterProviderBuilder; @@ -85,6 +85,23 @@ public static MeterProviderBuilder AddExportProcessor(this MeterProviderBuilder return meterProviderBuilder; } + /// + /// Add export processor. + /// + /// . + /// Measurement Processors. + /// Perion in milliseconds. + /// . + public static MeterProviderBuilder AddExportProcessor(this MeterProviderBuilder meterProviderBuilder, MetricProcessor processor, int periodMilliseconds) + { + if (meterProviderBuilder is MeterProviderBuilderSdk meterProviderBuilderSdk) + { + return meterProviderBuilderSdk.AddExporter(processor, periodMilliseconds); + } + + return meterProviderBuilder; + } + /// /// Run the given actions to initialize the . /// diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs index 5d574f4cc90..a43e880ed67 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs @@ -59,7 +59,7 @@ internal MeterProviderBuilderSdk SetObservationPeriod(int periodMilliseconds) return this; } - internal MeterProviderBuilderSdk SetCollectionPeriod(int periodMilliseconds) + internal MeterProviderBuilderSdk SetDefaultCollectionPeriod(int periodMilliseconds) { this.collectionPeriodMilliseconds = periodMilliseconds; return this; @@ -77,6 +77,12 @@ internal MeterProviderBuilderSdk AddExporter(MetricProcessor processor) return this; } + internal MeterProviderBuilderSdk AddExporter(MetricProcessor processor, int periodMilliseconds) + { + this.ExportProcessors.Add(new KeyValuePair(processor, periodMilliseconds)); + return this; + } + internal MeterProvider Build() { // TODO: Need to review using a struct for BuildOptions diff --git a/test/Benchmarks/Metrics/MetricsBenchmarks.cs b/test/Benchmarks/Metrics/MetricsBenchmarks.cs index b0d7f2a8bcc..18d7b42e56a 100644 --- a/test/Benchmarks/Metrics/MetricsBenchmarks.cs +++ b/test/Benchmarks/Metrics/MetricsBenchmarks.cs @@ -84,7 +84,7 @@ public void Setup() this.provider = Sdk.CreateMeterProviderBuilder() .AddSource("TestMeter") // All instruments from this meter are enabled. .SetObservationPeriod(10000) - .SetCollectionPeriod(10000) + .SetDefaultCollectionPeriod(10000) // .AddExportProcessor(new MetricConsoleExporter()) .Build(); diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index f2295bc74e3..29f595711a5 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -31,7 +31,7 @@ public void SimpleTest() using var provider = Sdk.CreateMeterProviderBuilder() .AddSource("BasicAllTest") .SetObservationPeriod(300) - .SetCollectionPeriod(1000) + .SetDefaultCollectionPeriod(1000) .AddProcessor(new TagEnrichmentProcessor("newAttrib", "newAttribValue")) .AddExportProcessor(new MetricConsoleExporter("Test")) .Build(); From 7ce3aa0d1069c7283e69580ba14297ae73b3d41a Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Fri, 4 Jun 2021 10:37:12 -0700 Subject: [PATCH 3/9] Define Exemplar --- .../Metrics/DataPoint/DataPoint.cs | 57 +++++---- .../Metrics/DataPoint/DataPoint{T}.cs | 41 ++----- .../Metrics/DataPoint/Exemplar.cs | 110 ++++++++++++++++++ .../Metrics/DataPoint/Exemplar{T}.cs | 54 +++++++++ .../Metrics/DataPoint/IExemplar.cs | 34 ++++++ .../GaugeMetricAggregator.cs | 2 +- .../HistogramMetricAggregator.cs | 2 +- .../Metrics/MetricAggregators/IGaugeMetric.cs | 2 +- .../MetricAggregators/IHistogramMetric.cs | 2 +- .../Metrics/MetricAggregators/ISumMetric.cs | 2 +- .../MetricAggregators/SumMetricAggregator.cs | 2 +- 11 files changed, 238 insertions(+), 70 deletions(-) create mode 100644 src/OpenTelemetry/Metrics/DataPoint/Exemplar.cs create mode 100644 src/OpenTelemetry/Metrics/DataPoint/Exemplar{T}.cs create mode 100644 src/OpenTelemetry/Metrics/DataPoint/IExemplar.cs diff --git a/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs b/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs index 98544d3b374..5331129cc9b 100644 --- a/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs +++ b/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs @@ -16,65 +16,60 @@ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; namespace OpenTelemetry.Metrics { internal readonly struct DataPoint : IDataPoint { - internal readonly Type ValueType; - internal readonly int IntValue; - internal readonly double DoubleValue; + private static readonly KeyValuePair[] EmptyTag = new KeyValuePair[0]; - private readonly DateTimeOffset timestamp; - - private readonly KeyValuePair[] tags; + private readonly Type valueType; + private readonly int intValue; + private readonly double doubleValue; internal DataPoint(DateTimeOffset timestamp, int value, KeyValuePair[] tags) { - this.timestamp = timestamp; - this.tags = tags; - this.ValueType = value.GetType(); - this.IntValue = value; - this.DoubleValue = 0; + this.Timestamp = timestamp; + this.Tags = tags; + this.valueType = value.GetType(); + this.intValue = value; + this.doubleValue = 0; } internal DataPoint(DateTimeOffset timestamp, double value, KeyValuePair[] tags) { - this.timestamp = timestamp; - this.tags = tags; - this.ValueType = value.GetType(); - this.IntValue = 0; - this.DoubleValue = value; + this.Timestamp = timestamp; + this.Tags = tags; + this.valueType = value.GetType(); + this.intValue = 0; + this.doubleValue = value; } - public KeyValuePair[] Tags + internal DataPoint(DateTimeOffset timestamp, int value) + : this(timestamp, value, DataPoint.EmptyTag) { - get - { - return this.tags; - } } - public DateTimeOffset Timestamp + internal DataPoint(DateTimeOffset timestamp, double value) + : this(timestamp, value, DataPoint.EmptyTag) { - get - { - return this.timestamp; - } } + public DateTimeOffset Timestamp { get; } + + public readonly KeyValuePair[] Tags { get; } + public object Value { get { - if (this.ValueType == typeof(int)) + if (this.valueType == typeof(int)) { - return this.IntValue; + return this.intValue; } - else if (this.ValueType == typeof(double)) + else if (this.valueType == typeof(double)) { - return this.DoubleValue; + return this.doubleValue; } else { diff --git a/src/OpenTelemetry/Metrics/DataPoint/DataPoint{T}.cs b/src/OpenTelemetry/Metrics/DataPoint/DataPoint{T}.cs index 60a10145db6..3885283e50d 100644 --- a/src/OpenTelemetry/Metrics/DataPoint/DataPoint{T}.cs +++ b/src/OpenTelemetry/Metrics/DataPoint/DataPoint{T}.cs @@ -16,7 +16,6 @@ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; namespace OpenTelemetry.Metrics { @@ -27,46 +26,22 @@ namespace OpenTelemetry.Metrics private readonly T value; - private readonly DateTimeOffset timestamp; - - private readonly KeyValuePair[] tags; - - internal DataPoint(DateTimeOffset timestamp, T value) - { - this.timestamp = timestamp; - this.value = value; - this.tags = DataPoint.EmptyTag; - } - internal DataPoint(DateTimeOffset timestamp, T value, KeyValuePair[] tags) { - this.timestamp = timestamp; + this.Timestamp = timestamp; + this.Tags = tags; this.value = value; - this.tags = tags; } - public KeyValuePair[] Tags + internal DataPoint(DateTimeOffset timestamp, T value) + : this(timestamp, value, DataPoint.EmptyTag) { - get - { - return this.tags; - } } - public DateTimeOffset Timestamp - { - get - { - return this.timestamp; - } - } + public DateTimeOffset Timestamp { get; } - public object Value - { - get - { - return (object)this.value; - } - } + public readonly KeyValuePair[] Tags { get; } + + public object Value => (object)this.value; } } diff --git a/src/OpenTelemetry/Metrics/DataPoint/Exemplar.cs b/src/OpenTelemetry/Metrics/DataPoint/Exemplar.cs new file mode 100644 index 00000000000..ade461a40e6 --- /dev/null +++ b/src/OpenTelemetry/Metrics/DataPoint/Exemplar.cs @@ -0,0 +1,110 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal readonly struct Exemplar : IExemplar + { + private static readonly KeyValuePair[] EmptyTag = new KeyValuePair[0]; + private static readonly byte[] EmptyId = new byte[0]; + + private readonly Type valueType; + private readonly int intValue; + private readonly double doubleValue; + + internal Exemplar(DateTimeOffset timestamp, int value, byte[] spanId, byte[] traceId, KeyValuePair[] filteredTags) + { + this.Timestamp = timestamp; + this.FilteredTags = filteredTags; + this.SpanId = spanId; + this.TraceId = traceId; + this.valueType = value.GetType(); + this.intValue = value; + this.doubleValue = 0; + } + + internal Exemplar(DateTimeOffset timestamp, double value, byte[] spanId, byte[] traceId, KeyValuePair[] filteredTags) + { + this.Timestamp = timestamp; + this.FilteredTags = filteredTags; + this.SpanId = spanId; + this.TraceId = traceId; + this.valueType = value.GetType(); + this.intValue = 0; + this.doubleValue = value; + } + + internal Exemplar(DateTimeOffset timestamp, int value) + : this(timestamp, value, Exemplar.EmptyId, Exemplar.EmptyId, Exemplar.EmptyTag) + { + } + + internal Exemplar(DateTimeOffset timestamp, double value) + : this(timestamp, value, Exemplar.EmptyId, Exemplar.EmptyId, Exemplar.EmptyTag) + { + } + + public DateTimeOffset Timestamp { get; } + + public readonly KeyValuePair[] FilteredTags { get; } + + public readonly byte[] SpanId { get; } + + public readonly byte[] TraceId { get; } + + public object Value + { + get + { + if (this.valueType == typeof(int)) + { + return this.intValue; + } + else if (this.valueType == typeof(double)) + { + return this.doubleValue; + } + else + { + throw new Exception("Unsupported Type"); + } + } + } + + internal static Exemplar CreateExemplar(DateTimeOffset timestamp, T value, byte[] spanId, byte[] traceId, KeyValuePair[] filteredTags) + { + Exemplar dp; + + if (typeof(T) == typeof(int)) + { + dp = new Exemplar(timestamp, (int)(object)value, spanId, traceId, filteredTags); + } + else if (typeof(T) == typeof(double)) + { + dp = new Exemplar(timestamp, (double)(object)value, spanId, traceId, filteredTags); + } + else + { + throw new Exception("Unsupported Type"); + } + + return dp; + } + } +} diff --git a/src/OpenTelemetry/Metrics/DataPoint/Exemplar{T}.cs b/src/OpenTelemetry/Metrics/DataPoint/Exemplar{T}.cs new file mode 100644 index 00000000000..50ab08f4b66 --- /dev/null +++ b/src/OpenTelemetry/Metrics/DataPoint/Exemplar{T}.cs @@ -0,0 +1,54 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal readonly struct Exemplar : IExemplar + where T : struct + { + private static readonly KeyValuePair[] EmptyTag = new KeyValuePair[0]; + private static readonly byte[] EmptyId = new byte[0]; + + private readonly T value; + + internal Exemplar(DateTimeOffset timestamp, T value, byte[] spanId, byte[] traceId, KeyValuePair[] filteredTags) + { + this.Timestamp = timestamp; + this.FilteredTags = filteredTags; + this.SpanId = spanId; + this.TraceId = traceId; + this.value = value; + } + + internal Exemplar(DateTimeOffset timestamp, T value) + : this(timestamp, value, Exemplar.EmptyId, Exemplar.EmptyId, Exemplar.EmptyTag) + { + } + + public DateTimeOffset Timestamp { get; } + + public readonly KeyValuePair[] FilteredTags { get; } + + public readonly byte[] SpanId { get; } + + public readonly byte[] TraceId { get; } + + public object Value => (object)this.value; + } +} diff --git a/src/OpenTelemetry/Metrics/DataPoint/IExemplar.cs b/src/OpenTelemetry/Metrics/DataPoint/IExemplar.cs new file mode 100644 index 00000000000..3c0bf730f79 --- /dev/null +++ b/src/OpenTelemetry/Metrics/DataPoint/IExemplar.cs @@ -0,0 +1,34 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + internal interface IExemplar + { + DateTimeOffset Timestamp { get; } + + KeyValuePair[] FilteredTags { get; } + + byte[] SpanId { get; } + + byte[] TraceId { get; } + + object Value { get; } + } +} diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs index 2c14aaf39ae..052c0c4ee52 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs @@ -45,7 +45,7 @@ internal GaugeMetricAggregator(string name, DateTimeOffset startTimeExclusive, K public bool IsDeltaTemporality { get; } - public IEnumerable Exemplars { get; private set; } = new List(); + public IEnumerable Exemplars { get; private set; } = new List(); public IDataPoint LastValue { diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs index 4d92ccb640a..a7e82c269cb 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs @@ -43,7 +43,7 @@ internal HistogramMetricAggregator(string name, DateTimeOffset startTimeExclusiv public bool IsDeltaTemporality { get; } - public IEnumerable Exemplars { get; private set; } = new List(); + public IEnumerable Exemplars { get; private set; } = new List(); public long PopulationCount { get; private set; } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs b/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs index 8b3621c1921..054845afe4d 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs @@ -22,7 +22,7 @@ internal interface IGaugeMetric : IMetric { bool IsDeltaTemporality { get; } - IEnumerable Exemplars { get; } + IEnumerable Exemplars { get; } IDataPoint LastValue { get; } } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/IHistogramMetric.cs b/src/OpenTelemetry/Metrics/MetricAggregators/IHistogramMetric.cs index 475250bf1da..ce205229513 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/IHistogramMetric.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/IHistogramMetric.cs @@ -22,7 +22,7 @@ internal interface IHistogramMetric : IMetric { bool IsDeltaTemporality { get; } - IEnumerable Exemplars { get; } + IEnumerable Exemplars { get; } long PopulationCount { get; } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs b/src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs index f95fdd8ed4e..bf6514f4c5e 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs @@ -24,7 +24,7 @@ internal interface ISumMetric : IMetric bool IsMonotonic { get; } - IEnumerable Exemplars { get; } + IEnumerable Exemplars { get; } object Sum { get; } } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs index 7a13c306bcf..0210f489805 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs @@ -49,7 +49,7 @@ internal SumMetricAggregator(string name, DateTimeOffset startTimeExclusive, Key public bool IsMonotonic { get; } - public IEnumerable Exemplars { get; private set; } = new List(); + public IEnumerable Exemplars { get; private set; } = new List(); public object Sum { From 3003b196ba6298370f1b7f74a7d0f68c90a2a33e Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Fri, 4 Jun 2021 14:23:28 -0700 Subject: [PATCH 4/9] Refactor int to long for Aggregators (to match OTLP) --- .../Metrics/DataPoint/DataPoint.cs | 23 +++-- .../Metrics/DataPoint/Exemplar.cs | 23 +++-- .../GaugeMetricAggregator.cs | 19 ++-- .../MetricAggregators/SumMetricAggregator.cs | 98 ++++++++++++++----- .../SummaryMetricAggregator.cs | 16 ++- 5 files changed, 126 insertions(+), 53 deletions(-) diff --git a/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs b/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs index 5331129cc9b..1b59f5e6d82 100644 --- a/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs +++ b/src/OpenTelemetry/Metrics/DataPoint/DataPoint.cs @@ -24,15 +24,15 @@ namespace OpenTelemetry.Metrics private static readonly KeyValuePair[] EmptyTag = new KeyValuePair[0]; private readonly Type valueType; - private readonly int intValue; + private readonly long longValue; private readonly double doubleValue; - internal DataPoint(DateTimeOffset timestamp, int value, KeyValuePair[] tags) + internal DataPoint(DateTimeOffset timestamp, long value, KeyValuePair[] tags) { this.Timestamp = timestamp; this.Tags = tags; - this.valueType = value.GetType(); - this.intValue = value; + this.valueType = typeof(long); + this.longValue = value; this.doubleValue = 0; } @@ -40,12 +40,12 @@ internal DataPoint(DateTimeOffset timestamp, double value, KeyValuePair(DateTimeOffset timestamp, T value, if (typeof(T) == typeof(int)) { + // Promoted to Long dp = new DataPoint(timestamp, (int)(object)value, tags); } + else if (typeof(T) == typeof(long)) + { + dp = new DataPoint(timestamp, (long)(object)value, tags); + } else if (typeof(T) == typeof(double)) { dp = new DataPoint(timestamp, (double)(object)value, tags); diff --git a/src/OpenTelemetry/Metrics/DataPoint/Exemplar.cs b/src/OpenTelemetry/Metrics/DataPoint/Exemplar.cs index ade461a40e6..8d9e8590d82 100644 --- a/src/OpenTelemetry/Metrics/DataPoint/Exemplar.cs +++ b/src/OpenTelemetry/Metrics/DataPoint/Exemplar.cs @@ -25,17 +25,17 @@ namespace OpenTelemetry.Metrics private static readonly byte[] EmptyId = new byte[0]; private readonly Type valueType; - private readonly int intValue; + private readonly long longValue; private readonly double doubleValue; - internal Exemplar(DateTimeOffset timestamp, int value, byte[] spanId, byte[] traceId, KeyValuePair[] filteredTags) + internal Exemplar(DateTimeOffset timestamp, long value, byte[] spanId, byte[] traceId, KeyValuePair[] filteredTags) { this.Timestamp = timestamp; this.FilteredTags = filteredTags; this.SpanId = spanId; this.TraceId = traceId; - this.valueType = value.GetType(); - this.intValue = value; + this.valueType = typeof(long); + this.longValue = value; this.doubleValue = 0; } @@ -45,12 +45,12 @@ internal Exemplar(DateTimeOffset timestamp, double value, byte[] spanId, byte[] this.FilteredTags = filteredTags; this.SpanId = spanId; this.TraceId = traceId; - this.valueType = value.GetType(); - this.intValue = 0; + this.valueType = typeof(double); + this.longValue = 0; this.doubleValue = value; } - internal Exemplar(DateTimeOffset timestamp, int value) + internal Exemplar(DateTimeOffset timestamp, long value) : this(timestamp, value, Exemplar.EmptyId, Exemplar.EmptyId, Exemplar.EmptyTag) { } @@ -72,9 +72,9 @@ public object Value { get { - if (this.valueType == typeof(int)) + if (this.valueType == typeof(long)) { - return this.intValue; + return this.longValue; } else if (this.valueType == typeof(double)) { @@ -93,8 +93,13 @@ internal static Exemplar CreateExemplar(DateTimeOffset timestamp, T value, by if (typeof(T) == typeof(int)) { + // Promoted to Long dp = new Exemplar(timestamp, (int)(object)value, spanId, traceId, filteredTags); } + else if (typeof(T) == typeof(long)) + { + dp = new Exemplar(timestamp, (long)(object)value, spanId, traceId, filteredTags); + } else if (typeof(T) == typeof(double)) { dp = new Exemplar(timestamp, (double)(object)value, spanId, traceId, filteredTags); diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs index 052c0c4ee52..3bb49539962 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs @@ -23,7 +23,7 @@ internal class GaugeMetricAggregator : IGaugeMetric, IMetricBuilder { private readonly object lockUpdate = new object(); private Type valueType; - private int intValue; + private long longValue; private double doubleValue; internal GaugeMetricAggregator(string name, DateTimeOffset startTimeExclusive, KeyValuePair[] attributes, bool isDelta) @@ -51,9 +51,9 @@ public IDataPoint LastValue { get { - if (this.valueType == typeof(int)) + if (this.valueType == typeof(long)) { - return DataPoint.CreateDataPoint(this.EndTimeInclusive, this.intValue, this.Attributes); + return DataPoint.CreateDataPoint(this.EndTimeInclusive, this.longValue, this.Attributes); } else if (this.valueType == typeof(double)) { @@ -72,13 +72,20 @@ public void Update(DateTimeOffset dt, T value) lock (this.lockUpdate) { this.EndTimeInclusive = dt; - this.valueType = typeof(T); if (typeof(T) == typeof(int)) { - this.intValue = (int)(object)value; + // Promote to Long + this.valueType = typeof(long); + this.longValue = (int)(object)value; + } + else if (typeof(T) == typeof(long)) + { + this.valueType = typeof(T); + this.longValue = (long)(object)value; } else if (typeof(T) == typeof(double)) { + this.valueType = typeof(T); this.doubleValue = (double)(object)value; } } @@ -93,7 +100,7 @@ public IMetric Collect(DateTimeOffset dt) cloneItem.Exemplars = this.Exemplars; cloneItem.EndTimeInclusive = dt; cloneItem.valueType = this.valueType; - cloneItem.intValue = this.intValue; + cloneItem.longValue = this.longValue; cloneItem.doubleValue = this.doubleValue; } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs index 0210f489805..429acc1f26c 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs @@ -23,9 +23,12 @@ internal class SumMetricAggregator : ISumMetric, IMetricBuilder { private readonly object lockUpdate = new object(); private Type valueType; - private long sum = 0; - private double dsum = 0; - private long count = 0; + private long sumPos = 0; + private double dsumPos = 0; + private long countPos = 0; + private long sumNeg = 0; + private double dsumNeg = 0; + private long countNeg = 0; internal SumMetricAggregator(string name, DateTimeOffset startTimeExclusive, KeyValuePair[] attributes, bool isDelta, bool isMonotonic) { @@ -55,16 +58,30 @@ public object Sum { get { - if (this.valueType == typeof(int)) + if (this.valueType == typeof(long)) { - return this.sum; + if (this.IsMonotonic) + { + return this.sumPos + (long)this.dsumPos; + } + else + { + return this.sumPos + (long)this.dsumPos + this.sumNeg + (long)this.dsumNeg; + } } else if (this.valueType == typeof(double)) { - return this.dsum; + if (this.IsMonotonic) + { + return this.dsumPos + (double)this.sumPos; + } + else + { + return this.dsumPos + (double)this.sumPos + this.dsumNeg + (double)this.sumNeg; + } } - return "Unknown"; + throw new Exception("Unsupported Type"); } } @@ -75,31 +92,54 @@ public void Update(DateTimeOffset dt, T value) { this.EndTimeInclusive = dt; - this.valueType = typeof(T); - if (typeof(T) == typeof(int)) { - var val = (int)(object)value; + // Promote to Long + this.valueType = typeof(long); + var val = (long)(int)(object)value; - if (this.IsMonotonic && val < 0) + if (val >= 0) + { + this.sumPos += val; + this.countPos++; + } + else { - return; + this.sumNeg += val; + this.countNeg++; } + } + else if (typeof(T) == typeof(long)) + { + this.valueType = typeof(T); + var val = (long)(object)value; - this.sum += val; - this.count++; + if (val >= 0) + { + this.sumPos += val; + this.countPos++; + } + else + { + this.sumNeg += val; + this.countNeg++; + } } else if (typeof(T) == typeof(double)) { + this.valueType = typeof(T); var val = (double)(object)value; - if (this.IsMonotonic && val < 0) + if (val >= 0) { - return; + this.dsumPos += val; + this.countPos++; + } + else + { + this.dsumNeg += val; + this.countNeg++; } - - this.dsum += val; - this.count++; } else { @@ -117,16 +157,22 @@ public IMetric Collect(DateTimeOffset dt) cloneItem.Exemplars = this.Exemplars; cloneItem.EndTimeInclusive = dt; cloneItem.valueType = this.valueType; - cloneItem.count = this.count; - cloneItem.sum = this.sum; - cloneItem.dsum = this.dsum; + cloneItem.countPos = this.countPos; + cloneItem.sumPos = this.sumPos; + cloneItem.dsumPos = this.dsumPos; + cloneItem.countNeg = this.countNeg; + cloneItem.sumNeg = this.sumNeg; + cloneItem.dsumNeg = this.dsumNeg; if (this.IsDeltaTemporality) { this.StartTimeExclusive = dt; - this.count = 0; - this.sum = 0; - this.dsum = 0; + this.countPos = 0; + this.sumPos = 0; + this.dsumPos = 0; + this.countNeg = 0; + this.sumNeg = 0; + this.dsumNeg = 0; } } @@ -135,7 +181,7 @@ public IMetric Collect(DateTimeOffset dt) public string ToDisplayString() { - return $"Delta={this.IsDeltaTemporality},Count={this.count},Sum={this.Sum}"; + return $"Delta={this.IsDeltaTemporality},Count={this.countPos},Sum={this.Sum}"; } } } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs index cd34f553e4a..a0f9104620a 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs @@ -21,7 +21,6 @@ namespace OpenTelemetry.Metrics { internal class SummaryMetricAggregator : ISummaryMetric, IMetricBuilder { - internal readonly bool IsMonotonic; private readonly object lockUpdate = new object(); private List quantiles = new List(); @@ -43,6 +42,8 @@ internal SummaryMetricAggregator(string name, DateTimeOffset startTimeExclusive, public KeyValuePair[] Attributes { get; private set; } + public bool IsMonotonic { get; } + public long PopulationCount { get; private set; } public double PopulationSum { get; private set; } @@ -64,6 +65,16 @@ public void Update(DateTimeOffset dt, T value) if (val > 0 || !this.IsMonotonic) { this.PopulationSum += (double)val; + this.PopulationCount++; + } + } + else if (typeof(T) == typeof(long)) + { + var val = (long)(object)value; + if (val > 0 || !this.IsMonotonic) + { + this.PopulationSum += (double)val; + this.PopulationCount++; } } else if (typeof(T) == typeof(double)) @@ -72,10 +83,9 @@ public void Update(DateTimeOffset dt, T value) if (val > 0 || !this.IsMonotonic) { this.PopulationSum += (double)val; + this.PopulationCount++; } } - - this.PopulationCount++; } } From 6508b3465684ce487e1e83bbd667f6138c74ba1d Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Wed, 9 Jun 2021 11:23:52 -0700 Subject: [PATCH 5/9] Remove ObservationPeriod. Add instrument options to example metric console app. --- examples/Console/Program.cs | 28 ++++++---- examples/Console/TestMetrics.cs | 56 +++++++++++++------ .../Metrics/MeterProviderBuilderExtensions.cs | 22 +------- .../Metrics/MeterProviderBuilderSdk.cs | 16 +----- src/OpenTelemetry/Metrics/MeterProviderSdk.cs | 32 +---------- test/Benchmarks/Metrics/MetricsBenchmarks.cs | 1 - .../Metrics/MetricAPITest.cs | 4 +- 7 files changed, 66 insertions(+), 93 deletions(-) diff --git a/examples/Console/Program.cs b/examples/Console/Program.cs index a4c6b6a687d..69d10800ff2 100644 --- a/examples/Console/Program.cs +++ b/examples/Console/Program.cs @@ -103,26 +103,32 @@ internal class PrometheusOptions [Verb("metrics", HelpText = "Specify the options required to test Metrics")] internal class MetricsOptions { - [Option('p', "prompt", HelpText = "Prompt for exit", Default = false)] - public bool? Prompt { get; set; } + [Option('g', "Gauge", HelpText = "Observable Gauge.", Required = false)] + public bool? FlagGauge { get; set; } - [Option("runtime", Default = 5000, HelpText = "Run time in milliseconds.", Required = false)] - public int RunTime { get; set; } + [Option('u', "UpDownCounter", HelpText = "Observable Up/Down Counter.", Required = false)] + public bool? FlagUpDownCounter { get; set; } + + [Option('c', "Counter", HelpText = "Counter.", Required = false)] + public bool? FlagCounter { get; set; } - [Option("observationPeriodMilliseconds", Default = 100, HelpText = "Observation period.", Required = false)] - public int ObservationPeriodMilliseconds { get; set; } + [Option('h', "Histogram", HelpText = "Histogram.", Required = false)] + public bool? FlagHistogram { get; set; } - [Option("collectionPeriodMilliseconds", Default = 500, HelpText = "Collection period.", Required = false)] - public int CollectionPeriodMilliseconds { get; set; } + [Option("defaultCollectionPeriodMilliseconds", Default = 500, HelpText = "Default Collection period.", Required = false)] + public int DefaultCollectionPeriodMilliseconds { get; set; } - [Option('o', "runObservable", Default = true, HelpText = "Run observable counters.", Required = false)] - public bool? RunObservable { get; set; } + [Option("runtime", Default = 5000, HelpText = "Run time in milliseconds.", Required = false)] + public int RunTime { get; set; } - [Option('t', "numTasks", Default = 1, HelpText = "Run # of tasks.", Required = false)] + [Option("tasks", Default = 1, HelpText = "Run # of tasks.", Required = false)] public int NumTasks { get; set; } [Option("maxLoops", Default = 0, HelpText = "Maximum number of loops. 0 = No Limit", Required = false)] public int MaxLoops { get; set; } + + [Option('p', "prompt", HelpText = "Do not Prompt for exit", Required = false)] + public bool? Prompt { get; set; } } [Verb("grpc", HelpText = "Specify the options required to test Grpc.Net.Client")] diff --git a/examples/Console/TestMetrics.cs b/examples/Console/TestMetrics.cs index 98f2383dd73..a193034df53 100644 --- a/examples/Console/TestMetrics.cs +++ b/examples/Console/TestMetrics.cs @@ -28,26 +28,46 @@ internal class TestMetrics { internal static object Run(MetricsOptions options, ref bool prompt) { - prompt = options.Prompt.Value; + prompt = options.Prompt ?? false; using var provider = Sdk.CreateMeterProviderBuilder() .AddSource("TestMeter") // All instruments from this meter are enabled. - .SetDefaultCollectionPeriod(options.CollectionPeriodMilliseconds) - .SetObservationPeriod(options.ObservationPeriodMilliseconds) + .SetDefaultCollectionPeriod(options.DefaultCollectionPeriodMilliseconds) .AddProcessor(new TagEnrichmentProcessor("resource", "here")) .AddExportProcessor(new MetricConsoleExporter("A")) - .AddExportProcessor(new MetricConsoleExporter("B"), 5 * options.CollectionPeriodMilliseconds) + .AddExportProcessor(new MetricConsoleExporter("B"), 5 * options.DefaultCollectionPeriodMilliseconds) .Build(); using var meter = new Meter("TestMeter", "0.0.1"); - var counter = meter.CreateCounter("counter1"); + Counter counter = null; + if (options.FlagCounter ?? true) + { + counter = meter.CreateCounter("counter"); + } + + Histogram histogram = null; + if (options.FlagHistogram ?? true) + { + histogram = meter.CreateHistogram("histogram"); + } - var histogram = meter.CreateHistogram("histogram"); + if (options.FlagGauge ?? true) + { + var observableCounter = meter.CreateObservableGauge("gauge", () => + { + return new List>() + { + new Measurement( + (int)Process.GetCurrentProcess().PrivateMemorySize64, + new KeyValuePair("tag1", "value1")), + }; + }); + } - if (options.RunObservable ?? true) + if (options.FlagUpDownCounter ?? true) { - var observableCounter = meter.CreateObservableGauge("CurrentMemoryUsage", () => + var observableCounter = meter.CreateObservableCounter("updown", () => { return new List>() { @@ -79,42 +99,42 @@ internal static object Run(MetricsOptions options, ref bool prompt) break; } - histogram.Record(10); + histogram?.Record(10); - histogram.Record( + histogram?.Record( 100, new KeyValuePair("tag1", "value1")); - histogram.Record( + histogram?.Record( 200, new KeyValuePair("tag1", "value2"), new KeyValuePair("tag2", "value2")); - histogram.Record( + histogram?.Record( 100, new KeyValuePair("tag1", "value1")); - histogram.Record( + histogram?.Record( 200, new KeyValuePair("tag2", "value2"), new KeyValuePair("tag1", "value2")); - counter.Add(10); + counter?.Add(10); - counter.Add( + counter?.Add( 100, new KeyValuePair("tag1", "value1")); - counter.Add( + counter?.Add( 200, new KeyValuePair("tag1", "value2"), new KeyValuePair("tag2", "value2")); - counter.Add( + counter?.Add( 100, new KeyValuePair("tag1", "value1")); - counter.Add( + counter?.Add( 200, new KeyValuePair("tag2", "value2"), new KeyValuePair("tag1", "value2")); diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs index 86259abbf33..a964d100990 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs @@ -21,22 +21,6 @@ namespace OpenTelemetry.Metrics /// public static class MeterProviderBuilderExtensions { - /// - /// Sets observation period. - /// - /// . - /// Perion in milliseconds. - /// . - public static MeterProviderBuilder SetObservationPeriod(this MeterProviderBuilder meterProviderBuilder, int periodMilliseconds) - { - if (meterProviderBuilder is MeterProviderBuilderSdk meterProviderBuilderSdk) - { - return meterProviderBuilderSdk.SetObservationPeriod(periodMilliseconds); - } - - return meterProviderBuilder; - } - /// /// Sets default collection period. /// @@ -90,13 +74,13 @@ public static MeterProviderBuilder AddExportProcessor(this MeterProviderBuilder /// /// . /// Measurement Processors. - /// Perion in milliseconds. + /// Period in milliseconds between Collections. /// . - public static MeterProviderBuilder AddExportProcessor(this MeterProviderBuilder meterProviderBuilder, MetricProcessor processor, int periodMilliseconds) + public static MeterProviderBuilder AddExportProcessor(this MeterProviderBuilder meterProviderBuilder, MetricProcessor processor, int collectionPeriodMilliseconds) { if (meterProviderBuilder is MeterProviderBuilderSdk meterProviderBuilderSdk) { - return meterProviderBuilderSdk.AddExporter(processor, periodMilliseconds); + return meterProviderBuilderSdk.AddExporter(processor, collectionPeriodMilliseconds); } return meterProviderBuilder; diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs index a43e880ed67..1801805d0d5 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs @@ -22,8 +22,7 @@ namespace OpenTelemetry.Metrics internal class MeterProviderBuilderSdk : MeterProviderBuilder { private readonly List meterSources = new List(); - private int observationPeriodMilliseconds = 1000; - private int collectionPeriodMilliseconds = 1000; + private int defaultCollectionPeriodMilliseconds = 1000; internal MeterProviderBuilderSdk() { @@ -53,15 +52,9 @@ public override MeterProviderBuilder AddSource(params string[] names) return this; } - internal MeterProviderBuilderSdk SetObservationPeriod(int periodMilliseconds) - { - this.observationPeriodMilliseconds = periodMilliseconds; - return this; - } - internal MeterProviderBuilderSdk SetDefaultCollectionPeriod(int periodMilliseconds) { - this.collectionPeriodMilliseconds = periodMilliseconds; + this.defaultCollectionPeriodMilliseconds = periodMilliseconds; return this; } @@ -73,7 +66,7 @@ internal MeterProviderBuilderSdk AddMeasurementProcessor(MeasurementProcessor pr internal MeterProviderBuilderSdk AddExporter(MetricProcessor processor) { - this.ExportProcessors.Add(new KeyValuePair(processor, this.collectionPeriodMilliseconds)); + this.ExportProcessors.Add(new KeyValuePair(processor, this.defaultCollectionPeriodMilliseconds)); return this; } @@ -85,11 +78,8 @@ internal MeterProviderBuilderSdk AddExporter(MetricProcessor processor, int peri internal MeterProvider Build() { - // TODO: Need to review using a struct for BuildOptions return new MeterProviderSdk( this.meterSources, - this.observationPeriodMilliseconds, - this.collectionPeriodMilliseconds, this.MeasurementProcessors.ToArray(), this.ExportProcessors.ToArray()); } diff --git a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs index 7e42cd4082f..59e7ccc87d0 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs @@ -34,7 +34,6 @@ public class MeterProviderSdk private static DateTimeOffset lastTimestamp = DateTimeOffset.MinValue; private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly Task observerTask; private readonly List collectorTasks = new List(); private readonly MeterListener listener; @@ -43,14 +42,9 @@ public class MeterProviderSdk internal MeterProviderSdk( IEnumerable meterSources, - int observationPeriodMilliseconds, - int collectionPeriodMilliseconds, MeasurementProcessor[] measurementProcessors, KeyValuePair[] metricExportProcessors) { - this.ObservationPeriodMilliseconds = observationPeriodMilliseconds; - this.CollectionPeriodMilliseconds = collectionPeriodMilliseconds; - // Setup our Processors this.MeasurementProcessors.AddRange(measurementProcessors); @@ -97,7 +91,6 @@ internal MeterProviderSdk( // Start our long running Task var token = this.cts.Token; - this.observerTask = Task.Run(async () => await this.ObserverTask(token)); // Group Export processors by their collectionPeriod. var groups = this.ExportProcessors.GroupBy(k => k.Value, v => v.Key); @@ -107,10 +100,6 @@ internal MeterProviderSdk( } } - internal int ObservationPeriodMilliseconds { get; } = 1000; - - internal int CollectionPeriodMilliseconds { get; } = 1000; - internal List MeasurementProcessors { get; } = new List(); internal List MetricProcessors { get; } = new List(); @@ -175,30 +164,12 @@ protected override void Dispose(bool disposing) this.cts.Cancel(); - this.observerTask.Wait(); - foreach (var collectorTask in this.collectorTasks) { collectorTask.Wait(); } } - private async Task ObserverTask(CancellationToken token) - { - while (!token.IsCancellationRequested) - { - try - { - await Task.Delay(this.ObservationPeriodMilliseconds, token); - } - catch (TaskCanceledException) - { - } - - this.listener.RecordObservableInstruments(); - } - } - private async Task CollectorTask(CancellationToken token, int collectionPeriodMilliseconds, MetricProcessor[] processors) { while (!token.IsCancellationRequested) @@ -217,6 +188,9 @@ private async Task CollectorTask(CancellationToken token, int collectionPeriodMi private void Collect(int collectionPeriodMilliseconds, MetricProcessor[] processors) { + // Record all observable instruments + this.listener.RecordObservableInstruments(); + var metricItem = new MetricItem(); foreach (var kv in this.AggregatorStores) diff --git a/test/Benchmarks/Metrics/MetricsBenchmarks.cs b/test/Benchmarks/Metrics/MetricsBenchmarks.cs index 18d7b42e56a..94f57056bdd 100644 --- a/test/Benchmarks/Metrics/MetricsBenchmarks.cs +++ b/test/Benchmarks/Metrics/MetricsBenchmarks.cs @@ -83,7 +83,6 @@ public void Setup() { this.provider = Sdk.CreateMeterProviderBuilder() .AddSource("TestMeter") // All instruments from this meter are enabled. - .SetObservationPeriod(10000) .SetDefaultCollectionPeriod(10000) // .AddExportProcessor(new MetricConsoleExporter()) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index 29f595711a5..6b05e93fc33 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -30,10 +30,10 @@ public void SimpleTest() { using var provider = Sdk.CreateMeterProviderBuilder() .AddSource("BasicAllTest") - .SetObservationPeriod(300) .SetDefaultCollectionPeriod(1000) .AddProcessor(new TagEnrichmentProcessor("newAttrib", "newAttribValue")) - .AddExportProcessor(new MetricConsoleExporter("Test")) + .AddExportProcessor(new MetricConsoleExporter("Test1")) + .AddExportProcessor(new MetricConsoleExporter("Test2"), 2000) .Build(); using var meter = new Meter("BasicAllTest", "0.0.1"); From 31ca3657a668d4572857f7dcf8b316f9e2ad43ba Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Wed, 9 Jun 2021 11:38:57 -0700 Subject: [PATCH 6/9] Example Console App should not prompt on error --- examples/Console/Program.cs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/examples/Console/Program.cs b/examples/Console/Program.cs index 69d10800ff2..3618d32d8f9 100644 --- a/examples/Console/Program.cs +++ b/examples/Console/Program.cs @@ -59,7 +59,11 @@ public static void Main(string[] args) (OpenTracingShimOptions options) => TestOpenTracingShim.Run(options), (OtlpOptions options) => TestOtlpExporter.Run(options.Endpoint), (InMemoryOptions options) => TestInMemoryExporter.Run(options), - errs => 1); + errs => + { + prompt = false; + return 1; + }); if (prompt) { @@ -103,31 +107,31 @@ internal class PrometheusOptions [Verb("metrics", HelpText = "Specify the options required to test Metrics")] internal class MetricsOptions { - [Option('g', "Gauge", HelpText = "Observable Gauge.", Required = false)] + [Option('g', "Gauge", HelpText = "Include Observable Gauge.", Required = false)] public bool? FlagGauge { get; set; } - [Option('u', "UpDownCounter", HelpText = "Observable Up/Down Counter.", Required = false)] + [Option('u', "UpDownCounter", HelpText = "Include Observable Up/Down Counter.", Required = false)] public bool? FlagUpDownCounter { get; set; } - [Option('c', "Counter", HelpText = "Counter.", Required = false)] + [Option('c', "Counter", HelpText = "Include Counter.", Required = false)] public bool? FlagCounter { get; set; } - [Option('h', "Histogram", HelpText = "Histogram.", Required = false)] + [Option('h', "Histogram", HelpText = "Include Histogram.", Required = false)] public bool? FlagHistogram { get; set; } - [Option("defaultCollectionPeriodMilliseconds", Default = 500, HelpText = "Default Collection period.", Required = false)] + [Option("defaultCollection", Default = 500, HelpText = "Default collection period in milliseconds.", Required = false)] public int DefaultCollectionPeriodMilliseconds { get; set; } [Option("runtime", Default = 5000, HelpText = "Run time in milliseconds.", Required = false)] public int RunTime { get; set; } - [Option("tasks", Default = 1, HelpText = "Run # of tasks.", Required = false)] + [Option("tasks", Default = 1, HelpText = "Run # of concurrent tasks.", Required = false)] public int NumTasks { get; set; } - [Option("maxLoops", Default = 0, HelpText = "Maximum number of loops. 0 = No Limit", Required = false)] + [Option("maxLoops", Default = 0, HelpText = "Maximum number of loops/iterations per task. (0 = No Limit)", Required = false)] public int MaxLoops { get; set; } - [Option('p', "prompt", HelpText = "Do not Prompt for exit", Required = false)] + [Option('p', "prompt", HelpText = "Do not prompt for exit.", Required = false)] public bool? Prompt { get; set; } } From f63b2248543a16b92575ff66c4a13e9ff482c9e7 Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Wed, 9 Jun 2021 12:03:03 -0700 Subject: [PATCH 7/9] Move annoying ReadLine() in Main into each Test. --- examples/Console/Program.cs | 18 ++---------------- examples/Console/TestGrpcNetClient.cs | 1 + examples/Console/TestHttpClient.cs | 1 + examples/Console/TestMetrics.cs | 9 +-------- .../Console/TestOTelShimWithConsoleExporter.cs | 1 + examples/Console/TestOpenTracingShim.cs | 1 + examples/Console/TestPrometheusExporter.cs | 2 ++ examples/Console/TestRedis.cs | 3 +++ 8 files changed, 12 insertions(+), 24 deletions(-) diff --git a/examples/Console/Program.cs b/examples/Console/Program.cs index 3618d32d8f9..42dac16bb1f 100644 --- a/examples/Console/Program.cs +++ b/examples/Console/Program.cs @@ -42,14 +42,12 @@ public class Program /// Arguments from command line. public static void Main(string[] args) { - bool prompt = true; - Parser.Default.ParseArguments(args) .MapResult( (JaegerOptions options) => TestJaegerExporter.Run(options.Host, options.Port), (ZipkinOptions options) => TestZipkinExporter.Run(options.Uri), (PrometheusOptions options) => TestPrometheusExporter.Run(options.Port, options.PushIntervalInSecs, options.DurationInMins), - (MetricsOptions options) => TestMetrics.Run(options, ref prompt), + (MetricsOptions options) => TestMetrics.Run(options), (GrpcNetClientOptions options) => TestGrpcNetClient.Run(), (HttpClientOptions options) => TestHttpClient.Run(), (RedisOptions options) => TestRedis.Run(options.Uri), @@ -59,16 +57,7 @@ public static void Main(string[] args) (OpenTracingShimOptions options) => TestOpenTracingShim.Run(options), (OtlpOptions options) => TestOtlpExporter.Run(options.Endpoint), (InMemoryOptions options) => TestInMemoryExporter.Run(options), - errs => - { - prompt = false; - return 1; - }); - - if (prompt) - { - System.Console.ReadLine(); - } + errs => 1); } } @@ -130,9 +119,6 @@ internal class MetricsOptions [Option("maxLoops", Default = 0, HelpText = "Maximum number of loops/iterations per task. (0 = No Limit)", Required = false)] public int MaxLoops { get; set; } - - [Option('p', "prompt", HelpText = "Do not prompt for exit.", Required = false)] - public bool? Prompt { get; set; } } [Verb("grpc", HelpText = "Specify the options required to test Grpc.Net.Client")] diff --git a/examples/Console/TestGrpcNetClient.cs b/examples/Console/TestGrpcNetClient.cs index ade965950c8..a15bd6fbde3 100644 --- a/examples/Console/TestGrpcNetClient.cs +++ b/examples/Console/TestGrpcNetClient.cs @@ -66,6 +66,7 @@ internal static object Run() } System.Console.WriteLine("Press Enter key to exit."); + System.Console.ReadLine(); return null; } diff --git a/examples/Console/TestHttpClient.cs b/examples/Console/TestHttpClient.cs index 1e08e48d5d4..78d0047a993 100644 --- a/examples/Console/TestHttpClient.cs +++ b/examples/Console/TestHttpClient.cs @@ -47,6 +47,7 @@ internal static object Run() } System.Console.WriteLine("Press Enter key to exit."); + System.Console.ReadLine(); return null; } diff --git a/examples/Console/TestMetrics.cs b/examples/Console/TestMetrics.cs index a193034df53..3568d4ae833 100644 --- a/examples/Console/TestMetrics.cs +++ b/examples/Console/TestMetrics.cs @@ -26,10 +26,8 @@ namespace Examples.Console { internal class TestMetrics { - internal static object Run(MetricsOptions options, ref bool prompt) + internal static object Run(MetricsOptions options) { - prompt = options.Prompt ?? false; - using var provider = Sdk.CreateMeterProviderBuilder() .AddSource("TestMeter") // All instruments from this meter are enabled. .SetDefaultCollectionPeriod(options.DefaultCollectionPeriodMilliseconds) @@ -153,11 +151,6 @@ internal static object Run(MetricsOptions options, ref bool prompt) Task.WaitAll(tasks.ToArray()); - if (prompt) - { - System.Console.WriteLine("Press Enter key to exit."); - } - return null; } } diff --git a/examples/Console/TestOTelShimWithConsoleExporter.cs b/examples/Console/TestOTelShimWithConsoleExporter.cs index cb439b8a041..984ac7ad380 100644 --- a/examples/Console/TestOTelShimWithConsoleExporter.cs +++ b/examples/Console/TestOTelShimWithConsoleExporter.cs @@ -51,6 +51,7 @@ internal static object Run(OpenTelemetryShimOptions options) } System.Console.WriteLine("Press Enter key to exit."); + System.Console.ReadLine(); return null; } diff --git a/examples/Console/TestOpenTracingShim.cs b/examples/Console/TestOpenTracingShim.cs index a0fbdf9c286..a5d75eac7dc 100644 --- a/examples/Console/TestOpenTracingShim.cs +++ b/examples/Console/TestOpenTracingShim.cs @@ -60,6 +60,7 @@ internal static object Run(OpenTracingShimOptions options) } System.Console.WriteLine("Press Enter key to exit."); + System.Console.ReadLine(); return null; } diff --git a/examples/Console/TestPrometheusExporter.cs b/examples/Console/TestPrometheusExporter.cs index 3b78c169098..098846b4793 100644 --- a/examples/Console/TestPrometheusExporter.cs +++ b/examples/Console/TestPrometheusExporter.cs @@ -43,6 +43,8 @@ internal static object Run(int port, int pushIntervalInSecs, int totalDurationIn - targets: ['localhost:9184'] */ System.Console.WriteLine("Press Enter key to exit."); + System.Console.ReadLine(); + return null; } } diff --git a/examples/Console/TestRedis.cs b/examples/Console/TestRedis.cs index 745b077043c..12981cc7928 100644 --- a/examples/Console/TestRedis.cs +++ b/examples/Console/TestRedis.cs @@ -70,6 +70,9 @@ internal static object Run(string zipkinUri) } } + System.Console.Write("Press ENTER to stop."); + System.Console.ReadLine(); + return null; } From f7d01d4fa27565163023613bcc2f478c2ec53fcd Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Wed, 9 Jun 2021 13:16:09 -0700 Subject: [PATCH 8/9] Update Unit Test for more coverage --- .../Metrics/MetricAPITest.cs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index 6b05e93fc33..f9c0e1c6992 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -38,9 +38,26 @@ public void SimpleTest() using var meter = new Meter("BasicAllTest", "0.0.1"); - var counter = meter.CreateCounter("counter1"); + var counter = meter.CreateCounter("counter"); - var observableCounter = meter.CreateObservableGauge("MemoryUsage", () => + var histogram = meter.CreateHistogram("histogram"); + + var observableCounter = meter.CreateObservableCounter("asynccounter", () => + { + return new List>() + { + new Measurement( + 30, + new KeyValuePair("attrb1", "value1")), + + new Measurement( + 40, + new KeyValuePair("label1", "value1"), + new KeyValuePair("label2", "value2")), + }; + }); + + var observableGauge = meter.CreateObservableGauge("asyncgauge", () => { return new List>() { @@ -66,6 +83,17 @@ public void SimpleTest() new KeyValuePair("label1", "value1"), new KeyValuePair("label2", "value2")); + histogram.Record(10); + + histogram.Record( + 100, + new KeyValuePair("label1", "value1")); + + histogram.Record( + 200, + new KeyValuePair("label1", "value1"), + new KeyValuePair("label2", "value2")); + Task.Delay(3000).Wait(); } } From 786c636797761f609a031a39b1c3dd24fbe32085 Mon Sep 17 00:00:00 2001 From: Victor Lu Date: Thu, 10 Jun 2021 23:16:33 -0700 Subject: [PATCH 9/9] Refactor from PR feedback --- src/OpenTelemetry/Metrics/AggregatorStore.cs | 12 +++--------- .../MetricAggregators/GaugeMetricAggregator.cs | 9 +++------ .../MetricAggregators/HistogramMetricAggregator.cs | 2 +- .../{IMetricBuilder.cs => IAggregator.cs} | 4 ++-- .../Metrics/MetricAggregators/IGaugeMetric.cs | 2 -- .../Metrics/MetricAggregators/SumMetricAggregator.cs | 2 +- .../MetricAggregators/SummaryMetricAggregator.cs | 2 +- 7 files changed, 11 insertions(+), 22 deletions(-) rename src/OpenTelemetry/Metrics/MetricAggregators/{IMetricBuilder.cs => IAggregator.cs} (87%) diff --git a/src/OpenTelemetry/Metrics/AggregatorStore.cs b/src/OpenTelemetry/Metrics/AggregatorStore.cs index 9fe058228c9..fafcd6e4ab0 100644 --- a/src/OpenTelemetry/Metrics/AggregatorStore.cs +++ b/src/OpenTelemetry/Metrics/AggregatorStore.cs @@ -69,12 +69,10 @@ internal MetricAgg[] MapToMetrics(string[] seqKey, object[] seqVal) { metricpairs.Add(new MetricAgg(timeperiod, new SumMetricAggregator(name, dt, tags, false, true))); metricpairs.Add(new MetricAgg(timeperiod, new SumMetricAggregator(name, dt, tags, true, true))); - metricpairs.Add(new MetricAgg(timeperiod, new SummaryMetricAggregator(name, dt, tags, false))); } else if (this.instrument.GetType().Name.Contains("Gauge")) { - metricpairs.Add(new MetricAgg(timeperiod, new GaugeMetricAggregator(name, dt, tags, false))); - metricpairs.Add(new MetricAgg(timeperiod, new SummaryMetricAggregator(name, dt, tags, false))); + metricpairs.Add(new MetricAgg(timeperiod, new GaugeMetricAggregator(name, dt, tags))); } else if (this.instrument.GetType().Name.Contains("Histogram")) { @@ -82,11 +80,7 @@ internal MetricAgg[] MapToMetrics(string[] seqKey, object[] seqVal) } else { - metricpairs.Add(new MetricAgg(timeperiod, new GaugeMetricAggregator(name, dt, tags, false))); - metricpairs.Add(new MetricAgg(timeperiod, new SumMetricAggregator(name, dt, tags, false, true))); - metricpairs.Add(new MetricAgg(timeperiod, new SumMetricAggregator(name, dt, tags, true, true))); metricpairs.Add(new MetricAgg(timeperiod, new SummaryMetricAggregator(name, dt, tags, false))); - metricpairs.Add(new MetricAgg(timeperiod, new HistogramMetricAggregator(name, dt, tags, false))); } } @@ -205,9 +199,9 @@ internal List Collect(int periodMilliseconds) internal class MetricAgg { internal int TimePeriod; - internal IMetricBuilder Metric; + internal IAggregator Metric; - internal MetricAgg(int timePeriod, IMetricBuilder metric) + internal MetricAgg(int timePeriod, IAggregator metric) { this.TimePeriod = timePeriod; this.Metric = metric; diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs index 3bb49539962..8bf0fbfb582 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs @@ -19,20 +19,19 @@ namespace OpenTelemetry.Metrics { - internal class GaugeMetricAggregator : IGaugeMetric, IMetricBuilder + internal class GaugeMetricAggregator : IGaugeMetric, IAggregator { private readonly object lockUpdate = new object(); private Type valueType; private long longValue; private double doubleValue; - internal GaugeMetricAggregator(string name, DateTimeOffset startTimeExclusive, KeyValuePair[] attributes, bool isDelta) + internal GaugeMetricAggregator(string name, DateTimeOffset startTimeExclusive, KeyValuePair[] attributes) { this.Name = name; this.StartTimeExclusive = startTimeExclusive; this.EndTimeInclusive = startTimeExclusive; this.Attributes = attributes; - this.IsDeltaTemporality = isDelta; } public string Name { get; private set; } @@ -43,8 +42,6 @@ internal GaugeMetricAggregator(string name, DateTimeOffset startTimeExclusive, K public KeyValuePair[] Attributes { get; private set; } - public bool IsDeltaTemporality { get; } - public IEnumerable Exemplars { get; private set; } = new List(); public IDataPoint LastValue @@ -93,7 +90,7 @@ public void Update(DateTimeOffset dt, T value) public IMetric Collect(DateTimeOffset dt) { - var cloneItem = new GaugeMetricAggregator(this.Name, this.StartTimeExclusive, this.Attributes, this.IsDeltaTemporality); + var cloneItem = new GaugeMetricAggregator(this.Name, this.StartTimeExclusive, this.Attributes); lock (this.lockUpdate) { diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs index a7e82c269cb..0d819d32a8e 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs @@ -19,7 +19,7 @@ namespace OpenTelemetry.Metrics { - internal class HistogramMetricAggregator : IHistogramMetric, IMetricBuilder + internal class HistogramMetricAggregator : IHistogramMetric, IAggregator { private readonly object lockUpdate = new object(); private List buckets = new List(); diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/IMetricBuilder.cs b/src/OpenTelemetry/Metrics/MetricAggregators/IAggregator.cs similarity index 87% rename from src/OpenTelemetry/Metrics/MetricAggregators/IMetricBuilder.cs rename to src/OpenTelemetry/Metrics/MetricAggregators/IAggregator.cs index ddf1e97cbac..21330af0316 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/IMetricBuilder.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/IAggregator.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ namespace OpenTelemetry.Metrics { - internal interface IMetricBuilder + internal interface IAggregator { void Update(DateTimeOffset dt, T value) where T : struct; diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs b/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs index 054845afe4d..aaaeefaffbc 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/IGaugeMetric.cs @@ -20,8 +20,6 @@ namespace OpenTelemetry.Metrics { internal interface IGaugeMetric : IMetric { - bool IsDeltaTemporality { get; } - IEnumerable Exemplars { get; } IDataPoint LastValue { get; } diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs index 429acc1f26c..de2f0ca24f9 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/SumMetricAggregator.cs @@ -19,7 +19,7 @@ namespace OpenTelemetry.Metrics { - internal class SumMetricAggregator : ISumMetric, IMetricBuilder + internal class SumMetricAggregator : ISumMetric, IAggregator { private readonly object lockUpdate = new object(); private Type valueType; diff --git a/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs b/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs index a0f9104620a..d003e0ad8d0 100644 --- a/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs +++ b/src/OpenTelemetry/Metrics/MetricAggregators/SummaryMetricAggregator.cs @@ -19,7 +19,7 @@ namespace OpenTelemetry.Metrics { - internal class SummaryMetricAggregator : ISummaryMetric, IMetricBuilder + internal class SummaryMetricAggregator : ISummaryMetric, IAggregator { private readonly object lockUpdate = new object();