opentelemetry-sdk 0.13.1 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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