opentelemetry-sdk 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1 -0
- data/LICENSE +201 -0
- data/lib/opentelemetry/sdk.rb +18 -0
- data/lib/opentelemetry/sdk/internal.rb +32 -0
- data/lib/opentelemetry/sdk/resources.rb +15 -0
- data/lib/opentelemetry/sdk/resources/resource.rb +75 -0
- data/lib/opentelemetry/sdk/trace.rb +24 -0
- data/lib/opentelemetry/sdk/trace/config.rb +18 -0
- data/lib/opentelemetry/sdk/trace/config/trace_config.rb +77 -0
- data/lib/opentelemetry/sdk/trace/export.rb +35 -0
- data/lib/opentelemetry/sdk/trace/export/batch_span_processor.rb +149 -0
- data/lib/opentelemetry/sdk/trace/export/console_span_exporter.rb +40 -0
- data/lib/opentelemetry/sdk/trace/export/in_memory_span_exporter.rb +86 -0
- data/lib/opentelemetry/sdk/trace/export/multi_span_exporter.rb +64 -0
- data/lib/opentelemetry/sdk/trace/export/noop_span_exporter.rb +42 -0
- data/lib/opentelemetry/sdk/trace/export/simple_span_processor.rb +63 -0
- data/lib/opentelemetry/sdk/trace/multi_span_processor.rb +51 -0
- data/lib/opentelemetry/sdk/trace/noop_span_processor.rb +41 -0
- data/lib/opentelemetry/sdk/trace/samplers.rb +106 -0
- data/lib/opentelemetry/sdk/trace/samplers/decision.rb +26 -0
- data/lib/opentelemetry/sdk/trace/samplers/probability_sampler.rb +74 -0
- data/lib/opentelemetry/sdk/trace/samplers/result.rb +54 -0
- data/lib/opentelemetry/sdk/trace/span.rb +317 -0
- data/lib/opentelemetry/sdk/trace/span_data.rb +32 -0
- data/lib/opentelemetry/sdk/trace/tracer.rb +67 -0
- data/lib/opentelemetry/sdk/trace/tracer_factory.rb +84 -0
- data/lib/opentelemetry/sdk/version.rb +12 -0
- metadata +196 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019 OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Trace
|
10
|
+
# The Export module contains the built-in exporters for the OpenTelemetry
|
11
|
+
# reference implementation.
|
12
|
+
module Export
|
13
|
+
# Result codes for the SpanExporter#export method.
|
14
|
+
|
15
|
+
# The export operation finished successfully.
|
16
|
+
SUCCESS = 0
|
17
|
+
|
18
|
+
# The export operation finished with an error, but retrying may
|
19
|
+
# succeed.
|
20
|
+
FAILED_RETRYABLE = 1
|
21
|
+
|
22
|
+
# The export operation finished with an error, the caller should not
|
23
|
+
# try to export the same data again.
|
24
|
+
FAILED_NOT_RETRYABLE = 2
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'opentelemetry/sdk/trace/export/batch_span_processor'
|
31
|
+
require 'opentelemetry/sdk/trace/export/console_span_exporter'
|
32
|
+
require 'opentelemetry/sdk/trace/export/in_memory_span_exporter'
|
33
|
+
require 'opentelemetry/sdk/trace/export/multi_span_exporter'
|
34
|
+
require 'opentelemetry/sdk/trace/export/noop_span_exporter'
|
35
|
+
require 'opentelemetry/sdk/trace/export/simple_span_processor'
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019 OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
require 'timeout'
|
8
|
+
|
9
|
+
module OpenTelemetry
|
10
|
+
module SDK
|
11
|
+
module Trace
|
12
|
+
module Export
|
13
|
+
# Implementation of the duck type SpanProcessor that batches spans
|
14
|
+
# exported by the SDK then pushes them to the exporter pipeline.
|
15
|
+
#
|
16
|
+
# All spans reported by the SDK implementation are first added to a
|
17
|
+
# synchronized queue (with a {max_queue_size} maximum size, after the
|
18
|
+
# size is reached spans are dropped) and exported every
|
19
|
+
# schedule_delay_millis to the exporter pipeline in batches of
|
20
|
+
# max_export_batch_size.
|
21
|
+
#
|
22
|
+
# If the queue gets half full a preemptive notification is sent to the
|
23
|
+
# worker thread that exports the spans to wake up and start a new
|
24
|
+
# export cycle.
|
25
|
+
#
|
26
|
+
# max_export_attempts attempts are made to export each batch, while
|
27
|
+
# export fails with {FAILED_RETRYABLE}, backing off linearly in 100ms
|
28
|
+
# increments.
|
29
|
+
class BatchSpanProcessor
|
30
|
+
EXPORTER_TIMEOUT_MILLIS = 30_000
|
31
|
+
SCHEDULE_DELAY_MILLIS = 5_000
|
32
|
+
MAX_QUEUE_SIZE = 2048
|
33
|
+
MAX_EXPORT_BATCH_SIZE = 512
|
34
|
+
MAX_EXPORT_ATTEMPTS = 5
|
35
|
+
private_constant(:SCHEDULE_DELAY_MILLIS, :MAX_QUEUE_SIZE, :MAX_EXPORT_BATCH_SIZE, :MAX_EXPORT_ATTEMPTS)
|
36
|
+
|
37
|
+
def initialize(exporter:,
|
38
|
+
exporter_timeout_millis: EXPORTER_TIMEOUT_MILLIS,
|
39
|
+
schedule_delay_millis: SCHEDULE_DELAY_MILLIS,
|
40
|
+
max_queue_size: MAX_QUEUE_SIZE,
|
41
|
+
max_export_batch_size: MAX_EXPORT_BATCH_SIZE,
|
42
|
+
max_export_attempts: MAX_EXPORT_ATTEMPTS)
|
43
|
+
raise ArgumentError if max_export_batch_size > max_queue_size
|
44
|
+
|
45
|
+
@exporter = exporter
|
46
|
+
@exporter_timeout_seconds = exporter_timeout_millis / 1000.0
|
47
|
+
@mutex = Mutex.new
|
48
|
+
@condition = ConditionVariable.new
|
49
|
+
@keep_running = true
|
50
|
+
@delay_seconds = schedule_delay_millis / 1000.0
|
51
|
+
@max_queue_size = max_queue_size
|
52
|
+
@batch_size = max_export_batch_size
|
53
|
+
@export_attempts = max_export_attempts
|
54
|
+
@spans = []
|
55
|
+
@thread = Thread.new { work }
|
56
|
+
end
|
57
|
+
|
58
|
+
# does nothing for this processor
|
59
|
+
def on_start(span)
|
60
|
+
# noop
|
61
|
+
end
|
62
|
+
|
63
|
+
# adds a span to the batcher, threadsafe may block on lock
|
64
|
+
def on_finish(span) # rubocop:disable Metrics/AbcSize
|
65
|
+
return unless span.context.trace_flags.sampled?
|
66
|
+
|
67
|
+
lock do
|
68
|
+
n = spans.size + 1 - max_queue_size
|
69
|
+
spans.shift(n) if n.positive?
|
70
|
+
spans << span
|
71
|
+
@condition.signal if spans.size > max_queue_size / 2
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# shuts the consumer thread down and flushes the current accumulated buffer
|
76
|
+
# will block until the thread is finished
|
77
|
+
def shutdown
|
78
|
+
lock do
|
79
|
+
@keep_running = false
|
80
|
+
@condition.signal
|
81
|
+
end
|
82
|
+
|
83
|
+
@thread.join
|
84
|
+
flush
|
85
|
+
@exporter.shutdown
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
attr_reader :spans, :max_queue_size, :batch_size
|
91
|
+
|
92
|
+
def work
|
93
|
+
loop do
|
94
|
+
batch = lock do
|
95
|
+
@condition.wait(@mutex, @delay_seconds) if spans.size < batch_size && @keep_running
|
96
|
+
@condition.wait(@mutex, @delay_seconds) while spans.empty? && @keep_running
|
97
|
+
return unless @keep_running
|
98
|
+
|
99
|
+
fetch_batch
|
100
|
+
end
|
101
|
+
|
102
|
+
export_batch(batch)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def export_batch(batch)
|
107
|
+
result_code = nil
|
108
|
+
@export_attempts.times do |attempts|
|
109
|
+
result_code = export_with_timeout(batch)
|
110
|
+
break unless result_code == FAILED_RETRYABLE
|
111
|
+
|
112
|
+
sleep(0.1 * attempts)
|
113
|
+
end
|
114
|
+
report_result(result_code, batch)
|
115
|
+
end
|
116
|
+
|
117
|
+
def export_with_timeout(batch)
|
118
|
+
Timeout.timeout(@exporter_timeout_seconds) { @exporter.export(batch) }
|
119
|
+
rescue Timeout::Error
|
120
|
+
FAILED_NOT_RETRYABLE
|
121
|
+
end
|
122
|
+
|
123
|
+
def report_result(result_code, batch)
|
124
|
+
OpenTelemetry.logger.error("Unable to export #{batch.size} spans") unless result_code == SUCCESS
|
125
|
+
end
|
126
|
+
|
127
|
+
def flush
|
128
|
+
snapshot = lock { spans.shift(spans.size) }
|
129
|
+
until snapshot.empty?
|
130
|
+
batch = snapshot.shift(@batch_size).map!(&:to_span_data)
|
131
|
+
result_code = @exporter.export(batch)
|
132
|
+
report_result(result_code, batch)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def fetch_batch
|
137
|
+
spans.shift(@batch_size).map!(&:to_span_data)
|
138
|
+
end
|
139
|
+
|
140
|
+
def lock
|
141
|
+
@mutex.synchronize do
|
142
|
+
yield
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019 OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
module OpenTelemetry
|
10
|
+
module SDK
|
11
|
+
module Trace
|
12
|
+
module Export
|
13
|
+
# Outputs {SpanData} to the console.
|
14
|
+
#
|
15
|
+
# Potentially useful for exploratory purposes.
|
16
|
+
class ConsoleSpanExporter
|
17
|
+
ResultCodes = OpenTelemetry::SDK::Trace::Export
|
18
|
+
|
19
|
+
private_constant(:ResultCodes)
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@stopped = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def export(spans)
|
26
|
+
return ResultCodes::FAILED_NOT_RETRYABLE if @stopped
|
27
|
+
|
28
|
+
Array(spans).each { |s| pp s }
|
29
|
+
|
30
|
+
ResultCodes::SUCCESS
|
31
|
+
end
|
32
|
+
|
33
|
+
def shutdown
|
34
|
+
@stopped = true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019 OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Trace
|
10
|
+
module Export
|
11
|
+
# A SpanExporter implementation that can be used to test OpenTelemetry integration.
|
12
|
+
#
|
13
|
+
# Example usage:
|
14
|
+
#
|
15
|
+
# class MyClassTest
|
16
|
+
# def setup
|
17
|
+
# @tracer_factory = TracerFactory.new
|
18
|
+
# @exporter = InMemorySpanExporter.new
|
19
|
+
# @tracer_factory.add_span_processor(SimpleSampledSpansProcessor.new(@exporter))
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# def test_finished_spans
|
23
|
+
# @tracer_factory.tracer.in_span("span") {}
|
24
|
+
#
|
25
|
+
# spans = @exporter.finished_spans
|
26
|
+
# spans.wont_be_nil
|
27
|
+
# spans.size.must_equal(1)
|
28
|
+
# spans[0].name.must_equal("span")
|
29
|
+
# end
|
30
|
+
class InMemorySpanExporter
|
31
|
+
# Returns a new instance of the {InMemorySpanExporter}.
|
32
|
+
#
|
33
|
+
# @return a new instance of the {InMemorySpanExporter}.
|
34
|
+
def initialize
|
35
|
+
@finished_spans = []
|
36
|
+
@stopped = false
|
37
|
+
@mutex = Mutex.new
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a frozen array of the finished {SpanData}s, represented by
|
41
|
+
# {io.opentelemetry.proto.trace.v1.Span}.
|
42
|
+
#
|
43
|
+
# @return [Array<SpanData>] a frozen array of the finished {SpanData}s.
|
44
|
+
def finished_spans
|
45
|
+
@mutex.synchronize do
|
46
|
+
@finished_spans.clone.freeze
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Clears the internal collection of finished {Span}s.
|
51
|
+
#
|
52
|
+
# Does not reset the state of this exporter if already shutdown.
|
53
|
+
def reset
|
54
|
+
@mutex.synchronize do
|
55
|
+
@finished_spans.clear
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Called to export sampled {SpanData}s.
|
60
|
+
#
|
61
|
+
# @param [Enumerable<SpanData>] span_datas the list of sampled {SpanData}s to be
|
62
|
+
# exported.
|
63
|
+
# @return [Integer] the result of the export, SUCCESS or
|
64
|
+
# FAILED_NOT_RETRYABLE
|
65
|
+
def export(span_datas)
|
66
|
+
@mutex.synchronize do
|
67
|
+
return FAILED_NOT_RETRYABLE if @stopped
|
68
|
+
|
69
|
+
@finished_spans.concat(span_datas.to_a)
|
70
|
+
end
|
71
|
+
SUCCESS
|
72
|
+
end
|
73
|
+
|
74
|
+
# Called when {TracerFactory#shutdown} is called, if this exporter is
|
75
|
+
# registered to a {TracerFactory} object.
|
76
|
+
def shutdown
|
77
|
+
@mutex.synchronize do
|
78
|
+
@finished_spans.clear
|
79
|
+
@stopped = true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019 OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Trace
|
10
|
+
module Export
|
11
|
+
# Implementation of the SpanExporter duck type that simply forwards all
|
12
|
+
# received spans to a collection of SpanExporters.
|
13
|
+
#
|
14
|
+
# Can be used to export to multiple backends using the same
|
15
|
+
# SpanProcessor like a {SimpleSpanProcessor} or a
|
16
|
+
# {BatchSpanProcessor}.
|
17
|
+
class MultiSpanExporter
|
18
|
+
def initialize(span_exporters)
|
19
|
+
@span_exporters = span_exporters.clone.freeze
|
20
|
+
end
|
21
|
+
|
22
|
+
# Called to export sampled {Span}s.
|
23
|
+
#
|
24
|
+
# @param [Enumerable<Span>] spans the list of sampled {Span}s to be
|
25
|
+
# exported.
|
26
|
+
# @return [Integer] the result of the export.
|
27
|
+
def export(spans)
|
28
|
+
@span_exporters.inject(SUCCESS) do |result_code, span_exporter|
|
29
|
+
begin
|
30
|
+
merge_result_code(result_code, span_exporter.export(spans))
|
31
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
32
|
+
OpenTelemetry.logger.warn("exception raised by export - #{e}")
|
33
|
+
FAILED_NOT_RETRYABLE
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Called when {TracerFactory#shutdown} is called, if this exporter is
|
39
|
+
# registered to a {TracerFactory} object.
|
40
|
+
def shutdown
|
41
|
+
@span_exporters.each(&:shutdown)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Returns a merged error code, see the rules in the code.
|
47
|
+
def merge_result_code(result_code, new_result_code)
|
48
|
+
if result_code == SUCCESS && new_result_code == SUCCESS
|
49
|
+
# If both errors are success then return success.
|
50
|
+
SUCCESS
|
51
|
+
elsif result_code == FAILED_NOT_RETRYABLE || new_result_code == FAILED_NOT_RETRYABLE
|
52
|
+
# If any of the codes is not retryable then return not_retryable.
|
53
|
+
FAILED_NOT_RETRYABLE
|
54
|
+
else
|
55
|
+
# At this point at least one of the code is FAILED_RETRYABLE and
|
56
|
+
# none are FAILED_NOT_RETRYABLE, so return FAILED_RETRYABLE.
|
57
|
+
FAILED_RETRYABLE
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019 OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Trace
|
10
|
+
module Export
|
11
|
+
# A noop exporter that demonstrates and documents the SpanExporter
|
12
|
+
# duck type. SpanExporter allows different tracing services to export
|
13
|
+
# recorded data for sampled spans in their own format.
|
14
|
+
#
|
15
|
+
# To export data an exporter MUST be registered to the {TracerFactory} using
|
16
|
+
# a {SimpleSpanProcessor} or a {BatchSpanProcessor}.
|
17
|
+
class NoopSpanExporter
|
18
|
+
def initialize
|
19
|
+
@stopped = false
|
20
|
+
end
|
21
|
+
|
22
|
+
# Called to export sampled {Span}s.
|
23
|
+
#
|
24
|
+
# @param [Enumerable<Span>] spans the list of sampled {Span}s to be
|
25
|
+
# exported.
|
26
|
+
# @return [Integer] the result of the export.
|
27
|
+
def export(spans)
|
28
|
+
return SUCCESS unless @stopped
|
29
|
+
|
30
|
+
FAILED_NOT_RETRYABLE
|
31
|
+
end
|
32
|
+
|
33
|
+
# Called when {TracerFactory#shutdown} is called, if this exporter is
|
34
|
+
# registered to a {TracerFactory} object.
|
35
|
+
def shutdown
|
36
|
+
@stopped = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019 OpenTelemetry Authors
|
4
|
+
#
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
|
7
|
+
module OpenTelemetry
|
8
|
+
module SDK
|
9
|
+
module Trace
|
10
|
+
module Export
|
11
|
+
# An implementation of the duck type SpanProcessor that converts the
|
12
|
+
# {Span} to {io.opentelemetry.proto.trace.v1.Span} and passes it to the
|
13
|
+
# configured exporter.
|
14
|
+
#
|
15
|
+
# Only spans that are recorded are converted, {OpenTelemetry::Trace::Span#is_recording?} must
|
16
|
+
# return true.
|
17
|
+
class SimpleSpanProcessor
|
18
|
+
# Returns a new {SimpleSpanProcessor} that converts spans to
|
19
|
+
# proto and forwards them to the given span_exporter.
|
20
|
+
#
|
21
|
+
# @param span_exporter the (duck type) SpanExporter to where the
|
22
|
+
# recorded Spans are pushed.
|
23
|
+
# @return [SimpleSpanProcessor]
|
24
|
+
# @raise ArgumentError if the span_exporter is nil.
|
25
|
+
def initialize(span_exporter)
|
26
|
+
@span_exporter = span_exporter
|
27
|
+
end
|
28
|
+
|
29
|
+
# Called when a {Span} is started, if the {Span#recording?}
|
30
|
+
# returns true.
|
31
|
+
#
|
32
|
+
# This method is called synchronously on the execution thread, should
|
33
|
+
# not throw or block the execution thread.
|
34
|
+
#
|
35
|
+
# @param [Span] span the {Span} that just started.
|
36
|
+
def on_start(span)
|
37
|
+
# Do nothing.
|
38
|
+
end
|
39
|
+
|
40
|
+
# Called when a {Span} is ended, if the {Span#recording?}
|
41
|
+
# returns true.
|
42
|
+
#
|
43
|
+
# This method is called synchronously on the execution thread, should
|
44
|
+
# not throw or block the execution thread.
|
45
|
+
#
|
46
|
+
# @param [Span] span the {Span} that just ended.
|
47
|
+
def on_finish(span)
|
48
|
+
return unless span.context.trace_flags.sampled?
|
49
|
+
|
50
|
+
@span_exporter&.export([span.to_span_data])
|
51
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
52
|
+
OpenTelemetry.logger.error("unexpected error in span.on_finish - #{e}")
|
53
|
+
end
|
54
|
+
|
55
|
+
# Called when {TracerFactory#shutdown} is called.
|
56
|
+
def shutdown
|
57
|
+
@span_exporter&.shutdown
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|