opentelemetry-metrics-sdk 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|