opentelemetry-sdk 0.4.0 → 0.8.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -2
  3. data/CHANGELOG.md +42 -0
  4. data/README.md +1 -1
  5. data/lib/opentelemetry/sdk.rb +4 -3
  6. data/lib/opentelemetry/sdk/baggage.rb +16 -0
  7. data/lib/opentelemetry/sdk/{correlation_context → baggage}/builder.rb +5 -5
  8. data/lib/opentelemetry/sdk/{correlation_context → baggage}/manager.rb +37 -27
  9. data/lib/opentelemetry/sdk/configurator.rb +73 -39
  10. data/lib/opentelemetry/sdk/instrumentation_library.rb +13 -0
  11. data/lib/opentelemetry/sdk/resources.rb +1 -0
  12. data/lib/opentelemetry/sdk/resources/constants.rb +120 -0
  13. data/lib/opentelemetry/sdk/resources/resource.rb +38 -19
  14. data/lib/opentelemetry/sdk/trace.rb +1 -0
  15. data/lib/opentelemetry/sdk/trace/config/trace_config.rb +3 -3
  16. data/lib/opentelemetry/sdk/trace/event.rb +48 -0
  17. data/lib/opentelemetry/sdk/trace/export.rb +9 -9
  18. data/lib/opentelemetry/sdk/trace/export/batch_span_processor.rb +49 -28
  19. data/lib/opentelemetry/sdk/trace/export/console_span_exporter.rb +3 -6
  20. data/lib/opentelemetry/sdk/trace/export/in_memory_span_exporter.rb +6 -2
  21. data/lib/opentelemetry/sdk/trace/export/multi_span_exporter.rb +7 -8
  22. data/lib/opentelemetry/sdk/trace/export/noop_span_exporter.rb +2 -1
  23. data/lib/opentelemetry/sdk/trace/export/simple_span_processor.rb +13 -3
  24. data/lib/opentelemetry/sdk/trace/multi_span_processor.rb +12 -4
  25. data/lib/opentelemetry/sdk/trace/noop_span_processor.rb +15 -3
  26. data/lib/opentelemetry/sdk/trace/samplers.rb +52 -51
  27. data/lib/opentelemetry/sdk/trace/samplers/constant_sampler.rb +33 -0
  28. data/lib/opentelemetry/sdk/trace/samplers/decision.rb +3 -3
  29. data/lib/opentelemetry/sdk/trace/samplers/parent_based.rb +53 -0
  30. data/lib/opentelemetry/sdk/trace/samplers/result.rb +3 -3
  31. data/lib/opentelemetry/sdk/trace/samplers/trace_id_ratio_based.rb +45 -0
  32. data/lib/opentelemetry/sdk/trace/span.rb +33 -36
  33. data/lib/opentelemetry/sdk/trace/span_data.rb +18 -3
  34. data/lib/opentelemetry/sdk/trace/tracer.rb +36 -20
  35. data/lib/opentelemetry/sdk/trace/tracer_provider.rb +4 -4
  36. data/lib/opentelemetry/sdk/version.rb +1 -1
  37. metadata +19 -10
  38. data/lib/opentelemetry/sdk/correlation_context.rb +0 -16
  39. data/lib/opentelemetry/sdk/trace/samplers/probability_sampler.rb +0 -61
@@ -14,24 +14,21 @@ module OpenTelemetry
14
14
  #
15
15
  # Potentially useful for exploratory purposes.
16
16
  class ConsoleSpanExporter
17
- ResultCodes = OpenTelemetry::SDK::Trace::Export
18
-
19
- private_constant(:ResultCodes)
20
-
21
17
  def initialize
22
18
  @stopped = false
23
19
  end
24
20
 
25
21
  def export(spans)
26
- return ResultCodes::FAILED_NOT_RETRYABLE if @stopped
22
+ return FAILURE if @stopped
27
23
 
28
24
  Array(spans).each { |s| pp s }
29
25
 
30
- ResultCodes::SUCCESS
26
+ SUCCESS
31
27
  end
32
28
 
33
29
  def shutdown
34
30
  @stopped = true
31
+ SUCCESS
35
32
  end
36
33
  end
37
34
  end
@@ -61,10 +61,10 @@ module OpenTelemetry
61
61
  # @param [Enumerable<SpanData>] span_datas the list of sampled {SpanData}s to be
62
62
  # exported.
63
63
  # @return [Integer] the result of the export, SUCCESS or
64
- # FAILED_NOT_RETRYABLE
64
+ # FAILURE
65
65
  def export(span_datas)
