opentelemetry-sdk 0.16.0 → 1.0.0.rc3
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 +133 -61
- data/README.md +25 -2
- data/lib/opentelemetry/sdk.rb +5 -3
- data/lib/opentelemetry/sdk/configurator.rb +54 -43
- data/lib/opentelemetry/sdk/forwarding_logger.rb +69 -0
- data/lib/opentelemetry/sdk/internal.rb +3 -3
- data/lib/opentelemetry/sdk/resources.rb +0 -1
- data/lib/opentelemetry/sdk/resources/resource.rb +16 -9
- data/lib/opentelemetry/sdk/trace.rb +2 -3
- data/lib/opentelemetry/sdk/trace/event.rb +7 -36
- data/lib/opentelemetry/sdk/trace/export.rb +3 -2
- data/lib/opentelemetry/sdk/trace/export/batch_span_processor.rb +4 -3
- data/lib/opentelemetry/sdk/trace/export/in_memory_span_exporter.rb +13 -4
- data/lib/opentelemetry/sdk/trace/export/simple_span_processor.rb +2 -0
- data/lib/opentelemetry/sdk/trace/export/{noop_span_exporter.rb → span_exporter.rb} +8 -7
- data/lib/opentelemetry/sdk/trace/span.rb +55 -39
- data/lib/opentelemetry/sdk/trace/span_data.rb +25 -18
- data/lib/opentelemetry/sdk/trace/span_limits.rb +60 -0
- data/lib/opentelemetry/sdk/trace/{noop_span_processor.rb → span_processor.rb} +5 -8
- data/lib/opentelemetry/sdk/trace/tracer.rb +1 -37
- data/lib/opentelemetry/sdk/trace/tracer_provider.rb +89 -19
- data/lib/opentelemetry/sdk/version.rb +1 -1
- metadata +74 -24
- 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
- data/lib/opentelemetry/sdk/resources/constants.rb +0 -205
- data/lib/opentelemetry/sdk/trace/config.rb +0 -18
- data/lib/opentelemetry/sdk/trace/config/trace_config.rb +0 -79
- data/lib/opentelemetry/sdk/trace/export/multi_span_exporter.rb +0 -76
- data/lib/opentelemetry/sdk/trace/multi_span_processor.rb +0 -86
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module OpenTelemetry
|
6
|
+
module SDK
|
7
|
+
# The ForwardingLogger provides a wrapper to control the OpenTelemetry
|
8
|
+
# log level, while respecting the configured level of the supplied logger.
|
9
|
+
# If the OTEL_LOG_LEVEL is set to debug, and the supplied logger is configured
|
10
|
+
# with an ERROR log level, only OpenTelemetry logs at the ERROR level or higher
|
11
|
+
# will be emitted.
|
12
|
+
class ForwardingLogger
|
13
|
+
def initialize(logger, level:) # rubocop:disable Metrics/CyclomaticComplexity
|
14
|
+
@logger = logger
|
15
|
+
|
16
|
+
if level.is_a?(Integer)
|
17
|
+
@level = level
|
18
|
+
else
|
19
|
+
case level.to_s.downcase
|
20
|
+
when 'debug'
|
21
|
+
@level = Logger::DEBUG
|
22
|
+
when 'info'
|
23
|
+
@level = Logger::INFO
|
24
|
+
when 'warn'
|
25
|
+
@level = Logger::WARN
|
26
|
+
when 'error'
|
27
|
+
@level = Logger::ERROR
|
28
|
+
when 'fatal'
|
29
|
+
@level = Logger::FATAL
|
30
|
+
when 'unknown'
|
31
|
+
@level = Logger::UNKNOWN
|
32
|
+
else
|
33
|
+
raise ArgumentError, "invalid log level: #{level}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add(severity, message = nil, progname = nil)
|
39
|
+
return true if severity < @level
|
40
|
+
|
41
|
+
@logger.add(severity, message, progname)
|
42
|
+
end
|
43
|
+
|
44
|
+
def debug(progname = nil, &block)
|
45
|
+
add(Logger::DEBUG, nil, progname, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def info(progname = nil, &block)
|
49
|
+
add(Logger::INFO, nil, progname, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
def warn(progname = nil, &block)
|
53
|
+
add(Logger::WARN, nil, progname, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def error(progname = nil, &block)
|
57
|
+
add(Logger::ERROR, nil, progname, &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
def fatal(progname = nil, &block)
|
61
|
+
add(Logger::FATAL, nil, progname, &block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def unknown(progname = nil, &block)
|
65
|
+
add(Logger::UNKNOWN, nil, progname, &block)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -44,13 +44,13 @@ module OpenTelemetry
|
|
44
44
|
valid_simple_value?(value) || valid_array_value?(value)
|
45
45
|
end
|
46
46
|
|
47
|
-
def valid_attributes?(attrs)
|
47
|
+
def valid_attributes?(owner, kind, attrs)
|
48
48
|
attrs.nil? || attrs.all? do |k, v|
|
49
49
|
if !valid_key?(k)
|
50
|
-
OpenTelemetry.handle_error(message: "invalid attribute key type #{
|
50
|
+
OpenTelemetry.handle_error(message: "invalid #{kind} attribute key type #{k.class} on span '#{owner}'")
|
51
51
|
false
|
52
52
|
elsif !valid_value?(v)
|
53
|
-
OpenTelemetry.handle_error(message: "invalid attribute value type #{v.class}")
|
53
|
+
OpenTelemetry.handle_error(message: "invalid #{kind} attribute value type #{v.class} for key '#{k}' on span '#{owner}'")
|
54
54
|
false
|
55
55
|
else
|
56
56
|
true
|
@@ -31,14 +31,14 @@ module OpenTelemetry
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def default
|
34
|
-
@default ||= create(
|
34
|
+
@default ||= create(SemanticConventions::Resource::SERVICE_NAME => 'unknown_service').merge(process).merge(telemetry_sdk).merge(service_name_from_env)
|
35
35
|
end
|
36
36
|
|
37
37
|
def telemetry_sdk
|
38
38
|
resource_attributes = {
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
SemanticConventions::Resource::TELEMETRY_SDK_NAME => 'opentelemetry',
|
40
|
+
SemanticConventions::Resource::TELEMETRY_SDK_LANGUAGE => 'ruby',
|
41
|
+
SemanticConventions::Resource::TELEMETRY_SDK_VERSION => OpenTelemetry::SDK::VERSION
|
42
42
|
}
|
43
43
|
|
44
44
|
resource_pairs = ENV['OTEL_RESOURCE_ATTRIBUTES']
|
@@ -55,15 +55,22 @@ module OpenTelemetry
|
|
55
55
|
|
56
56
|
def process
|
57
57
|
resource_attributes = {
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
SemanticConventions::Resource::PROCESS_PID => Process.pid,
|
59
|
+
SemanticConventions::Resource::PROCESS_COMMAND => $PROGRAM_NAME,
|
60
|
+
SemanticConventions::Resource::PROCESS_RUNTIME_NAME => RUBY_ENGINE,
|
61
|
+
SemanticConventions::Resource::PROCESS_RUNTIME_VERSION => RUBY_VERSION,
|
62
|
+
SemanticConventions::Resource::PROCESS_RUNTIME_DESCRIPTION => RUBY_DESCRIPTION
|
63
63
|
}
|
64
64
|
|
65
65
|
create(resource_attributes)
|
66
66
|
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def service_name_from_env
|
71
|
+
service_name = ENV['OTEL_SERVICE_NAME']
|
72
|
+
create(SemanticConventions::Resource::SERVICE_NAME => service_name) unless service_name.nil?
|
73
|
+
end
|
67
74
|
end
|
68
75
|
|
69
76
|
# @api private
|
@@ -14,12 +14,11 @@ module OpenTelemetry
|
|
14
14
|
end
|
15
15
|
|
16
16
|
require 'opentelemetry/sdk/trace/samplers'
|
17
|
-
require 'opentelemetry/sdk/trace/
|
17
|
+
require 'opentelemetry/sdk/trace/span_limits'
|
18
18
|
require 'opentelemetry/sdk/trace/event'
|
19
19
|
require 'opentelemetry/sdk/trace/export'
|
20
|
-
require 'opentelemetry/sdk/trace/multi_span_processor'
|
21
|
-
require 'opentelemetry/sdk/trace/noop_span_processor'
|
22
20
|
require 'opentelemetry/sdk/trace/span_data'
|
21
|
+
require 'opentelemetry/sdk/trace/span_processor'
|
23
22
|
require 'opentelemetry/sdk/trace/span'
|
24
23
|
require 'opentelemetry/sdk/trace/tracer'
|
25
24
|
require 'opentelemetry/sdk/trace/tracer_provider'
|
@@ -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
|
@@ -10,6 +10,8 @@ module OpenTelemetry
|
|
10
10
|
# The Export module contains the built-in exporters and span processors for the OpenTelemetry
|
11
11
|
# reference implementation.
|
12
12
|
module Export
|
13
|
+
ExportError = Class.new(OpenTelemetry::Error)
|
14
|
+
|
13
15
|
# Result codes for the SpanExporter#export method and the SpanProcessor#force_flush and SpanProcessor#shutdown methods.
|
14
16
|
|
15
17
|
# The operation finished successfully.
|
@@ -31,6 +33,5 @@ require 'opentelemetry/sdk/trace/export/batch_span_processor'
|
|
31
33
|
require 'opentelemetry/sdk/trace/export/console_span_exporter'
|
32
34
|
require 'opentelemetry/sdk/trace/export/in_memory_span_exporter'
|
33
35
|
require 'opentelemetry/sdk/trace/export/metrics_reporter'
|
34
|
-
require 'opentelemetry/sdk/trace/export/
|
35
|
-
require 'opentelemetry/sdk/trace/export/noop_span_exporter'
|
36
|
+
require 'opentelemetry/sdk/trace/export/span_exporter'
|
36
37
|
require 'opentelemetry/sdk/trace/export/simple_span_processor'
|
@@ -52,6 +52,7 @@ module OpenTelemetry
|
|
52
52
|
start_thread_on_boot: String(ENV['OTEL_RUBY_BSP_START_THREAD_ON_BOOT']) !~ /false/i,
|
53
53
|
metrics_reporter: nil)
|
54
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)
|
55
56
|
|
56
57
|
@exporter = exporter
|
57
58
|
@exporter_timeout_seconds = exporter_timeout / 1000.0
|
@@ -100,7 +101,7 @@ module OpenTelemetry
|
|
100
101
|
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
101
102
|
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
102
103
|
def force_flush(timeout: nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
103
|
-
start_time =
|
104
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
104
105
|
snapshot = lock do
|
105
106
|
reset_on_fork if @keep_running
|
106
107
|
spans.shift(spans.size)
|
@@ -136,7 +137,7 @@ module OpenTelemetry
|
|
136
137
|
# @return [Integer] SUCCESS if no error occurred, FAILURE if a
|
137
138
|
# non-specific failure occurred, TIMEOUT if a timeout occurred.
|
138
139
|
def shutdown(timeout: nil)
|
139
|
-
start_time =
|
140
|
+
start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
|
140
141
|
thread = lock do
|
141
142
|
@keep_running = false
|
142
143
|
@condition.signal
|
@@ -193,7 +194,7 @@ module OpenTelemetry
|
|
193
194
|
@metrics_reporter.add_to_counter('otel.bsp.export.success')
|
194
195
|
@metrics_reporter.add_to_counter('otel.bsp.exported_spans', increment: batch.size)
|
195
196
|
else
|
196
|
-
OpenTelemetry.handle_error(
|
197
|
+
OpenTelemetry.handle_error(exception: ExportError.new("Unable to export #{batch.size} spans"))
|
197
198
|
@metrics_reporter.add_to_counter('otel.bsp.export.failure')
|
198
199
|
report_dropped_spans(batch.size, reason: 'export-failure')
|
199
200
|
end
|
@@ -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,7 +76,7 @@ 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
|
@@ -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
|
|
@@ -8,24 +8,25 @@ module OpenTelemetry
|
|
8
8
|
module SDK
|
9
9
|
module Trace
|
10
10
|
module Export
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# SpanExporter describes a duck type. It is not required to subclass this
|
12
|
+
# class to provide an implementation of SpanExporter, provided the interface is
|
13
|
+
# satisfied. SpanExporter allows different tracing services to export
|
13
14
|
# recorded data for sampled spans in their own format.
|
14
15
|
#
|
15
16
|
# To export data an exporter MUST be registered to the {TracerProvider} using
|
16
|
-
# a {
|
17
|
-
class
|
17
|
+
# a {SpanProcessor} implementation.
|
18
|
+
class SpanExporter
|
18
19
|
def initialize
|
19
20
|
@stopped = false
|
20
21
|
end
|
21
22
|
|
22
|
-
# Called to export sampled {
|
23
|
+
# Called to export sampled {SpanData}s.
|
23
24
|
#
|
24
|
-
# @param [Enumerable<
|
25
|
+
# @param [Enumerable<SpanData>] span_data the list of sampled {SpanData} to be
|
25
26
|
# exported.
|
26
27
|
# @param [optional Numeric] timeout An optional timeout in seconds.
|
27
28
|
# @return [Integer] the result of the export.
|
28
|
-
def export(
|
29
|
+
def export(span_data, timeout: nil)
|
29
30
|
return SUCCESS unless @stopped
|
30
31
|
|
31
32
|
FAILURE
|
@@ -10,15 +10,16 @@ module OpenTelemetry
|
|
10
10
|
# Implementation of {OpenTelemetry::Trace::Span} that records trace events.
|
11
11
|
#
|
12
12
|
# This implementation includes reader methods intended to allow access to
|
13
|
-
# internal state by
|
13
|
+
# internal state by {SpanProcessor}s.
|
14
14
|
# Instrumentation should use the API provided by {OpenTelemetry::Trace::Span}
|
15
15
|
# and should consider {Span} to be write-only.
|
16
16
|
#
|
17
17
|
# rubocop:disable Metrics/ClassLength
|
18
18
|
class Span < OpenTelemetry::Trace::Span
|
19
|
-
DEFAULT_STATUS = OpenTelemetry::Trace::Status.
|
19
|
+
DEFAULT_STATUS = 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.
|
@@ -70,7 +71,6 @@ module OpenTelemetry
|
|
70
71
|
#
|
71
72
|
# @return [self] returns itself
|
72
73
|
def set_attribute(key, value)
|
73
|
-
super
|
74
74
|
@mutex.synchronize do
|
75
75
|
if @ended
|
76
76
|
OpenTelemetry.logger.warn('Calling set_attribute on an ended Span.')
|
@@ -99,7 +99,6 @@ module OpenTelemetry
|
|
99
99
|
#
|
100
100
|
# @return [self] returns itself
|
101
101
|
def add_attributes(attributes)
|
102
|
-
super
|
103
102
|
@mutex.synchronize do
|
104
103
|
if @ended
|
105
104
|
OpenTelemetry.logger.warn('Calling add_attributes on an ended Span.')
|
@@ -132,8 +131,7 @@ module OpenTelemetry
|
|
132
131
|
#
|
133
132
|
# @return [self] returns itself
|
134
133
|
def add_event(name, attributes: nil, timestamp: nil)
|
135
|
-
|
136
|
-
event = Event.new(name: name, attributes: attributes, timestamp: timestamp || Time.now)
|
134
|
+
event = Event.new(name, truncate_attribute_values(attributes), wall_clock(timestamp))
|
137
135
|
|
138
136
|
@mutex.synchronize do
|
139
137
|
if @ended
|
@@ -161,7 +159,7 @@ module OpenTelemetry
|
|
161
159
|
event_attributes = {
|
162
160
|
'exception.type' => exception.class.to_s,
|
163
161
|
'exception.message' => exception.message,
|
164
|
-
'exception.stacktrace' => exception.full_message(highlight: false, order: :top)
|
162
|
+
'exception.stacktrace' => exception.full_message(highlight: false, order: :top).encode('UTF-8', invalid: :replace, undef: :replace, replace: '�')
|
165
163
|
}
|
166
164
|
event_attributes.merge!(attributes) unless attributes.nil?
|
167
165
|
add_event('exception', attributes: event_attributes)
|
@@ -169,21 +167,23 @@ module OpenTelemetry
|
|
169
167
|
|
170
168
|
# Sets the Status to the Span
|
171
169
|
#
|
172
|
-
# If used, this will override the default Span status. Default
|
170
|
+
# If used, this will override the default Span status. Default has code = Status::UNSET.
|
173
171
|
#
|
174
|
-
#
|
175
|
-
#
|
172
|
+
# An attempt to set the status with code == Status::UNSET is ignored.
|
173
|
+
# If the status is set with code == Status::OK, any further attempt to set the status
|
174
|
+
# is ignored.
|
176
175
|
#
|
177
176
|
# @param [Status] status The new status, which overrides the default Span
|
178
|
-
# status, which
|
177
|
+
# status, which has code = Status::UNSET.
|
179
178
|
#
|
180
179
|
# @return [void]
|
181
180
|
def status=(status)
|
182
|
-
|
181
|
+
return if status.code == OpenTelemetry::Trace::Status::UNSET
|
182
|
+
|
183
183
|
@mutex.synchronize do
|
184
184
|
if @ended
|
185
185
|
OpenTelemetry.logger.warn('Calling status= on an ended Span.')
|
186
|
-
|
186
|
+
elsif @status.code != OpenTelemetry::Trace::Status::OK
|
187
187
|
@status = status
|
188
188
|
end
|
189
189
|
end
|
@@ -199,7 +199,6 @@ module OpenTelemetry
|
|
199
199
|
#
|
200
200
|
# @return [void]
|
201
201
|
def name=(new_name)
|
202
|
-
super
|
203
202
|
@mutex.synchronize do
|
204
203
|
if @ended
|
205
204
|
OpenTelemetry.logger.warn('Calling name= on an ended Span.')
|
@@ -234,12 +233,12 @@ module OpenTelemetry
|
|
234
233
|
OpenTelemetry.logger.warn('Calling finish on an ended Span.')
|
235
234
|
return self
|
236
235
|
end
|
237
|
-
@end_timestamp = end_timestamp
|
236
|
+
@end_timestamp = wall_clock(end_timestamp)
|
238
237
|
@attributes = validated_attributes(@attributes).freeze
|
239
238
|
@events.freeze
|
240
239
|
@ended = true
|
241
240
|
end
|
242
|
-
@
|
241
|
+
@span_processors.each { |processor| processor.on_finish(self) }
|
243
242
|
self
|
244
243
|
end
|
245
244
|
|
@@ -277,14 +276,14 @@ module OpenTelemetry
|
|
277
276
|
end
|
278
277
|
|
279
278
|
# @api private
|
280
|
-
def initialize(context, parent_context, name, kind, parent_span_id,
|
279
|
+
def initialize(context, parent_context, name, kind, parent_span_id, span_limits, span_processors, attributes, links, start_timestamp, resource, instrumentation_library) # rubocop:disable Metrics/AbcSize
|
281
280
|
super(span_context: context)
|
282
281
|
@mutex = Mutex.new
|
283
282
|
@name = name
|
284
283
|
@kind = kind
|
285
284
|
@parent_span_id = parent_span_id.freeze || OpenTelemetry::Trace::INVALID_SPAN_ID
|
286
|
-
@
|
287
|
-
@
|
285
|
+
@span_limits = span_limits
|
286
|
+
@span_processors = span_processors
|
288
287
|
@resource = resource
|
289
288
|
@instrumentation_library = instrumentation_library
|
290
289
|
@ended = false
|
@@ -292,13 +291,13 @@ module OpenTelemetry
|
|
292
291
|
@total_recorded_events = 0
|
293
292
|
@total_recorded_links = links&.size || 0
|
294
293
|
@total_recorded_attributes = attributes&.size || 0
|
295
|
-
@start_timestamp = start_timestamp
|
294
|
+
@start_timestamp = wall_clock(start_timestamp)
|
296
295
|
@end_timestamp = nil
|
297
296
|
@attributes = attributes.nil? ? nil : Hash[attributes] # We need a mutable copy of attributes.
|
298
297
|
trim_span_attributes(@attributes)
|
299
298
|
@events = nil
|
300
|
-
@links = trim_links(links,
|
301
|
-
@
|
299
|
+
@links = trim_links(links, span_limits.link_count_limit, span_limits.link_attribute_count_limit)
|
300
|
+
@span_processors.each { |processor| processor.on_start(self, parent_context) }
|
302
301
|
end
|
303
302
|
|
304
303
|
# TODO: Java implementation overrides finalize to log if a span isn't finished.
|
@@ -306,7 +305,7 @@ module OpenTelemetry
|
|
306
305
|
private
|
307
306
|
|
308
307
|
def validated_attributes(attrs)
|
309
|
-
return attrs if Internal.valid_attributes?(attrs)
|
308
|
+
return attrs if Internal.valid_attributes?(name, 'span', attrs)
|
310
309
|
|
311
310
|
attrs.keep_if { |key, value| Internal.valid_key?(key) && Internal.valid_value?(value) }
|
312
311
|
end
|
@@ -314,56 +313,73 @@ module OpenTelemetry
|
|
314
313
|
def trim_span_attributes(attrs)
|
315
314
|
return if attrs.nil?
|
316
315
|
|
317
|
-
excess = attrs.size - @
|
316
|
+
excess = attrs.size - @span_limits.attribute_count_limit
|
318
317
|
excess.times { attrs.shift } if excess.positive?
|
318
|
+
truncate_attribute_values(attrs)
|
319
319
|
nil
|
320
320
|
end
|
321
321
|
|
322
|
-
def
|
322
|
+
def truncate_attribute_values(attrs)
|
323
|
+
return EMPTY_ATTRIBUTES if attrs.nil?
|
324
|
+
|
325
|
+
attribute_length_limit = @span_limits.attribute_length_limit
|
326
|
+
attrs.each { |key, value| attrs[key] = OpenTelemetry::Common::Utilities.truncate(value, attribute_length_limit) } if attribute_length_limit
|
327
|
+
attrs
|
328
|
+
end
|
329
|
+
|
330
|
+
def trim_links(links, link_count_limit, link_attribute_count_limit) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
323
331
|
# Fast path (likely) common cases.
|
324
332
|
return nil if links.nil?
|
325
333
|
|
326
|
-
if links.size <=
|
327
|
-
links.all? { |link| link.attributes.size <=
|
334
|
+
if links.size <= link_count_limit &&
|
335
|
+
links.all? { |link| link.span_context.valid? && link.attributes.size <= link_attribute_count_limit && Internal.valid_attributes?(name, 'link', link.attributes) }
|
328
336
|
return links.frozen? ? links : links.clone.freeze
|
329
337
|
end
|
330
338
|
|
331
339
|
# Slow path: trim attributes for each Link.
|
332
|
-
links.
|
340
|
+
valid_links = links.select { |link| link.span_context.valid? }
|
341
|
+
excess_link_count = valid_links.size - link_count_limit
|
342
|
+
valid_links.pop(excess_link_count) if excess_link_count.positive?
|
343
|
+
valid_links.map! do |link|
|
333
344
|
attrs = Hash[link.attributes] # link.attributes is frozen, so we need an unfrozen copy to adjust.
|
334
345
|
attrs.keep_if { |key, value| Internal.valid_key?(key) && Internal.valid_value?(value) }
|
335
|
-
excess = attrs.size -
|
346
|
+
excess = attrs.size - link_attribute_count_limit
|
336
347
|
excess.times { attrs.shift } if excess.positive?
|
337
348
|
OpenTelemetry::Trace::Link.new(link.span_context, attrs)
|
338
349
|
end.freeze
|
339
350
|
end
|
340
351
|
|
341
352
|
def append_event(events, event) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
342
|
-
|
343
|
-
|
344
|
-
valid_attributes = Internal.valid_attributes?(event.attributes)
|
353
|
+
event_count_limit = @span_limits.event_count_limit
|
354
|
+
event_attribute_count_limit = @span_limits.event_attribute_count_limit
|
355
|
+
valid_attributes = Internal.valid_attributes?(name, 'event', event.attributes)
|
345
356
|
|
346
357
|
# Fast path (likely) common case.
|
347
|
-
if events.size <
|
348
|
-
event.attributes.size <=
|
358
|
+
if events.size < event_count_limit &&
|
359
|
+
event.attributes.size <= event_attribute_count_limit &&
|
349
360
|
valid_attributes
|
350
361
|
return events << event
|
351
362
|
end
|
352
363
|
|
353
364
|
# Slow path.
|
354
|
-
excess = events.size + 1 -
|
365
|
+
excess = events.size + 1 - event_count_limit
|
355
366
|
events.shift(excess) if excess.positive?
|
356
367
|
|
357
|
-
excess = event.attributes.size -
|
368
|
+
excess = event.attributes.size - event_attribute_count_limit
|
358
369
|
if excess.positive? || !valid_attributes
|
359
370
|
attrs = Hash[event.attributes] # event.attributes is frozen, so we need an unfrozen copy to adjust.
|
360
371
|
attrs.keep_if { |key, value| Internal.valid_key?(key) && Internal.valid_value?(value) }
|
361
|
-
excess = attrs.size -
|
372
|
+
excess = attrs.size - event_attribute_count_limit
|
362
373
|
excess.times { attrs.shift } if excess.positive?
|
363
|
-
event = Event.new(
|
374
|
+
event = Event.new(event.name, attrs.freeze, event.timestamp)
|
364
375
|
end
|
365
376
|
events << event
|
366
377
|
end
|
378
|
+
|
379
|
+
def wall_clock(timestamp)
|
380
|
+
timestamp = (timestamp.to_r * 1_000_000_000).to_i unless timestamp.nil?
|
381
|
+
timestamp || Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
|
382
|
+
end
|
367
383
|
end
|
368
384
|
# rubocop:enable Metrics/ClassLength
|
369
385
|
end
|