opentelemetry-api 0.12.1 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/README.md +4 -4
  4. data/lib/opentelemetry.rb +24 -20
  5. data/lib/opentelemetry/baggage.rb +4 -1
  6. data/lib/opentelemetry/baggage/builder.rb +30 -4
  7. data/lib/opentelemetry/baggage/entry.rb +20 -0
  8. data/lib/opentelemetry/baggage/manager.rb +76 -13
  9. data/lib/opentelemetry/baggage/noop_builder.rb +18 -0
  10. data/lib/opentelemetry/baggage/noop_manager.rb +45 -0
  11. data/lib/opentelemetry/baggage/propagation.rb +9 -38
  12. data/lib/opentelemetry/baggage/propagation/text_map_propagator.rb +109 -0
  13. data/lib/opentelemetry/context/propagation.rb +62 -7
  14. data/lib/opentelemetry/context/propagation/composite_text_map_propagator.rb +105 -0
  15. data/lib/opentelemetry/context/propagation/noop_text_map_propagator.rb +51 -0
  16. data/lib/opentelemetry/context/propagation/rack_env_getter.rb +48 -0
  17. data/lib/opentelemetry/context/propagation/text_map_getter.rb +27 -0
  18. data/lib/opentelemetry/context/propagation/text_map_propagator.rb +71 -0
  19. data/lib/opentelemetry/context/propagation/text_map_setter.rb +21 -0
  20. data/lib/opentelemetry/internal.rb +17 -0
  21. data/lib/opentelemetry/internal/proxy_tracer.rb +38 -0
  22. data/lib/opentelemetry/internal/proxy_tracer_provider.rb +59 -0
  23. data/lib/opentelemetry/trace/propagation/trace_context.rb +7 -37
  24. data/lib/opentelemetry/trace/propagation/trace_context/text_map_propagator.rb +73 -0
  25. data/lib/opentelemetry/trace/span.rb +25 -1
  26. data/lib/opentelemetry/version.rb +1 -1
  27. metadata +20 -25
  28. data/lib/opentelemetry/baggage/propagation/text_map_extractor.rb +0 -60
  29. data/lib/opentelemetry/baggage/propagation/text_map_injector.rb +0 -55
  30. data/lib/opentelemetry/context/propagation/composite_propagator.rb +0 -73
  31. data/lib/opentelemetry/context/propagation/default_getter.rb +0 -26
  32. data/lib/opentelemetry/context/propagation/default_setter.rb +0 -26
  33. data/lib/opentelemetry/context/propagation/noop_extractor.rb +0 -26
  34. data/lib/opentelemetry/context/propagation/noop_injector.rb +0 -26
  35. data/lib/opentelemetry/context/propagation/propagation.rb +0 -27
  36. data/lib/opentelemetry/context/propagation/propagator.rb +0 -64
  37. data/lib/opentelemetry/instrumentation.rb +0 -15
  38. data/lib/opentelemetry/instrumentation/base.rb +0 -245
  39. data/lib/opentelemetry/instrumentation/registry.rb +0 -86
  40. data/lib/opentelemetry/metrics.rb +0 -16
  41. data/lib/opentelemetry/metrics/handles.rb +0 -44
  42. data/lib/opentelemetry/metrics/instruments.rb +0 -105
  43. data/lib/opentelemetry/metrics/meter.rb +0 -72
  44. data/lib/opentelemetry/metrics/meter_provider.rb +0 -22
  45. data/lib/opentelemetry/trace/propagation/trace_context/text_map_extractor.rb +0 -57
  46. data/lib/opentelemetry/trace/propagation/trace_context/text_map_injector.rb +0 -54
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ require 'cgi'
8
+
9
+ module OpenTelemetry
10
+ module Baggage
11
+ module Propagation
12
+ # Propagates baggage using the W3C Baggage format
13
+ class TextMapPropagator
14
+ # Maximums according to W3C Baggage spec
15
+ MAX_ENTRIES = 180
16
+ MAX_ENTRY_LENGTH = 4096
17
+ MAX_TOTAL_LENGTH = 8192
18
+
19
+ BAGGAGE_KEY = 'baggage'
20
+ FIELDS = [BAGGAGE_KEY].freeze
21
+
22
+ private_constant :BAGGAGE_KEY, :FIELDS, :MAX_ENTRIES, :MAX_ENTRY_LENGTH, :MAX_TOTAL_LENGTH
23
+
24
+ # Inject in-process baggage into the supplied carrier.
25
+ #
26
+ # @param [Carrier] carrier The mutable carrier to inject baggage into
27
+ # @param [Context] context The context to read baggage from
28
+ # @param [optional Setter] setter If the optional setter is provided, it
29
+ # will be used to write context into the carrier, otherwise the default
30
+ # text map setter will be used.
31
+ def inject(carrier, context: Context.current, setter: Context::Propagation.text_map_setter)
32
+ baggage = OpenTelemetry.baggage.raw_entries(context: context)
33
+
34
+ return if baggage.nil? || baggage.empty?
35
+
36
+ encoded_baggage = encode(baggage)
37
+ setter.set(carrier, BAGGAGE_KEY, encoded_baggage) unless encoded_baggage&.empty?
38
+ nil
39
+ end
40
+
41
+ # Extract remote baggage from the supplied carrier.
42
+ # If extraction fails, the original context will be returned
43
+ #
44
+ # @param [Carrier] carrier The carrier to get the header from
45
+ # @param [optional Context] context Context to be updated with the baggage
46
+ # extracted from the carrier. Defaults to +Context.current+.
47
+ # @param [optional Getter] getter If the optional getter is provided, it
48
+ # will be used to read the header from the carrier, otherwise the default
49
+ # text map getter will be used.
50
+ #
51
+ # @return [Context] context updated with extracted baggage, or the original context
52
+ # if extraction fails
53
+ def extract(carrier, context: Context.current, getter: Context::Propagation.text_map_getter)
54
+ header = getter.get(carrier, BAGGAGE_KEY)
55
+
56
+ entries = header.gsub(/\s/, '').split(',')
57
+
58
+ OpenTelemetry.baggage.build(context: context) do |builder|
59
+ entries.each do |entry|
60
+ # Note metadata is currently unused in OpenTelemetry, but is part
61
+ # the W3C spec where it's referred to as properties. We preserve
62
+ # the properties (as-is) so that they can be propagated elsewhere.
63
+ kv, meta = entry.split(';', 2)
64
+ k, v = kv.split('=').map!(&CGI.method(:unescape))
65
+ builder.set_value(k, v, metadata: meta)
66
+ end
67
+ end
68
+ rescue StandardError => e
69
+ OpenTelemetry.logger.debug "Error extracting W3C baggage: #{e.message}"
70
+ context
71
+ end
72
+
73
+ # Returns the predefined propagation fields. If your carrier is reused, you
74
+ # should delete the fields returned by this method before calling +inject+.
75
+ #
76
+ # @return [Array<String>] a list of fields that will be used by this propagator.
77
+ def fields
78
+ FIELDS
79
+ end
80
+
81
+ private
82
+
83
+ def encode(baggage)
84
+ result = +''
85
+ encoded_count = 0
86
+ baggage.each_pair do |key, entry|
87
+ break unless encoded_count < MAX_ENTRIES
88
+
89
+ encoded_entry = encode_value(key, entry)
90
+ next unless encoded_entry.size <= MAX_ENTRY_LENGTH &&
91
+ encoded_entry.size + result.size <= MAX_TOTAL_LENGTH
92
+
93
+ result << encoded_entry << ','
94
+ encoded_count += 1
95
+ end
96
+ result.chop!
97
+ end
98
+
99
+ def encode_value(key, entry)
100
+ result = +"#{CGI.escape(key.to_s)}=#{CGI.escape(entry.value.to_s)}"
101
+ # We preserve metadata recieved on extract and assume it's already formatted
102
+ # for transport. It's sent as-is without further processing.
103
+ result << ";#{entry.metadata}" if entry.metadata
104
+ result
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -4,19 +4,74 @@
4
4
  #