66
66
  @mutex.synchronize do
67
- return FAILED_NOT_RETRYABLE if @stopped
67
+ return FAILURE if @stopped
68
68
 
69
69
  @finished_spans.concat(span_datas.to_a)
70
70
  end
@@ -73,11 +73,15 @@ module OpenTelemetry
73
73
 
74
74
  # Called when {TracerProvider#shutdown} is called, if this exporter is
75
75
  # registered to a {TracerProvider} object.
76
+ #
77
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
78
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
76
79
  def shutdown
77
80
  @mutex.synchronize do
78
81
  @finished_spans.clear
79
82
  @stopped = true
80
83
  end
84
+ SUCCESS
81
85
  end
82
86
  end
83
87
  end
@@ -29,14 +29,17 @@ module OpenTelemetry
29
29
  merge_result_code(result_code, span_exporter.export(spans))
30
30
  rescue => e # rubocop:disable Style/RescueStandardError
31
31
  OpenTelemetry.logger.warn("exception raised by export - #{e}")
32
- FAILED_NOT_RETRYABLE
32
+ FAILURE
33
33
  end
34
34
  end
35
35
 
36
36
  # Called when {TracerProvider#shutdown} is called, if this exporter is
37
37
  # registered to a {TracerProvider} object.
38
+ #
39
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
40
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
38
41
  def shutdown
39
- @span_exporters.each(&:shutdown)
42
+ @span_exporters.map(&:shutdown).uniq.max
40
43
  end
41
44
 
42
45
  private
@@ -46,13 +49,9 @@ module OpenTelemetry
46
49
  if result_code == SUCCESS && new_result_code == SUCCESS
47
50
  # If both errors are success then return success.
48
51
  SUCCESS
49
- elsif result_code == FAILED_NOT_RETRYABLE || new_result_code == FAILED_NOT_RETRYABLE
50
- # If any of the codes is not retryable then return not_retryable.
51
- FAILED_NOT_RETRYABLE
52
52
  else
53
- # At this point at least one of the code is FAILED_RETRYABLE and
54
- # none are FAILED_NOT_RETRYABLE, so return FAILED_RETRYABLE.
55
- FAILED_RETRYABLE
53
+ # At this point at least one of the code is FAILURE, so return FAILURE.
54
+ FAILURE
56
55
  end
57
56
  end
58
57
  end
@@ -27,13 +27,14 @@ module OpenTelemetry
27
27
  def export(spans)
28
28
  return SUCCESS unless @stopped
29
29
 
30
- FAILED_NOT_RETRYABLE
30
+ FAILURE
31
31
  end
32
32
 
33
33
  # Called when {TracerProvider#shutdown} is called, if this exporter is
34
34
  # registered to a {TracerProvider} object.
35
35
  def shutdown
36
36
  @stopped = true
37
+ SUCCESS
37
38
  end
38
39
  end
39
40
  end
@@ -33,7 +33,9 @@ module OpenTelemetry
33
33
  # not throw or block the execution thread.
34
34
  #
35
35
  # @param [Span] span the {Span} that just started.
36
- def on_start(span)
36
+ # @param [Context] parent_context the parent {Context} of the newly
37
+ # started span.
38
+ def on_start(span, parent_context)
37
39
  # Do nothing.
38
40
  end
39
41
 
@@ -59,11 +61,19 @@ module OpenTelemetry
59
61
  # necessary, such as when using some FaaS providers that may suspend
60
62
  # the process after an invocation, but before the `Processor` exports
61
63
  # the completed spans.
62
- def force_flush; end
64
+ #
65
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
66
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
67
+ def force_flush
68
+ SUCCESS
69
+ end
63
70
 
64
71
  # Called when {TracerProvider#shutdown} is called.
72
+ #
73
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
74
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
65
75
  def shutdown
66
- @span_exporter&.shutdown
76
+ @span_exporter&.shutdown || SUCCESS
67
77
  end
68
78
  end
69
79
  end
@@ -26,8 +26,10 @@ module OpenTelemetry
26
26
  # not throw or block the execution thread.
27
27
  #
28
28
  # @param [Span] span the {Span} that just started.
29
- def on_start(span)
30
- @span_processors.each { |processor| processor.on_start(span) }
29
+ # @param [Context] parent_context the parent {Context} of the newly
30
+ # started span.
31
+ def on_start(span, parent_context)
32
+ @span_processors.each { |processor| processor.on_start(span, parent_context) }
31
33
  end
32
34
 
