opentelemetry-api 0.16.0 → 1.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -0
  3. data/README.md +3 -3
  4. data/lib/opentelemetry.rb +21 -28
  5. data/lib/opentelemetry/baggage.rb +95 -2
  6. data/lib/opentelemetry/baggage/builder.rb +30 -4
  7. data/lib/opentelemetry/baggage/entry.rb +20 -0
  8. data/lib/opentelemetry/baggage/propagation.rb +9 -18
  9. data/lib/opentelemetry/baggage/propagation/text_map_propagator.rb +111 -0
  10. data/lib/opentelemetry/context.rb +48 -33
  11. data/lib/opentelemetry/context/propagation.rb +35 -5
  12. data/lib/opentelemetry/context/propagation/composite_text_map_propagator.rb +105 -0
  13. data/lib/opentelemetry/context/propagation/noop_text_map_propagator.rb +27 -0
  14. data/lib/opentelemetry/context/propagation/{propagator.rb → text_map_propagator.rb} +23 -16
  15. data/lib/opentelemetry/internal.rb +17 -0
  16. data/lib/opentelemetry/internal/proxy_tracer.rb +38 -0
  17. data/lib/opentelemetry/internal/proxy_tracer_provider.rb +59 -0
  18. data/lib/opentelemetry/trace.rb +10 -0
  19. data/lib/opentelemetry/trace/propagation/trace_context.rb +7 -18
  20. data/lib/opentelemetry/trace/propagation/trace_context/text_map_propagator.rb +73 -0
  21. data/lib/opentelemetry/trace/status.rb +34 -5
  22. data/lib/opentelemetry/trace/tracer.rb +8 -9
  23. data/lib/opentelemetry/version.rb +1 -1
  24. metadata +16 -25
  25. data/lib/opentelemetry/baggage/manager.rb +0 -41
  26. data/lib/opentelemetry/baggage/propagation/text_map_extractor.rb +0 -57
  27. data/lib/opentelemetry/baggage/propagation/text_map_injector.rb +0 -52
  28. data/lib/opentelemetry/context/propagation/composite_propagator.rb +0 -72
  29. data/lib/opentelemetry/context/propagation/noop_extractor.rb +0 -26
  30. data/lib/opentelemetry/context/propagation/noop_injector.rb +0 -26
  31. data/lib/opentelemetry/instrumentation.rb +0 -15
  32. data/lib/opentelemetry/instrumentation/base.rb +0 -307
  33. data/lib/opentelemetry/instrumentation/registry.rb +0 -86
  34. data/lib/opentelemetry/metrics.rb +0 -16
  35. data/lib/opentelemetry/metrics/handles.rb +0 -44
  36. data/lib/opentelemetry/metrics/instruments.rb +0 -105
  37. data/lib/opentelemetry/metrics/meter.rb +0 -72
  38. data/lib/opentelemetry/metrics/meter_provider.rb +0 -22
  39. data/lib/opentelemetry/trace/propagation/trace_context/text_map_extractor.rb +0 -52
  40. data/lib/opentelemetry/trace/propagation/trace_context/text_map_injector.rb +0 -49
  41. data/lib/opentelemetry/trace/util/http_to_status.rb +0 -28
@@ -10,8 +10,11 @@ require 'opentelemetry/context/propagation'
10
10
  module OpenTelemetry
11
11
  # Manages context on a per-fiber basis
12
12
  class Context
13
- KEY = :__opentelemetry_context__
14
13
  EMPTY_ENTRIES = {}.freeze
14
+ STACK_KEY = :__opentelemetry_context_storage__
15
+ private_constant :EMPTY_ENTRIES, :STACK_KEY
16
+
17
+ DetachError = Class.new(OpenTelemetry::Error)
15
18
 
16
19
  class << self
17
20
  # Returns a key used to index a value in a Context
@@ -26,14 +29,36 @@ module OpenTelemetry
26
29
  #
27
30
  # @return [Context]
28
31
  def current
29
- Thread.current[KEY] ||= ROOT
32
+ stack.last || ROOT
30
33
  end
31
34
 
32
- # Sets the current context
35
+ # Associates a Context with the caller's current Fiber. Every call to
36
+ # this operation should be paired with a corresponding call to detach.
33
37
  #
