opentelemetry-metrics-sdk 0.13.1 → 0.15.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 +12 -0
- data/README.md +4 -4
- data/lib/opentelemetry/sdk/metrics/aggregation/drop.rb +1 -1
- data/lib/opentelemetry/sdk/metrics/aggregation/explicit_bucket_histogram.rb +56 -39
- data/lib/opentelemetry/sdk/metrics/aggregation/exponential_bucket_histogram.rb +61 -48
- data/lib/opentelemetry/sdk/metrics/aggregation/last_value.rb +38 -15
- data/lib/opentelemetry/sdk/metrics/aggregation/sum.rb +36 -16
- data/lib/opentelemetry/sdk/metrics/exemplar/exemplar_reservoir.rb +12 -0
- data/lib/opentelemetry/sdk/metrics/exemplar/noop_exemplar_reservoir.rb +4 -0
- data/lib/opentelemetry/sdk/metrics/export/console_metric_pull_exporter.rb +2 -2
- data/lib/opentelemetry/sdk/metrics/export/in_memory_metric_pull_exporter.rb +2 -2
- data/lib/opentelemetry/sdk/metrics/export/metric_reader.rb +2 -2
- data/lib/opentelemetry/sdk/metrics/export/periodic_metric_reader.rb +3 -2
- data/lib/opentelemetry/sdk/metrics/meter_provider.rb +3 -5
- data/lib/opentelemetry/sdk/metrics/state/asynchronous_metric_stream.rb +8 -2
- data/lib/opentelemetry/sdk/metrics/state/metric_store.rb +3 -1
- data/lib/opentelemetry/sdk/metrics/state/metric_stream.rb +28 -4
- data/lib/opentelemetry/sdk/metrics/version.rb +1 -1
- data/lib/opentelemetry/sdk/metrics/view/registered_view.rb +2 -1
- metadata +5 -117
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fee8234836c749267c8ef70c3a6e1edd1e7f07f2f684be31be5bbb692783bbe5
|
|
4
|
+
data.tar.gz: d95498e59164701c62e415db1d99d20f201f77a7a9d621667603bdb7485c668c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 13fc13a8866034bbd502032c7b6aef1fe485591d065cd01d533eec77ed9aa3fc8c3e11def8317b891bda9347317558ea0322bc211c00d46c3ee0cbc3a57c2bce
|
|
7
|
+
data.tar.gz: 123a2e82d19c865243d45d0e2e29dce12e2c3166813ccdc8ad5e10ea45fb6e31d6d9c54b9558f36c380e8ece670146c9ba1b2450286b03a6ab6c70ec28db0839
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Release History: opentelemetry-metrics-sdk
|
|
2
2
|
|
|
3
|
+
### v0.15.0 / 2026-06-16
|
|
4
|
+
|
|
5
|
+
* BREAKING CHANGE: Metrics cardinality limit (#1909)
|
|
6
|
+
* ADDED: Metrics cardinality limit (#1909)
|
|
7
|
+
|
|
8
|
+
### v0.14.0 / 2026-05-12
|
|
9
|
+
|
|
10
|
+
* BREAKING CHANGE: Use trace_based exemplar filter by default (#2112)
|
|
11
|
+
* ADDED: Use trace_based exemplar filter by default (#2112)
|
|
12
|
+
* ADDED: Add git tag to source URI in gemspec (#2101)
|
|
13
|
+
* FIXED: Return false if it is noop_exemplar_reservoir (#2104)
|
|
14
|
+
|
|
3
15
|
### v0.13.1 / 2026-04-15
|
|
4
16
|
|
|
5
17
|
* FIXED: Move the metrics-sdk requires to support "require 'opentelemetry/sdk/metrics'" (#1956)
|
data/README.md
CHANGED
|
@@ -39,8 +39,8 @@ At this time, you should be able to:
|
|
|
39
39
|
* Export metrics on a schedule using `PeriodicMetricReader` with any compatible push exporter (e.g. OTLP via `opentelemetry-exporter-otlp-metrics`)
|
|
40
40
|
* Attach exemplars to metric data points for trace correlation:
|
|
41
41
|
* `AlwaysOnExemplarFilter` — every measurement is eligible
|
|
42
|
-
* `AlwaysOffExemplarFilter` — no exemplars collected
|
|
43
|
-
* `TraceBasedExemplarFilter` — only measurements inside a sampled trace
|
|
42
|
+
* `AlwaysOffExemplarFilter` — no exemplars collected
|
|
43
|
+
* `TraceBasedExemplarFilter` — only measurements inside a sampled trace (default)
|
|
44
44
|
|
|
45
45
|
We do not yet have support for:
|
|
46
46
|
|
|
@@ -278,7 +278,7 @@ OpenTelemetry.meter_provider.shutdown
|
|
|
278
278
|
|
|
279
279
|
Exemplars attach individual raw measurements — along with the trace context active at the time of the measurement — to an exported metric data point. This lets you jump from a metric spike directly to the trace that caused it.
|
|
280
280
|
|
|
281
|
-
By default exemplars
|
|
281
|
+
By default, exemplars use `TraceBasedExemplarFilter`, which records measurements only when they occur inside a sampled trace.
|
|
282
282
|
|
|
283
283
|
#### Enable via environment variable
|
|
284
284
|
|
|
@@ -289,7 +289,7 @@ export OTEL_METRICS_EXEMPLAR_FILTER=trace_based
|
|
|
289
289
|
# Eligible for every measurement regardless of trace context
|
|
290
290
|
export OTEL_METRICS_EXEMPLAR_FILTER=always_on
|
|
291
291
|
|
|
292
|
-
# Disabled
|
|
292
|
+
# Disabled
|
|
293
293
|
export OTEL_METRICS_EXEMPLAR_FILTER=always_off
|
|
294
294
|
```
|
|
295
295
|
|
|
@@ -22,7 +22,7 @@ module OpenTelemetry
|
|
|
22
22
|
data_points.values.map!(&:dup)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
def update(increment, attributes, data_points, exemplar_offer: false)
|
|
25
|
+
def update(increment, attributes, data_points, cardinality_limit, exemplar_offer: false)
|
|
26
26
|
data_points[attributes] = NumberDataPoint.new(
|
|
27
27
|
{},
|
|
28
28
|
0,
|
|
@@ -11,6 +11,7 @@ module OpenTelemetry
|
|
|
11
11
|
# Contains the implementation of the ExplicitBucketHistogram aggregation
|
|
12
12
|
# https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#explicit-bucket-histogram-aggregation
|
|
13
13
|
class ExplicitBucketHistogram
|
|
14
|
+
OVERFLOW_ATTRIBUTE_SET = { 'otel.metric.overflow' => true }.freeze
|
|
14
15
|
attr_reader :exemplar_reservoir
|
|
15
16
|
|
|
16
17
|
DEFAULT_BOUNDARIES = [0, 5, 10, 25, 50, 75, 100, 250, 500, 1000].freeze
|
|
@@ -59,41 +60,48 @@ module OpenTelemetry
|
|
|
59
60
|
end
|
|
60
61
|
end
|
|
61
62
|
|
|
62
|
-
def update(amount, attributes, data_points, exemplar_offer: false)
|
|
63
|
-
hdp = data_points.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
def update(amount, attributes, data_points, cardinality_limit, exemplar_offer: false)
|
|
64
|
+
hdp = if data_points.key?(attributes)
|
|
65
|
+
data_points[attributes]
|
|
66
|
+
elsif data_points.size >= cardinality_limit - 1
|
|
67
|
+
data_points[OVERFLOW_ATTRIBUTE_SET] || create_new_data_point(OVERFLOW_ATTRIBUTE_SET, data_points)
|
|
68
|
+
else
|
|
69
|
+
create_new_data_point(attributes, data_points)
|
|
70
|
+
end
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
nil, # :time_unix_nano
|
|
73
|
-
0, # :count
|
|
74
|
-
0, # :sum
|
|
75
|
-
empty_bucket_counts, # :bucket_counts
|
|
76
|
-
@boundaries, # :explicit_bounds
|
|
77
|
-
nil, # :exemplars
|
|
78
|
-
min, # :min
|
|
79
|
-
max # :max
|
|
80
|
-
)
|
|
81
|
-
end
|
|
72
|
+
update_histogram_data_point(hdp, amount, exemplar_offer: exemplar_offer)
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
82
75
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
reservoir.reset
|
|
87
|
-
@exemplar_reservoir_storage[attributes] = reservoir
|
|
88
|
-
end
|
|
76
|
+
def aggregation_temporality
|
|
77
|
+
@aggregation_temporality.temporality
|
|
78
|
+
end
|
|
89
79
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def create_new_data_point(attributes, data_points)
|
|
83
|
+
if @record_min_max
|
|
84
|
+
min = Float::INFINITY
|
|
85
|
+
max = -Float::INFINITY
|
|
95
86
|
end
|
|
96
87
|
|
|
88
|
+
data_points[attributes] = HistogramDataPoint.new(
|
|
89
|
+
attributes,
|
|
90
|
+
nil, # :start_time_unix_nano
|
|
91
|
+
nil, # :time_unix_nano
|
|
92
|
+
0, # :count
|
|
93
|
+
0, # :sum
|
|
94
|
+
empty_bucket_counts, # :bucket_counts
|
|
95
|
+
@boundaries, # :explicit_bounds
|
|
96
|
+
nil, # :exemplars
|
|
97
|
+
min, # :min
|
|
98
|
+
max # :max
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def update_histogram_data_point(hdp, amount, exemplar_offer: false)
|
|
103
|
+
reservior_update(hdp.attributes, amount, exemplar_offer)
|
|
104
|
+
|
|
97
105
|
if @record_min_max
|
|
98
106
|
hdp.max = amount if amount > hdp.max
|
|
99
107
|
hdp.min = amount if amount < hdp.min
|
|
@@ -101,18 +109,27 @@ module OpenTelemetry
|
|
|
101
109
|
|
|
102
110
|
hdp.sum += amount
|
|
103
111
|
hdp.count += 1
|
|
104
|
-
|
|
105
|
-
bucket_index = @boundaries.bsearch_index { |i| i >= amount } || @boundaries.size
|
|
106
|
-
hdp.bucket_counts[bucket_index] += 1
|
|
107
|
-
end
|
|
108
|
-
nil
|
|
109
|
-
end
|
|
112
|
+
return unless @boundaries
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
bucket_index = @boundaries.bsearch_index { |i| i >= amount } || @boundaries.size
|
|
115
|
+
hdp.bucket_counts[bucket_index] += 1
|
|
113
116
|
end
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
def reservior_update(attributes, amount, exemplar_offer)
|
|
119
|
+
reservoir = @exemplar_reservoir_storage[attributes]
|
|
120
|
+
unless reservoir
|
|
121
|
+
reservoir = @exemplar_reservoir.dup
|
|
122
|
+
reservoir.reset
|
|
123
|
+
@exemplar_reservoir_storage[attributes] = reservoir
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
return unless exemplar_offer
|
|
127
|
+
|
|
128
|
+
reservoir.offer(value: amount,
|
|
129
|
+
timestamp: OpenTelemetry::Common::Utilities.time_in_nanoseconds,
|
|
130
|
+
attributes: attributes,
|
|
131
|
+
context: OpenTelemetry::Context.current)
|
|
132
|
+
end
|
|
116
133
|
|
|
117
134
|
def empty_bucket_counts
|
|
118
135
|
@boundaries ? Array.new(@boundaries.size + 1, 0) : nil
|
|
@@ -17,6 +17,8 @@ module OpenTelemetry
|
|
|
17
17
|
module Aggregation
|
|
18
18
|
# Contains the implementation of the {https://opentelemetry.io/docs/specs/otel/metrics/data-model/#exponentialhistogram ExponentialBucketHistogram} aggregation
|
|
19
19
|
class ExponentialBucketHistogram # rubocop:disable Metrics/ClassLength
|
|
20
|
+
OVERFLOW_ATTRIBUTE_SET = { 'otel.metric.overflow' => true }.freeze
|
|
21
|
+
|
|
20
22
|
# relate to min max scale: https://opentelemetry.io/docs/specs/otel/metrics/sdk/#support-a-minimum-and-maximum-scale
|
|
21
23
|
DEFAULT_SIZE = 160
|
|
22
24
|
DEFAULT_SCALE = 20
|
|
@@ -94,7 +96,6 @@ module OpenTelemetry
|
|
|
94
96
|
|
|
95
97
|
# this will slow down the operation especially if large amount of data_points present
|
|
96
98
|
# but it should be fine since with cumulative, the data_points are merged into previous_* and not kept in data_points
|
|
97
|
-
# rubocop:disable Metrics/BlockLength
|
|
98
99
|
data_points.each do |attributes, hdp|
|
|
99
100
|
# Store current values
|
|
100
101
|
current_positive = hdp.positive
|
|
@@ -181,7 +182,6 @@ module OpenTelemetry
|
|
|
181
182
|
merged_data_points[attributes] = merged_hdp
|
|
182
183
|
@previous_mappings[attributes] = @mappings[attributes] if @mappings[attributes] # Preserve mapping for next collection
|
|
183
184
|
end
|
|
184
|
-
# rubocop:enable Metrics/BlockLength
|
|
185
185
|
|
|
186
186
|
# when you have no local_data_points, the loop from cumulative aggregation will not run
|
|
187
187
|
# so return last merged data points if exists
|
|
@@ -221,49 +221,53 @@ module OpenTelemetry
|
|
|
221
221
|
# rubocop:enable Metrics/MethodLength
|
|
222
222
|
|
|
223
223
|
# this is aggregate in python; there is no merge in aggregate; but rescale happened
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
224
|
+
def update(amount, attributes, data_points, cardinality_limit, exemplar_offer: false)
|
|
225
|
+
hdp = if data_points.key?(attributes)
|
|
226
|
+
data_points[attributes]
|
|
227
|
+
elsif data_points.size >= cardinality_limit - 1
|
|
228
|
+
data_points[OVERFLOW_ATTRIBUTE_SET] || create_new_data_point(OVERFLOW_ATTRIBUTE_SET, data_points)
|
|
229
|
+
else
|
|
230
|
+
create_new_data_point(attributes, data_points)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
update_histogram_data_point(hdp, attributes, amount, exemplar_offer: exemplar_offer)
|
|
234
|
+
nil
|
|
235
|
+
end
|
|
232
236
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
nil, # :start_time_unix_nano
|
|
237
|
-
0, # :time_unix_nano
|
|
238
|
-
0, # :count
|
|
239
|
-
0, # :sum
|
|
240
|
-
@scale, # :scale
|
|
241
|
-
@zero_count, # :zero_count
|
|
242
|
-
ExponentialHistogram::Buckets.new, # :positive
|
|
243
|
-
ExponentialHistogram::Buckets.new, # :negative
|
|
244
|
-
0, # :flags
|
|
245
|
-
nil, # :exemplars
|
|
246
|
-
min, # :min
|
|
247
|
-
max, # :max
|
|
248
|
-
@zero_threshold # :zero_threshold
|
|
249
|
-
)
|
|
250
|
-
end
|
|
237
|
+
def aggregation_temporality
|
|
238
|
+
@aggregation_temporality.temporality
|
|
239
|
+
end
|
|
251
240
|
|
|
252
|
-
|
|
253
|
-
unless reservoir
|
|
254
|
-
reservoir = @exemplar_reservoir.dup
|
|
255
|
-
reservoir.reset
|
|
256
|
-
@exemplar_reservoir_storage[attributes] = reservoir
|
|
257
|
-
end
|
|
241
|
+
private
|
|
258
242
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
context: OpenTelemetry::Context.current)
|
|
243
|
+
def create_new_data_point(attributes, data_points)
|
|
244
|
+
if @record_min_max
|
|
245
|
+
min = Float::INFINITY
|
|
246
|
+
max = -Float::INFINITY
|
|
264
247
|
end
|
|
265
248
|
|
|
266
|
-
|
|
249
|
+
data_points[attributes] = ExponentialHistogramDataPoint.new(
|
|
250
|
+
attributes,
|
|
251
|
+
nil, # :start_time_unix_nano
|
|
252
|
+
0, # :time_unix_nano
|
|
253
|
+
0, # :count
|
|
254
|
+
0, # :sum
|
|
255
|
+
@scale, # :scale
|
|
256
|
+
@zero_count, # :zero_count
|
|
257
|
+
ExponentialHistogram::Buckets.new, # :positive
|
|
258
|
+
ExponentialHistogram::Buckets.new, # :negative
|
|
259
|
+
0, # :flags
|
|
260
|
+
nil, # :exemplars
|
|
261
|
+
min, # :min
|
|
262
|
+
max, # :max
|
|
263
|
+
@zero_threshold # :zero_threshold
|
|
264
|
+
)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
|
|
268
|
+
def update_histogram_data_point(hdp, attributes, amount, exemplar_offer: false)
|
|
269
|
+
reservior_update(attributes, amount, exemplar_offer)
|
|
270
|
+
|
|
267
271
|
if @record_min_max
|
|
268
272
|
hdp.max = amount if amount > hdp.max
|
|
269
273
|
hdp.min = amount if amount < hdp.min
|
|
@@ -339,15 +343,8 @@ module OpenTelemetry
|
|
|
339
343
|
bucket_index += buckets.counts.size if bucket_index.negative?
|
|
340
344
|
|
|
341
345
|
buckets.increment_bucket(bucket_index)
|
|
342
|
-
nil
|
|
343
346
|
end
|
|
344
|
-
# rubocop:enable Metrics/
|
|
345
|
-
|
|
346
|
-
def aggregation_temporality
|
|
347
|
-
@aggregation_temporality.temporality
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
private
|
|
347
|
+
# rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
|
|
351
348
|
|
|
352
349
|
def grow_buckets(span, buckets)
|
|
353
350
|
return if span < buckets.counts.size
|
|
@@ -356,6 +353,22 @@ module OpenTelemetry
|
|
|
356
353
|
buckets.grow(span + 1, @size)
|
|
357
354
|
end
|
|
358
355
|
|
|
356
|
+
def reservior_update(attributes, amount, exemplar_offer)
|
|
357
|
+
reservoir = @exemplar_reservoir_storage[attributes]
|
|
358
|
+
unless reservoir
|
|
359
|
+
reservoir = @exemplar_reservoir.dup
|
|
360
|
+
reservoir.reset
|
|
361
|
+
@exemplar_reservoir_storage[attributes] = reservoir
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
return unless exemplar_offer
|
|
365
|
+
|
|
366
|
+
reservoir.offer(value: amount,
|
|
367
|
+
timestamp: OpenTelemetry::Common::Utilities.time_in_nanoseconds,
|
|
368
|
+
attributes: attributes,
|
|
369
|
+
context: OpenTelemetry::Context.current)
|
|
370
|
+
end
|
|
371
|
+
|
|
359
372
|
def new_mapping(scale)
|
|
360
373
|
scale = validate_scale(scale)
|
|
361
374
|
scale <= 0 ? ExponentialHistogram::ExponentMapping.new(scale) : ExponentialHistogram::LogarithmMapping.new(scale)
|
|
@@ -10,6 +10,7 @@ module OpenTelemetry
|
|
|
10
10
|
module Aggregation
|
|
11
11
|
# Contains the implementation of the LastValue aggregation
|
|
12
12
|
class LastValue
|
|
13
|
+
OVERFLOW_ATTRIBUTE_SET = { 'otel.metric.overflow' => true }.freeze
|
|
13
14
|
attr_reader :exemplar_reservoir
|
|
14
15
|
|
|
15
16
|
# if no reservoir pass from instrument, then use this empty reservoir to avoid no method found error
|
|
@@ -33,29 +34,51 @@ module OpenTelemetry
|
|
|
33
34
|
ndps
|
|
34
35
|
end
|
|
35
36
|
|
|
36
|
-
def update(increment, attributes, data_points, exemplar_offer: false)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
def update(increment, attributes, data_points, cardinality_limit, exemplar_offer: false)
|
|
38
|
+
# Check if we already have this attribute set
|
|
39
|
+
ndp = if data_points.key?(attributes)
|
|
40
|
+
data_points[attributes]
|
|
41
|
+
elsif data_points.size >= cardinality_limit - 1
|
|
42
|
+
data_points[OVERFLOW_ATTRIBUTE_SET] || create_new_data_point(OVERFLOW_ATTRIBUTE_SET, data_points)
|
|
43
|
+
else
|
|
44
|
+
create_new_data_point(attributes, data_points)
|
|
45
|
+
end
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
attributes: attributes,
|
|
48
|
-
context: OpenTelemetry::Context.current)
|
|
49
|
-
end
|
|
47
|
+
update_number_data_point(ndp, increment, exemplar_offer: exemplar_offer)
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
50
|
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def create_new_data_point(attributes, data_points)
|
|
51
54
|
data_points[attributes] = NumberDataPoint.new(
|
|
52
55
|
attributes,
|
|
53
56
|
nil,
|
|
54
57
|
nil,
|
|
55
|
-
|
|
58
|
+
0,
|
|
56
59
|
nil
|
|
57
60
|
)
|
|
58
|
-
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def update_number_data_point(ndp, increment, exemplar_offer: false)
|
|
64
|
+
ndp.value = increment
|
|
65
|
+
reservior_update(ndp.attributes, increment, exemplar_offer)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def reservior_update(attributes, increment, exemplar_offer)
|
|
69
|
+
reservoir = @exemplar_reservoir_storage[attributes]
|
|
70
|
+
unless reservoir
|
|
71
|
+
reservoir = @exemplar_reservoir.dup
|
|
72
|
+
reservoir.reset
|
|
73
|
+
@exemplar_reservoir_storage[attributes] = reservoir
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
return unless exemplar_offer
|
|
77
|
+
|
|
78
|
+
reservoir.offer(value: increment,
|
|
79
|
+
timestamp: OpenTelemetry::Common::Utilities.time_in_nanoseconds,
|
|
80
|
+
attributes: attributes,
|
|
81
|
+
context: OpenTelemetry::Context.current)
|
|
59
82
|
end
|
|
60
83
|
end
|
|
61
84
|
end
|
|
@@ -9,8 +9,8 @@ module OpenTelemetry
|
|
|
9
9
|
module Metrics
|
|
10
10
|
module Aggregation
|
|
11
11
|
# Contains the implementation of the Sum aggregation
|
|
12
|
-
# https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#sum-aggregation
|
|
13
12
|
class Sum
|
|
13
|
+
OVERFLOW_ATTRIBUTE_SET = { 'otel.metric.overflow' => true }.freeze
|
|
14
14
|
attr_reader :exemplar_reservoir
|
|
15
15
|
|
|
16
16
|
# if no reservior pass from instrument, then use this empty reservior to avoid no method found error
|
|
@@ -51,21 +51,48 @@ module OpenTelemetry
|
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
def update(increment, attributes, data_points, cardinality_limit, exemplar_offer: false)
|
|
55
|
+
return if @monotonic && increment < 0
|
|
56
|
+
|
|
57
|
+
# Check if we already have this attribute set
|
|
58
|
+
ndp = if data_points.key?(attributes)
|
|
59
|
+
data_points[attributes]
|
|
60
|
+
elsif data_points.size >= cardinality_limit - 1
|
|
61
|
+
data_points[OVERFLOW_ATTRIBUTE_SET] || create_new_data_point(OVERFLOW_ATTRIBUTE_SET, data_points)
|
|
62
|
+
else
|
|
63
|
+
create_new_data_point(attributes, data_points)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
update_number_data_point(ndp, increment, exemplar_offer: exemplar_offer)
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
|
|
54
70
|
def monotonic?
|
|
55
71
|
@monotonic
|
|
56
72
|
end
|
|
57
73
|
|
|
58
|
-
def
|
|
59
|
-
|
|
74
|
+
def aggregation_temporality
|
|
75
|
+
@aggregation_temporality.temporality
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
60
79
|
|
|
61
|
-
|
|
80
|
+
def create_new_data_point(attributes, data_points)
|
|
81
|
+
data_points[attributes] = NumberDataPoint.new(
|
|
62
82
|
attributes,
|
|
63
83
|
nil,
|
|
64
84
|
nil,
|
|
65
85
|
0,
|
|
66
86
|
nil
|
|
67
87
|
)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def update_number_data_point(ndp, increment, exemplar_offer: false)
|
|
91
|
+
reservior_update(ndp.attributes, increment, exemplar_offer)
|
|
92
|
+
ndp.value += increment
|
|
93
|
+
end
|
|
68
94
|
|
|
95
|
+
def reservior_update(attributes, increment, exemplar_offer)
|
|
69
96
|
reservoir = @exemplar_reservoir_storage[attributes]
|
|
70
97
|
unless reservoir
|
|
71
98
|
reservoir = @exemplar_reservoir.dup
|
|
@@ -73,19 +100,12 @@ module OpenTelemetry
|
|
|
73
100
|
@exemplar_reservoir_storage[attributes] = reservoir
|
|
74
101
|
end
|
|
75
102
|
|
|
76
|
-
|
|
77
|
-
reservoir.offer(value: increment,
|
|
78
|
-
timestamp: OpenTelemetry::Common::Utilities.time_in_nanoseconds,
|
|
79
|
-
attributes: attributes,
|
|
80
|
-
context: OpenTelemetry::Context.current)
|
|
81
|
-
end
|
|
103
|
+
return unless exemplar_offer
|
|
82
104
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def aggregation_temporality
|
|
88
|
-
@aggregation_temporality.temporality
|
|
105
|
+
reservoir.offer(value: increment,
|
|
106
|
+
timestamp: OpenTelemetry::Common::Utilities.time_in_nanoseconds,
|
|
107
|
+
attributes: attributes,
|
|
108
|
+
context: OpenTelemetry::Context.current)
|
|
89
109
|
end
|
|
90
110
|
end
|
|
91
111
|
end
|
|
@@ -32,6 +32,18 @@ module OpenTelemetry
|
|
|
32
32
|
def collect(attributes: nil, aggregation_temporality: :delta)
|
|
33
33
|
raise NotImplementedError, "#{self.class} must implement #collect"
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
# Called after dup to reset internal state before reuse for a new attribute set.
|
|
37
|
+
# Subclasses that hold mutable per-attribute state must override this.
|
|
38
|
+
def reset; end
|
|
39
|
+
|
|
40
|
+
# Returns true if this reservoir never stores exemplars.
|
|
41
|
+
# Used to skip the exemplar filter and timestamp lookups entirely.
|
|
42
|
+
#
|
|
43
|
+
# @return [Boolean]
|
|
44
|
+
def noop?
|
|
45
|
+
false
|
|
46
|
+
end
|
|
35
47
|
end
|
|
36
48
|
end
|
|
37
49
|
end
|
|
@@ -12,8 +12,8 @@ module OpenTelemetry
|
|
|
12
12
|
#
|
|
13
13
|
# Potentially useful for exploratory purposes.
|
|
14
14
|
class ConsoleMetricPullExporter < MetricReader
|
|
15
|
-
def initialize
|
|
16
|
-
super
|
|
15
|
+
def initialize(aggregation_cardinality_limit: nil)
|
|
16
|
+
super(aggregation_cardinality_limit: aggregation_cardinality_limit)
|
|
17
17
|
@stopped = false
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -13,8 +13,8 @@ module OpenTelemetry
|
|
|
13
13
|
class InMemoryMetricPullExporter < MetricReader
|
|
14
14
|
attr_reader :metric_snapshots
|
|
15
15
|
|
|
16
|
-
def initialize
|
|
17
|
-
super
|
|
16
|
+
def initialize(aggregation_cardinality_limit: nil)
|
|
17
|
+
super(aggregation_cardinality_limit: aggregation_cardinality_limit)
|
|
18
18
|
@metric_snapshots = []
|
|
19
19
|
@mutex = Mutex.new
|
|
20
20
|
end
|
|
@@ -14,8 +14,8 @@ module OpenTelemetry
|
|
|
14
14
|
class MetricReader
|
|
15
15
|
attr_reader :metric_store
|
|
16
16
|
|
|
17
|
-
def initialize
|
|
18
|
-
@metric_store = OpenTelemetry::SDK::Metrics::State::MetricStore.new
|
|
17
|
+
def initialize(aggregation_cardinality_limit: nil)
|
|
18
|
+
@metric_store = OpenTelemetry::SDK::Metrics::State::MetricStore.new(cardinality_limit: aggregation_cardinality_limit)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def collect
|
|
@@ -24,8 +24,9 @@ module OpenTelemetry
|
|
|
24
24
|
# @return a new instance of the {PeriodicMetricReader}.
|
|
25
25
|
def initialize(export_interval_millis: Float(ENV.fetch('OTEL_METRIC_EXPORT_INTERVAL', 60_000)),
|
|
26
26
|
export_timeout_millis: Float(ENV.fetch('OTEL_METRIC_EXPORT_TIMEOUT', 30_000)),
|
|
27
|
-
exporter: nil
|
|
28
|
-
|
|
27
|
+
exporter: nil,
|
|
28
|
+
aggregation_cardinality_limit: nil)
|
|
29
|
+
super(aggregation_cardinality_limit: aggregation_cardinality_limit)
|
|
29
30
|
|
|
30
31
|
@export_interval = export_interval_millis / 1000.0
|
|
31
32
|
@export_timeout = export_timeout_millis / 1000.0
|
|
@@ -130,19 +130,17 @@ module OpenTelemetry
|
|
|
130
130
|
end
|
|
131
131
|
alias register_asynchronous_instrument register_synchronous_instrument
|
|
132
132
|
|
|
133
|
-
# spec: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#exemplar
|
|
134
|
-
# this is one way to turn on the exemplar (exemplar should be turned off by default)
|
|
135
133
|
def exemplar_filter_setup
|
|
136
134
|
case ENV['OTEL_METRICS_EXEMPLAR_FILTER']
|
|
137
135
|
when 'always_on'
|
|
138
136
|
@exemplar_filter = Exemplar::AlwaysOnExemplarFilter
|
|
139
|
-
when 'trace_based'
|
|
137
|
+
when nil, '', 'trace_based'
|
|
140
138
|
@exemplar_filter = Exemplar::TraceBasedExemplarFilter
|
|
141
139
|
when 'always_off'
|
|
142
140
|
@exemplar_filter = Exemplar::AlwaysOffExemplarFilter
|
|
143
141
|
else
|
|
144
|
-
OpenTelemetry.logger.warn("OTEL_METRICS_EXEMPLAR_FILTER #{ENV['OTEL_METRICS_EXEMPLAR_FILTER']} is not part of the provided exemplar filters.
|
|
145
|
-
@exemplar_filter = Exemplar::
|
|
142
|
+
OpenTelemetry.logger.warn("OTEL_METRICS_EXEMPLAR_FILTER #{ENV['OTEL_METRICS_EXEMPLAR_FILTER']} is not part of the provided exemplar filters. Using trace_based.")
|
|
143
|
+
@exemplar_filter = Exemplar::TraceBasedExemplarFilter
|
|
146
144
|
end
|
|
147
145
|
end
|
|
148
146
|
|
|
@@ -51,17 +51,22 @@ module OpenTelemetry
|
|
|
51
51
|
|
|
52
52
|
def invoke_callback(timeout, attributes)
|
|
53
53
|
if @registered_views.empty?
|
|
54
|
+
|
|
55
|
+
resolved_cardinality_limit = @cardinality_limit || DEFAULT_CARDINALITY_LIMIT
|
|
54
56
|
@mutex.synchronize do
|
|
55
57
|
@callback.each do |cb|
|
|
56
58
|
value = safe_guard_callback(cb, timeout: timeout)
|
|
59
|
+
|
|
57
60
|
if value.is_a?(Numeric)
|
|
58
61
|
exemplar_offer = should_offer_exemplar?(value, attributes)
|
|
59
|
-
@default_aggregation.update(value, attributes, @data_points, exemplar_offer: exemplar_offer)
|
|
62
|
+
@default_aggregation.update(value, attributes, @data_points, resolved_cardinality_limit, exemplar_offer: exemplar_offer)
|
|
60
63
|
end
|
|
61
64
|
end
|
|
62
65
|
end
|
|
63
66
|
else
|
|
64
67
|
@registered_views.each do |view, data_points|
|
|
68
|
+
resolved_cardinality_limit = resolve_cardinality_limit(view)
|
|
69
|
+
|
|
65
70
|
@mutex.synchronize do
|
|
66
71
|
@callback.each do |cb|
|
|
67
72
|
value = safe_guard_callback(cb, timeout: timeout)
|
|
@@ -69,9 +74,10 @@ module OpenTelemetry
|
|
|
69
74
|
|
|
70
75
|
merged_attributes = attributes || {}
|
|
71
76
|
merged_attributes.merge!(view.attribute_keys)
|
|
77
|
+
|
|
72
78
|
if view.valid_aggregation?
|
|
73
79
|
exemplar_offer = should_offer_exemplar?(value, merged_attributes)
|
|
74
|
-
view.aggregation.update(value, attributes, data_points, exemplar_offer: exemplar_offer)
|
|
80
|
+
view.aggregation.update(value, attributes, data_points, resolved_cardinality_limit, exemplar_offer: exemplar_offer)
|
|
75
81
|
end
|
|
76
82
|
end
|
|
77
83
|
end
|
|
@@ -13,11 +13,12 @@ module OpenTelemetry
|
|
|
13
13
|
# The MetricStore module provides SDK internal functionality that is not a part of the
|
|
14
14
|
# public API.
|
|
15
15
|
class MetricStore
|
|
16
|
-
def initialize
|
|
16
|
+
def initialize(cardinality_limit: nil)
|
|
17
17
|
@mutex = Mutex.new
|
|
18
18
|
@epoch_start_time = OpenTelemetry::Common::Utilities.time_in_nanoseconds
|
|
19
19
|
@epoch_end_time = nil
|
|
20
20
|
@metric_streams = []
|
|
21
|
+
@cardinality_limit = cardinality_limit
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def collect
|
|
@@ -32,6 +33,7 @@ module OpenTelemetry
|
|
|
32
33
|
|
|
33
34
|
def add_metric_stream(metric_stream)
|
|
34
35
|
@mutex.synchronize do
|
|
36
|
+
metric_stream.cardinality_limit = @cardinality_limit
|
|
35
37
|
@metric_streams = @metric_streams.dup.push(metric_stream)
|
|
36
38
|
nil
|
|
37
39
|
end
|
|
@@ -12,9 +12,13 @@ module OpenTelemetry
|
|
|
12
12
|
#
|
|
13
13
|
# The MetricStream class provides SDK internal functionality that is not a part of the
|
|
14
14
|
# public API.
|
|
15
|
+
#
|
|
15
16
|
# rubocop:disable Metrics/ClassLength
|
|
16
17
|
class MetricStream
|
|
17
18
|
attr_reader :name, :description, :unit, :instrument_kind, :instrumentation_scope, :data_points
|
|
19
|
+
attr_writer :cardinality_limit
|
|
20
|
+
|
|
21
|
+
DEFAULT_CARDINALITY_LIMIT = 2000
|
|
18
22
|
|
|
19
23
|
def initialize(
|
|
20
24
|
name,
|
|
@@ -51,10 +55,14 @@ module OpenTelemetry
|
|
|
51
55
|
return metric_data if empty_data_point?
|
|
52
56
|
|
|
53
57
|
if @registered_views.empty?
|
|
54
|
-
metric_data << aggregate_metric_data(start_time,
|
|
58
|
+
metric_data << aggregate_metric_data(start_time,
|
|
59
|
+
end_time)
|
|
55
60
|
else
|
|
56
61
|
@registered_views.each do |view, data_points|
|
|
57
|
-
metric_data << aggregate_metric_data(start_time,
|
|
62
|
+
metric_data << aggregate_metric_data(start_time,
|
|
63
|
+
end_time,
|
|
64
|
+
aggregation: view.aggregation,
|
|
65
|
+
data_points: data_points)
|
|
58
66
|
end
|
|
59
67
|
end
|
|
60
68
|
|
|
@@ -62,20 +70,29 @@ module OpenTelemetry
|
|
|
62
70
|
end
|
|
63
71
|
end
|
|
64
72
|
|
|
73
|
+
# view has the cardinality, pass to aggregation update
|
|
74
|
+
# to determine if aggregation have the cardinality
|
|
75
|
+
# if the aggregation does not have the cardinality, then it will be default 2000
|
|
76
|
+
# it better to move overflowed data_points during update because if do it in collect,
|
|
77
|
+
# then we need to sort the entire data_points (~ 2000) based on time, which is time-consuming
|
|
78
|
+
# view will modify the data_point that is not suitable when there are multiple views
|
|
65
79
|
def update(value, attributes)
|
|
66
80
|
if @registered_views.empty?
|
|
81
|
+
resolved_cardinality_limit = resolve_cardinality_limit(nil)
|
|
67
82
|
@mutex.synchronize do
|
|
68
83
|
exemplar_offer = should_offer_exemplar?(value, attributes)
|
|
69
|
-
@default_aggregation.update(value, attributes, @data_points, exemplar_offer: exemplar_offer)
|
|
84
|
+
@default_aggregation.update(value, attributes, @data_points, resolved_cardinality_limit, exemplar_offer: exemplar_offer)
|
|
70
85
|
end
|
|
71
86
|
else
|
|
72
87
|
@registered_views.each do |view, data_points|
|
|
88
|
+
resolved_cardinality_limit = resolve_cardinality_limit(view)
|
|
73
89
|
@mutex.synchronize do
|
|
74
90
|
attributes ||= {}
|
|
75
91
|
attributes.merge!(view.attribute_keys)
|
|
92
|
+
|
|
76
93
|
if view.valid_aggregation?
|
|
77
94
|
exemplar_offer = should_offer_exemplar?(value, attributes)
|
|
78
|
-
view.aggregation.update(value, attributes, data_points, exemplar_offer: exemplar_offer)
|
|
95
|
+
view.aggregation.update(value, attributes, data_points, resolved_cardinality_limit, exemplar_offer: exemplar_offer)
|
|
79
96
|
end
|
|
80
97
|
end
|
|
81
98
|
end
|
|
@@ -119,7 +136,14 @@ module OpenTelemetry
|
|
|
119
136
|
end
|
|
120
137
|
end
|
|
121
138
|
|
|
139
|
+
def resolve_cardinality_limit(view)
|
|
140
|
+
cardinality_limit = view&.aggregation_cardinality_limit || @cardinality_limit || DEFAULT_CARDINALITY_LIMIT
|
|
141
|
+
[cardinality_limit, 0].max # if cardinality_limit is negative, then give it 0
|
|
142
|
+
end
|
|
143
|
+
|
|
122
144
|
def should_offer_exemplar?(value, attributes)
|
|
145
|
+
return false if @exemplar_reservoir&.noop?
|
|
146
|
+
|
|
123
147
|
context = OpenTelemetry::Context.current
|
|
124
148
|
time = OpenTelemetry::Common::Utilities.time_in_nanoseconds
|
|
125
149
|
@exemplar_filter&.should_sample?(value, time, attributes, context)
|
|
@@ -10,13 +10,14 @@ module OpenTelemetry
|
|
|
10
10
|
module View
|
|
11
11
|
# RegisteredView is an internal class used to match Views with a given {MetricStream}
|
|
12
12
|
class RegisteredView
|
|
13
|
-
attr_reader :name, :aggregation, :attribute_keys, :regex
|
|
13
|
+
attr_reader :name, :aggregation, :attribute_keys, :regex, :aggregation_cardinality_limit
|
|
14
14
|
|
|
15
15
|
def initialize(name, **options)
|
|
16
16
|
@name = name
|
|
17
17
|
@options = options
|
|
18
18
|
@aggregation = options[:aggregation]
|
|
19
19
|
@attribute_keys = options[:attribute_keys] || {}
|
|
20
|
+
@aggregation_cardinality_limit = options[:aggregation_cardinality_limit]
|
|
20
21
|
|
|
21
22
|
generate_regex_pattern(name)
|
|
22
23
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- OpenTelemetry Authors
|
|
@@ -51,118 +51,6 @@ dependencies:
|
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: '1.2'
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: benchmark-ipsa
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - "~>"
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: 0.2.0
|
|
61
|
-
type: :development
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - "~>"
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: 0.2.0
|
|
68
|
-
- !ruby/object:Gem::Dependency
|
|
69
|
-
name: minitest
|
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
|
71
|
-
requirements:
|
|
72
|
-
- - "~>"
|
|
73
|
-
- !ruby/object:Gem::Version
|
|
74
|
-
version: '5.0'
|
|
75
|
-
type: :development
|
|
76
|
-
prerelease: false
|
|
77
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
-
requirements:
|
|
79
|
-
- - "~>"
|
|
80
|
-
- !ruby/object:Gem::Version
|
|
81
|
-
version: '5.0'
|
|
82
|
-
- !ruby/object:Gem::Dependency
|
|
83
|
-
name: opentelemetry-test-helpers
|
|
84
|
-
requirement: !ruby/object:Gem::Requirement
|
|
85
|
-
requirements:
|
|
86
|
-
- - ">="
|
|
87
|
-
- !ruby/object:Gem::Version
|
|
88
|
-
version: '0'
|
|
89
|
-
type: :development
|
|
90
|
-
prerelease: false
|
|
91
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
-
requirements:
|
|
93
|
-
- - ">="
|
|
94
|
-
- !ruby/object:Gem::Version
|
|
95
|
-
version: '0'
|
|
96
|
-
- !ruby/object:Gem::Dependency
|
|
97
|
-
name: rake
|
|
98
|
-
requirement: !ruby/object:Gem::Requirement
|
|
99
|
-
requirements:
|
|
100
|
-
- - "~>"
|
|
101
|
-
- !ruby/object:Gem::Version
|
|
102
|
-
version: '13.3'
|
|
103
|
-
type: :development
|
|
104
|
-
prerelease: false
|
|
105
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
-
requirements:
|
|
107
|
-
- - "~>"
|
|
108
|
-
- !ruby/object:Gem::Version
|
|
109
|
-
version: '13.3'
|
|
110
|
-
- !ruby/object:Gem::Dependency
|
|
111
|
-
name: rubocop
|
|
112
|
-
requirement: !ruby/object:Gem::Requirement
|
|
113
|
-
requirements:
|
|
114
|
-
- - "~>"
|
|
115
|
-
- !ruby/object:Gem::Version
|
|
116
|
-
version: '1.65'
|
|
117
|
-
type: :development
|
|
118
|
-
prerelease: false
|
|
119
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
-
requirements:
|
|
121
|
-
- - "~>"
|
|
122
|
-
- !ruby/object:Gem::Version
|
|
123
|
-
version: '1.65'
|
|
124
|
-
- !ruby/object:Gem::Dependency
|
|
125
|
-
name: simplecov
|
|
126
|
-
requirement: !ruby/object:Gem::Requirement
|
|
127
|
-
requirements:
|
|
128
|
-
- - "~>"
|
|
129
|
-
- !ruby/object:Gem::Version
|
|
130
|
-
version: '0.17'
|
|
131
|
-
type: :development
|
|
132
|
-
prerelease: false
|
|
133
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
-
requirements:
|
|
135
|
-
- - "~>"
|
|
136
|
-
- !ruby/object:Gem::Version
|
|
137
|
-
version: '0.17'
|
|
138
|
-
- !ruby/object:Gem::Dependency
|
|
139
|
-
name: yard
|
|
140
|
-
requirement: !ruby/object:Gem::Requirement
|
|
141
|
-
requirements:
|
|
142
|
-
- - "~>"
|
|
143
|
-
- !ruby/object:Gem::Version
|
|
144
|
-
version: '0.9'
|
|
145
|
-
type: :development
|
|
146
|
-
prerelease: false
|
|
147
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
-
requirements:
|
|
149
|
-
- - "~>"
|
|
150
|
-
- !ruby/object:Gem::Version
|
|
151
|
-
version: '0.9'
|
|
152
|
-
- !ruby/object:Gem::Dependency
|
|
153
|
-
name: yard-doctest
|
|
154
|
-
requirement: !ruby/object:Gem::Requirement
|
|
155
|
-
requirements:
|
|
156
|
-
- - "~>"
|
|
157
|
-
- !ruby/object:Gem::Version
|
|
158
|
-
version: 0.1.6
|
|
159
|
-
type: :development
|
|
160
|
-
prerelease: false
|
|
161
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
162
|
-
requirements:
|
|
163
|
-
- - "~>"
|
|
164
|
-
- !ruby/object:Gem::Version
|
|
165
|
-
version: 0.1.6
|
|
166
54
|
description: A stats collection and distributed tracing framework
|
|
167
55
|
email:
|
|
168
56
|
- cncf-opentelemetry-contributors@lists.cncf.io
|
|
@@ -233,10 +121,10 @@ homepage: https://github.com/open-telemetry/opentelemetry-ruby
|
|
|
233
121
|
licenses:
|
|
234
122
|
- Apache-2.0
|
|
235
123
|
metadata:
|
|
236
|
-
changelog_uri: https://
|
|
237
|
-
source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby/tree/
|
|
124
|
+
changelog_uri: https://rubydoc.info/gems/opentelemetry-metrics-sdk/0.15.0/file/CHANGELOG.md
|
|
125
|
+
source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby/tree/opentelemetry-metrics-sdk/v0.15.0/metrics_sdk
|
|
238
126
|
bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby/issues
|
|
239
|
-
documentation_uri: https://
|
|
127
|
+
documentation_uri: https://rubydoc.info/gems/opentelemetry-metrics-sdk/0.15.0
|
|
240
128
|
rdoc_options: []
|
|
241
129
|
require_paths:
|
|
242
130
|
- lib
|
|
@@ -251,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
251
139
|
- !ruby/object:Gem::Version
|
|
252
140
|
version: '0'
|
|
253
141
|
requirements: []
|
|
254
|
-
rubygems_version: 4.0.
|
|
142
|
+
rubygems_version: 4.0.10
|
|
255
143
|
specification_version: 4
|
|
256
144
|
summary: A stats collection and distributed tracing framework
|
|
257
145
|
test_files: []
|