33
35
  # Called when a {Span} is ended, if the {Span#recording?}
@@ -48,13 +50,19 @@ module OpenTelemetry
48
50
  # necessary, such as when using some FaaS providers that may suspend
49
51
  # the process after an invocation, but before the `Processor` exports
50
52
  # the completed spans.
53
+ #
54
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
55
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
51
56
  def force_flush
52
- @span_processors.each(&:force_flush)
57
+ @span_processors.map(&:force_flush).uniq.max
53
58
  end
54
59
 
55
60
  # Called when {TracerProvider#shutdown} is called.
61
+ #
62
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
63
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
56
64
  def shutdown
57
- @span_processors.each(&:shutdown)
65
+ @span_processors.map(&:shutdown).uniq.max
58
66
  end
59
67
  end
60
68
  end
@@ -22,7 +22,9 @@ module OpenTelemetry
22
22
  # not throw or block the execution thread.
23
23
  #
24
24
  # @param [Span] span the {Span} that just started.
25
- def on_start(span); end
25
+ # @param [Context] parent_context the parent {Context} of the newly
26
+ # started span.
27
+ def on_start(span, parent_context); end
26
28
 
27
29
  # Called when a {Span} is ended, if the {Span#recording?}
28
30
  # returns true.
@@ -40,10 +42,20 @@ module OpenTelemetry
40
42
  # necessary, such as when using some FaaS providers that may suspend
41
43
  # the process after an invocation, but before the `Processor` exports
42
44
  # the completed spans.
43
- def force_flush; end
45
+ #
46
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
47
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
48
+ def force_flush
49
+ Export::SUCCESS
50
+ end
44
51
 
45
52
  # Called when {TracerProvider#shutdown} is called.
46
- def shutdown; end
53
+ #
54
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
55
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
56
+ def shutdown
57
+ Export::SUCCESS
58
+ end
47
59
  end
48
60
  end
49
61
  end
@@ -6,24 +6,25 @@
6
6
 
7
7
  require 'opentelemetry/sdk/trace/samplers/decision'
8
8
  require 'opentelemetry/sdk/trace/samplers/result'
9
- require 'opentelemetry/sdk/trace/samplers/probability_sampler'
9
+ require 'opentelemetry/sdk/trace/samplers/constant_sampler'
10
+ require 'opentelemetry/sdk/trace/samplers/parent_based'
11
+ require 'opentelemetry/sdk/trace/samplers/trace_id_ratio_based'
10
12
 
11
13
  module OpenTelemetry
12
14
  module SDK
13
15
  module Trace
14
16
  # The Samplers module contains the sampling logic for OpenTelemetry. The
15
- # reference implementation provides a {ProbabilitySampler}, {ALWAYS_ON},
16
- # {ALWAYS_OFF}, and {ALWAYS_PARENT}.
17
+ # reference implementation provides a {TraceIdRatioBased}, {ALWAYS_ON},
18
+ # {ALWAYS_OFF}, and {ParentBased}.
17
19
  #
18
- # Custom samplers can be provided by SDK users. The required interface is
19
- # a callable with the signature:
20
+ # Custom samplers can be provided by SDK users. The required interface is:
20
21
  #
21
- # (trace_id:, span_id:, parent_context:, links:, name:, kind:, attributes:) -> Result
22
+ # should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:) -> Result
23
+ # description -> String
22
24
  #
23
25
  # Where:
24
26
  #
25
27
  # @param [String] trace_id The trace_id of the {Span} to be created.
26
- # @param [String] span_id The span_id of the {Span} to be created.
27
28
  # @param [OpenTelemetry::Trace::SpanContext] parent_context The
28
29
  # {OpenTelemetry::Trace::SpanContext} of a parent span, typically
29
30
  # extracted from the wire. Can be nil for a root span.
@@ -36,59 +37,59 @@ module OpenTelemetry
36
37
  # to the {Span} to be created. Can be nil.
37
38
  # @return [Result] The sampling result.
38
39
  module Samplers
39
- RECORD_AND_SAMPLED = Result.new(decision: Decision::RECORD_AND_SAMPLED)
40
- NOT_RECORD = Result.new(decision: Decision::NOT_RECORD)
41
- RECORD = Result.new(decision: Decision::RECORD)
42
- SAMPLING_HINTS = [Decision::NOT_RECORD, Decision::RECORD, Decision::RECORD_AND_SAMPLED].freeze
43
- APPLY_PROBABILITY_TO_SYMBOLS = %i[root_spans root_spans_and_remote_parent all_spans].freeze
40
+ RECORD_AND_SAMPLE = Result.new(decision: Decision::RECORD_AND_SAMPLE)
41
+ DROP = Result.new(decision: Decision::DROP)
42
+ RECORD_ONLY = Result.new(decision: Decision::RECORD_ONLY)
43
+ SAMPLING_HINTS = [Decision::DROP, Decision::RECORD_ONLY, Decision::RECORD_AND_SAMPLE].freeze
44
44
 