34
- # @param [Context] ctx The context to be made active
35
- def current=(ctx)
36
- Thread.current[KEY] = ctx
38
+ # Returns a token to be used with the matching call to detach
39
+ #
40
+ # @param [Context] context The new context
41
+ # @return [Object] A token to be used when detaching
42
+ def attach(context)
43
+ s = stack
44
+ s.push(context)
45
+ s.size
46
+ end
47
+
48
+ # Restores the previous Context associated with the current Fiber.
49
+ # The supplied token is used to check if the call to detach is balanced
50
+ # with a corresponding attach call. A warning is logged if the
51
+ # calls are unbalanced.
52
+ #
53
+ # @param [Object] token The token provided by the matching call to attach
54
+ # @return [Boolean] True if the calls matched, false otherwise
55
+ def detach(token)
56
+ s = stack
57
+ calls_matched = (token == s.size)
58
+ OpenTelemetry.handle_error(exception: DetachError.new('calls to detach should match corresponding calls to attach.')) unless calls_matched
59
+
60
+ s.pop
61
+ calls_matched
37
62
  end
38
63
 
39
64
  # Executes a block with ctx as the current context. It restores
@@ -42,10 +67,10 @@ module OpenTelemetry
42
67
  # @param [Context] ctx The context to be made active
43
68
  # @yield [context] Yields context to the block
44
69
  def with_current(ctx)
45
- prev = ctx.attach
70
+ token = attach(ctx)
46
71
  yield ctx
47
72
  ensure
48
- ctx.detach(prev)
73
+ detach(token)
49
74
  end
50
75
 
51
76
  # Execute a block in a new context with key set to value. Restores the
@@ -58,10 +83,10 @@ module OpenTelemetry
58
83
  # the block
59
84
  def with_value(key, value)
60
85
  ctx = current.set_value(key, value)
61
- prev = ctx.attach
86
+ token = attach(ctx)
62
87
  yield ctx, value
63
88
  ensure
64
- ctx.detach(prev)
89
+ detach(token)
65
90
  end
66
91
 
67
92
  # Execute a block in a new context where its values are merged with the
@@ -75,10 +100,10 @@ module OpenTelemetry
75
100
  # to the block
76
101
  def with_values(values)
77
102
  ctx = current.set_values(values)
78
- prev = ctx.attach
103
+ token = attach(ctx)
79
104
  yield ctx, values
80
105
  ensure
81
- ctx.detach(prev)
106
+ detach(token)
82
107
  end
83
108
 
84
109
  # Returns the value associated with key in the current context
@@ -89,16 +114,21 @@ module OpenTelemetry
89
114
  end
90
115
 
91
116
  def clear
92
- self.current = ROOT
117
+ stack.clear
93
118
  end
94
119
 
95
120
  def empty
96
- new(nil, EMPTY_ENTRIES)
121
+ new(EMPTY_ENTRIES)
122
+ end
123
+
124
+ private
125
+
126
+ def stack
127
+ Thread.current[STACK_KEY] ||= []
97
128
  end
98
129
  end
99
130
 
100
- def initialize(parent, entries)
101
- @parent = parent
131
+ def initialize(entries)
102
132
  @entries = entries.freeze
103
133
  end
104
134
 
@@ -120,7 +150,7 @@ module OpenTelemetry
120
150
  def set_value(key, value)
121
151
  new_entries = @entries.dup
122
152
  new_entries[key] = value
123
- Context.new(self, new_entries)
153
+ Context.new(new_entries)
124
154
  end
125
155
 
126
156
  # Returns a new Context with the current context's entries merged with the
@@ -131,22 +161,7 @@ module OpenTelemetry
131
161
  # @param [Object] value Object to be stored under key
132
162
  # @return [Context]
133
163
  def set_values(values) # rubocop:disable Naming/AccessorMethodName:
134
- Context.new(self, @entries.merge(values))
135
- end
136
-
137
- # @api private
138
- def attach
139
- prev = self.class.current
140
- self.class.current = self
141
- prev
142
- end
143
-
144
- # @api private
145
- def detach(ctx_to_attach = nil)
146
- OpenTelemetry.logger.warn 'Calls to detach should match corresponding calls to attach' if self.class.current != self
147
-
148
- ctx_to_attach ||= @parent || ROOT
149
- ctx_to_attach.attach
164
+ Context.new(@entries.merge(values))
150
165
  end