5
5
  # SPDX-License-Identifier: Apache-2.0
6
6
 
7
- require 'opentelemetry/context/propagation/composite_propagator'
8
- require 'opentelemetry/context/propagation/default_getter'
9
- require 'opentelemetry/context/propagation/default_setter'
10
- require 'opentelemetry/context/propagation/noop_extractor'
11
- require 'opentelemetry/context/propagation/noop_injector'
12
- require 'opentelemetry/context/propagation/propagation'
13
- 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'
10
+ require 'opentelemetry/context/propagation/text_map_getter'
11
+ require 'opentelemetry/context/propagation/text_map_propagator'
12
+ require 'opentelemetry/context/propagation/text_map_setter'
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
50
+ extend self
51
+
52
+ TEXT_MAP_GETTER = TextMapGetter.new
53
+ TEXT_MAP_SETTER = TextMapSetter.new
54
+ RACK_ENV_GETTER = RackEnvGetter.new
55
+
56
+ private_constant :TEXT_MAP_GETTER, :TEXT_MAP_SETTER, :RACK_ENV_GETTER
57
+
58
+ # Returns a {TextMapGetter} instance suitable for reading values from a
59
+ # hash-like carrier
60
+ def text_map_getter
61
+ TEXT_MAP_GETTER
62
+ end
63
+
64
+ # Returns a {TextMapSetter} instance suitable for writing values into a
65
+ # hash-like carrier
66
+ def text_map_setter
67
+ TEXT_MAP_SETTER
68
+ end
69
+
70
+ # Returns a {RackEnvGetter} instance suitable for reading values from a
71
+ # Rack environment.
72
+ def rack_env_getter
73
+ RACK_ENV_GETTER
74
+ end
20
75
  end
