From 35cae08415d9d6d4c38aad9b27ae6acc95add09f Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Tue, 22 Mar 2022 13:01:27 -0700 Subject: [PATCH] Store immutable copies of Metric/MetricPoint inside in-memory exporter. --- .../InMemoryMetricExporter.cs | 78 +++++++++++++++++++ src/OpenTelemetry/AssemblyInfo.cs | 1 + src/OpenTelemetry/Metrics/HistogramBuckets.cs | 12 +++ src/OpenTelemetry/Metrics/MetricPoint.cs | 11 ++- 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/OpenTelemetry.Exporter.InMemory/InMemoryMetricExporter.cs diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryMetricExporter.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryMetricExporter.cs new file mode 100644 index 00000000000..3d2fef70252 --- /dev/null +++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryMetricExporter.cs @@ -0,0 +1,78 @@ +// +// 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; +using OpenTelemetry.Metrics; + +namespace OpenTelemetry.Exporter +{ + public class InMemoryMetricExporter : BaseExporter + { + private readonly ICollection exportedItems; + + public InMemoryMetricExporter(ICollection exportedItems) + { + this.exportedItems = exportedItems; + } + + public override ExportResult Export(in Batch batch) + { + if (this.exportedItems == null) + { + return ExportResult.Failure; + } + + foreach (var metric in batch) + { + List metricPoints = new(); + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + metricPoints.Add(metricPoint.Copy()); + } + + this.exportedItems.Add(new ExportedMetric(metric, metricPoints)); + } + + return ExportResult.Success; + } + + public readonly struct ExportedMetric + { + private readonly InstrumentIdentity instrumentIdentity; + + internal ExportedMetric( + Metric metric, + IReadOnlyList metricPoints) + { + this.instrumentIdentity = metric.InstrumentIdentity; + this.MetricPoints = metricPoints; + } + + public string Name => this.instrumentIdentity.InstrumentName; + + public string Description => this.instrumentIdentity.Description; + + public string Unit => this.instrumentIdentity.Unit; + + public string MeterName => this.instrumentIdentity.MeterName; + + public string MeterVersion => this.instrumentIdentity.MeterVersion; + + public IReadOnlyList MetricPoints { get; } + } + } +} diff --git a/src/OpenTelemetry/AssemblyInfo.cs b/src/OpenTelemetry/AssemblyInfo.cs index 8d6f5f821b6..786f45623a5 100644 --- a/src/OpenTelemetry/AssemblyInfo.cs +++ b/src/OpenTelemetry/AssemblyInfo.cs @@ -18,5 +18,6 @@ [assembly: InternalsVisibleTo("OpenTelemetry.Tests" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting.Tests" + AssemblyInfo.PublicKey)] +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.InMemory" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2" + AssemblyInfo.MoqPublicKey)] [assembly: InternalsVisibleTo("Benchmarks" + AssemblyInfo.PublicKey)] diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 71e1b52eb21..626779d4901 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -14,6 +14,8 @@ // limitations under the License. // +using System; + namespace OpenTelemetry.Metrics { /// @@ -45,6 +47,16 @@ internal HistogramBuckets(double[] explicitBounds) public Enumerator GetEnumerator() => new(this); + internal HistogramBuckets Copy() + { + HistogramBuckets copy = new HistogramBuckets(this.ExplicitBounds); + + Array.Copy(this.SnapshotBucketCounts, copy.SnapshotBucketCounts, this.SnapshotBucketCounts.Length); + copy.SnapshotSum = this.SnapshotSum; + + return copy; + } + /// /// Enumerates the elements of a . /// diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index e1e2fb8e180..75f6c040e4b 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -28,7 +28,7 @@ public struct MetricPoint { private readonly AggregationType aggType; - private readonly HistogramBuckets histogramBuckets; + private HistogramBuckets histogramBuckets; // Represents temporality adjusted "value" for double/long metric types or "count" when histogram private MetricPointValueStorage runningValue; @@ -541,6 +541,15 @@ internal void TakeSnapshot(bool outputDelta) } } + internal MetricPoint Copy() + { + MetricPoint copy = this; + + copy.histogramBuckets = this.histogramBuckets.Copy(); + + return copy; + } + [MethodImpl(MethodImplOptions.NoInlining)] private readonly void ThrowNotSupportedMetricTypeException(string methodName) {