45
- private_constant(:RECORD_AND_SAMPLED, :NOT_RECORD, :RECORD, :SAMPLING_HINTS, :APPLY_PROBABILITY_TO_SYMBOLS)
45
+ private_constant(:RECORD_AND_SAMPLE, :DROP, :RECORD_ONLY, :SAMPLING_HINTS)
46
46
 
47
- # rubocop:disable Lint/UnusedBlockArgument
47
+ # Returns a {Result} with {Decision::RECORD_AND_SAMPLE}.
48
+ ALWAYS_ON = ConstantSampler.new(result: RECORD_AND_SAMPLE, description: 'AlwaysOnSampler')
48
49
 
49
- # Returns a {Result} with {Decision::RECORD_AND_SAMPLED}.
50
- ALWAYS_ON = ->(trace_id:, span_id:, parent_context:, links:, name:, kind:, attributes:) { RECORD_AND_SAMPLED }
50
+ # Returns a {Result} with {Decision::DROP}.
51
+ ALWAYS_OFF = ConstantSampler.new(result: DROP, description: 'AlwaysOffSampler')
51
52
 
52
- # Returns a {Result} with {Decision::NOT_RECORD}.
53
- ALWAYS_OFF = ->(trace_id:, span_id:, parent_context:, links:, name:, kind:, attributes:) { NOT_RECORD }
54
-
55
- # Returns a {Result} with {Decision::RECORD_AND_SAMPLED} if the parent
56
- # context is sampled or {Decision::NOT_RECORD} otherwise, or if there
57
- # is no parent context.
58
- # rubocop:disable Style/Lambda
59
- ALWAYS_PARENT = ->(trace_id:, span_id:, parent_context:, links:, name:, kind:, attributes:) do
60
- if parent_context&.trace_flags&.sampled?
61
- RECORD_AND_SAMPLED
62
- else
63
- NOT_RECORD
64
- end
53
+ # Returns a new sampler. It delegates to samplers according to the following rules:
54
+ #
55
+ # | Parent | parent.remote? | parent.trace_flags.sampled? | Invoke sampler |
56
+ # |--|--|--|--|
57
+ # | absent | n/a | n/a | root |
58
+ # | present | true | true | remote_parent_sampled |
59
+ # | present | true | false | remote_parent_not_sampled |
60
+ # | present | false | true | local_parent_sampled |
61
+ # | present | false | false | local_parent_not_sampled |
62
+ #
63
+ # @param [Sampler] root The sampler to which the sampling
64
+ # decision is delegated for spans with no parent (root spans).
65
+ # @param [optional Sampler] remote_parent_sampled The sampler to which the sampling
66
+ # decision is delegated for remote parent sampled spans. Defaults to ALWAYS_ON.
67
+ # @param [optional Sampler] remote_parent_not_sampled The sampler to which the sampling
68
+ # decision is delegated for remote parent not sampled spans. Defaults to ALWAYS_OFF.
69
+ # @param [optional Sampler] local_parent_sampled The sampler to which the sampling
70
+ # decision is delegated for local parent sampled spans. Defaults to ALWAYS_ON.
71
+ # @param [optional Sampler] local_parent_not_sampled The sampler to which the sampling
72
+ # decision is delegated for local parent not sampld spans. Defaults to ALWAYS_OFF.
73
+ def self.parent_based(
74
+ root:,
75
+ remote_parent_sampled: ALWAYS_ON,
76
+ remote_parent_not_sampled: ALWAYS_OFF,
77
+ local_parent_sampled: ALWAYS_ON,
78
+ local_parent_not_sampled: ALWAYS_OFF
79
+ )
80
+ ParentBased.new(root, remote_parent_sampled, remote_parent_not_sampled, local_parent_sampled, local_parent_not_sampled)
65
81
  end
66
- # rubocop:enable Style/Lambda
67
- # rubocop:enable Lint/UnusedBlockArgument
68
82
 
69
- # Returns a new sampler. The probability of sampling a trace is equal
70
- # to that of the specified probability.
83
+ # Returns a new sampler. The ratio describes the proportion of the trace ID
84
+ # space that is sampled.
71
85
  #