21
76
  end
22
77
  end
@@ -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
@@ -0,0 +1,48 @@
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
+ # The RackEnvGetter class provides a common methods for reading
11
+ # keys from a rack environment. It abstracts away the rack-normalization
12
+ # process so that keys can be looked up without having to transform them
13
+ # first. With this class you can get +traceparent+ instead of
14
+ # +HTTP_TRACEPARENT+
15
+ class RackEnvGetter
16
+ # Converts key into a rack-normalized key and reads it from the carrier.
17
+ # Useful for extract operations.
18
+ def get(carrier, key)
19
+ carrier[to_rack_key(key)] || carrier[key]
20
+ end
21
+
22
+ # Reads all keys from a carrier and converts them from the rack-normalized
23
+ # form to the original. The resulting keys will be lowercase and
24
+ # underscores will be replaced with dashes.
25
+ def keys(carrier)
26
+ carrier.keys.map(&method(:from_rack_key))
27
+ end
28
+
29
+ private
30
+
31
+ def to_rack_key(key)
32
+ ret = 'HTTP_' + key
33
+ ret.tr!('-', '_')
34
+ ret.upcase!
35
+ ret
36
+ end
37
+
38
+ def from_rack_key(key)
39
+ start = key.start_with?('HTTP_') ? 5 : 0
40
+ ret = key[start..-1]
41
+ ret.tr!('_', '-')
42
+ ret.downcase!
43
+ ret
44
+ end
45
+ end
46
+ end
47
+ end
48
+ 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
+ # The default getter module provides a common methods for reading
11
+ # key from a carrier that implements +[]+ and a +keys+ method
12
+ class TextMapGetter
13
+ # Reads a key from a carrier that implements +[]+. Useful for extract
14
+ # operations.
15
+ def get(carrier, key)
16
+ carrier[key]
17
+ end
18
+
19
+ # Reads all keys from a carrier. Useful for iterating over a carrier's
20
+ # keys.
21
+ def keys(carrier)
22
+ carrier.keys
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,71 @@
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 text map propagator that composes an extractor and injector into a
11
+ # single interface exposing inject and extract methods.
12
+ class TextMapPropagator
13
+ # Returns a Propagator that delegates inject and extract to the provided
14
+ # injector and extractor
15
+ #
16
+ # @param [#inject] injector
17
+ # @param [#extract] extractor
18
+ def initialize(injector, extractor)
19
+ raise ArgumentError, 'injector and extractor must both be non-nil' if injector.nil? || extractor.nil?
20
+
21
+ @injector = injector
22
+ @extractor = extractor
23
+ end
24
+
25
+ # Injects the provided context into a carrier using the underlying
26
+ # injector. Logs a warning if injection fails.
27
+ #
28
+ # @param [Object] carrier A mutable carrier to inject context into.
29
+ # @param [optional Context] context Context to be injected into carrier. Defaults
30
+ # to +Context.current+.
31
+ # @param [optional Setter] setter If the optional setter is provided, it
32
+ # will be used to write context into the carrier, otherwise the default
33
+ # setter will be used.
34
+ def inject(carrier, context: Context.current, setter: Context::Propagation.text_map_setter)
35
+ @injector.inject(carrier, context, setter)
36
+ nil
37
+ rescue StandardError => e
38
+ OpenTelemetry.logger.warn "Error in Propagator#inject #{e.message}"
39
+ nil
40
+ end
41
+
42
+ # Extracts and returns context from a carrier. Returns the provided
43
+ # context and logs a warning if an error if extraction fails.
44
+ #
45
+ # @param [Object] carrier The carrier to extract context from.
46
+ # @param [optional Context] context Context to be updated with the state
47
+ # extracted from the carrier. Defaults to +Context.current+.
48
+ # @param [optional Getter] getter If the optional getter is provided, it
49
+ # will be used to read the header from the carrier, otherwise the default
50
+ # getter will be used.
51
+ #
52
+ # @return [Context] a new context updated with state extracted from the
53
+ # carrier
54
+ def extract(carrier, context: Context.current, getter: Context::Propagation.text_map_getter)
55
+ @extractor.extract(carrier, context, getter)
56
+ rescue StandardError => e
57
+ OpenTelemetry.logger.warn "Error in Propagator#extract #{e.message}"
58
+ context
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
68
+ end
69
+ end
70
+ end
71
+ end