opentelemetry-sdk 0.5.1

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/CHANGELOG.md +1 -0
  4. data/LICENSE +201 -0
  5. data/README.md +73 -0
  6. data/lib/opentelemetry-sdk.rb +7 -0
  7. data/lib/opentelemetry/sdk.rb +69 -0
  8. data/lib/opentelemetry/sdk/configurator.rb +171 -0
  9. data/lib/opentelemetry/sdk/correlation_context.rb +16 -0
  10. data/lib/opentelemetry/sdk/correlation_context/builder.rb +40 -0
  11. data/lib/opentelemetry/sdk/correlation_context/manager.rb +87 -0
  12. data/lib/opentelemetry/sdk/instrumentation_library.rb +13 -0
  13. data/lib/opentelemetry/sdk/internal.rb +52 -0
  14. data/lib/opentelemetry/sdk/resources.rb +16 -0
  15. data/lib/opentelemetry/sdk/resources/constants.rb +124 -0
  16. data/lib/opentelemetry/sdk/resources/resource.rb +84 -0
  17. data/lib/opentelemetry/sdk/trace.rb +24 -0
  18. data/lib/opentelemetry/sdk/trace/config.rb +18 -0
  19. data/lib/opentelemetry/sdk/trace/config/trace_config.rb +77 -0
  20. data/lib/opentelemetry/sdk/trace/export.rb +30 -0
  21. data/lib/opentelemetry/sdk/trace/export/batch_span_processor.rb +144 -0
  22. data/lib/opentelemetry/sdk/trace/export/console_span_exporter.rb +40 -0
  23. data/lib/opentelemetry/sdk/trace/export/in_memory_span_exporter.rb +86 -0
  24. data/lib/opentelemetry/sdk/trace/export/multi_span_exporter.rb +58 -0
  25. data/lib/opentelemetry/sdk/trace/export/noop_span_exporter.rb +42 -0
  26. data/lib/opentelemetry/sdk/trace/export/simple_span_processor.rb +72 -0
  27. data/lib/opentelemetry/sdk/trace/multi_span_processor.rb +62 -0
  28. data/lib/opentelemetry/sdk/trace/noop_span_processor.rb +50 -0
  29. data/lib/opentelemetry/sdk/trace/samplers.rb +90 -0
  30. data/lib/opentelemetry/sdk/trace/samplers/constant_sampler.rb +33 -0
  31. data/lib/opentelemetry/sdk/trace/samplers/decision.rb +26 -0
  32. data/lib/opentelemetry/sdk/trace/samplers/parent_or_else.rb +43 -0
  33. data/lib/opentelemetry/sdk/trace/samplers/probability_sampler.rb +64 -0
  34. data/lib/opentelemetry/sdk/trace/samplers/result.rb +55 -0
  35. data/lib/opentelemetry/sdk/trace/span.rb +336 -0
  36. data/lib/opentelemetry/sdk/trace/span_data.rb +34 -0
  37. data/lib/opentelemetry/sdk/trace/tracer.rb +78 -0
  38. data/lib/opentelemetry/sdk/trace/tracer_provider.rb +84 -0
  39. data/lib/opentelemetry/sdk/version.rb +12 -0
  40. metadata +207 -0