151
166
 
152
167
  ROOT = empty.freeze
@@ -4,18 +4,48 @@
4
4
  #
5
5
  # SPDX-License-Identifier: Apache-2.0
6
6
 
7
- require 'opentelemetry/context/propagation/composite_propagator'
8
- require 'opentelemetry/context/propagation/noop_extractor'
9
- require 'opentelemetry/context/propagation/noop_injector'
10
- require 'opentelemetry/context/propagation/propagator'
7
+ require 'opentelemetry/context/propagation/composite_text_map_propagator'
8
+ require 'opentelemetry/context/propagation/noop_text_map_propagator'
9
+ require 'opentelemetry/context/propagation/rack_env_getter'
11
10
  require 'opentelemetry/context/propagation/text_map_getter'
11
+ require 'opentelemetry/context/propagation/text_map_propagator'
12
12
  require 'opentelemetry/context/propagation/text_map_setter'
13
- require 'opentelemetry/context/propagation/rack_env_getter'
14
13
 
15
14
  module OpenTelemetry
16
15
  class Context
17
16
  # The propagation module contains APIs and utilities to interact with context
18
17
  # and propagate across process boundaries.
18
+ #
19
+ # The API implicitly defines 3 interfaces: TextMapPropagator, TextMapInjector
20
+ # and TextMapExtractor. Concrete implementations of TextMapPropagator are
21
+ # provided. Custom text map propagators can leverage these implementations
22
+ # or simply implement the expected interface. The interfaces are described
23
+ # below.
24
+ #
25
+ # The TextMapPropagator interface:
26
+ #
27
+ # inject(carrier, context:, setter:)
28
+ # extract(carrier, context:, getter:) -> Context
29
+ # fields -> Array<String>
30
+ #
31
+ # The TextMapInjector interface:
32
+ #
33
+ # inject(carrier, context:, setter:)
34
+ # fields -> Array<String>
35
+ #
36
+ # The TextMapExtractor interface:
37
+ #
38
+ # extract(carrier, context:, getter:) -> Context
39
+ #
40
+ # The API provides 3 TextMapPropagator implementations:
41
+ # - A default NoopTextMapPropagator that implements +inject+ and +extract+
42
+ # methods as no-ops. Its +fields+ method returns an empty list.
43
+ # - A TextMapPropagator that composes an Injector and an Extractor. Its
44
+ # +fields+ method delegates to the provided Injector.
45
+ # - A CompositeTextMapPropagator that wraps either a list of text map
46
+ # propagators or a list of Injectors and a list of Extractors. Its
47
+ # +fields+ method returns the union of fields returned by the Injectors
48
+ # it wraps.
19
49
  module Propagation
20
50
  extend self
