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.
@@ -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', 1000)),
37
- max_events_count: Integer(ENV.fetch('OTEL_SPAN_EVENT_COUNT_LIMIT', 1000)),
38
- max_links_count: Integer(ENV.fetch('OTEL_SPAN_LINK_COUNT_LIMIT', 1000)),
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['OTEL_TRACE_SAMPLER']
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('OTEL_TRACE_SAMPLER_ARG', 1.0)))
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('OTEL_TRACE_SAMPLER_ARG', 1.0))))
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
- class Event
12
- EMPTY_ATTRIBUTES = {}.freeze
13
-
14
- private_constant :EMPTY_ATTRIBUTES
15
-
16
- # Returns the name of this event
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 = Time.now
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
- SUCCESS
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 = Time.now
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)
@@ -26,6 +26,10 @@ module OpenTelemetry
26
26
  SUCCESS
27
27
  end
28
28
 
29
+ def force_flush(timeout: nil)
30
+ SUCCESS
31
+ end
32
+
29
33
  def shutdown(timeout: nil)
30
34
  @stopped = true
31
35
  SUCCESS
@@ -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
- # @exporter = InMemorySpanExporter.new
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 = Time.now
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 = Time.now
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 = Time.now
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 = Time.now
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(:DEFAULT_STATUS)
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
- super
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 || Time.now
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(name: event.name, attributes: attrs, timestamp: event.timestamp)
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