From a2ea6f75a4ef95165b21e6c4cf4cf26066a6f310 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 21 Feb 2024 15:32:34 -0500 Subject: [PATCH 01/16] feat: add basic metrics view support --- metrics_sdk/lib/opentelemetry/sdk/metrics.rb | 1 + .../opentelemetry/sdk/metrics/aggregation.rb | 2 + .../sdk/metrics/aggregation/drop.rb | 37 ++++ .../aggregation/explicit_bucket_histogram.rb | 15 +- .../sdk/metrics/aggregation/last_value.rb | 51 +++++ .../sdk/metrics/aggregation/sum.rb | 13 +- .../export/in_memory_metric_pull_exporter.rb | 2 +- .../sdk/metrics/meter_provider.rb | 14 +- .../sdk/metrics/state/metric_stream.rb | 60 ++++-- .../lib/opentelemetry/sdk/metrics/view.rb | 16 ++ .../sdk/metrics/view/registered_view.rb | 35 ++++ .../sdk/metrics/aggregation/drop_test.rb | 42 +++++ .../explicit_bucket_histogram_test.rb | 177 +++++++++--------- .../metrics/aggregation/last_value_test.rb | 40 ++++ .../sdk/metrics/aggregation/sum_test.rb | 38 ++-- .../sdk/metrics/meter_provider_test.rb | 20 +- .../sdk/metrics/view/registered_view_test.rb | 129 +++++++++++++ 17 files changed, 547 insertions(+), 145 deletions(-) create mode 100644 metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/drop.rb create mode 100644 metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/last_value.rb create mode 100644 metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb create mode 100644 metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb create mode 100644 metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/drop_test.rb create mode 100644 metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/last_value_test.rb create mode 100644 metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics.rb index 42807c708b..35593185f9 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics.rb @@ -20,3 +20,4 @@ module Metrics require 'opentelemetry/sdk/metrics/meter' require 'opentelemetry/sdk/metrics/meter_provider' require 'opentelemetry/sdk/metrics/state' +require 'opentelemetry/sdk/metrics/view' diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation.rb index f36aef0152..62f820eb93 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation.rb @@ -19,3 +19,5 @@ module Aggregation require 'opentelemetry/sdk/metrics/aggregation/histogram_data_point' require 'opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram' require 'opentelemetry/sdk/metrics/aggregation/sum' +require 'opentelemetry/sdk/metrics/aggregation/last_value' +require 'opentelemetry/sdk/metrics/aggregation/drop' diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/drop.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/drop.rb new file mode 100644 index 0000000000..8114f0d005 --- /dev/null +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/drop.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module SDK + module Metrics + module Aggregation + # Contains the implementation of the Drop aggregation + class Drop + def initialize(aggregation_temporality: :delta) + @aggregation_temporality = aggregation_temporality + end + + def collect(start_time, end_time, data_points) + data_points.values.map! do |ndp| + ndp.dup + end + end + + def update(increment, attributes, data_points) + data_points[attributes] = NumberDataPoint.new( + {}, + 0, + 0, + 0, + 0 + ) + nil + end + end + end + end + end +end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram.rb index 58d87ccaa4..feff9b76f4 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram.rb @@ -23,25 +23,24 @@ def initialize( boundaries: DEFAULT_BOUNDARIES, record_min_max: true ) - @data_points = {} @aggregation_temporality = aggregation_temporality @boundaries = boundaries && !boundaries.empty? ? boundaries.sort : nil @record_min_max = record_min_max end - def collect(start_time, end_time) + def collect(start_time, end_time, data_points) if @aggregation_temporality == :delta # Set timestamps and 'move' data point values to result. - hdps = @data_points.values.map! do |hdp| + hdps = data_points.values.map! do |hdp| hdp.start_time_unix_nano = start_time hdp.time_unix_nano = end_time hdp end - @data_points.clear + data_points.clear hdps else # Update timestamps and take a snapshot. - @data_points.values.map! do |hdp| + data_points.values.map! do |hdp| hdp.start_time_unix_nano ||= start_time # Start time of a data point is from the first observation. hdp.time_unix_nano = end_time hdp = hdp.dup @@ -51,14 +50,14 @@ def collect(start_time, end_time) end end - def update(amount, attributes) - hdp = @data_points.fetch(attributes) do + def update(amount, attributes, data_points) + hdp = data_points.fetch(attributes) do if @record_min_max min = Float::INFINITY max = -Float::INFINITY end - @data_points[attributes] = HistogramDataPoint.new( + data_points[attributes] = HistogramDataPoint.new( attributes, nil, # :start_time_unix_nano nil, # :time_unix_nano diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/last_value.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/last_value.rb new file mode 100644 index 0000000000..59df325f78 --- /dev/null +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/last_value.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module SDK + module Metrics + module Aggregation + # Contains the implementation of the LastValue aggregation + class LastValue + def initialize(aggregation_temporality: :delta) + @aggregation_temporality = aggregation_temporality + end + + def collect(start_time, end_time, data_points) + if @aggregation_temporality == :delta + # Set timestamps and 'move' data point values to result. + ndps = data_points.values.map! do |ndp| + ndp.start_time_unix_nano = start_time + ndp.time_unix_nano = end_time + ndp + end + data_points.clear + ndps + else + # Update timestamps and take a snapshot. + data_points.values.map! do |ndp| + ndp.start_time_unix_nano ||= start_time # Start time of a data point is from the first observation. + ndp.time_unix_nano = end_time + ndp.dup + end + end + end + + def update(increment, attributes, data_points) + data_points[attributes] = NumberDataPoint.new( + attributes, + nil, + nil, + increment, + nil + ) + nil + end + end + end + end + end +end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/sum.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/sum.rb index 31f8ac6681..2b1b1cb17d 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/sum.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/sum.rb @@ -13,22 +13,21 @@ module Aggregation class Sum def initialize(aggregation_temporality: :delta) @aggregation_temporality = aggregation_temporality - @data_points = {} end - def collect(start_time, end_time) + def collect(start_time, end_time, data_points) if @aggregation_temporality == :delta # Set timestamps and 'move' data point values to result. - ndps = @data_points.values.map! do |ndp| + ndps = data_points.values.map! do |ndp| ndp.start_time_unix_nano = start_time ndp.time_unix_nano = end_time ndp end - @data_points.clear + data_points.clear ndps else # Update timestamps and take a snapshot. - @data_points.values.map! do |ndp| + data_points.values.map! do |ndp| ndp.start_time_unix_nano ||= start_time # Start time of a data point is from the first observation. ndp.time_unix_nano = end_time ndp.dup @@ -36,8 +35,8 @@ def collect(start_time, end_time) end end - def update(increment, attributes) - ndp = @data_points[attributes] || @data_points[attributes] = NumberDataPoint.new( + def update(increment, attributes, data_points) + ndp = data_points[attributes] || data_points[attributes] = NumberDataPoint.new( attributes, nil, nil, diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb index 35c2dfe575..0b36abd4b3 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb @@ -25,7 +25,7 @@ def pull def export(metrics) @mutex.synchronize do - @metric_snapshots << metrics + metrics.class == Array ? @metric_snapshots.concat(metrics) : @metric_snapshots << metrics end SUCCESS end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb index 205ff5db0d..4d57ae0bf5 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb @@ -14,7 +14,7 @@ class MeterProvider < OpenTelemetry::Metrics::MeterProvider Key = Struct.new(:name, :version) private_constant(:Key) - attr_reader :resource, :metric_readers + attr_reader :resource, :metric_readers, :registered_views def initialize(resource: OpenTelemetry::SDK::Resources::Resource.create) @mutex = Mutex.new @@ -22,6 +22,7 @@ def initialize(resource: OpenTelemetry::SDK::Resources::Resource.create) @stopped = false @metric_readers = [] @resource = resource + @registered_views = [] end # Returns a {Meter} instance. @@ -125,13 +126,12 @@ def register_synchronous_instrument(instrument) end end - # The type of the Instrument(s) (optional). # The name of the Instrument(s). OpenTelemetry SDK authors MAY choose to support wildcard characters, with the question mark (?) matching exactly one character and the asterisk character (*) matching zero or more characters. - # The name of the Meter (optional). - # The version of the Meter (optional). - # The schema_url of the Meter (optional). - def add_view - # TODO: For each meter add this view to all applicable instruments + # The options of the Instrument(s). Useful key include: aggregation, type, unit, meter_name, meter_version, attribute_keys + # + # TODO: add schema_url as part of options + def add_view(name, **options) + @registered_views << View::RegisteredView.new(name, **options) end end end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb index d79d4a51ba..5bdd677fa2 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb @@ -28,33 +28,63 @@ def initialize( @description = description @unit = unit @instrument_kind = instrument_kind - @meter_provider = meter_provider + @meter_provider = meter_provider @instrumentation_scope = instrumentation_scope - @aggregation = aggregation + @default_aggregation = aggregation + @data_points = {} @mutex = Mutex.new end def collect(start_time, end_time) - @mutex.synchronize do - MetricData.new( - @name, - @description, - @unit, - @instrument_kind, - @meter_provider.resource, - @instrumentation_scope, - @aggregation.collect(start_time, end_time), - start_time, - end_time - ) + metric_data = Array.new + registred_views = find_registered_view + + if registred_views.empty? + metric_data << aggregate_metric_data(start_time, end_time) + else + registred_views.each { |view| metric_data << aggregate_metric_data(start_time, end_time, aggregation: view.aggregation) } end + + metric_data end def update(value, attributes) - @mutex.synchronize { @aggregation.update(value, attributes) } + registred_views = find_registered_view + if registred_views.empty? + @mutex.synchronize { @default_aggregation.update(value, attributes, @data_points) } + else + registred_views.each do |view| + @mutex.synchronize { + attributes = attributes || {} + attributes.merge!(view.attribute_keys) + view.aggregation.update(value, attributes, @data_points) + } + end + end end + def aggregate_metric_data(start_time, end_time, aggregation: nil) + aggregator = aggregation || @default_aggregation + MetricData.new( + @name, + @description, + @unit, + @instrument_kind, + @meter_provider.resource, + @instrumentation_scope, + aggregator.collect(start_time, end_time, @data_points), + start_time, + end_time + ) + end + + def find_registered_view + registred_views = Array.new + @meter_provider.registered_views.each { |view| registred_views << view if view.match_instrument(self) } + registred_views + end + def to_s instrument_info = String.new instrument_info << "name=#{@name}" diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb new file mode 100644 index 0000000000..597fee8142 --- /dev/null +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module SDK + module Metrics + module View + end + end + end +end + +require 'opentelemetry/sdk/metrics/view/registered_view' diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb new file mode 100644 index 0000000000..31b36be07d --- /dev/null +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module SDK + module Metrics + module View + class RegisteredView + attr_reader :name, :aggregation, :attribute_keys + + def initialize(name, **options) + @name = name + @options = options + @aggregation = options[:aggregation] + @attribute_keys = options[:attribute_keys] || {} + end + + def match_instrument(metric_stream) + return false if @aggregation.nil? + return false if @name && @name != metric_stream.name + return false if @options[:type] && @options[:type] != metric_stream.instrument_kind + return false if @options[:unit] && @options[:unit] != metric_stream.unit + return false if @options[:meter_name] && @options[:meter_name] != metric_stream.instrumentation_scope.name + return false if @options[:meter_version] && @options[:meter_version] != metric_stream.instrumentation_scope.version + + true + end + end + end + end + end +end diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/drop_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/drop_test.rb new file mode 100644 index 0000000000..76a3c44202 --- /dev/null +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/drop_test.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::SDK::Metrics::Aggregation::LastValue do + + let(:data_points) { {} } + let(:drop_aggregation) { OpenTelemetry::SDK::Metrics::Aggregation::Drop.new(aggregation_temporality: aggregation_temporality) } + let(:aggregation_temporality) { :delta } + + # Time in nano + let(:start_time) { (Time.now.to_r * 1_000_000_000).to_i } + let(:end_time) { ((Time.now + 60).to_r * 1_000_000_000).to_i } + + it 'sets the timestamps' do + drop_aggregation.update(0, {}, data_points) + ndp = drop_aggregation.collect(start_time, end_time, data_points)[0] + _(ndp.start_time_unix_nano).must_equal(0) + _(ndp.time_unix_nano).must_equal(0) + end + + it 'aggregates and collects should collect no value for all collection' do + drop_aggregation.update(1, {}, data_points) + drop_aggregation.update(2, {}, data_points) + + drop_aggregation.update(2, {'foo' => 'bar'}, data_points) + drop_aggregation.update(2, {'foo' => 'bar'}, data_points) + + ndps = drop_aggregation.collect(start_time, end_time, data_points) + + _(ndps.size).must_equal(2) + _(ndps[0].value).must_equal(0) + _(ndps[0].attributes).must_equal({}) + + _(ndps[1].value).must_equal(0) + _(ndps[1].attributes).must_equal({}) + end +end diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram_test.rb index 06c0e7b799..fa2f3dfed8 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram_test.rb @@ -7,6 +7,7 @@ require 'test_helper' describe OpenTelemetry::SDK::Metrics::Aggregation::ExplicitBucketHistogram do + let(:data_points) { {} } let(:ebh) do OpenTelemetry::SDK::Metrics::Aggregation::ExplicitBucketHistogram.new( aggregation_temporality: aggregation_temporality, @@ -23,19 +24,19 @@ describe '#collect' do it 'returns all the data points' do - ebh.update(0, {}) - ebh.update(1, {}) - ebh.update(5, {}) - ebh.update(6, {}) - ebh.update(10, {}) - - ebh.update(-10, 'foo' => 'bar') - ebh.update(1, 'foo' => 'bar') - ebh.update(22, 'foo' => 'bar') - ebh.update(55, 'foo' => 'bar') - ebh.update(80, 'foo' => 'bar') - - hdps = ebh.collect(start_time, end_time) + ebh.update(0, {}, data_points) + ebh.update(1, {}, data_points) + ebh.update(5, {}, data_points) + ebh.update(6, {}, data_points) + ebh.update(10, {}, data_points) + + ebh.update(-10, {'foo' => 'bar'}, data_points) + ebh.update(1, {'foo' => 'bar'}, data_points) + ebh.update(22, {'foo' => 'bar'}, data_points) + ebh.update(55, {'foo' => 'bar'}, data_points) + ebh.update(80, {'foo' => 'bar'}, data_points) + + hdps = ebh.collect(start_time, end_time, data_points) _(hdps.size).must_equal(2) _(hdps[0].attributes).must_equal({}) _(hdps[0].count).must_equal(5) @@ -55,34 +56,34 @@ end it 'sets the timestamps' do - ebh.update(0, {}) - hdp = ebh.collect(start_time, end_time)[0] + ebh.update(0, {}, data_points) + hdp = ebh.collect(start_time, end_time, data_points)[0] _(hdp.start_time_unix_nano).must_equal(start_time) _(hdp.time_unix_nano).must_equal(end_time) end it 'calculates the count' do - ebh.update(0, {}) - ebh.update(0, {}) - ebh.update(0, {}) - ebh.update(0, {}) - hdp = ebh.collect(start_time, end_time)[0] + ebh.update(0, {}, data_points) + ebh.update(0, {}, data_points) + ebh.update(0, {}, data_points) + ebh.update(0, {}, data_points) + hdp = ebh.collect(start_time, end_time, data_points)[0] _(hdp.count).must_equal(4) end it 'does not aggregate between collects with default delta aggregation' do - ebh.update(0, {}) - ebh.update(1, {}) - ebh.update(5, {}) - ebh.update(6, {}) - ebh.update(10, {}) - hdps = ebh.collect(start_time, end_time) - - ebh.update(0, {}) - ebh.update(1, {}) - ebh.update(5, {}) - ebh.update(6, {}) - ebh.update(10, {}) + ebh.update(0, {}, data_points) + ebh.update(1, {}, data_points) + ebh.update(5, {}, data_points) + ebh.update(6, {}, data_points) + ebh.update(10, {}, data_points) + hdps = ebh.collect(start_time, end_time, data_points) + + ebh.update(0, {}, data_points) + ebh.update(1, {}, data_points) + ebh.update(5, {}, data_points) + ebh.update(6, {}, data_points) + ebh.update(10, {}, data_points) # Assert that the recent update does not # impact the already collected metrics _(hdps[0].count).must_equal(5) @@ -91,7 +92,7 @@ _(hdps[0].max).must_equal(10) _(hdps[0].bucket_counts).must_equal([1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0]) - hdps = ebh.collect(start_time, end_time) + hdps = ebh.collect(start_time, end_time, data_points) # Assert that we are not accumulating values # between calls to collect _(hdps[0].count).must_equal(5) @@ -105,18 +106,18 @@ let(:aggregation_temporality) { :not_delta } it 'allows metrics to accumulate' do - ebh.update(0, {}) - ebh.update(1, {}) - ebh.update(5, {}) - ebh.update(6, {}) - ebh.update(10, {}) - hdps = ebh.collect(start_time, end_time) - - ebh.update(0, {}) - ebh.update(1, {}) - ebh.update(5, {}) - ebh.update(6, {}) - ebh.update(10, {}) + ebh.update(0, {}, data_points) + ebh.update(1, {}, data_points) + ebh.update(5, {}, data_points) + ebh.update(6, {}, data_points) + ebh.update(10, {}, data_points) + hdps = ebh.collect(start_time, end_time, data_points) + + ebh.update(0, {}, data_points) + ebh.update(1, {}, data_points) + ebh.update(5, {}, data_points) + ebh.update(6, {}, data_points) + ebh.update(10, {}, data_points) # Assert that the recent update does not # impact the already collected metrics _(hdps[0].count).must_equal(5) @@ -125,7 +126,7 @@ _(hdps[0].max).must_equal(10) _(hdps[0].bucket_counts).must_equal([1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0]) - hdps1 = ebh.collect(start_time, end_time) + hdps1 = ebh.collect(start_time, end_time, data_points) # Assert that we are accumulating values # and not just capturing the delta since # the previous collect call @@ -148,38 +149,38 @@ describe '#update' do it 'accumulates across the default boundaries' do - ebh.update(0, {}) + ebh.update(0, {}, data_points) - ebh.update(1, {}) - ebh.update(5, {}) + ebh.update(1, {}, data_points) + ebh.update(5, {}, data_points) - ebh.update(6, {}) - ebh.update(10, {}) + ebh.update(6, {}, data_points) + ebh.update(10, {}, data_points) - ebh.update(11, {}) - ebh.update(25, {}) + ebh.update(11, {}, data_points) + ebh.update(25, {}, data_points) - ebh.update(26, {}) - ebh.update(50, {}) + ebh.update(26, {}, data_points) + ebh.update(50, {}, data_points) - ebh.update(51, {}) - ebh.update(75, {}) + ebh.update(51, {}, data_points) + ebh.update(75, {}, data_points) - ebh.update(76, {}) - ebh.update(100, {}) + ebh.update(76, {}, data_points) + ebh.update(100, {}, data_points) - ebh.update(101, {}) - ebh.update(250, {}) + ebh.update(101, {}, data_points) + ebh.update(250, {}, data_points) - ebh.update(251, {}) - ebh.update(500, {}) + ebh.update(251, {}, data_points) + ebh.update(500, {}, data_points) - ebh.update(501, {}) - ebh.update(1000, {}) + ebh.update(501, {}, data_points) + ebh.update(1000, {}, data_points) - ebh.update(1001, {}) + ebh.update(1001, {}, data_points) - hdp = ebh.collect(start_time, end_time)[0] + hdp = ebh.collect(start_time, end_time, data_points)[0] _(hdp.bucket_counts).must_equal([1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1]) _(hdp.sum).must_equal(4040) _(hdp.min).must_equal(0) @@ -190,8 +191,8 @@ let(:boundaries) { [4, 2, 1] } it 'sorts it' do - ebh.update(0, {}) - _(ebh.collect(start_time, end_time)[0].explicit_bounds).must_equal([1, 2, 4]) + ebh.update(0, {}, data_points) + _(ebh.collect(start_time, end_time, data_points)[0].explicit_bounds).must_equal([1, 2, 4]) end end @@ -199,8 +200,8 @@ let(:record_min_max) { false } it 'does not record min max values' do - ebh.update(-1, {}) - hdp = ebh.collect(start_time, end_time)[0] + ebh.update(-1, {}, data_points) + hdp = ebh.collect(start_time, end_time, data_points)[0] _(hdp.min).must_be_nil _(hdp.min).must_be_nil end @@ -210,14 +211,14 @@ let(:boundaries) { [0, 2, 4] } it 'aggregates' do - ebh.update(-1, {}) - ebh.update(0, {}) - ebh.update(1, {}) - ebh.update(2, {}) - ebh.update(3, {}) - ebh.update(4, {}) - ebh.update(5, {}) - hdp = ebh.collect(start_time, end_time)[0] + ebh.update(-1, {}, data_points) + ebh.update(0, {}, data_points) + ebh.update(1, {}, data_points) + ebh.update(2, {}, data_points) + ebh.update(3, {}, data_points) + ebh.update(4, {}, data_points) + ebh.update(5, {}, data_points) + hdp = ebh.collect(start_time, end_time, data_points)[0] _(hdp.bucket_counts).must_equal([2, 2, 2, 1]) end @@ -227,9 +228,9 @@ let(:boundaries) { [0] } it 'aggregates' do - ebh.update(-1, {}) - ebh.update(1, {}) - hdp = ebh.collect(start_time, end_time)[0] + ebh.update(-1, {}, data_points) + ebh.update(1, {}, data_points) + hdp = ebh.collect(start_time, end_time, data_points)[0] _(hdp.bucket_counts).must_equal([1, 1]) end @@ -239,9 +240,9 @@ let(:boundaries) { [] } it 'aggregates but does not record bucket counts' do - ebh.update(-1, {}) - ebh.update(3, {}) - hdp = ebh.collect(start_time, end_time)[0] + ebh.update(-1, {}, data_points) + ebh.update(3, {}, data_points) + hdp = ebh.collect(start_time, end_time, data_points)[0] _(hdp.bucket_counts).must_be_nil _(hdp.explicit_bounds).must_be_nil @@ -256,9 +257,9 @@ let(:boundaries) { nil } it 'aggregates but does not record bucket counts' do - ebh.update(-1, {}) - ebh.update(3, {}) - hdp = ebh.collect(start_time, end_time)[0] + ebh.update(-1, {}, data_points) + ebh.update(3, {}, data_points) + hdp = ebh.collect(start_time, end_time, data_points)[0] _(hdp.bucket_counts).must_be_nil _(hdp.explicit_bounds).must_be_nil diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/last_value_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/last_value_test.rb new file mode 100644 index 0000000000..f83f9be1f2 --- /dev/null +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/last_value_test.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::SDK::Metrics::Aggregation::LastValue do + + let(:data_points) { {} } + let(:last_value_aggregation) { OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new(aggregation_temporality: aggregation_temporality) } + let(:aggregation_temporality) { :delta } + + # Time in nano + let(:start_time) { (Time.now.to_r * 1_000_000_000).to_i } + let(:end_time) { ((Time.now + 60).to_r * 1_000_000_000).to_i } + + it 'sets the timestamps' do + last_value_aggregation.update(0, {}, data_points) + ndp = last_value_aggregation.collect(start_time, end_time, data_points)[0] + _(ndp.start_time_unix_nano).must_equal(start_time) + _(ndp.time_unix_nano).must_equal(end_time) + end + + it 'aggregates and collects should collect the last value' do + last_value_aggregation.update(1, {}, data_points) + last_value_aggregation.update(2, {}, data_points) + + last_value_aggregation.update(2, {'foo' => 'bar'}, data_points) + last_value_aggregation.update(2, {'foo' => 'bar'}, data_points) + + ndps = last_value_aggregation.collect(start_time, end_time, data_points) + _(ndps[0].value).must_equal(2) + _(ndps[0].attributes).must_equal({}, data_points) + + _(ndps[1].value).must_equal(2) + _(ndps[1].attributes).must_equal('foo' => 'bar') + end +end diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/sum_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/sum_test.rb index 3c0a3931e3..3800f4159e 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/sum_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/sum_test.rb @@ -7,6 +7,8 @@ require 'test_helper' describe OpenTelemetry::SDK::Metrics::Aggregation::Sum do + + let(:data_points) { {} } let(:sum_aggregation) { OpenTelemetry::SDK::Metrics::Aggregation::Sum.new(aggregation_temporality: aggregation_temporality) } let(:aggregation_temporality) { :delta } @@ -15,38 +17,38 @@ let(:end_time) { ((Time.now + 60).to_r * 1_000_000_000).to_i } it 'sets the timestamps' do - sum_aggregation.update(0, {}) - ndp = sum_aggregation.collect(start_time, end_time)[0] + sum_aggregation.update(0, {}, data_points) + ndp = sum_aggregation.collect(start_time, end_time, data_points)[0] _(ndp.start_time_unix_nano).must_equal(start_time) _(ndp.time_unix_nano).must_equal(end_time) end it 'aggregates and collects' do - sum_aggregation.update(1, {}) - sum_aggregation.update(2, {}) + sum_aggregation.update(1, {}, data_points) + sum_aggregation.update(2, {}, data_points) - sum_aggregation.update(2, 'foo' => 'bar') - sum_aggregation.update(2, 'foo' => 'bar') + sum_aggregation.update(2, {'foo' => 'bar'}, data_points) + sum_aggregation.update(2, {'foo' => 'bar'}, data_points) - ndps = sum_aggregation.collect(start_time, end_time) + ndps = sum_aggregation.collect(start_time, end_time, data_points) _(ndps[0].value).must_equal(3) - _(ndps[0].attributes).must_equal({}) + _(ndps[0].attributes).must_equal({}, data_points) _(ndps[1].value).must_equal(4) _(ndps[1].attributes).must_equal('foo' => 'bar') end it 'does not aggregate between collects' do - sum_aggregation.update(1, {}) - sum_aggregation.update(2, {}) - ndps = sum_aggregation.collect(start_time, end_time) + sum_aggregation.update(1, {}, data_points) + sum_aggregation.update(2, {}, data_points) + ndps = sum_aggregation.collect(start_time, end_time, data_points) - sum_aggregation.update(1, {}) + sum_aggregation.update(1, {}, data_points) # Assert that the recent update does not # impact the already collected metrics _(ndps[0].value).must_equal(3) - ndps = sum_aggregation.collect(start_time, end_time) + ndps = sum_aggregation.collect(start_time, end_time, data_points) # Assert that we are not accumulating values # between calls to collect _(ndps[0].value).must_equal(1) @@ -56,16 +58,16 @@ let(:aggregation_temporality) { :not_delta } it 'allows metrics to accumulate' do - sum_aggregation.update(1, {}) - sum_aggregation.update(2, {}) - ndps = sum_aggregation.collect(start_time, end_time) + sum_aggregation.update(1, {}, data_points) + sum_aggregation.update(2, {}, data_points) + ndps = sum_aggregation.collect(start_time, end_time, data_points) - sum_aggregation.update(1, {}) + sum_aggregation.update(1, {}, data_points) # Assert that the recent update does not # impact the already collected metrics _(ndps[0].value).must_equal(3) - ndps = sum_aggregation.collect(start_time, end_time) + ndps = sum_aggregation.collect(start_time, end_time, data_points) # Assert that we are accumulating values # and not just capturing the delta since # the previous collect call diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/meter_provider_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/meter_provider_test.rb index f781d613b3..37aea3b5ab 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/meter_provider_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/meter_provider_test.rb @@ -134,8 +134,26 @@ end end - # TODO: OpenTelemetry.meter_provider.add_view describe '#add_view' do + it 'adds a view with aggregation' do + OpenTelemetry.meter_provider.add_view("test", aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::Drop.new()) + + registered_views = OpenTelemetry.meter_provider.instance_variable_get(:@registered_views) + + _(registered_views.size).must_equal 1 + _(registered_views[0].class).must_equal ::OpenTelemetry::SDK::Metrics::View::RegisteredView + _(registered_views[0].name).must_equal 'test' + _(registered_views[0].aggregation.class).must_equal ::OpenTelemetry::SDK::Metrics::Aggregation::Drop + end + + it 'add a view without aggregation but aggregation as nil' do + OpenTelemetry.meter_provider.add_view("test") + + registered_views = OpenTelemetry.meter_provider.instance_variable_get(:@registered_views) + + _(registered_views.size).must_equal 1 + _(registered_views[0].aggregation).must_be_nil + end end private diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb new file mode 100644 index 0000000000..a18ad683dd --- /dev/null +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::SDK::Metrics::View::RegisteredView do + describe '#registered_view' do + before { reset_metrics_sdk } + + it 'emits metrics with no data_points if view is drop' do + OpenTelemetry::SDK.configure + + metric_exporter = OpenTelemetry::SDK::Metrics::Export::InMemoryMetricPullExporter.new + OpenTelemetry.meter_provider.add_metric_reader(metric_exporter) + + meter = OpenTelemetry.meter_provider.meter('test') + counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') + + OpenTelemetry.meter_provider.add_view("counter", aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::Drop.new()) + + counter.add(1) + counter.add(2, attributes: { 'a' => 'b' }) + + metric_exporter.pull + last_snapshot = metric_exporter.metric_snapshots.last + + _(last_snapshot).wont_be_empty + _(last_snapshot[0].name).must_equal('counter') + _(last_snapshot[0].unit).must_equal('smidgen') + _(last_snapshot[0].description).must_equal('a small amount of something') + + _(last_snapshot[0].instrumentation_scope.name).must_equal('test') + + _(last_snapshot[0].data_points[0].value).must_equal 0 + _(last_snapshot[0].data_points[0].start_time_unix_nano).must_equal 0 + _(last_snapshot[0].data_points[0].time_unix_nano).must_equal 0 + + _(last_snapshot[0].data_points[1].value).must_equal 0 + _(last_snapshot[0].data_points[1].start_time_unix_nano).must_equal 0 + _(last_snapshot[0].data_points[1].time_unix_nano).must_equal 0 + end + + it 'emits metrics with only last value in data_points if view is last_value' do + OpenTelemetry::SDK.configure + + metric_exporter = OpenTelemetry::SDK::Metrics::Export::InMemoryMetricPullExporter.new + OpenTelemetry.meter_provider.add_metric_reader(metric_exporter) + + meter = OpenTelemetry.meter_provider.meter('test') + counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') + + OpenTelemetry.meter_provider.add_view("counter", aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new()) + + counter.add(1) + counter.add(2) + counter.add(3) + counter.add(4) + + metric_exporter.pull + last_snapshot = metric_exporter.metric_snapshots.last + + _(last_snapshot[0].data_points).wont_be_empty + _(last_snapshot[0].data_points[0].value).must_equal 4 + end + + it 'emits metrics with sum of value in data_points if view is last_value but not matching to instrument' do + OpenTelemetry::SDK.configure + + metric_exporter = OpenTelemetry::SDK::Metrics::Export::InMemoryMetricPullExporter.new + OpenTelemetry.meter_provider.add_metric_reader(metric_exporter) + + meter = OpenTelemetry.meter_provider.meter('test') + counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') + + OpenTelemetry.meter_provider.add_view("retnuoc", aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new()) + + counter.add(1) + counter.add(2) + counter.add(3) + counter.add(4) + + metric_exporter.pull + last_snapshot = metric_exporter.metric_snapshots.last + + _(last_snapshot[0].data_points).wont_be_empty + _(last_snapshot[0].data_points[0].value).must_equal 10 + end + end + + describe '#registered_view select instrument' do + let(:registered_view) { OpenTelemetry::SDK::Metrics::View::RegisteredView.new(nil, aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new()) } + let(:instrumentation_scope) { + OpenTelemetry::SDK::InstrumentationScope.new('test_scope', '1.0.1') + } + + let(:metric_stream) { + OpenTelemetry::SDK::Metrics::State::MetricStream.new('test', 'description', 'smidgen', :counter, nil, instrumentation_scope ,nil) + } + + it 'registered view with matching name' do + registered_view.instance_variable_set(:@name,'test') + _(registered_view.match_instrument(metric_stream)).must_equal true + end + + it 'registered view with matching type' do + registered_view.instance_variable_set(:@options, {:type => :counter}) + _(registered_view.match_instrument(metric_stream)).must_equal true + end + + it 'registered view with matching version' do + registered_view.instance_variable_set(:@options, {:meter_version => '1.0.1'}) + _(registered_view.match_instrument(metric_stream)).must_equal true + end + + it 'registered view with matching meter_name' do + registered_view.instance_variable_set(:@options, {:meter_name => 'test_scope'}) + _(registered_view.match_instrument(metric_stream)).must_equal true + end + + it 'do not registered view with unmatching name and matching type' do + registered_view.instance_variable_set(:@options, {:type => :counter}) + registered_view.instance_variable_set(:@name, 'tset') + _(registered_view.match_instrument(metric_stream)).must_equal false + end + end +end From 3a9431e270cdfaa8027fc955980d1ae0bdcf70af Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 21 Feb 2024 15:41:08 -0500 Subject: [PATCH 02/16] feat: lint --- .../sdk/metrics/aggregation/drop.rb | 4 +-- .../export/in_memory_metric_pull_exporter.rb | 2 +- .../sdk/metrics/meter_provider.rb | 2 +- .../sdk/metrics/state/metric_stream.rb | 14 +++++----- .../lib/opentelemetry/sdk/metrics/view.rb | 1 + .../sdk/metrics/view/registered_view.rb | 1 + .../sdk/metrics/aggregation/drop_test.rb | 5 ++-- .../explicit_bucket_histogram_test.rb | 10 +++---- .../metrics/aggregation/last_value_test.rb | 5 ++-- .../sdk/metrics/aggregation/sum_test.rb | 5 ++-- .../sdk/metrics/meter_provider_test.rb | 8 +++--- .../sdk/metrics/view/registered_view_test.rb | 28 +++++++++---------- 12 files changed, 41 insertions(+), 44 deletions(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/drop.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/drop.rb index 0725ede2ac..f638c649a5 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/drop.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/aggregation/drop.rb @@ -17,9 +17,7 @@ def initialize(aggregation_temporality: :delta) end def collect(start_time, end_time, data_points) - data_points.values.map! do |ndp| - ndp.dup - end + data_points.values.map!(&:dup) end def update(increment, attributes, data_points) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb index 0b36abd4b3..8e071dedeb 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb @@ -25,7 +25,7 @@ def pull def export(metrics) @mutex.synchronize do - metrics.class == Array ? @metric_snapshots.concat(metrics) : @metric_snapshots << metrics + metrics.instance_of?(Array) ? @metric_snapshots.concat(metrics) : @metric_snapshots << metrics end SUCCESS end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb index 4d57ae0bf5..9abf34cf68 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb @@ -128,7 +128,7 @@ def register_synchronous_instrument(instrument) # The name of the Instrument(s). OpenTelemetry SDK authors MAY choose to support wildcard characters, with the question mark (?) matching exactly one character and the asterisk character (*) matching zero or more characters. # The options of the Instrument(s). Useful key include: aggregation, type, unit, meter_name, meter_version, attribute_keys - # + # # TODO: add schema_url as part of options def add_view(name, **options) @registered_views << View::RegisteredView.new(name, **options) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb index 58e84abfe8..ea19c090ad 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb @@ -37,7 +37,7 @@ def initialize( end def collect(start_time, end_time) - metric_data = Array.new + metric_data = [] registred_views = find_registered_view if registred_views.empty? @@ -55,11 +55,11 @@ def update(value, attributes) @mutex.synchronize { @default_aggregation.update(value, attributes, @data_points) } else registred_views.each do |view| - @mutex.synchronize { - attributes = attributes || {} + @mutex.synchronize do + attributes ||= {} attributes.merge!(view.attribute_keys) - view.aggregation.update(value, attributes, @data_points) - } + view.aggregation.update(value, attributes, @data_points) + end end end end @@ -81,11 +81,11 @@ def aggregate_metric_data(start_time, end_time, aggregation: nil) end def find_registered_view - registred_views = Array.new + registred_views = [] @meter_provider.registered_views.each { |view| registred_views << view if view.match_instrument(self) } registred_views end - + def to_s instrument_info = String.new instrument_info << "name=#{@name}" diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb index 597fee8142..c5e23c0676 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb @@ -7,6 +7,7 @@ module OpenTelemetry module SDK module Metrics + # View module View end end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb index 31b36be07d..aaac950b09 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb @@ -8,6 +8,7 @@ module OpenTelemetry module SDK module Metrics module View + # RegisteredView class RegisteredView attr_reader :name, :aggregation, :attribute_keys diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/drop_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/drop_test.rb index 76a3c44202..8c873107d9 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/drop_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/drop_test.rb @@ -7,7 +7,6 @@ require 'test_helper' describe OpenTelemetry::SDK::Metrics::Aggregation::LastValue do - let(:data_points) { {} } let(:drop_aggregation) { OpenTelemetry::SDK::Metrics::Aggregation::Drop.new(aggregation_temporality: aggregation_temporality) } let(:aggregation_temporality) { :delta } @@ -27,8 +26,8 @@ drop_aggregation.update(1, {}, data_points) drop_aggregation.update(2, {}, data_points) - drop_aggregation.update(2, {'foo' => 'bar'}, data_points) - drop_aggregation.update(2, {'foo' => 'bar'}, data_points) + drop_aggregation.update(2, { 'foo' => 'bar' }, data_points) + drop_aggregation.update(2, { 'foo' => 'bar' }, data_points) ndps = drop_aggregation.collect(start_time, end_time, data_points) diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram_test.rb index fa2f3dfed8..52ae019269 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram_test.rb @@ -30,11 +30,11 @@ ebh.update(6, {}, data_points) ebh.update(10, {}, data_points) - ebh.update(-10, {'foo' => 'bar'}, data_points) - ebh.update(1, {'foo' => 'bar'}, data_points) - ebh.update(22, {'foo' => 'bar'}, data_points) - ebh.update(55, {'foo' => 'bar'}, data_points) - ebh.update(80, {'foo' => 'bar'}, data_points) + ebh.update(-10, { 'foo' => 'bar' }, data_points) + ebh.update(1, { 'foo' => 'bar' }, data_points) + ebh.update(22, { 'foo' => 'bar' }, data_points) + ebh.update(55, { 'foo' => 'bar' }, data_points) + ebh.update(80, { 'foo' => 'bar' }, data_points) hdps = ebh.collect(start_time, end_time, data_points) _(hdps.size).must_equal(2) diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/last_value_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/last_value_test.rb index f83f9be1f2..8714b698d5 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/last_value_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/last_value_test.rb @@ -7,7 +7,6 @@ require 'test_helper' describe OpenTelemetry::SDK::Metrics::Aggregation::LastValue do - let(:data_points) { {} } let(:last_value_aggregation) { OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new(aggregation_temporality: aggregation_temporality) } let(:aggregation_temporality) { :delta } @@ -27,8 +26,8 @@ last_value_aggregation.update(1, {}, data_points) last_value_aggregation.update(2, {}, data_points) - last_value_aggregation.update(2, {'foo' => 'bar'}, data_points) - last_value_aggregation.update(2, {'foo' => 'bar'}, data_points) + last_value_aggregation.update(2, { 'foo' => 'bar' }, data_points) + last_value_aggregation.update(2, { 'foo' => 'bar' }, data_points) ndps = last_value_aggregation.collect(start_time, end_time, data_points) _(ndps[0].value).must_equal(2) diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/sum_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/sum_test.rb index 3800f4159e..18e07ec32d 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/sum_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/aggregation/sum_test.rb @@ -7,7 +7,6 @@ require 'test_helper' describe OpenTelemetry::SDK::Metrics::Aggregation::Sum do - let(:data_points) { {} } let(:sum_aggregation) { OpenTelemetry::SDK::Metrics::Aggregation::Sum.new(aggregation_temporality: aggregation_temporality) } let(:aggregation_temporality) { :delta } @@ -27,8 +26,8 @@ sum_aggregation.update(1, {}, data_points) sum_aggregation.update(2, {}, data_points) - sum_aggregation.update(2, {'foo' => 'bar'}, data_points) - sum_aggregation.update(2, {'foo' => 'bar'}, data_points) + sum_aggregation.update(2, { 'foo' => 'bar' }, data_points) + sum_aggregation.update(2, { 'foo' => 'bar' }, data_points) ndps = sum_aggregation.collect(start_time, end_time, data_points) _(ndps[0].value).must_equal(3) diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/meter_provider_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/meter_provider_test.rb index 37aea3b5ab..a82513a3c4 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/meter_provider_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/meter_provider_test.rb @@ -136,10 +136,10 @@ describe '#add_view' do it 'adds a view with aggregation' do - OpenTelemetry.meter_provider.add_view("test", aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::Drop.new()) + OpenTelemetry.meter_provider.add_view('test', aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::Drop.new) registered_views = OpenTelemetry.meter_provider.instance_variable_get(:@registered_views) - + _(registered_views.size).must_equal 1 _(registered_views[0].class).must_equal ::OpenTelemetry::SDK::Metrics::View::RegisteredView _(registered_views[0].name).must_equal 'test' @@ -147,10 +147,10 @@ end it 'add a view without aggregation but aggregation as nil' do - OpenTelemetry.meter_provider.add_view("test") + OpenTelemetry.meter_provider.add_view('test') registered_views = OpenTelemetry.meter_provider.instance_variable_get(:@registered_views) - + _(registered_views.size).must_equal 1 _(registered_views[0].aggregation).must_be_nil end diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb index a18ad683dd..2211b9d4c6 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb @@ -19,7 +19,7 @@ meter = OpenTelemetry.meter_provider.meter('test') counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') - OpenTelemetry.meter_provider.add_view("counter", aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::Drop.new()) + OpenTelemetry.meter_provider.add_view('counter', aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::Drop.new) counter.add(1) counter.add(2, attributes: { 'a' => 'b' }) @@ -52,7 +52,7 @@ meter = OpenTelemetry.meter_provider.meter('test') counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') - OpenTelemetry.meter_provider.add_view("counter", aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new()) + OpenTelemetry.meter_provider.add_view('counter', aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new) counter.add(1) counter.add(2) @@ -75,7 +75,7 @@ meter = OpenTelemetry.meter_provider.meter('test') counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') - OpenTelemetry.meter_provider.add_view("retnuoc", aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new()) + OpenTelemetry.meter_provider.add_view('retnuoc', aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new) counter.add(1) counter.add(2) @@ -91,37 +91,37 @@ end describe '#registered_view select instrument' do - let(:registered_view) { OpenTelemetry::SDK::Metrics::View::RegisteredView.new(nil, aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new()) } - let(:instrumentation_scope) { + let(:registered_view) { OpenTelemetry::SDK::Metrics::View::RegisteredView.new(nil, aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new) } + let(:instrumentation_scope) do OpenTelemetry::SDK::InstrumentationScope.new('test_scope', '1.0.1') - } + end - let(:metric_stream) { - OpenTelemetry::SDK::Metrics::State::MetricStream.new('test', 'description', 'smidgen', :counter, nil, instrumentation_scope ,nil) - } + let(:metric_stream) do + OpenTelemetry::SDK::Metrics::State::MetricStream.new('test', 'description', 'smidgen', :counter, nil, instrumentation_scope, nil) + end it 'registered view with matching name' do - registered_view.instance_variable_set(:@name,'test') + registered_view.instance_variable_set(:@name, 'test') _(registered_view.match_instrument(metric_stream)).must_equal true end it 'registered view with matching type' do - registered_view.instance_variable_set(:@options, {:type => :counter}) + registered_view.instance_variable_set(:@options, { type: :counter }) _(registered_view.match_instrument(metric_stream)).must_equal true end it 'registered view with matching version' do - registered_view.instance_variable_set(:@options, {:meter_version => '1.0.1'}) + registered_view.instance_variable_set(:@options, { meter_version: '1.0.1' }) _(registered_view.match_instrument(metric_stream)).must_equal true end it 'registered view with matching meter_name' do - registered_view.instance_variable_set(:@options, {:meter_name => 'test_scope'}) + registered_view.instance_variable_set(:@options, { meter_name: 'test_scope' }) _(registered_view.match_instrument(metric_stream)).must_equal true end it 'do not registered view with unmatching name and matching type' do - registered_view.instance_variable_set(:@options, {:type => :counter}) + registered_view.instance_variable_set(:@options, { type: :counter }) registered_view.instance_variable_set(:@name, 'tset') _(registered_view.match_instrument(metric_stream)).must_equal false end From cc99becc256061dd802174eaff60e339171a6583 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Thu, 22 Feb 2024 14:57:56 -0500 Subject: [PATCH 03/16] feat: metric view lint --- .../sdk/metrics/state/metric_stream.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb index ea19c090ad..5dff361c2a 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb @@ -37,24 +37,24 @@ def initialize( end def collect(start_time, end_time) - metric_data = [] - registred_views = find_registered_view + metric_data = [] + registered_views = find_registered_view - if registred_views.empty? + if registered_views.empty? metric_data << aggregate_metric_data(start_time, end_time) else - registred_views.each { |view| metric_data << aggregate_metric_data(start_time, end_time, aggregation: view.aggregation) } + registered_views.each { |view| metric_data << aggregate_metric_data(start_time, end_time, aggregation: view.aggregation) } end metric_data end def update(value, attributes) - registred_views = find_registered_view - if registred_views.empty? + registered_views = find_registered_view + if registered_views.empty? @mutex.synchronize { @default_aggregation.update(value, attributes, @data_points) } else - registred_views.each do |view| + registered_views.each do |view| @mutex.synchronize do attributes ||= {} attributes.merge!(view.attribute_keys) @@ -81,9 +81,9 @@ def aggregate_metric_data(start_time, end_time, aggregation: nil) end def find_registered_view - registred_views = [] - @meter_provider.registered_views.each { |view| registred_views << view if view.match_instrument(self) } - registred_views + registered_views = [] + @meter_provider.registered_views.each { |view| registered_views << view if view.match_instrument(self) } + registered_views end def to_s From de366c6a9f8a7f2f3a3214c7e53433fe9f33291a Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Thu, 11 Jul 2024 14:47:48 -0400 Subject: [PATCH 04/16] feat: metrics - use flatten for 1-d array MetricData --- exporter/otlp-metrics/test/test_helper.rb | 2 +- .../lib/opentelemetry/sdk/metrics/state/metric_store.rb | 2 +- .../test/integration/in_memory_metric_pull_exporter_test.rb | 2 +- .../opentelemetry/sdk/metrics/instrument/counter_test.rb | 2 +- .../opentelemetry/sdk/metrics/instrument/histogram_test.rb | 2 +- .../sdk/metrics/instrument/up_down_counter_test.rb | 2 +- .../opentelemetry/sdk/metrics/view/registered_view_test.rb | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/exporter/otlp-metrics/test/test_helper.rb b/exporter/otlp-metrics/test/test_helper.rb index 461b180653..9fc4466458 100644 --- a/exporter/otlp-metrics/test/test_helper.rb +++ b/exporter/otlp-metrics/test/test_helper.rb @@ -17,7 +17,7 @@ OpenTelemetry.logger = Logger.new(File::NULL) module MockSum - def collect(start_time, end_time) + def collect(start_time, end_time, data_points) start_time = 1_699_593_427_329_946_585 # rubocop:disable Lint/ShadowedArgument end_time = 1_699_593_427_329_946_586 # rubocop:disable Lint/ShadowedArgument super diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_store.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_store.rb index de2ecb83b6..207079ff4f 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_store.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_store.rb @@ -25,7 +25,7 @@ def collect @epoch_end_time = now_in_nano snapshot = @metric_streams.map { |ms| ms.collect(@epoch_start_time, @epoch_end_time) } @epoch_start_time = @epoch_end_time - snapshot + snapshot.flatten! end end diff --git a/metrics_sdk/test/integration/in_memory_metric_pull_exporter_test.rb b/metrics_sdk/test/integration/in_memory_metric_pull_exporter_test.rb index bed4bdf935..3e060e79dc 100644 --- a/metrics_sdk/test/integration/in_memory_metric_pull_exporter_test.rb +++ b/metrics_sdk/test/integration/in_memory_metric_pull_exporter_test.rb @@ -26,7 +26,7 @@ counter.add(4, attributes: { 'd' => 'e' }) metric_exporter.pull - last_snapshot = metric_exporter.metric_snapshots.last + last_snapshot = metric_exporter.metric_snapshots _(last_snapshot).wont_be_empty _(last_snapshot[0].name).must_equal('counter') diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/counter_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/counter_test.rb index c00e2eba7b..ff5c3edfe2 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/counter_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/counter_test.rb @@ -20,7 +20,7 @@ it 'counts' do counter.add(1, attributes: { 'foo' => 'bar' }) metric_exporter.pull - last_snapshot = metric_exporter.metric_snapshots.last + last_snapshot = metric_exporter.metric_snapshots _(last_snapshot[0].name).must_equal('counter') _(last_snapshot[0].unit).must_equal('smidgen') diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/histogram_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/histogram_test.rb index bddc7f5568..771ffaef83 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/histogram_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/histogram_test.rb @@ -21,7 +21,7 @@ histogram.record(5, attributes: { 'foo' => 'bar' }) histogram.record(6, attributes: { 'foo' => 'bar' }) metric_exporter.pull - last_snapshot = metric_exporter.metric_snapshots.last + last_snapshot = metric_exporter.metric_snapshots _(last_snapshot[0].name).must_equal('histogram') _(last_snapshot[0].unit).must_equal('smidgen') diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/up_down_counter_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/up_down_counter_test.rb index 456c2c5052..687ad27a89 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/up_down_counter_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/instrument/up_down_counter_test.rb @@ -21,7 +21,7 @@ up_down_counter.add(1, attributes: { 'foo' => 'bar' }) up_down_counter.add(-2, attributes: { 'foo' => 'bar' }) metric_exporter.pull - last_snapshot = metric_exporter.metric_snapshots.last + last_snapshot = metric_exporter.metric_snapshots _(last_snapshot[0].name).must_equal('up_down_counter') _(last_snapshot[0].unit).must_equal('smidgen') diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb index 2211b9d4c6..b76f3f505b 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb @@ -25,7 +25,7 @@ counter.add(2, attributes: { 'a' => 'b' }) metric_exporter.pull - last_snapshot = metric_exporter.metric_snapshots.last + last_snapshot = metric_exporter.metric_snapshots _(last_snapshot).wont_be_empty _(last_snapshot[0].name).must_equal('counter') @@ -60,7 +60,7 @@ counter.add(4) metric_exporter.pull - last_snapshot = metric_exporter.metric_snapshots.last + last_snapshot = metric_exporter.metric_snapshots _(last_snapshot[0].data_points).wont_be_empty _(last_snapshot[0].data_points[0].value).must_equal 4 @@ -83,7 +83,7 @@ counter.add(4) metric_exporter.pull - last_snapshot = metric_exporter.metric_snapshots.last + last_snapshot = metric_exporter.metric_snapshots _(last_snapshot[0].data_points).wont_be_empty _(last_snapshot[0].data_points[0].value).must_equal 10 From cf05b7e420594af5dd237812f2ce9b8435de23bd Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:47:57 -0400 Subject: [PATCH 05/16] Update metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/sdk/metrics/state/metric_stream.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb index 5dff361c2a..c807010da3 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb @@ -28,7 +28,7 @@ def initialize( @description = description @unit = unit @instrument_kind = instrument_kind - @meter_provider = meter_provider + @meter_provider = meter_provider @instrumentation_scope = instrumentation_scope @default_aggregation = aggregation @data_points = {} From f1d65d95a4e89946a07724d0c0335f98e33ac937 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:48:01 -0400 Subject: [PATCH 06/16] Update metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb index 9abf34cf68..97384f4c07 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb @@ -127,7 +127,7 @@ def register_synchronous_instrument(instrument) end # The name of the Instrument(s). OpenTelemetry SDK authors MAY choose to support wildcard characters, with the question mark (?) matching exactly one character and the asterisk character (*) matching zero or more characters. - # The options of the Instrument(s). Useful key include: aggregation, type, unit, meter_name, meter_version, attribute_keys + # The options of the Instrument(s). Useful keys include: aggregation, type, unit, meter_name, meter_version, attribute_keys # # TODO: add schema_url as part of options def add_view(name, **options) From 749a8207ac07823be5a032b2b4703c2f7380dcd1 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Thu, 18 Jul 2024 11:18:46 -0400 Subject: [PATCH 07/16] update doc --- .../sdk/metrics/meter_provider.rb | 25 +++++++++++++++++-- .../sdk/metrics/state/metric_stream.rb | 2 +- .../sdk/metrics/view/registered_view.rb | 2 +- .../sdk/metrics/view/registered_view_test.rb | 10 ++++---- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb index 97384f4c07..afaaa70216 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb @@ -126,12 +126,33 @@ def register_synchronous_instrument(instrument) end end - # The name of the Instrument(s). OpenTelemetry SDK authors MAY choose to support wildcard characters, with the question mark (?) matching exactly one character and the asterisk character (*) matching zero or more characters. - # The options of the Instrument(s). Useful keys include: aggregation, type, unit, meter_name, meter_version, attribute_keys + # Register a view. + # + # Example: + # + # OpenTelemetry.meter_provider.add_view('test', :aggregation => Aggregation::Drop.new, + # :type => :counter, :unit => 'smidgen', + # :meter_name => 'test', :meter_version => '1.0') + # + # Note that OpenTelemetry SDK authors MAY choose to support wildcard characters, + # with the question mark (?) matching exactly one character and the asterisk + # character (*) matching zero or more characters. + # + # @param [String] name Name of the view. + # @param [optional Hash] options For more precise matching view and metrics stream + # options may include: + # aggregation: aggregation type e.g. ExplicitBucketHistogram, Sum, LastValue + # type: instrumentation kind (instrument_kind) e.g. observable_gauge, counter, etc. + # unit: instrumentation unit e.g. smidgen + # meter_name: meter name e.g. meter_provider.meter("sample_meter_name", version: '1.2.0') + # meter_version: meter version e.g. meter_provider.meter("sample_meter_name", version: '1.2.0') + # + # @return [nil] returns nil # # TODO: add schema_url as part of options def add_view(name, **options) @registered_views << View::RegisteredView.new(name, **options) + nil end end end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb index c807010da3..1ff7cf695e 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb @@ -82,7 +82,7 @@ def aggregate_metric_data(start_time, end_time, aggregation: nil) def find_registered_view registered_views = [] - @meter_provider.registered_views.each { |view| registered_views << view if view.match_instrument(self) } + @meter_provider.registered_views.each { |view| registered_views << view if view.match_instrument?(self) } registered_views end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb index aaac950b09..81060590dd 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb @@ -19,7 +19,7 @@ def initialize(name, **options) @attribute_keys = options[:attribute_keys] || {} end - def match_instrument(metric_stream) + def match_instrument?(metric_stream) return false if @aggregation.nil? return false if @name && @name != metric_stream.name return false if @options[:type] && @options[:type] != metric_stream.instrument_kind diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb index b76f3f505b..c2534b0d5f 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb @@ -102,28 +102,28 @@ it 'registered view with matching name' do registered_view.instance_variable_set(:@name, 'test') - _(registered_view.match_instrument(metric_stream)).must_equal true + _(registered_view.match_instrument?(metric_stream)).must_equal true end it 'registered view with matching type' do registered_view.instance_variable_set(:@options, { type: :counter }) - _(registered_view.match_instrument(metric_stream)).must_equal true + _(registered_view.match_instrument?(metric_stream)).must_equal true end it 'registered view with matching version' do registered_view.instance_variable_set(:@options, { meter_version: '1.0.1' }) - _(registered_view.match_instrument(metric_stream)).must_equal true + _(registered_view.match_instrument?(metric_stream)).must_equal true end it 'registered view with matching meter_name' do registered_view.instance_variable_set(:@options, { meter_name: 'test_scope' }) - _(registered_view.match_instrument(metric_stream)).must_equal true + _(registered_view.match_instrument?(metric_stream)).must_equal true end it 'do not registered view with unmatching name and matching type' do registered_view.instance_variable_set(:@options, { type: :counter }) registered_view.instance_variable_set(:@name, 'tset') - _(registered_view.match_instrument(metric_stream)).must_equal false + _(registered_view.match_instrument?(metric_stream)).must_equal false end end end From c96ce2063857ba79aac1426eafdd0c2653fcd587 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 22 Jul 2024 18:03:05 -0400 Subject: [PATCH 08/16] revision --- .../sdk/metrics/meter_provider.rb | 16 +++++++------- .../sdk/metrics/state/metric_stream.rb | 21 +++++++++---------- .../sdk/metrics/view/registered_view.rb | 17 +++++++++++++-- .../sdk/metrics/view/registered_view_test.rb | 8 +++---- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb index afaaa70216..e294597603 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb @@ -126,7 +126,7 @@ def register_synchronous_instrument(instrument) end end - # Register a view. + # A View provides SDK users with the flexibility to customize the metrics that are output by the SDK. # # Example: # @@ -139,18 +139,18 @@ def register_synchronous_instrument(instrument) # character (*) matching zero or more characters. # # @param [String] name Name of the view. - # @param [optional Hash] options For more precise matching view and metrics stream + # @param [optional Hash] options For more precise matching, {View} and {MetricsStream} # options may include: - # aggregation: aggregation type e.g. ExplicitBucketHistogram, Sum, LastValue - # type: instrumentation kind (instrument_kind) e.g. observable_gauge, counter, etc. - # unit: instrumentation unit e.g. smidgen - # meter_name: meter name e.g. meter_provider.meter("sample_meter_name", version: '1.2.0') - # meter_version: meter version e.g. meter_provider.meter("sample_meter_name", version: '1.2.0') + # aggregation: An instance of an aggregation class, e.g. {ExplicitBucketHistogram}, {Sum}, {LastValue} + # type: A Symbol representing the instrument kind, e.g. :observable_gauge, :counter + # unit: A String matching an instrumentation unit, e.g. 'smidgen' + # meter_name: A String matching a meter name, e.g. meter_provider.meter('sample_meter_name', version: '1.2.0'), would be 'sample_meter_name' + # meter_version: A String matching a meter version, e.g. meter_provider.meter('sample_meter_name', version: '1.2.0'), would be '1.2.0' # # @return [nil] returns nil # - # TODO: add schema_url as part of options def add_view(name, **options) + # TODO: add schema_url as part of options @registered_views << View::RegisteredView.new(name, **options) nil end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb index 1ff7cf695e..65d5527cce 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb @@ -32,33 +32,32 @@ def initialize( @instrumentation_scope = instrumentation_scope @default_aggregation = aggregation @data_points = {} + @registered_views = [] + find_registered_view @mutex = Mutex.new end def collect(start_time, end_time) metric_data = [] - registered_views = find_registered_view - - if registered_views.empty? + if @registered_views.empty? metric_data << aggregate_metric_data(start_time, end_time) else - registered_views.each { |view| metric_data << aggregate_metric_data(start_time, end_time, aggregation: view.aggregation) } + @registered_views.each { |view| metric_data << aggregate_metric_data(start_time, end_time, aggregation: view.aggregation) } end metric_data end def update(value, attributes) - registered_views = find_registered_view - if registered_views.empty? + if @registered_views.empty? @mutex.synchronize { @default_aggregation.update(value, attributes, @data_points) } else - registered_views.each do |view| + @registered_views.each do |view| @mutex.synchronize do attributes ||= {} attributes.merge!(view.attribute_keys) - view.aggregation.update(value, attributes, @data_points) + view.aggregation.update(value, attributes, @data_points) if view.valid_aggregation? end end end @@ -81,9 +80,9 @@ def aggregate_metric_data(start_time, end_time, aggregation: nil) end def find_registered_view - registered_views = [] - @meter_provider.registered_views.each { |view| registered_views << view if view.match_instrument?(self) } - registered_views + return if @meter_provider.nil? + + @meter_provider.registered_views.each { |view| @registered_views << view if view.match_instrument?(self) } end def to_s diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb index 81060590dd..cdc9e3305d 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb @@ -20,8 +20,7 @@ def initialize(name, **options) end def match_instrument?(metric_stream) - return false if @aggregation.nil? - return false if @name && @name != metric_stream.name + return false if @name && !name_match(metric_stream.name) return false if @options[:type] && @options[:type] != metric_stream.instrument_kind return false if @options[:unit] && @options[:unit] != metric_stream.unit return false if @options[:meter_name] && @options[:meter_name] != metric_stream.instrumentation_scope.name @@ -29,6 +28,20 @@ def match_instrument?(metric_stream) true end + + def name_match(stream_name) + regex_pattern = Regexp.escape(@name) + + regex_pattern.gsub!('\*', '.*') + regex_pattern.gsub!('\?', '.') + + regex = Regexp.new("^#{regex_pattern}$") + !!regex.match(stream_name) + end + + def valid_aggregation? + @aggregation.class.name.rpartition('::')[0] == 'OpenTelemetry::SDK::Metrics::Aggregation' + end end end end diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb index c2534b0d5f..3cb7db5b0f 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb @@ -17,10 +17,10 @@ OpenTelemetry.meter_provider.add_metric_reader(metric_exporter) meter = OpenTelemetry.meter_provider.meter('test') - counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') - OpenTelemetry.meter_provider.add_view('counter', aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::Drop.new) + counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') + counter.add(1) counter.add(2, attributes: { 'a' => 'b' }) @@ -50,10 +50,10 @@ OpenTelemetry.meter_provider.add_metric_reader(metric_exporter) meter = OpenTelemetry.meter_provider.meter('test') - counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') - OpenTelemetry.meter_provider.add_view('counter', aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new) + counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') + counter.add(1) counter.add(2) counter.add(3) From 469f234a592541cda2c0e84548d1be4251bfbf9e Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 22 Jul 2024 18:23:45 -0400 Subject: [PATCH 09/16] align the test case --- .../opentelemetry/sdk/metrics/view/registered_view_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb index 3cb7db5b0f..983b1e01b4 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb @@ -73,10 +73,10 @@ OpenTelemetry.meter_provider.add_metric_reader(metric_exporter) meter = OpenTelemetry.meter_provider.meter('test') - counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') - OpenTelemetry.meter_provider.add_view('retnuoc', aggregation: ::OpenTelemetry::SDK::Metrics::Aggregation::LastValue.new) + counter = meter.create_counter('counter', unit: 'smidgen', description: 'a small amount of something') + counter.add(1) counter.add(2) counter.add(3) From 89ee8ce291e01b3c2f92bb54913f7705fd44cf20 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Mon, 22 Jul 2024 18:24:06 -0400 Subject: [PATCH 10/16] Update metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb index e294597603..b24499e524 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb @@ -126,6 +126,8 @@ def register_synchronous_instrument(instrument) end end + # A View provides SDK users with the flexibility to customize the metrics that are output by the SDK. + # # A View provides SDK users with the flexibility to customize the metrics that are output by the SDK. # # Example: From cbbf0d64d0c58cafece38e66ece5dabb66d2b49c Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Mon, 22 Jul 2024 18:24:46 -0400 Subject: [PATCH 11/16] Update metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb index b24499e524..c68437b4b8 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb @@ -136,9 +136,6 @@ def register_synchronous_instrument(instrument) # :type => :counter, :unit => 'smidgen', # :meter_name => 'test', :meter_version => '1.0') # - # Note that OpenTelemetry SDK authors MAY choose to support wildcard characters, - # with the question mark (?) matching exactly one character and the asterisk - # character (*) matching zero or more characters. # # @param [String] name Name of the view. # @param [optional Hash] options For more precise matching, {View} and {MetricsStream} From 3d7c20e7793f054aa4cd08e1a27dcd5f389e0826 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:05:07 -0400 Subject: [PATCH 12/16] Update metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb index c68437b4b8..1f3f867052 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/meter_provider.rb @@ -126,8 +126,6 @@ def register_synchronous_instrument(instrument) end end - # A View provides SDK users with the flexibility to customize the metrics that are output by the SDK. - # # A View provides SDK users with the flexibility to customize the metrics that are output by the SDK. # # Example: From 9f52a97872cf7e1d31597dbfc66107ed2f9b247d Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:05:16 -0400 Subject: [PATCH 13/16] Update metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb index c5e23c0676..c1a1de45c3 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb @@ -7,7 +7,7 @@ module OpenTelemetry module SDK module Metrics - # View + # A View provides SDK users with the flexibility to customize the metrics that are output by the SDK. module View end end From 5eb1734163b47032bcb95b44fc1fbe156d6ac260 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:05:23 -0400 Subject: [PATCH 14/16] Update metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/sdk/metrics/view/registered_view.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb index cdc9e3305d..23b7886579 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb @@ -8,7 +8,7 @@ module OpenTelemetry module SDK module Metrics module View - # RegisteredView + # RegisteredView is an internal class used to match Views with a given {MetricStream} class RegisteredView attr_reader :name, :aggregation, :attribute_keys From 86ea4dd9862fefb0e55c874cd3e1e23d3429171f Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 10 Sep 2024 14:02:33 -0400 Subject: [PATCH 15/16] refactor view and add test --- .../lib/opentelemetry/sdk/metrics/view.rb | 2 +- .../sdk/metrics/view/registered_view.rb | 25 +++++++++++++------ .../periodic_metric_reader_test.rb | 2 +- .../sdk/metrics/view/registered_view_test.rb | 19 ++++++++++++++ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb index c1a1de45c3..9606f383b1 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view.rb @@ -7,7 +7,7 @@ module OpenTelemetry module SDK module Metrics - # A View provides SDK users with the flexibility to customize the metrics that are output by the SDK. + # A View provides SDK users with the flexibility to customize the metrics that are output by the SDK. module View end end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb index 23b7886579..881f0f261e 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/view/registered_view.rb @@ -10,13 +10,15 @@ module Metrics module View # RegisteredView is an internal class used to match Views with a given {MetricStream} class RegisteredView - attr_reader :name, :aggregation, :attribute_keys + attr_reader :name, :aggregation, :attribute_keys, :regex def initialize(name, **options) @name = name @options = options @aggregation = options[:aggregation] @attribute_keys = options[:attribute_keys] || {} + + generate_regex_pattern(name) end def match_instrument?(metric_stream) @@ -30,18 +32,25 @@ def match_instrument?(metric_stream) end def name_match(stream_name) - regex_pattern = Regexp.escape(@name) - - regex_pattern.gsub!('\*', '.*') - regex_pattern.gsub!('\?', '.') - - regex = Regexp.new("^#{regex_pattern}$") - !!regex.match(stream_name) + !!@regex&.match(stream_name) end def valid_aggregation? @aggregation.class.name.rpartition('::')[0] == 'OpenTelemetry::SDK::Metrics::Aggregation' end + + private + + def generate_regex_pattern(view_name) + regex_pattern = Regexp.escape(view_name) + + regex_pattern.gsub!('\*', '.*') + regex_pattern.gsub!('\?', '.') + + @regex = Regexp.new("^#{regex_pattern}$") + rescue StandardError + @regex = nil + end end end end diff --git a/metrics_sdk/test/integration/periodic_metric_reader_test.rb b/metrics_sdk/test/integration/periodic_metric_reader_test.rb index 7bf00a08fc..5abdfbbf8d 100644 --- a/metrics_sdk/test/integration/periodic_metric_reader_test.rb +++ b/metrics_sdk/test/integration/periodic_metric_reader_test.rb @@ -34,7 +34,7 @@ _(snapshot.size).must_equal(2) - first_snapshot = snapshot[0] + first_snapshot = snapshot _(first_snapshot[0].name).must_equal('counter') _(first_snapshot[0].unit).must_equal('smidgen') _(first_snapshot[0].description).must_equal('a small amount of something') diff --git a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb index 983b1e01b4..4638485777 100644 --- a/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb +++ b/metrics_sdk/test/opentelemetry/sdk/metrics/view/registered_view_test.rb @@ -102,6 +102,7 @@ it 'registered view with matching name' do registered_view.instance_variable_set(:@name, 'test') + registered_view.send(:generate_regex_pattern, 'test') _(registered_view.match_instrument?(metric_stream)).must_equal true end @@ -125,5 +126,23 @@ registered_view.instance_variable_set(:@name, 'tset') _(registered_view.match_instrument?(metric_stream)).must_equal false end + + describe '#name_match' do + it 'name_match_for_wild_card' do + registered_view.instance_variable_set(:@name, 'log*2024?.txt') + registered_view.send(:generate_regex_pattern, 'log*2024?.txt') + _(registered_view.name_match('logfile20242.txt')).must_equal true + _(registered_view.name_match('log2024a.txt')).must_equal true + _(registered_view.name_match('log_test_2024.txt')).must_equal false + end + + it 'name_match_for_*' do + registered_view.instance_variable_set(:@name, '*') + registered_view.send(:generate_regex_pattern, '*') + _(registered_view.name_match('*')).must_equal true + _(registered_view.name_match('aaaaaaaaa')).must_equal true + _(registered_view.name_match('!@#$%^&')).must_equal true + end + end end end From 08f7c1e0ac9529ed28baf299db3f758940af7635 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Fri, 4 Oct 2024 16:43:20 -0400 Subject: [PATCH 16/16] revision --- .../export/in_memory_metric_pull_exporter.rb | 2 +- .../sdk/metrics/state/metric_store.rb | 5 +++-- .../sdk/metrics/state/metric_stream.rb | 16 +++++++++------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb index 37a17df92a..d0d8ccb902 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb @@ -25,7 +25,7 @@ def pull def export(metrics, timeout: nil) @mutex.synchronize do - metrics.instance_of?(Array) ? @metric_snapshots.concat(metrics) : @metric_snapshots << metrics + @metric_snapshots.concat(Array(metrics)) end SUCCESS end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_store.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_store.rb index 207079ff4f..b89eb09161 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_store.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_store.rb @@ -23,9 +23,10 @@ def initialize def collect @mutex.synchronize do @epoch_end_time = now_in_nano - snapshot = @metric_streams.map { |ms| ms.collect(@epoch_start_time, @epoch_end_time) } + # snapshot = @metric_streams.map { |ms| ms.collect(@epoch_start_time, @epoch_end_time) } + snapshot = @metric_streams.flat_map { |ms| ms.collect(@epoch_start_time, @epoch_end_time) } @epoch_start_time = @epoch_end_time - snapshot.flatten! + snapshot end end diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb index 65d5527cce..05033f522c 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/state/metric_stream.rb @@ -39,14 +39,16 @@ def initialize( end def collect(start_time, end_time) - metric_data = [] - if @registered_views.empty? - metric_data << aggregate_metric_data(start_time, end_time) - else - @registered_views.each { |view| metric_data << aggregate_metric_data(start_time, end_time, aggregation: view.aggregation) } - end + @mutex.synchronize do + metric_data = [] + if @registered_views.empty? + metric_data << aggregate_metric_data(start_time, end_time) + else + @registered_views.each { |view| metric_data << aggregate_metric_data(start_time, end_time, aggregation: view.aggregation) } + end - metric_data + metric_data + end end def update(value, attributes)