72
- # @param [Numeric] probability The desired probability of sampling.
86
+ # @param [Numeric] ratio The desired sampling ratio.
73
87
  # Must be within [0.0, 1.0].
74
- # @param [optional Boolean] ignore_parent Whether to ignore parent
75
- # sampling. Defaults to not ignore parent sampling.
76
- # @param [optional Symbol] apply_probability_to Whether to apply
77
- # probability sampling to root spans, root spans and remote parents,
78
- # or all spans. Allowed values include :root_spans, :root_spans_and_remote_parent,
79
- # and :all_spans. Defaults to :root_spans_and_remote_parent.
80
- # @raise [ArgumentError] if probability is out of range
81
- # @raise [ArgumentError] if apply_probability_to is not one of the allowed symbols
82
- def self.probability(probability,
83
- ignore_parent: false,
84
- apply_probability_to: :root_spans_and_remote_parent)
85
- raise ArgumentError, 'probability must be in range [0.0, 1.0]' unless (0.0..1.0).include?(probability)
86
- raise ArgumentError, 'apply_probability_to' unless APPLY_PROBABILITY_TO_SYMBOLS.include?(apply_probability_to)
88
+ # @raise [ArgumentError] if ratio is out of range
89
+ def self.trace_id_ratio_based(ratio)
90
+ raise ArgumentError, 'ratio must be in range [0.0, 1.0]' unless (0.0..1.0).include?(ratio)
87
91
 
88
- ProbabilitySampler.new(probability,
89
- ignore_parent: ignore_parent,
90
- apply_to_remote_parent: apply_probability_to != :root_spans,
91
- apply_to_all_spans: apply_probability_to == :all_spans)
92
+ TraceIdRatioBased.new(ratio)
92
93
  end
93
94
  end
94
95
  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
@@ -12,13 +12,13 @@ module OpenTelemetry
12
12
  # decision part of a sampling {Result}.
13
13
  module Decision
14
14
  # Decision to not record events and not sample.
15
- NOT_RECORD = :__not_record__
15
+ DROP = :__drop__
16
16
 
17
17
  # Decision to record events and not sample.
18
- RECORD = :__record__
18
+ RECORD_ONLY = :__record_only__
19
19
 
20
20
  # Decision to record events and sample.
21
- RECORD_AND_SAMPLED = :__record_and_sampled__
21
+ RECORD_AND_SAMPLE = :__record_and_sample__
22
22
  end
23
23
  end
24
24
  end
@@ -0,0 +1,53 @@
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. ParentBased helps distinguished between the
14
+ # following cases:
15
+ # * No parent (root span).
16
+ # * Remote parent (SpanContext.remote? with trace_flags.sampled?)
17
+ # * Remote parent (SpanContext.remote? with !trace_flags.sampled?)
18
+ # * Local parent (!SpanContext.remote? with trace_flags.sampled?)
19
+ # * Local parent (!SpanContext.remote? with !trace_flags.sampled?)
20
+ class ParentBased
21
+ def initialize(root, remote_parent_sampled, remote_parent_not_sampled, local_parent_sampled, local_parent_not_sampled)
22
+ @root = root
23
+ @remote_parent_sampled = remote_parent_sampled
24
+ @remote_parent_not_sampled = remote_parent_not_sampled
25
+ @local_parent_sampled = local_parent_sampled
26
+ @local_parent_not_sampled = local_parent_not_sampled
27
+ end
28
+
29
+ # @api private
30
+ #
31
+ # See {Samplers}.
32
+ def description
33
+ "ParentBased{root=#{@root.description}, remote_parent_sampled=#{@remote_parent_sampled.description}, remote_parent_not_sampled=#{@remote_parent_not_sampled.description}, local_parent_sampled=#{@local_parent_sampled.description}, local_parent_not_sampled=#{@local_parent_not_sampled.description}}"
34
+ end
35
+
36
+ # @api private
37
+ #
38
+ # See {Samplers}.
39
+ def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:)
40
+ delegate = if parent_context.nil?
41
+ @root
42
+ elsif parent_context.remote?
43
+ parent_context.trace_flags.sampled? ? @remote_parent_sampled : @remote_parent_not_sampled
44
+ else
45
+ parent_context.trace_flags.sampled? ? @local_parent_sampled : @local_parent_not_sampled
46
+ end
47
+ delegate.should_sample?(trace_id: trace_id, parent_context: parent_context, links: links, name: name, kind: kind, attributes: attributes)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end