@@ -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 {TracerProvider} 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
+ FAILURE
31
+ end
32
+
33
+ # Called when {TracerProvider#shutdown} is called, if this exporter is
34
+ # registered to a {TracerProvider} object.
35
+ def shutdown
36
+ @stopped = true
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,72 @@
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
+ # Export all ended spans to the configured `Exporter` that have not yet
56
+ # been exported.
57
+ #
58
+ # This method should only be called in cases where it is absolutely
59
+ # necessary, such as when using some FaaS providers that may suspend
60
+ # the process after an invocation, but before the `Processor` exports
61
+ # the completed spans.
62
+ def force_flush; end
63
+
64
+ # Called when {TracerProvider#shutdown} is called.
65
+ def shutdown
66
+ @span_exporter&.shutdown
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,62 @@
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
+ # Implementation of the SpanProcessor duck type that simply forwards all
11
+ # received events to a list of SpanProcessors.
12
+ class MultiSpanProcessor
13
+ # Creates a new {MultiSpanProcessor}.
14
+ #
15
+ # @param [Enumerable<SpanProcessor>] span_processors a collection of
16
+ # SpanProcessors.
17
+ # @return [MultiSpanProcessor]
18
+ def initialize(span_processors)
19
+ @span_processors = span_processors.to_a.freeze
20
+ end
21
+
22
+ # Called when a {Span} is started, if the {Span#recording?}
23
+ # returns true.
24
+ #
25
+ # This method is called synchronously on the execution thread, should
26
+ # not throw or block the execution thread.
27
+ #
28
+ # @param [Span] span the {Span} that just started.
29
+ def on_start(span)
30
+ @span_processors.each { |processor| processor.on_start(span) }
31
+ end
32
+
33
+ # Called when a {Span} is ended, if the {Span#recording?}
34
+ # returns true.
35
+ #
36
+ # This method is called synchronously on the execution thread, should
37
+ # not throw or block the execution thread.
38
+ #
39
+ # @param [Span] span the {Span} that just ended.
40
+ def on_finish(span)
41
+ @span_processors.each { |processor| processor.on_finish(span) }
42
+ end
43
+
44
+ # Export all ended spans to the configured `Exporter` that have not yet
45
+ # been exported.
46
+ #
47
+ # This method should only be called in cases where it is absolutely
48
+ # necessary, such as when using some FaaS providers that may suspend
49
+ # the process after an invocation, but before the `Processor` exports
50
+ # the completed spans.
51
+ def force_flush
52
+ @span_processors.each(&:force_flush)
53
+ end
54
+
55
+ # Called when {TracerProvider#shutdown} is called.
56
+ def shutdown
57
+ @span_processors.each(&:shutdown)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ require 'singleton'
8
+
9
+ module OpenTelemetry
10
+ module SDK
11
+ module Trace
12
+ # NoopSpanProcessor is a singleton implementation of the duck type
13
+ # SpanProcessor that provides synchronous no-op hooks for when a
14
+ # {Span} is started or when a {Span} is ended.
15
+ class NoopSpanProcessor
16
+ include Singleton
17
+
18
+ # Called when a {Span} is started, if the {Span#recording?}
19
+ # returns true.
20
+ #
21
+ # This method is called synchronously on the execution thread, should
22
+ # not throw or block the execution thread.
23
+ #
24
+ # @param [Span] span the {Span} that just started.
25
+ def on_start(span); end
26
+
27
+ # Called when a {Span} is ended, if the {Span#recording?}
28
+ # returns true.
29
+ #
30
+ # This method is called synchronously on the execution thread, should
31
+ # not throw or block the execution thread.
32
+ #
33
+ # @param [Span] span the {Span} that just ended.
34
+ def on_finish(span); end
35
+
36
+ # Export all ended spans to the configured `Exporter` that have not yet
37
+ # been exported.
38
+ #
39
+ # This method should only be called in cases where it is absolutely
40
+ # necessary, such as when using some FaaS providers that may suspend
41
+ # the process after an invocation, but before the `Processor` exports
42
+ # the completed spans.
43
+ def force_flush; end
44
+
45
+ # Called when {TracerProvider#shutdown} is called.
46
+ def shutdown; end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ require 'opentelemetry/sdk/trace/samplers/decision'
8
+ require 'opentelemetry/sdk/trace/samplers/result'
9
+ require 'opentelemetry/sdk/trace/samplers/constant_sampler'
10
+ require 'opentelemetry/sdk/trace/samplers/parent_or_else'
11
+ require 'opentelemetry/sdk/trace/samplers/probability_sampler'
12
+
13
+ module OpenTelemetry
14
+ module SDK
15
+ module Trace
16
+ # The Samplers module contains the sampling logic for OpenTelemetry. The
17
+ # reference implementation provides a {ProbabilitySampler}, {ALWAYS_ON},
18
+ # {ALWAYS_OFF}, and {ParentOrElse}.
19
+ #
20
+ # Custom samplers can be provided by SDK users. The required interface is:
21
+ #
22
+ # should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:) -> Result
23
+ # description -> String
24
+ #
25
+ # Where:
26
+ #
27
+ # @param [String] trace_id The trace_id of the {Span} to be created.
28
+ # @param [OpenTelemetry::Trace::SpanContext] parent_context The
29
+ # {OpenTelemetry::Trace::SpanContext} of a parent span, typically
30
+ # extracted from the wire. Can be nil for a root span.
31
+ # @param [Enumerable<Link>] links A collection of links to be associated
32
+ # with the {Span} to be created. Can be nil.
33
+ # @param [String] name Name of the {Span} to be created.
34
+ # @param [Symbol] kind The {OpenTelemetry::Trace::SpanKind} of the {Span}
35
+ # to be created. Can be nil.
36
+ # @param [Hash<String, Object>] attributes Attributes to be attached
37
+ # to the {Span} to be created. Can be nil.
38
+ # @return [Result] The sampling result.
39
+ module Samplers
40
+ RECORD_AND_SAMPLED = Result.new(decision: Decision::RECORD_AND_SAMPLED)
41
+ NOT_RECORD = Result.new(decision: Decision::NOT_RECORD)
42
+ RECORD = Result.new(decision: Decision::RECORD)
43
+ SAMPLING_HINTS = [Decision::NOT_RECORD, Decision::RECORD, Decision::RECORD_AND_SAMPLED].freeze
44
+ APPLY_PROBABILITY_TO_SYMBOLS = %i[root_spans root_spans_and_remote_parent all_spans].freeze
45
+
46
+ private_constant(:RECORD_AND_SAMPLED, :NOT_RECORD, :RECORD, :SAMPLING_HINTS, :APPLY_PROBABILITY_TO_SYMBOLS)
47
+
48
+ # Returns a {Result} with {Decision::RECORD_AND_SAMPLED}.
49
+ ALWAYS_ON = ConstantSampler.new(result: RECORD_AND_SAMPLED, description: 'AlwaysOnSampler')
50
+
51
+ # Returns a {Result} with {Decision::NOT_RECORD}.
52
+ ALWAYS_OFF = ConstantSampler.new(result: NOT_RECORD, description: 'AlwaysOffSampler')
53
+
54
+ # Returns a new sampler. It either respects the parent span's sampling
55
+ # decision or delegates to delegate_sampler for root spans.
56
+ #
57
+ # @param [Sampler] delegate_sampler The sampler to which the sampling
58
+ # decision is delegated for root spans.
59
+ def self.parent_or_else(delegate_sampler)
60
+ ParentOrElse.new(delegate_sampler)
61
+ end
62
+
63
+ # Returns a new sampler. The probability of sampling a trace is equal
64
+ # to that of the specified probability.
65
+ #
66
+ # @param [Numeric] probability The desired probability of sampling.
67
+ # Must be within [0.0, 1.0].
68
+ # @param [optional Boolean] ignore_parent Whether to ignore parent
69
+ # sampling. Defaults to not ignore parent sampling.
70
+ # @param [optional Symbol] apply_probability_to Whether to apply
71
+ # probability sampling to root spans, root spans and remote parents,
72
+ # or all spans. Allowed values include :root_spans, :root_spans_and_remote_parent,
73
+ # and :all_spans. Defaults to :root_spans_and_remote_parent.
74
+ # @raise [ArgumentError] if probability is out of range
75
+ # @raise [ArgumentError] if apply_probability_to is not one of the allowed symbols
76
+ def self.probability(probability,
77
+ ignore_parent: false,
78
+ apply_probability_to: :root_spans_and_remote_parent)
79
+ raise ArgumentError, 'probability must be in range [0.0, 1.0]' unless (0.0..1.0).include?(probability)
80
+ raise ArgumentError, 'apply_probability_to' unless APPLY_PROBABILITY_TO_SYMBOLS.include?(apply_probability_to)
81
+
82
+ ProbabilitySampler.new(probability,
83
+ ignore_parent: ignore_parent,
84
+ apply_to_remote_parent: apply_probability_to != :root_spans,
85
+ apply_to_all_spans: apply_probability_to == :all_spans)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module SDK
9
+ module Trace
10
+ module Samplers
11
+ # @api private
12
+ #
13
+ # Implements a sampler returning a constant result.
14
+ class ConstantSampler
15
+ attr_reader :description
16
+
17
+ def initialize(result:, description:)
18
+ @result = result
19
+ @description = description
20
+ end
21
+
22
+ # @api private
23
+ #
24
+ # See {Samplers}.
25
+ def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:)
26
+ # All arguments ignored for sampling decision.
27
+ @result
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
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 Samplers
11
+ # The Decision module contains a set of constants to be used in the
12
+ # decision part of a sampling {Result}.
13
+ module Decision
14
+ # Decision to not record events and not sample.
15
+ NOT_RECORD = :__not_record__
16
+
17
+ # Decision to record events and not sample.
18
+ RECORD = :__record__
19
+
20
+ # Decision to record events and sample.
21
+ RECORD_AND_SAMPLED = :__record_and_sampled__
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module SDK
9
+ module Trace
10
+ module Samplers
11
+ # @api private
12
+ #
13
+ # This is a composite sampler. It either respects the parent span's sampling
14
+ # decision or delegates to delegate_sampler for root spans.
15
+ class ParentOrElse
16
+ def initialize(delegate_sampler)
17
+ @delegate_sampler = delegate_sampler
18
+ end
19
+
20
+ # @api private
21
+ #
22
+ # See {Samplers}.
23
+ def description
24
+ "ParentOrElse{#{@delegate_sampler.description}}"
25
+ end
26
+
27
+ # @api private
28
+ #
29
+ # See {Samplers}.
30
+ def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:)
31
+ if parent_context.nil?
32
+ @delegate_sampler.should_sample?(trace_id: trace_id, parent_context: parent_context, links: links, name: name, kind: kind, attributes: attributes)
33
+ elsif parent_context.trace_flags.sampled?
34
+ RECORD_AND_SAMPLED
35
+ else
36
+ NOT_RECORD
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ 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 Samplers
11
+ # @api private
12
+ #
13
+ # Implements sampling based on a probability.
14
+ class ProbabilitySampler
15
+ attr_reader :description
16
+
17
+ def initialize(probability, ignore_parent:, apply_to_remote_parent:, apply_to_all_spans:)
18
+ @probability = probability
19
+ @id_upper_bound = (probability * (2**64 - 1)).ceil
20
+ @use_parent_sampled_flag = !ignore_parent
21
+ @apply_to_remote_parent = apply_to_remote_parent
22
+ @apply_to_all_spans = apply_to_all_spans
23
+ @description = format('ProbabilitySampler{%.6f}', probability)
24
+ end
25
+
26
+ # @api private
27
+ #
28
+ # See {Samplers}.
29
+ def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:)
30
+ # Ignored for sampling decision: links, name, kind, attributes.
31
+
32
+ if sample?(trace_id, parent_context)
33
+ RECORD_AND_SAMPLED
34
+ else
35
+ NOT_RECORD
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def sample?(trace_id, parent_context)
42
+ if parent_context.nil?
43
+ sample_trace_id?(trace_id)
44
+ else
45
+ parent_sampled?(parent_context) || sample_trace_id_for_child?(parent_context, trace_id)
46
+ end
47
+ end
48
+
49
+ def parent_sampled?(parent_context)
50
+ @use_parent_sampled_flag && parent_context.trace_flags.sampled?
51
+ end
52
+
53
+ def sample_trace_id_for_child?(parent_context, trace_id)
54
+ (@apply_to_all_spans || (@apply_to_remote_parent && parent_context.remote?)) && sample_trace_id?(trace_id)
55
+ end
56
+
57
+ def sample_trace_id?(trace_id)
58
+ @probability == 1.0 || trace_id[8, 8].unpack1('Q>') < @id_upper_bound
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end