opentelemetry-metrics-sdk 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +3 -2
- data/lib/opentelemetry/sdk/metrics/aggregation/drop.rb +37 -0
- data/lib/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram.rb +9 -9
- data/lib/opentelemetry/sdk/metrics/aggregation/last_value.rb +53 -0
- data/lib/opentelemetry/sdk/metrics/aggregation/sum.rb +7 -8
- data/lib/opentelemetry/sdk/metrics/aggregation.rb +2 -0
- data/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb +2 -2
- data/lib/opentelemetry/sdk/metrics/export/periodic_metric_reader.rb +100 -0
- data/lib/opentelemetry/sdk/metrics/export.rb +1 -0
- data/lib/opentelemetry/sdk/metrics/instrument/histogram.rb +1 -1
- data/lib/opentelemetry/sdk/metrics/instrument/up_down_counter.rb +1 -1
- data/lib/opentelemetry/sdk/metrics/meter.rb +14 -1
- data/lib/opentelemetry/sdk/metrics/meter_provider.rb +27 -8
- data/lib/opentelemetry/sdk/metrics/state/metric_store.rb +2 -1
- data/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +45 -14
- data/lib/opentelemetry/sdk/metrics/version.rb +1 -1
- data/lib/opentelemetry/sdk/metrics/view/registered_view.rb +58 -0
- data/lib/opentelemetry/sdk/metrics/view.rb +17 -0
- data/lib/opentelemetry/sdk/metrics.rb +1 -0
- metadata +15 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0394fb7c1a15117d165ce69b4419700868f9a9a2b662c9f1a5c933f71dc1a25
|
4
|
+
data.tar.gz: 58b977f251b7eea72c6935058073cd46aa0803c21e10686571cd9ffa0e23792f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 969ec426ccc294ba7fff17b3edc5c0536d885e4c410f2a91c49b36afbd6ad2595a8073332c86e3109ba50d7ac51d119f30a3c9f24a3074576b79279f46ec7b34
|
7
|
+
data.tar.gz: ea08bec0926c227147edaa1dc66d9da4a4f0b714a9d01fb7e2db4edca81e152cfdae9338ac1e900bb29a1a24e2dab6df8c9653a5539fbce02a248ab4eeca3650
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Release History: opentelemetry-metrics-sdk
|
2
2
|
|
3
|
+
### v0.3.0 / 2024-10-22
|
4
|
+
|
5
|
+
* ADDED: Add basic metrics view
|
6
|
+
* FIXED: Coerce aggregation_temporality to symbol
|
7
|
+
* FIXED: Add warning if invalid meter name given
|
8
|
+
|
9
|
+
### v0.2.0 / 2024-08-27
|
10
|
+
|
11
|
+
* ADDED: Add basic periodic exporting metric_reader
|
12
|
+
|
3
13
|
### v0.1.0 / 2024-07-31
|
4
14
|
|
5
15
|
Initial release.
|
data/README.md
CHANGED
@@ -15,6 +15,7 @@ Metrics is one of the core signals in OpenTelemetry. This package allows you to
|
|
15
15
|
This gem does not have a full implementation of the Metrics SDK specification. The work is in progress.
|
16
16
|
|
17
17
|
At this time, you should be able to:
|
18
|
+
|
18
19
|
* Create synchronous:
|
19
20
|
* counters
|
20
21
|
* up down counters
|
@@ -26,6 +27,7 @@ At this time, you should be able to:
|
|
26
27
|
* Use delta aggregation temporality
|
27
28
|
|
28
29
|
We do not yet have support for:
|
30
|
+
|
29
31
|
* Asynchronous instruments
|
30
32
|
* Cumulative aggregation temporality
|
31
33
|
* Metrics Views
|
@@ -41,7 +43,7 @@ Until the Ruby implementation of OpenTelemetry Metrics becomes stable, the funct
|
|
41
43
|
|
42
44
|
Install the gems using:
|
43
45
|
|
44
|
-
```
|
46
|
+
```sh
|
45
47
|
gem install opentelemetry-metrics-sdk
|
46
48
|
gem install opentelemetry-sdk
|
47
49
|
```
|
@@ -97,7 +99,6 @@ During this experimental stage, we're looking for lots of community feedback abo
|
|
97
99
|
|
98
100
|
The `opentelemetry-metrics-sdk` gem is distributed under the Apache 2.0 license. See [LICENSE][license-github] for more information.
|
99
101
|
|
100
|
-
|
101
102
|
[metrics-sdk]: https://opentelemetry.io/docs/specs/otel/metrics/sdk/
|
102
103
|
[opentelemetry-home]: https://opentelemetry.io
|
103
104
|
[bundler-home]: https://bundler.io
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright The OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Metrics
|
10
|
+
module Aggregation
|
11
|
+
# Contains the implementation of the Drop aggregation
|
12
|
+
class Drop
|
13
|
+
attr_reader :aggregation_temporality
|
14
|
+
|
15
|
+
def initialize(aggregation_temporality: :delta)
|
16
|
+
@aggregation_temporality = aggregation_temporality
|
17
|
+
end
|
18
|
+
|
19
|
+
def collect(start_time, end_time, data_points)
|
20
|
+
data_points.values.map!(&:dup)
|
21
|
+
end
|
22
|
+
|
23
|
+
def update(increment, attributes, data_points)
|
24
|
+
data_points[attributes] = NumberDataPoint.new(
|
25
|
+
{},
|
26
|
+
0,
|
27
|
+
0,
|
28
|
+
0,
|
29
|
+
0
|
30
|
+
)
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -25,25 +25,25 @@ module OpenTelemetry
|
|
25
25
|
boundaries: DEFAULT_BOUNDARIES,
|
26
26
|
record_min_max: true
|
27
27
|
)
|
28
|
-
|
29
|
-
@aggregation_temporality = aggregation_temporality
|
28
|
+
|
29
|
+
@aggregation_temporality = aggregation_temporality.to_sym
|
30
30
|
@boundaries = boundaries && !boundaries.empty? ? boundaries.sort : nil
|
31
31
|
@record_min_max = record_min_max
|
32
32
|
end
|
33
33
|
|
34
|
-
def collect(start_time, end_time)
|
34
|
+
def collect(start_time, end_time, data_points)
|
35
35
|
if @aggregation_temporality == :delta
|
36
36
|
# Set timestamps and 'move' data point values to result.
|
37
|
-
hdps =
|
37
|
+
hdps = data_points.values.map! do |hdp|
|
38
38
|
hdp.start_time_unix_nano = start_time
|
39
39
|
hdp.time_unix_nano = end_time
|
40
40
|
hdp
|
41
41
|
end
|
42
|
-
|
42
|
+
data_points.clear
|
43
43
|
hdps
|
44
44
|
else
|
45
45
|
# Update timestamps and take a snapshot.
|
46
|
-
|
46
|
+
data_points.values.map! do |hdp|
|
47
47
|
hdp.start_time_unix_nano ||= start_time # Start time of a data point is from the first observation.
|
48
48
|
hdp.time_unix_nano = end_time
|
49
49
|
hdp = hdp.dup
|
@@ -53,14 +53,14 @@ module OpenTelemetry
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
def update(amount, attributes)
|
57
|
-
hdp =
|
56
|
+
def update(amount, attributes, data_points)
|
57
|
+
hdp = data_points.fetch(attributes) do
|
58
58
|
if @record_min_max
|
59
59
|
min = Float::INFINITY
|
60
60
|
max = -Float::INFINITY
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
data_points[attributes] = HistogramDataPoint.new(
|
64
64
|
attributes,
|
65
65
|
nil, # :start_time_unix_nano
|
66
66
|
nil, # :time_unix_nano
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright The OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Metrics
|
10
|
+
module Aggregation
|
11
|
+
# Contains the implementation of the LastValue aggregation
|
12
|
+
class LastValue
|
13
|
+
attr_reader :aggregation_temporality
|
14
|
+
|
15
|
+
def initialize(aggregation_temporality: :delta)
|
16
|
+
@aggregation_temporality = aggregation_temporality
|
17
|
+
end
|
18
|
+
|
19
|
+
def collect(start_time, end_time, data_points)
|
20
|
+
if @aggregation_temporality == :delta
|
21
|
+
# Set timestamps and 'move' data point values to result.
|
22
|
+
ndps = data_points.values.map! do |ndp|
|
23
|
+
ndp.start_time_unix_nano = start_time
|
24
|
+
ndp.time_unix_nano = end_time
|
25
|
+
ndp
|
26
|
+
end
|
27
|
+
data_points.clear
|
28
|
+
ndps
|
29
|
+
else
|
30
|
+
# Update timestamps and take a snapshot.
|
31
|
+
data_points.values.map! do |ndp|
|
32
|
+
ndp.start_time_unix_nano ||= start_time # Start time of a data point is from the first observation.
|
33
|
+
ndp.time_unix_nano = end_time
|
34
|
+
ndp.dup
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(increment, attributes, data_points)
|
40
|
+
data_points[attributes] = NumberDataPoint.new(
|
41
|
+
attributes,
|
42
|
+
nil,
|
43
|
+
nil,
|
44
|
+
increment,
|
45
|
+
nil
|
46
|
+
)
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -15,23 +15,22 @@ module OpenTelemetry
|
|
15
15
|
|
16
16
|
def initialize(aggregation_temporality: ENV.fetch('OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE', :delta))
|
17
17
|
# TODO: the default should be :cumulative, see issue #1555
|
18
|
-
@aggregation_temporality = aggregation_temporality
|
19
|
-
@data_points = {}
|
18
|
+
@aggregation_temporality = aggregation_temporality.to_sym
|
20
19
|
end
|
21
20
|
|
22
|
-
def collect(start_time, end_time)
|
21
|
+
def collect(start_time, end_time, data_points)
|
23
22
|
if @aggregation_temporality == :delta
|
24
23
|
# Set timestamps and 'move' data point values to result.
|
25
|
-
ndps =
|
24
|
+
ndps = data_points.values.map! do |ndp|
|
26
25
|
ndp.start_time_unix_nano = start_time
|
27
26
|
ndp.time_unix_nano = end_time
|
28
27
|
ndp
|
29
28
|
end
|
30
|
-
|
29
|
+
data_points.clear
|
31
30
|
ndps
|
32
31
|
else
|
33
32
|
# Update timestamps and take a snapshot.
|
34
|
-
|
33
|
+
data_points.values.map! do |ndp|
|
35
34
|
ndp.start_time_unix_nano ||= start_time # Start time of a data point is from the first observation.
|
36
35
|
ndp.time_unix_nano = end_time
|
37
36
|
ndp.dup
|
@@ -39,8 +38,8 @@ module OpenTelemetry
|
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
|
-
def update(increment, attributes)
|
43
|
-
ndp =
|
41
|
+
def update(increment, attributes, data_points)
|
42
|
+
ndp = data_points[attributes] || data_points[attributes] = NumberDataPoint.new(
|
44
43
|
attributes,
|
45
44
|
nil,
|
46
45
|
nil,
|
@@ -19,3 +19,5 @@ require 'opentelemetry/sdk/metrics/aggregation/number_data_point'
|
|
19
19
|
require 'opentelemetry/sdk/metrics/aggregation/histogram_data_point'
|
20
20
|
require 'opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram'
|
21
21
|
require 'opentelemetry/sdk/metrics/aggregation/sum'
|
22
|
+
require 'opentelemetry/sdk/metrics/aggregation/last_value'
|
23
|
+
require 'opentelemetry/sdk/metrics/aggregation/drop'
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright The OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Metrics
|
10
|
+
module Export
|
11
|
+
# PeriodicMetricReader provides a minimal example implementation.
|
12
|
+
class PeriodicMetricReader < MetricReader
|
13
|
+
# Returns a new instance of the {PeriodicMetricReader}.
|
14
|
+
#
|
15
|
+
# @param [Integer] export_interval_millis the maximum interval time.
|
16
|
+
# Defaults to the value of the OTEL_METRIC_EXPORT_INTERVAL environment
|
17
|
+
# variable, if set, or 60_000.
|
18
|
+
# @param [Integer] export_timeout_millis the maximum export timeout.
|
19
|
+
# Defaults to the value of the OTEL_METRIC_EXPORT_TIMEOUT environment
|
20
|
+
# variable, if set, or 30_000.
|
21
|
+
# @param [MetricReader] exporter the (duck type) MetricReader to where the
|
22
|
+
# recorded metrics are pushed after certain interval.
|
23
|
+
#
|
24
|
+
# @return a new instance of the {PeriodicMetricReader}.
|
25
|
+
def initialize(export_interval_millis: Float(ENV.fetch('OTEL_METRIC_EXPORT_INTERVAL', 60_000)),
|
26
|
+
export_timeout_millis: Float(ENV.fetch('OTEL_METRIC_EXPORT_TIMEOUT', 30_000)),
|
27
|
+
exporter: nil)
|
28
|
+
super()
|
29
|
+
|
30
|
+
@export_interval = export_interval_millis / 1000.0
|
31
|
+
@export_timeout = export_timeout_millis / 1000.0
|
32
|
+
@exporter = exporter
|
33
|
+
@thread = nil
|
34
|
+
@continue = false
|
35
|
+
@mutex = Mutex.new
|
36
|
+
@export_mutex = Mutex.new
|
37
|
+
|
38
|
+
start
|
39
|
+
end
|
40
|
+
|
41
|
+
def shutdown(timeout: nil)
|
42
|
+
thread = lock do
|
43
|
+
@continue = false # force termination in next iteration
|
44
|
+
@thread
|
45
|
+
end
|
46
|
+
thread&.join(@export_interval)
|
47
|
+
@exporter.force_flush if @exporter.respond_to?(:force_flush)
|
48
|
+
@exporter.shutdown
|
49
|
+
Export::SUCCESS
|
50
|
+
rescue StandardError => e
|
51
|
+
OpenTelemetry.handle_error(exception: e, message: 'Fail to shutdown PeriodicMetricReader.')
|
52
|
+
Export::FAILURE
|
53
|
+
end
|
54
|
+
|
55
|
+
def force_flush(timeout: nil)
|
56
|
+
export(timeout: timeout)
|
57
|
+
Export::SUCCESS
|
58
|
+
rescue StandardError
|
59
|
+
Export::FAILURE
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def start
|
65
|
+
@continue = true
|
66
|
+
if @exporter.nil?
|
67
|
+
OpenTelemetry.logger.warn 'Missing exporter in PeriodicMetricReader.'
|
68
|
+
elsif @thread&.alive?
|
69
|
+
OpenTelemetry.logger.warn 'PeriodicMetricReader is still running. Please shutdown it if it needs to restart.'
|
70
|
+
else
|
71
|
+
@thread = Thread.new do
|
72
|
+
while @continue
|
73
|
+
sleep(@export_interval)
|
74
|
+
begin
|
75
|
+
Timeout.timeout(@export_timeout) do
|
76
|
+
export(timeout: @export_timeout)
|
77
|
+
end
|
78
|
+
rescue Timeout::Error => e
|
79
|
+
OpenTelemetry.handle_error(exception: e, message: 'PeriodicMetricReader timeout.')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def export(timeout: nil)
|
87
|
+
@export_mutex.synchronize do
|
88
|
+
collected_metrics = collect
|
89
|
+
@exporter.export(collected_metrics, timeout: timeout || @export_timeout) unless collected_metrics.empty?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def lock(&block)
|
94
|
+
@mutex.synchronize(&block)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -26,3 +26,4 @@ end
|
|
26
26
|
require 'opentelemetry/sdk/metrics/export/metric_reader'
|
27
27
|
require 'opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter'
|
28
28
|
require 'opentelemetry/sdk/metrics/export/console_metric_pull_exporter'
|
29
|
+
require 'opentelemetry/sdk/metrics/export/periodic_metric_reader'
|
@@ -24,7 +24,7 @@ module OpenTelemetry
|
|
24
24
|
# Values must be non-nil and (array of) string, boolean or numeric type.
|
25
25
|
# Array values must not contain nil elements and all elements must be of
|
26
26
|
# the same basic type (string, numeric, boolean).
|
27
|
-
def record(amount, attributes:
|
27
|
+
def record(amount, attributes: {})
|
28
28
|
update(amount, attributes)
|
29
29
|
nil
|
30
30
|
rescue StandardError => e
|
@@ -24,7 +24,7 @@ module OpenTelemetry
|
|
24
24
|
# Values must be non-nil and (array of) string, boolean or numeric type.
|
25
25
|
# Array values must not contain nil elements and all elements must be of
|
26
26
|
# the same basic type (string, numeric, boolean).
|
27
|
-
def add(amount, attributes:
|
27
|
+
def add(amount, attributes: {})
|
28
28
|
update(amount, attributes)
|
29
29
|
nil
|
30
30
|
rescue StandardError => e
|
@@ -11,6 +11,8 @@ module OpenTelemetry
|
|
11
11
|
module Metrics
|
12
12
|
# {Meter} is the SDK implementation of {OpenTelemetry::Metrics::Meter}.
|
13
13
|
class Meter < OpenTelemetry::Metrics::Meter
|
14
|
+
NAME_REGEX = /\A[a-zA-Z][-.\w]{0,62}\z/
|
15
|
+
|
14
16
|
# @api private
|
15
17
|
#
|
16
18
|
# Returns a new {Meter} instance.
|
@@ -28,12 +30,18 @@ module OpenTelemetry
|
|
28
30
|
|
29
31
|
# @api private
|
30
32
|
def add_metric_reader(metric_reader)
|
31
|
-
@instrument_registry.
|
33
|
+
@instrument_registry.each_value do |instrument|
|
32
34
|
instrument.register_with_new_metric_store(metric_reader.metric_store)
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
38
|
def create_instrument(kind, name, unit, description, callback)
|
39
|
+
raise InstrumentNameError if name.nil?
|
40
|
+
raise InstrumentNameError if name.empty?
|
41
|
+
raise InstrumentNameError unless NAME_REGEX.match?(name)
|
42
|
+
raise InstrumentUnitError if unit && (!unit.ascii_only? || unit.size > 63)
|
43
|
+
raise InstrumentDescriptionError if description && (description.size > 1023 || !utf8mb3_encoding?(description.dup))
|
44
|
+
|
37
45
|
super do
|
38
46
|
case kind
|
39
47
|
when :counter then OpenTelemetry::SDK::Metrics::Instrument::Counter.new(name, unit, description, @instrumentation_scope, @meter_provider)
|
@@ -45,6 +53,11 @@ module OpenTelemetry
|
|
45
53
|
end
|
46
54
|
end
|
47
55
|
end
|
56
|
+
|
57
|
+
def utf8mb3_encoding?(string)
|
58
|
+
string.force_encoding('UTF-8').valid_encoding? &&
|
59
|
+
string.each_char { |c| return false if c.bytesize >= 4 }
|
60
|
+
end
|
48
61
|
end
|
49
62
|
end
|
50
63
|
end
|
@@ -14,7 +14,7 @@ module OpenTelemetry
|
|
14
14
|
Key = Struct.new(:name, :version)
|
15
15
|
private_constant(:Key)
|
16
16
|
|
17
|
-
attr_reader :resource, :metric_readers
|
17
|
+
attr_reader :resource, :metric_readers, :registered_views
|
18
18
|
|
19
19
|
def initialize(resource: OpenTelemetry::SDK::Resources::Resource.create)
|
20
20
|
@mutex = Mutex.new
|
@@ -22,6 +22,7 @@ module OpenTelemetry
|
|
22
22
|
@stopped = false
|
23
23
|
@metric_readers = []
|
24
24
|
@resource = resource
|
25
|
+
@registered_views = []
|
25
26
|
end
|
26
27
|
|
27
28
|
# Returns a {Meter} instance.
|
@@ -36,6 +37,7 @@ module OpenTelemetry
|
|
36
37
|
OpenTelemetry.logger.warn 'calling MeterProvider#meter after shutdown, a noop meter will be returned.'
|
37
38
|
OpenTelemetry::Metrics::Meter.new
|
38
39
|
else
|
40
|
+
OpenTelemetry.logger.warn "Invalid meter name provided: #{name.nil? ? 'nil' : 'empty'} value" if name.to_s.empty?
|
39
41
|
@mutex.synchronize { @meter_registry[Key.new(name, version)] ||= Meter.new(name, version, self) }
|
40
42
|
end
|
41
43
|
end
|
@@ -125,13 +127,30 @@ module OpenTelemetry
|
|
125
127
|
end
|
126
128
|
end
|
127
129
|
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
|
134
|
-
|
130
|
+
# A View provides SDK users with the flexibility to customize the metrics that are output by the SDK.
|
131
|
+
#
|
132
|
+
# Example:
|
133
|
+
#
|
134
|
+
# OpenTelemetry.meter_provider.add_view('test', :aggregation => Aggregation::Drop.new,
|
135
|
+
# :type => :counter, :unit => 'smidgen',
|
136
|
+
# :meter_name => 'test', :meter_version => '1.0')
|
137
|
+
#
|
138
|
+
#
|
139
|
+
# @param [String] name Name of the view.
|
140
|
+
# @param [optional Hash] options For more precise matching, {View} and {MetricsStream}
|
141
|
+
# options may include:
|
142
|
+
# aggregation: An instance of an aggregation class, e.g. {ExplicitBucketHistogram}, {Sum}, {LastValue}
|
143
|
+
# type: A Symbol representing the instrument kind, e.g. :observable_gauge, :counter
|
144
|
+
# unit: A String matching an instrumentation unit, e.g. 'smidgen'
|
145
|
+
# 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'
|
146
|
+
# 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'
|
147
|
+
#
|
148
|
+
# @return [nil] returns nil
|
149
|
+
#
|
150
|
+
def add_view(name, **options)
|
151
|
+
# TODO: add schema_url as part of options
|
152
|
+
@registered_views << View::RegisteredView.new(name, **options)
|
153
|
+
nil
|
135
154
|
end
|
136
155
|
end
|
137
156
|
end
|
@@ -23,7 +23,8 @@ module OpenTelemetry
|
|
23
23
|
def collect
|
24
24
|
@mutex.synchronize do
|
25
25
|
@epoch_end_time = now_in_nano
|
26
|
-
snapshot = @metric_streams.map { |ms| ms.collect(@epoch_start_time, @epoch_end_time) }
|
26
|
+
# snapshot = @metric_streams.map { |ms| ms.collect(@epoch_start_time, @epoch_end_time) }
|
27
|
+
snapshot = @metric_streams.flat_map { |ms| ms.collect(@epoch_start_time, @epoch_end_time) }
|
27
28
|
@epoch_start_time = @epoch_end_time
|
28
29
|
snapshot
|
29
30
|
end
|
@@ -30,30 +30,61 @@ module OpenTelemetry
|
|
30
30
|
@instrument_kind = instrument_kind
|
31
31
|
@meter_provider = meter_provider
|
32
32
|
@instrumentation_scope = instrumentation_scope
|
33
|
-
@
|
33
|
+
@default_aggregation = aggregation
|
34
|
+
@data_points = {}
|
35
|
+
@registered_views = []
|
34
36
|
|
37
|
+
find_registered_view
|
35
38
|
@mutex = Mutex.new
|
36
39
|
end
|
37
40
|
|
38
41
|
def collect(start_time, end_time)
|
39
42
|
@mutex.synchronize do
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
@aggregation.aggregation_temporality,
|
49
|
-
start_time,
|
50
|
-
end_time
|
51
|
-
)
|
43
|
+
metric_data = []
|
44
|
+
if @registered_views.empty?
|
45
|
+
metric_data << aggregate_metric_data(start_time, end_time)
|
46
|
+
else
|
47
|
+
@registered_views.each { |view| metric_data << aggregate_metric_data(start_time, end_time, aggregation: view.aggregation) }
|
48
|
+
end
|
49
|
+
|
50
|
+
metric_data
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
55
54
|
def update(value, attributes)
|
56
|
-
|
55
|
+
if @registered_views.empty?
|
56
|
+
@mutex.synchronize { @default_aggregation.update(value, attributes, @data_points) }
|
57
|
+
else
|
58
|
+
@registered_views.each do |view|
|
59
|
+
@mutex.synchronize do
|
60
|
+
attributes ||= {}
|
61
|
+
attributes.merge!(view.attribute_keys)
|
62
|
+
view.aggregation.update(value, attributes, @data_points) if view.valid_aggregation?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def aggregate_metric_data(start_time, end_time, aggregation: nil)
|
69
|
+
aggregator = aggregation || @default_aggregation
|
70
|
+
MetricData.new(
|
71
|
+
@name,
|
72
|
+
@description,
|
73
|
+
@unit,
|
74
|
+
@instrument_kind,
|
75
|
+
@meter_provider.resource,
|
76
|
+
@instrumentation_scope,
|
77
|
+
aggregator.collect(start_time, end_time, @data_points),
|
78
|
+
aggregator.aggregation_temporality,
|
79
|
+
start_time,
|
80
|
+
end_time
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def find_registered_view
|
85
|
+
return if @meter_provider.nil?
|
86
|
+
|
87
|
+
@meter_provider.registered_views.each { |view| @registered_views << view if view.match_instrument?(self) }
|
57
88
|
end
|
58
89
|
|
59
90
|
def to_s
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright The OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Metrics
|
10
|
+
module View
|
11
|
+
# RegisteredView is an internal class used to match Views with a given {MetricStream}
|
12
|
+
class RegisteredView
|
13
|
+
attr_reader :name, :aggregation, :attribute_keys, :regex
|
14
|
+
|
15
|
+
def initialize(name, **options)
|
16
|
+
@name = name
|
17
|
+
@options = options
|
18
|
+
@aggregation = options[:aggregation]
|
19
|
+
@attribute_keys = options[:attribute_keys] || {}
|
20
|
+
|
21
|
+
generate_regex_pattern(name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def match_instrument?(metric_stream)
|
25
|
+
return false if @name && !name_match(metric_stream.name)
|
26
|
+
return false if @options[:type] && @options[:type] != metric_stream.instrument_kind
|
27
|
+
return false if @options[:unit] && @options[:unit] != metric_stream.unit
|
28
|
+
return false if @options[:meter_name] && @options[:meter_name] != metric_stream.instrumentation_scope.name
|
29
|
+
return false if @options[:meter_version] && @options[:meter_version] != metric_stream.instrumentation_scope.version
|
30
|
+
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def name_match(stream_name)
|
35
|
+
!!@regex&.match(stream_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid_aggregation?
|
39
|
+
@aggregation.class.name.rpartition('::')[0] == 'OpenTelemetry::SDK::Metrics::Aggregation'
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def generate_regex_pattern(view_name)
|
45
|
+
regex_pattern = Regexp.escape(view_name)
|
46
|
+
|
47
|
+
regex_pattern.gsub!('\*', '.*')
|
48
|
+
regex_pattern.gsub!('\?', '.')
|
49
|
+
|
50
|
+
@regex = Regexp.new("^#{regex_pattern}$")
|
51
|
+
rescue StandardError
|
52
|
+
@regex = nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright The OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Metrics
|
10
|
+
# A View provides SDK users with the flexibility to customize the metrics that are output by the SDK.
|
11
|
+
module View
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'opentelemetry/sdk/metrics/view/registered_view'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opentelemetry-metrics-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OpenTelemetry Authors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opentelemetry-api
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: opentelemetry-metrics-api
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.1.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.1.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: opentelemetry-sdk
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 1.
|
145
|
+
version: '1.65'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 1.
|
152
|
+
version: '1.65'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: simplecov
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -206,8 +206,10 @@ files:
|
|
206
206
|
- lib/opentelemetry-metrics-sdk.rb
|
207
207
|
- lib/opentelemetry/sdk/metrics.rb
|
208
208
|
- lib/opentelemetry/sdk/metrics/aggregation.rb
|
209
|
+
- lib/opentelemetry/sdk/metrics/aggregation/drop.rb
|
209
210
|
- lib/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram.rb
|
210
211
|
- lib/opentelemetry/sdk/metrics/aggregation/histogram_data_point.rb
|
212
|
+
- lib/opentelemetry/sdk/metrics/aggregation/last_value.rb
|
211
213
|
- lib/opentelemetry/sdk/metrics/aggregation/number_data_point.rb
|
212
214
|
- lib/opentelemetry/sdk/metrics/aggregation/sum.rb
|
213
215
|
- lib/opentelemetry/sdk/metrics/configuration_patch.rb
|
@@ -215,6 +217,7 @@ files:
|
|
215
217
|
- lib/opentelemetry/sdk/metrics/export/console_metric_pull_exporter.rb
|
216
218
|
- lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb
|
217
219
|
- lib/opentelemetry/sdk/metrics/export/metric_reader.rb
|
220
|
+
- lib/opentelemetry/sdk/metrics/export/periodic_metric_reader.rb
|
218
221
|
- lib/opentelemetry/sdk/metrics/instrument.rb
|
219
222
|
- lib/opentelemetry/sdk/metrics/instrument/counter.rb
|
220
223
|
- lib/opentelemetry/sdk/metrics/instrument/histogram.rb
|
@@ -230,14 +233,16 @@ files:
|
|
230
233
|
- lib/opentelemetry/sdk/metrics/state/metric_store.rb
|
231
234
|
- lib/opentelemetry/sdk/metrics/state/metric_stream.rb
|
232
235
|
- lib/opentelemetry/sdk/metrics/version.rb
|
236
|
+
- lib/opentelemetry/sdk/metrics/view.rb
|
237
|
+
- lib/opentelemetry/sdk/metrics/view/registered_view.rb
|
233
238
|
homepage: https://github.com/open-telemetry/opentelemetry-ruby
|
234
239
|
licenses:
|
235
240
|
- Apache-2.0
|
236
241
|
metadata:
|
237
|
-
changelog_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-metrics-sdk/v0.
|
242
|
+
changelog_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-metrics-sdk/v0.3.0/file.CHANGELOG.html
|
238
243
|
source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby/tree/main/metrics_sdk
|
239
244
|
bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby/issues
|
240
|
-
documentation_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-metrics-sdk/v0.
|
245
|
+
documentation_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-metrics-sdk/v0.3.0
|
241
246
|
post_install_message:
|
242
247
|
rdoc_options: []
|
243
248
|
require_paths:
|