opentelemetry-api 0.14.0 → 1.0.0.rc2

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -0
  3. data/README.md +2 -2
  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 +110 -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 +51 -0
  14. data/lib/opentelemetry/context/propagation/rack_env_getter.rb +3 -1
  15. data/lib/opentelemetry/context/propagation/{propagator.rb → text_map_propagator.rb} +23 -16
  16. data/lib/opentelemetry/internal.rb +17 -0
  17. data/lib/opentelemetry/internal/proxy_tracer.rb +38 -0
  18. data/lib/opentelemetry/internal/proxy_tracer_provider.rb +59 -0
  19. data/lib/opentelemetry/trace.rb +10 -0
  20. data/lib/opentelemetry/trace/propagation/trace_context.rb +7 -18
  21. data/lib/opentelemetry/trace/propagation/trace_context/text_map_propagator.rb +73 -0
  22. data/lib/opentelemetry/trace/span.rb +20 -0
  23. data/lib/opentelemetry/trace/status.rb +34 -5
  24. data/lib/opentelemetry/trace/tracer.rb +8 -9
  25. data/lib/opentelemetry/version.rb +1 -1
  26. metadata +16 -25
  27. data/lib/opentelemetry/baggage/manager.rb +0 -41
  28. data/lib/opentelemetry/baggage/propagation/text_map_extractor.rb +0 -57
  29. data/lib/opentelemetry/baggage/propagation/text_map_injector.rb +0 -52
  30. data/lib/opentelemetry/context/propagation/composite_propagator.rb +0 -72
  31. data/lib/opentelemetry/context/propagation/noop_extractor.rb +0 -26
  32. data/lib/opentelemetry/context/propagation/noop_injector.rb +0 -26
  33. data/lib/opentelemetry/instrumentation.rb +0 -15
  34. data/lib/opentelemetry/instrumentation/base.rb +0 -245
  35. data/lib/opentelemetry/instrumentation/registry.rb +0 -86
  36. data/lib/opentelemetry/metrics.rb +0 -16
  37. data/lib/opentelemetry/metrics/handles.rb +0 -44
  38. data/lib/opentelemetry/metrics/instruments.rb +0 -105
  39. data/lib/opentelemetry/metrics/meter.rb +0 -72
  40. data/lib/opentelemetry/metrics/meter_provider.rb +0 -22
  41. data/lib/opentelemetry/trace/propagation/trace_context/text_map_extractor.rb +0 -52
  42. data/lib/opentelemetry/trace/propagation/trace_context/text_map_injector.rb +0 -49
  43. 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,51 @@
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 no-op text map propagator implementation
11
+ class NoopTextMapPropagator
12
+ EMPTY_LIST = [].freeze
13
+ private_constant(:EMPTY_LIST)
14
+
15
+ # Injects the provided context into a carrier.
16
+ #
17
+ # @param [Object] carrier A mutable carrier to inject context into.
18
+ # @param [optional Context] context Context to be injected into carrier. Defaults
19
+ # to +Context.current+.
20
+ # @param [optional Setter] setter If the optional setter is provided, it
21
+ # will be used to write context into the carrier, otherwise the default
22
+ # setter will be used.
23
+ def inject(carrier, context: Context.current, setter: Context::Propagation.text_map_setter); end
24
+
25
+ # Extracts and returns context from a carrier. Returns the provided
26
+ # context and logs a warning if an error if extraction fails.
27
+ #
28
+ # @param [Object] carrier The carrier to extract context from.
29
+ # @param [optional Context] context Context to be updated with the state
30
+ # extracted from the carrier. Defaults to +Context.current+.
31
+ # @param [optional Getter] getter If the optional getter is provided, it
32
+ # will be used to read the header from the carrier, otherwise the default
33
+ # getter will be used.
34
+ #
35
+ # @return [Context] a new context updated with state extracted from the
36
+ # carrier
37
+ def extract(carrier, context: Context.current, getter: Context::Propagation.text_map_getter)
38
+ context
39
+ end
40
+
41
+ # Returns the predefined propagation fields. If your carrier is reused, you
42
+ # should delete the fields returned by this method before calling +inject+.
43
+ #
44
+ # @return [Array<String>] a list of fields that will be used by this propagator.
45
+ def fields
46
+ EMPTY_LIST
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -16,7 +16,7 @@ module OpenTelemetry
16
16
  # Converts key into a rack-normalized key and reads it from the carrier.
17
17
  # Useful for extract operations.
18
18
  def get(carrier, key)
19
- carrier[to_rack_key(key)]
19
+ carrier[to_rack_key(key)] || carrier[key]
20
20
  end
21
21
 
22
22
  # Reads all keys from a carrier and converts them from the rack-normalized
@@ -32,6 +32,7 @@ module OpenTelemetry
32
32
  ret = 'HTTP_' + key
33
33
  ret.tr!('-', '_')
34
34
  ret.upcase!
35
+ ret
35
36
  end
36
37
 
37
38
  def from_rack_key(key)
@@ -39,6 +40,7 @@ module OpenTelemetry
39
40
  ret = key[start..-1]
40
41
  ret.tr!('_', '-')
41
42
  ret.downcase!
43
+ ret
42
44
  end
43
45
  end
44
46
  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