21
51
 
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ class Context
9
+ module Propagation
10
+ # A composite text map propagator either composes a list of injectors and a
11
+ # list of extractors, or wraps a list of propagators, into a single interface
12
+ # exposing inject and extract methods. Injection and extraction will preserve
13
+ # the order of the injectors and extractors (or propagators) passed in during
14
+ # initialization.
15
+ class CompositeTextMapPropagator
16
+ class << self
17
+ private :new # rubocop:disable Style/AccessModifierDeclarations
18
+
19
+ # Returns a Propagator that extracts using the provided extractors
20
+ # and injectors.
21
+ #
22
+ # @param [Array<#inject, #fields>] injectors An array of text map injectors
23
+ # @param [Array<#extract>] extractors An array of text map extractors
24
+ def compose(injectors:, extractors:)
25
+ raise ArgumentError, 'injectors and extractors must both be non-nil arrays' unless injectors.is_a?(Array) && extractors.is_a?(Array)
26
+
27
+ new(injectors: injectors, extractors: extractors)
28
+ end
29
+
30
+ # Returns a Propagator that extracts using the provided propagators.
31
+ #
32
+ # @param [Array<#inject, #extract, #fields>] propagators An array of
33
+ # text map propagators
34
+ def compose_propagators(propagators)
35
+ raise ArgumentError, 'propagators must be a non-nil array' unless propagators.is_a?(Array)
36
+ return NoopTextMapPropagator.new if propagators.empty?
37
+ return propagators.first if propagators.size == 1
38
+
39
+ new(propagators: propagators)
40
+ end
41
+ end
42
+
43
+ # @api private
44
+ def initialize(injectors: nil, extractors: nil, propagators: nil)
45
+ @injectors = injectors
46
+ @extractors = extractors
47
+ @propagators = propagators
48
+ end
49
+
50
+ # Runs injectors or propagators in order. If an injection fails
51
+ # a warning will be logged and remaining injectors will be executed.
52
+ #
53
+ # @param [Object] carrier A mutable carrier to inject context into.
54
+ # @param [optional Context] context Context to be injected into carrier. Defaults
55
+ # to +Context.current+.
56
+ # @param [optional Setter] setter If the optional setter is provided, it
57
+ # will be used to write context into the carrier, otherwise the default
58
+ # setter will be used.
59
+ def inject(carrier, context: Context.current, setter: Context::Propagation.text_map_setter)
60
+ injectors = @injectors || @propagators
61
+ injectors.each do |injector|
62
+ injector.inject(carrier, context: context, setter: setter)
63
+ rescue StandardError => e
64
+ OpenTelemetry.logger.warn "Error in CompositePropagator#inject #{e.message}"
65
+ end
66
+ nil
67
+ end
68
+
69
+ # Runs extractors or propagators in order and returns a Context updated
70
+ # with the results of each extraction. If an extraction fails, a warning
71
+ # will be logged and remaining extractors will continue to be executed. Always
72
+ # returns a valid context.
73
+ #
74
+ # @param [Object] carrier The carrier to extract context from.
75
+ # @param [optional Context] context Context to be updated with the state
76
+ # extracted from the carrier. Defaults to +Context.current+.
77
+ # @param [optional Getter] getter If the optional getter is provided, it
78
+ # will be used to read the header from the carrier, otherwise the default
79
+ # getter will be used.
80
+ #
81
+ # @return [Context] a new context updated with state extracted from the
82
+ # carrier
83
+ def extract(carrier, context: Context.current, getter: Context::Propagation.text_map_getter)
84
+ extractors = @extractors || @propagators
85
+ extractors.inject(context) do |ctx, extractor|
86
+ extractor.extract(carrier, context: ctx, getter: getter)
87
+ rescue StandardError => e
88
+ OpenTelemetry.logger.warn "Error in CompositePropagator#extract #{e.message}"
89
+ ctx
90
+ end
91
+ end
92
+
93
+ # Returns the union of the propagation fields returned by the composed injectors
94
+ # or propagators. If your carrier is reused, you should delete the fields returned
95
+ # by this method before calling +inject+.
96
+ #
97
+ # @return [Array<String>] a list of fields that will be used by this propagator.
98
+ def fields
99
+ injectors = @injectors || @propagators
100
+ injectors.flat_map(&fields).uniq
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ class Context
9
+ module Propagation
10
+ # @api private
11
+ class NoopTextMapPropagator
12
+ EMPTY_LIST = [].freeze
13
+ private_constant(:EMPTY_LIST)
14
+
15
+ def inject(carrier, context: Context.current, setter: Context::Propagation.text_map_setter); end
16
+
17
+ def extract(carrier, context: Context.current, getter: Context::Propagation.text_map_getter)
18
+ context
19
+ end
20
+
21
+ def fields
22
+ EMPTY_LIST
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -7,45 +7,44 @@
7
7
  module OpenTelemetry
8
8
  class Context
9
9
  module Propagation
10
- # A propagator composes an extractor and injector into a single interface
11
- # exposing inject and extract methods
12
- class Propagator
10
+ # A text map propagator that composes an extractor and injector into a
11
+ # single interface exposing inject and extract methods.
12
+ class TextMapPropagator
13
13
  # Returns a Propagator that delegates inject and extract to the provided
14
14
  # injector and extractor
15
15
  #
16
16
  # @param [#inject] injector
17
17
  # @param [#extract] extractor
18
18
  def initialize(injector, extractor)
19
+ raise ArgumentError, 'injector and extractor must both be non-nil' if injector.nil? || extractor.nil?
20
+
19
21
  @injector = injector
20
22
  @extractor = extractor
21
23
  end
22
24
 
23
- # Returns a carrier with the provided context injected according the
24
- # underlying injector. Returns the carrier and logs a warning if
25
- # injection fails.
25
+ # Injects the provided context into a carrier using the underlying
26
+ # injector. Logs a warning if injection fails.
26
27
  #
