opentelemetry-sdk 0.13.1 → 1.0.0.rc1
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 +97 -42
- data/README.md +2 -2
- data/lib/opentelemetry/sdk.rb +2 -2
- data/lib/opentelemetry/sdk/configurator.rb +41 -45
- data/lib/opentelemetry/sdk/internal.rb +3 -3
- data/lib/opentelemetry/sdk/resources/constants.rb +48 -3
- data/lib/opentelemetry/sdk/trace/config/trace_config.rb +13 -7
- data/lib/opentelemetry/sdk/trace/event.rb +7 -36
- data/lib/opentelemetry/sdk/trace/export/batch_span_processor.rb +10 -5
- data/lib/opentelemetry/sdk/trace/export/console_span_exporter.rb +4 -0
- data/lib/opentelemetry/sdk/trace/export/in_memory_span_exporter.rb +23 -4
- data/lib/opentelemetry/sdk/trace/export/multi_span_exporter.rb +19 -2
- data/lib/opentelemetry/sdk/trace/export/noop_span_exporter.rb +10 -0
- data/lib/opentelemetry/sdk/trace/export/simple_span_processor.rb +4 -2
- data/lib/opentelemetry/sdk/trace/multi_span_processor.rb +2 -2
- data/lib/opentelemetry/sdk/trace/span.rb +54 -13
- data/lib/opentelemetry/sdk/trace/span_data.rb +25 -18
- data/lib/opentelemetry/sdk/trace/tracer.rb +1 -1
- data/lib/opentelemetry/sdk/trace/tracer_provider.rb +25 -7
- data/lib/opentelemetry/sdk/version.rb +1 -1
- metadata +39 -14
- data/lib/opentelemetry/sdk/baggage.rb +0 -16
- data/lib/opentelemetry/sdk/baggage/builder.rb +0 -40
- data/lib/opentelemetry/sdk/baggage/manager.rb +0 -97
@@ -16,6 +16,9 @@ module OpenTelemetry
|
|
16
16
|
# The global default max number of attributes per {Span}.
|
17
17
|
attr_reader :max_attributes_count
|
18
18
|
|
19
|
+
# The global default max length of attribute value per {Span}.
|
20
|
+
attr_reader :max_attributes_length
|
21
|
+
|
19
22
|
# The global default max number of {OpenTelemetry::SDK::Trace::Event}s per {Span}.
|
20
23
|
attr_reader :max_events_count
|
21
24
|
|
@@ -32,13 +35,15 @@ module OpenTelemetry
|
|
32
35
|
#
|
33
36
|
# @return [TraceConfig] with the desired values.
|
34
37
|
# @raise [ArgumentError] if any of the max numbers are not positive.
|
35
|
-
def initialize(sampler: sampler_from_environment(Samplers.parent_based(root: Samplers::ALWAYS_ON)),
|
36
|
-
max_attributes_count: Integer(ENV.fetch('OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT',
|
37
|
-
|
38
|
-
|
38
|
+
def initialize(sampler: sampler_from_environment(Samplers.parent_based(root: Samplers::ALWAYS_ON)), # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
39
|
+
max_attributes_count: Integer(ENV.fetch('OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT', 128)),
|
40
|
+
max_attributes_length: ENV['OTEL_RUBY_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT'],
|
41
|
+
max_events_count: Integer(ENV.fetch('OTEL_SPAN_EVENT_COUNT_LIMIT', 128)),
|
42
|
+
max_links_count: Integer(ENV.fetch('OTEL_SPAN_LINK_COUNT_LIMIT', 128)),
|
39
43
|
max_attributes_per_event: max_attributes_count,
|
40
44
|
max_attributes_per_link: max_attributes_count)
|
41
45
|
raise ArgumentError, 'max_attributes_count must be positive' unless max_attributes_count.positive?
|
46
|
+
raise ArgumentError, 'max_attributes_length must not be less than 32' unless max_attributes_length.nil? || Integer(max_attributes_length) >= 32
|
42
47
|
raise ArgumentError, 'max_events_count must be positive' unless max_events_count.positive?
|
43
48
|
raise ArgumentError, 'max_links_count must be positive' unless max_links_count.positive?
|
44
49
|
raise ArgumentError, 'max_attributes_per_event must be positive' unless max_attributes_per_event.positive?
|
@@ -46,6 +51,7 @@ module OpenTelemetry
|
|
46
51
|
|
47
52
|
@sampler = sampler
|
48
53
|
@max_attributes_count = max_attributes_count
|
54
|
+
@max_attributes_length = max_attributes_length.nil? ? nil : Integer(max_attributes_length)
|
49
55
|
@max_events_count = max_events_count
|
50
56
|
@max_links_count = max_links_count
|
51
57
|
@max_attributes_per_event = max_attributes_per_event
|
@@ -56,13 +62,13 @@ module OpenTelemetry
|
|
56
62
|
private
|
57
63
|
|
58
64
|
def sampler_from_environment(default_sampler) # rubocop:disable Metrics/CyclomaticComplexity
|
59
|
-
case ENV['
|
65
|
+
case ENV['OTEL_TRACES_SAMPLER']
|
60
66
|
when 'always_on' then Samplers::ALWAYS_ON
|
61
67
|
when 'always_off' then Samplers::ALWAYS_OFF
|
62
|
-
when 'traceidratio' then Samplers.trace_id_ratio_based(Float(ENV.fetch('
|
68
|
+
when 'traceidratio' then Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACES_SAMPLER_ARG', 1.0)))
|
63
69
|
when 'parentbased_always_on' then Samplers.parent_based(root: Samplers::ALWAYS_ON)
|
64
70
|
when 'parentbased_always_off' then Samplers.parent_based(root: Samplers::ALWAYS_OFF)
|
65
|
-
when 'parentbased_traceidratio' then Samplers.parent_based(root: Samplers.trace_id_ratio_based(Float(ENV.fetch('
|
71
|
+
when 'parentbased_traceidratio' then Samplers.parent_based(root: Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACES_SAMPLER_ARG', 1.0))))
|
66
72
|
else default_sampler
|
67
73
|
end
|
68
74
|
rescue StandardError => e
|
@@ -7,42 +7,13 @@
|
|
7
7
|
module OpenTelemetry
|
8
8
|
module SDK
|
9
9
|
module Trace
|
10
|
-
# A text annotation with a set of attributes and a timestamp.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
# @return [String]
|
19
|
-
attr_reader :name
|
20
|
-
|
21
|
-
# Returns the frozen attributes for this event
|
22
|
-
#
|
23
|
-
# @return [Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}]
|
24
|
-
attr_reader :attributes
|
25
|
-
|
26
|
-
# Returns the timestamp for this event
|
27
|
-
#
|
28
|
-
# @return [Time]
|
29
|
-
attr_reader :timestamp
|
30
|
-
|
31
|
-
# Returns a new immutable {Event}.
|
32
|
-
#
|
33
|
-
# @param [String] name The name of this event
|
34
|
-
# @param [optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}]
|
35
|
-
# attributes A hash of attributes for this event. Attributes will be
|
36
|
-
# frozen during Event initialization.
|
37
|
-
# @param [optional Time] timestamp The timestamp for this event.
|
38
|
-
# Defaults to Time.now.
|
39
|
-
# @return [Event]
|
40
|
-
def initialize(name:, attributes: nil, timestamp: nil)
|
41
|
-
@name = name
|
42
|
-
@attributes = attributes.freeze || EMPTY_ATTRIBUTES
|
43
|
-
@timestamp = timestamp || Time.now
|
44
|
-
end
|
45
|
-
end
|
10
|
+
# A text annotation with a set of attributes and a timestamp for export.
|
11
|
+
#
|
12
|
+
# Field types are as follows:
|
13
|
+
# name: String
|
14
|
+
# attributes: frozen Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}
|
15
|
+
# timestamp: Integer nanoseconds since Epoch
|
16
|
+
Event = Struct.new(:name, :attributes, :timestamp)
|
46
17
|
end
|
47
18
|
end
|
48
19
|
end
|
@@ -28,7 +28,8 @@ module OpenTelemetry
|
|
28
28
|
class BatchSpanProcessor # rubocop:disable Metrics/ClassLength
|
29
29
|
# Returns a new instance of the {BatchSpanProcessor}.
|
30
30
|
#
|
31
|
-
# @param [SpanExporter] exporter
|
31
|
+
# @param [SpanExporter] exporter the (duck type) SpanExporter to where the
|
32
|
+
# recorded Spans are pushed after batching.
|
32
33
|
# @param [Numeric] exporter_timeout the delay interval between two
|
33
34
|
# consecutive exports. Defaults to the value of the OTEL_BSP_EXPORT_TIMEOUT
|
34
35
|
# environment variable, if set, or 30,000 (30 seconds).
|
@@ -43,7 +44,7 @@ module OpenTelemetry
|
|
43
44
|
# variable, if set, or 512.
|
44
45
|
#
|
45
46
|
# @return a new instance of the {BatchSpanProcessor}.
|
46
|
-
def initialize(exporter
|
47
|
+
def initialize(exporter,
|
47
48
|
exporter_timeout: Float(ENV.fetch('OTEL_BSP_EXPORT_TIMEOUT', 30_000)),
|
48
49
|
schedule_delay: Float(ENV.fetch('OTEL_BSP_SCHEDULE_DELAY', 5_000)),
|
49
50
|
max_queue_size: Integer(ENV.fetch('OTEL_BSP_MAX_QUEUE_SIZE', 2048)),
|
@@ -51,6 +52,7 @@ module OpenTelemetry
|
|
51
52
|
start_thread_on_boot: String(ENV['OTEL_RUBY_BSP_START_THREAD_ON_BOOT']) !~ /false/i,
|
52
53
|
metrics_reporter: nil)
|
53
54
|
raise ArgumentError if max_export_batch_size > max_queue_size
|
55
|
+
raise ArgumentError, "exporter #{exporter.inspect} does not appear to be a valid exporter" unless Common::Utilities.valid_exporter?(exporter)
|
54
56
|
|
55
57
|
@exporter = exporter
|
56
58
|
@exporter_timeout_seconds = exporter_timeout / 1000.0
|
@@ -99,7 +101,7 @@ module OpenTelemetry
|
|
99
101
|
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
100
102
|
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
101
103
|
def force_flush(timeout: nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
102
|
-
start_time =
|
104
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
103
105
|
snapshot = lock do
|
104
106
|
reset_on_fork if @keep_running
|
105
107
|
spans.shift(spans.size)
|
@@ -113,7 +115,7 @@ module OpenTelemetry
|
|
113
115
|
return result_code unless result_code == SUCCESS
|
114
116
|
end
|
115
117
|
|
116
|
-
|
118
|
+
@exporter.force_flush(timeout: OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time))
|
117
119
|
ensure
|
118
120
|
# Unshift the remaining spans if we timed out. We drop excess spans from
|
119
121
|
# the snapshot because they're older than any spans in the spans buffer.
|
@@ -135,7 +137,7 @@ module OpenTelemetry
|
|
135
137
|
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
136
138
|
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
137
139
|
def shutdown(timeout: nil)
|
138
|
-
start_time =
|
140
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
139
141
|
thread = lock do
|
140
142
|
@keep_running = false
|
141
143
|
@condition.signal
|
@@ -176,6 +178,9 @@ module OpenTelemetry
|
|
176
178
|
@pid = pid
|
177
179
|
spans.clear
|
178
180
|
@thread = restart_thread ? Thread.new { work } : nil
|
181
|
+
rescue ThreadError => e
|
182
|
+
@metrics_reporter.add_to_counter('otel.bsp.error', labels: { 'reason' => 'ThreadError' })
|
183
|
+
OpenTelemetry.handle_error(exception: e, message: 'unexpected error in BatchSpanProcessor#reset_on_fork')
|
179
184
|
end
|
180
185
|
|
181
186
|
def export_batch(batch, timeout: @exporter_timeout_seconds)
|
@@ -10,30 +10,39 @@ module OpenTelemetry
|
|
10
10
|
module Export
|
11
11
|
# A SpanExporter implementation that can be used to test OpenTelemetry integration.
|
12
12
|
#
|
13
|
-
# Example usage:
|
13
|
+
# Example usage in a test suite:
|
14
14
|
#
|
15
15
|
# class MyClassTest
|
16
16
|
# def setup
|
17
17
|
# @tracer_provider = TracerProvider.new
|
18
|
-
#
|
18
|
+
# # The default is `recording: true`, which is appropriate in non-test environments.
|
19
|
+
# @exporter = InMemorySpanExporter.new(recording: false)
|
19
20
|
# @tracer_provider.add_span_processor(SimpleSampledSpansProcessor.new(@exporter))
|
20
21
|
# end
|
21
22
|
#
|
22
23
|
# def test_finished_spans
|
24
|
+
# @exporter.recording = true
|
23
25
|
# @tracer_provider.tracer.in_span("span") {}
|
24
26
|
#
|
25
27
|
# spans = @exporter.finished_spans
|
26
28
|
# spans.wont_be_nil
|
27
29
|
# spans.size.must_equal(1)
|
28
30
|
# spans[0].name.must_equal("span")
|
31
|
+
#
|
32
|
+
# @exporter.recording = false
|
29
33
|
# end
|
30
34
|
class InMemorySpanExporter
|
35
|
+
# Controls whether or not the exporter will record spans, or discard them.
|
36
|
+
# @return [Boolean] when true, the exporter is recording. By default, this is true.
|
37
|
+
attr_accessor :recording
|
38
|
+
|
31
39
|
# Returns a new instance of the {InMemorySpanExporter}.
|
32
40
|
#
|
33
41
|
# @return a new instance of the {InMemorySpanExporter}.
|
34
|
-
def initialize
|
42
|
+
def initialize(recording: true)
|
35
43
|
@finished_spans = []
|
36
44
|
@stopped = false
|
45
|
+
@recording = recording
|
37
46
|
@mutex = Mutex.new
|
38
47
|
end
|
39
48
|
|
@@ -67,11 +76,21 @@ module OpenTelemetry
|
|
67
76
|
@mutex.synchronize do
|
68
77
|
return FAILURE if @stopped
|
69
78
|
|
70
|
-
@finished_spans.concat(span_datas.to_a)
|
79
|
+
@finished_spans.concat(span_datas.to_a) if @recording
|
71
80
|
end
|
72
81
|
SUCCESS
|
73
82
|
end
|
74
83
|
|
84
|
+
# Called when {TracerProvider#force_flush} is called, if this exporter is
|
85
|
+
# registered to a {TracerProvider} object.
|
86
|
+
#
|
87
|
+
# @param [optional Numeric] timeout An optional timeout in seconds.
|
88
|
+
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
89
|
+
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
90
|
+
def force_flush(timeout: nil)
|
91
|
+
SUCCESS
|
92
|
+
end
|
93
|
+
|
75
94
|
# Called when {TracerProvider#shutdown} is called, if this exporter is
|
76
95
|
# registered to a {TracerProvider} object.
|
77
96
|
#
|
@@ -26,7 +26,7 @@ module OpenTelemetry
|
|
26
26
|
# @param [optional Numeric] timeout An optional timeout in seconds.
|
27
27
|
# @return [Integer] the result of the export.
|
28
28
|
def export(spans, timeout: nil)
|
29
|
-
start_time =
|
29
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
30
30
|
results = @span_exporters.map do |span_exporter|
|
31
31
|
span_exporter.export(spans, timeout: OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time))
|
32
32
|
rescue => e # rubocop:disable Style/RescueStandardError
|
@@ -36,6 +36,23 @@ module OpenTelemetry
|
|
36
36
|
results.uniq.max || SUCCESS
|
37
37
|
end
|
38
38
|
|
39
|
+
# Called when {TracerProvider#force_flush} is called, if this exporter is
|
40
|
+
# registered to a {TracerProvider} object.
|
41
|
+
#
|
42
|
+
# @param [optional Numeric] timeout An optional timeout in seconds.
|
43
|
+
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
44
|
+
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
45
|
+
def force_flush(timeout: nil)
|
46
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
47
|
+
results = @span_exporters.map do |processor|
|
48
|
+
remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
|
49
|
+
return TIMEOUT if remaining_timeout&.zero?
|
50
|
+
|
51
|
+
processor.force_flush(timeout: remaining_timeout)
|
52
|
+
end
|
53
|
+
results.uniq.max || SUCCESS
|
54
|
+
end
|
55
|
+
|
39
56
|
# Called when {TracerProvider#shutdown} is called, if this exporter is
|
40
57
|
# registered to a {TracerProvider} object.
|
41
58
|
#
|
@@ -43,7 +60,7 @@ module OpenTelemetry
|
|
43
60
|
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
44
61
|
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
45
62
|
def shutdown(timeout: nil)
|
46
|
-
start_time =
|
63
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
47
64
|
results = @span_exporters.map do |processor|
|
48
65
|
remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
|
49
66
|
return TIMEOUT if remaining_timeout&.zero?
|
@@ -31,6 +31,16 @@ module OpenTelemetry
|
|
31
31
|
FAILURE
|
32
32
|
end
|
33
33
|
|
34
|
+
# Called when {TracerProvider#force_flush} is called, if this exporter is
|
35
|
+
# registered to a {TracerProvider} object.
|
36
|
+
#
|
37
|
+
# @param [optional Numeric] timeout An optional timeout in seconds.
|
38
|
+
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
39
|
+
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
40
|
+
def force_flush(timeout: nil)
|
41
|
+
SUCCESS
|
42
|
+
end
|
43
|
+
|
34
44
|
# Called when {TracerProvider#shutdown} is called, if this exporter is
|
35
45
|
# registered to a {TracerProvider} object.
|
36
46
|
#
|
@@ -29,6 +29,8 @@ module OpenTelemetry
|
|
29
29
|
# @return [SimpleSpanProcessor]
|
30
30
|
# @raise ArgumentError if the span_exporter is nil.
|
31
31
|
def initialize(span_exporter)
|
32
|
+
raise ArgumentError, "exporter #{span_exporter.inspect} does not appear to be a valid exporter" unless Common::Utilities.valid_exporter?(span_exporter)
|
33
|
+
|
32
34
|
@span_exporter = span_exporter
|
33
35
|
end
|
34
36
|
|
@@ -61,7 +63,7 @@ module OpenTelemetry
|
|
61
63
|
end
|
62
64
|
|
63
65
|
# Export all ended spans to the configured `Exporter` that have not yet
|
64
|
-
# been exported.
|
66
|
+
# been exported, then call {Exporter#force_flush}.
|
65
67
|
#
|
66
68
|
# This method should only be called in cases where it is absolutely
|
67
69
|
# necessary, such as when using some FaaS providers that may suspend
|
@@ -72,7 +74,7 @@ module OpenTelemetry
|
|
72
74
|
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
73
75
|
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
74
76
|
def force_flush(timeout: nil)
|
75
|
-
SUCCESS
|
77
|
+
@span_exporter&.force_flush(timeout: timeout) || SUCCESS
|
76
78
|
end
|
77
79
|
|
78
80
|
# Called when {TracerProvider#shutdown} is called.
|
@@ -55,7 +55,7 @@ module OpenTelemetry
|
|
55
55
|
# @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
|
56
56
|
# a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
|
57
57
|
def force_flush(timeout: nil)
|
58
|
-
start_time =
|
58
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
59
59
|
results = @span_processors.map do |processor|
|
60
60
|
remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
|
61
61
|
return Export::TIMEOUT if remaining_timeout&.zero?
|
@@ -71,7 +71,7 @@ module OpenTelemetry
|
|
71
71
|
# @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
|
72
72
|
# a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
|
73
73
|
def shutdown(timeout: nil)
|
74
|
-
start_time =
|
74
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
75
75
|
results = @span_processors.map do |processor|
|
76
76
|
remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
|
77
77
|
return Export::TIMEOUT if remaining_timeout&.zero?
|
@@ -17,8 +17,9 @@ module OpenTelemetry
|
|
17
17
|
# rubocop:disable Metrics/ClassLength
|
18
18
|
class Span < OpenTelemetry::Trace::Span
|
19
19
|
DEFAULT_STATUS = OpenTelemetry::Trace::Status.new(OpenTelemetry::Trace::Status::UNSET)
|
20
|
+
EMPTY_ATTRIBUTES = {}.freeze
|
20
21
|
|
21
|
-
private_constant
|
22
|
+
private_constant :DEFAULT_STATUS, :EMPTY_ATTRIBUTES
|
22
23
|
|
23
24
|
# The following readers are intended for the use of SpanProcessors and
|
24
25
|
# should not be considered part of the public interface for instrumentation.
|
@@ -64,10 +65,12 @@ module OpenTelemetry
|
|
64
65
|
#
|
65
66
|
# @param [String] key
|
66
67
|
# @param [String, Boolean, Numeric, Array<String, Numeric, Boolean>] value
|
68
|
+
# Values must be non-nil and (array of) string, boolean or numeric type.
|
69
|
+
# Array values must not contain nil elements and all elements must be of
|
70
|
+
# the same basic type (string, numeric, boolean).
|
67
71
|
#
|
68
72
|
# @return [self] returns itself
|
69
73
|
def set_attribute(key, value)
|
70
|
-
super
|
71
74
|
@mutex.synchronize do
|
72
75
|
if @ended
|
73
76
|
OpenTelemetry.logger.warn('Calling set_attribute on an ended Span.')
|
@@ -82,6 +85,33 @@ module OpenTelemetry
|
|
82
85
|
end
|
83
86
|
alias []= set_attribute
|
84
87
|
|
88
|
+
# Add attributes
|
89
|
+
#
|
90
|
+
# Note that the OpenTelemetry project
|
91
|
+
# {https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
|
92
|
+
# documents} certain "standard attributes" that have prescribed semantic
|
93
|
+
# meanings.
|
94
|
+
#
|
95
|
+
# @param [Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}] attributes
|
96
|
+
# Values must be non-nil and (array of) string, boolean or numeric type.
|
97
|
+
# Array values must not contain nil elements and all elements must be of
|
98
|
+
# the same basic type (string, numeric, boolean).
|
99
|
+
#
|
100
|
+
# @return [self] returns itself
|
101
|
+
def add_attributes(attributes)
|
102
|
+
@mutex.synchronize do
|
103
|
+
if @ended
|
104
|
+
OpenTelemetry.logger.warn('Calling add_attributes on an ended Span.')
|
105
|
+
else
|
106
|
+
@attributes ||= {}
|
107
|
+
@attributes.merge!(attributes)
|
108
|
+
trim_span_attributes(@attributes)
|
109
|
+
@total_recorded_attributes += attributes.size
|
110
|
+
end
|
111
|
+
end
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
85
115
|
# Add an Event to a {Span}.
|
86
116
|
#
|
87
117
|
# Example:
|
@@ -96,13 +126,12 @@ module OpenTelemetry
|
|
96
126
|
# @param [String] name Name of the event.
|
97
127
|
# @param [optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}] attributes
|
98
128
|
# One or more key:value pairs, where the keys must be strings and the
|
99
|
-
# values may be string, boolean or numeric type.
|
129
|
+
# values may be (array of) string, boolean or numeric type.
|
100
130
|
# @param [optional Time] timestamp Optional timestamp for the event.
|
101
131
|
#
|
102
132
|
# @return [self] returns itself
|
103
133
|
def add_event(name, attributes: nil, timestamp: nil)
|
104
|
-
|
105
|
-
event = Event.new(name: name, attributes: attributes, timestamp: timestamp || Time.now)
|
134
|
+
event = Event.new(name, truncate_attribute_values(attributes), wall_clock(timestamp))
|
106
135
|
|
107
136
|
@mutex.synchronize do
|
108
137
|
if @ended
|
@@ -148,7 +177,6 @@ module OpenTelemetry
|
|
148
177
|
#
|
149
178
|
# @return [void]
|
150
179
|
def status=(status)
|
151
|
-
super
|
152
180
|
@mutex.synchronize do
|
153
181
|
if @ended
|
154
182
|
OpenTelemetry.logger.warn('Calling status= on an ended Span.')
|
@@ -168,7 +196,6 @@ module OpenTelemetry
|
|
168
196
|
#
|
169
197
|
# @return [void]
|
170
198
|
def name=(new_name)
|
171
|
-
super
|
172
199
|
@mutex.synchronize do
|
173
200
|
if @ended
|
174
201
|
OpenTelemetry.logger.warn('Calling name= on an ended Span.')
|
@@ -203,7 +230,7 @@ module OpenTelemetry
|
|
203
230
|
OpenTelemetry.logger.warn('Calling finish on an ended Span.')
|
204
231
|
return self
|
205
232
|
end
|
206
|
-
@end_timestamp = end_timestamp
|
233
|
+
@end_timestamp = wall_clock(end_timestamp)
|
207
234
|
@attributes = validated_attributes(@attributes).freeze
|
208
235
|
@events.freeze
|
209
236
|
@ended = true
|
@@ -261,7 +288,7 @@ module OpenTelemetry
|
|
261
288
|
@total_recorded_events = 0
|
262
289
|
@total_recorded_links = links&.size || 0
|
263
290
|
@total_recorded_attributes = attributes&.size || 0
|
264
|
-
@start_timestamp = start_timestamp
|
291
|
+
@start_timestamp = wall_clock(start_timestamp)
|
265
292
|
@end_timestamp = nil
|
266
293
|
@attributes = attributes.nil? ? nil : Hash[attributes] # We need a mutable copy of attributes.
|
267
294
|
trim_span_attributes(@attributes)
|
@@ -275,7 +302,7 @@ module OpenTelemetry
|
|
275
302
|
private
|
276
303
|
|
277
304
|
def validated_attributes(attrs)
|
278
|
-
return attrs if Internal.valid_attributes?(attrs)
|
305
|
+
return attrs if Internal.valid_attributes?(name, 'span', attrs)
|
279
306
|
|
280
307
|
attrs.keep_if { |key, value| Internal.valid_key?(key) && Internal.valid_value?(value) }
|
281
308
|
end
|
@@ -285,15 +312,24 @@ module OpenTelemetry
|
|
285
312
|
|
286
313
|
excess = attrs.size - @trace_config.max_attributes_count
|
287
314
|
excess.times { attrs.shift } if excess.positive?
|
315
|
+
truncate_attribute_values(attrs)
|
288
316
|
nil
|
289
317
|
end
|
290
318
|
|
319
|
+
def truncate_attribute_values(attrs)
|
320
|
+
return EMPTY_ATTRIBUTES if attrs.nil?
|
321
|
+
|
322
|
+
max_attributes_length = @trace_config.max_attributes_length
|
323
|
+
attrs.each { |key, value| attrs[key] = OpenTelemetry::Common::Utilities.truncate(value, max_attributes_length) } if max_attributes_length
|
324
|
+
attrs
|
325
|
+
end
|
326
|
+
|
291
327
|
def trim_links(links, max_links_count, max_attributes_per_link) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
292
328
|
# Fast path (likely) common cases.
|
293
329
|
return nil if links.nil?
|
294
330
|
|
295
331
|
if links.size <= max_links_count &&
|
296
|
-
links.all? { |link| link.attributes.size <= max_attributes_per_link && Internal.valid_attributes?(link.attributes) }
|
332
|
+
links.all? { |link| link.attributes.size <= max_attributes_per_link && Internal.valid_attributes?(name, 'link', link.attributes) }
|
297
333
|
return links.frozen? ? links : links.clone.freeze
|
298
334
|
end
|
299
335
|
|
@@ -310,7 +346,7 @@ module OpenTelemetry
|
|
310
346
|
def append_event(events, event) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
311
347
|
max_events_count = @trace_config.max_events_count
|
312
348
|
max_attributes_per_event = @trace_config.max_attributes_per_event
|
313
|
-
valid_attributes = Internal.valid_attributes?(event.attributes)
|
349
|
+
valid_attributes = Internal.valid_attributes?(name, 'event', event.attributes)
|
314
350
|
|
315
351
|
# Fast path (likely) common case.
|
316
352
|
if events.size < max_events_count &&
|
@@ -329,10 +365,15 @@ module OpenTelemetry
|
|
329
365
|
attrs.keep_if { |key, value| Internal.valid_key?(key) && Internal.valid_value?(value) }
|
330
366
|
excess = attrs.size - max_attributes_per_event
|
331
367
|
excess.times { attrs.shift } if excess.positive?
|
332
|
-
event = Event.new(
|
368
|
+
event = Event.new(event.name, attrs.freeze, event.timestamp)
|
333
369
|
end
|
334
370
|
events << event
|
335
371
|
end
|
372
|
+
|
373
|
+
def wall_clock(timestamp)
|
374
|
+
timestamp = (timestamp.to_r * 1_000_000_000).to_i unless timestamp.nil?
|
375
|
+
timestamp || Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
|
376
|
+
end
|
336
377
|
end
|
337
378
|
# rubocop:enable Metrics/ClassLength
|
338
379
|
end
|