27
- # @param [Object] carrier A carrier to inject context into
28
- # context into
28
+ # @param [Object] carrier A mutable carrier to inject context into.
29
29
  # @param [optional Context] context Context to be injected into carrier. Defaults
30
- # to +Context.current+
30
+ # to +Context.current+.
31
31
  # @param [optional Setter] setter If the optional setter is provided, it
32
32
  # will be used to write context into the carrier, otherwise the default
33
33
  # setter will be used.
34
- #
35
- # @return [Object] carrier
36
34
  def inject(carrier, context: Context.current, setter: Context::Propagation.text_map_setter)
37
35
  @injector.inject(carrier, context, setter)
38
- rescue => e # rubocop:disable Style/RescueStandardError
36
+ nil
37
+ rescue StandardError => e
39
38
  OpenTelemetry.logger.warn "Error in Propagator#inject #{e.message}"
40
- carrier
39
+ nil
41
40
  end
42
41
 
43
42
  # Extracts and returns context from a carrier. Returns the provided
44
43
  # context and logs a warning if an error if extraction fails.
45
44
  #
46
- # @param [Object] carrier The carrier to extract context from
45
+ # @param [Object] carrier The carrier to extract context from.
47
46
  # @param [optional Context] context Context to be updated with the state
48
- # extracted from the carrier. Defaults to +Context.current+
47
+ # extracted from the carrier. Defaults to +Context.current+.
49
48
  # @param [optional Getter] getter If the optional getter is provided, it
50
49
  # will be used to read the header from the carrier, otherwise the default
51
50
  # getter will be used.
@@ -54,10 +53,18 @@ module OpenTelemetry
54
53
  # carrier
55
54
  def extract(carrier, context: Context.current, getter: Context::Propagation.text_map_getter)
56
55
  @extractor.extract(carrier, context, getter)
57
- rescue => e # rubocop:disable Style/RescueStandardError
56
+ rescue StandardError => e
58
57
  OpenTelemetry.logger.warn "Error in Propagator#extract #{e.message}"
59
58
  context
60
59
  end
60
+
61
+ # Returns the predefined propagation fields. If your carrier is reused, you
62
+ # should delete the fields returned by this method before calling +inject+.
63
+ #
64
+ # @return [Array<String>] a list of fields that will be used by this propagator.
65
+ def fields
66
+ @injector.fields
67
+ end
61
68
  end
62
69
  end
63
70
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ require 'opentelemetry/internal/proxy_tracer'
8
+ require 'opentelemetry/internal/proxy_tracer_provider'
9
+
10
+ module OpenTelemetry
11
+ # @api private
12
+ #
13
+ # The Internal module provides API internal functionality that is not a part of the
14
+ # public API.
15
+ module Internal
16
+ end
17
+ end
@@ -0,0 +1,38 @@
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 Internal
9
+ # @api private
10
+ #
11
+ # {ProxyTracer} is an implementation of {OpenTelemetry::Trace::Tracer}. It is returned from
12
+ # the ProxyTracerProvider until a delegate tracer provider is installed. After the delegate
13
+ # tracer provider is installed, the ProxyTracer will delegate to the corresponding "real"
14
+ # tracer.
15
+ class ProxyTracer < Trace::Tracer
16
+ attr_writer :delegate
17
+
18
+ # Returns a new {ProxyTracer} instance.
19
+ #
20
+ # @return [ProxyTracer]
21
+ def initialize
22
+ @delegate = nil
23
+ end
24
+
25
+ def start_root_span(name, attributes: nil, links: nil, start_timestamp: nil, kind: nil)
26
+ return @delegate.start_root_span(name, attributes: attributes, links: links, start_timestamp: start_timestamp, kind: kind) unless @delegate.nil?
27
+
28
+ super
29
+ end
30
+
31
+ def start_span(name, with_parent: nil, attributes: nil, links: nil, start_timestamp: nil, kind: nil)
32
+ return @delegate.start_span(name, with_parent: with_parent, attributes: attributes, links: links, start_timestamp: start_timestamp, kind: kind) unless @delegate.nil?
33
+
34
+ super
35
+ end
36
+ end
37
+ end
38
+ end