opentelemetry-sdk 0.13.0 → 0.17.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b64da58e8086f08efd2f7bace98369ec16936abcf95996588bda288a592d5912
4
- data.tar.gz: 4d67cd982c51998cf0396531bcbaae6f62f23b89314793def72410624c87a645
3
+ metadata.gz: 4be88dba1f3a925ceb97494267f2d27cfb24f5f89e417236d5cca698c0388b9b
4
+ data.tar.gz: 8e43a87d87dc739c1323acecaa18e93dac8a911fc28a119c016e5e834ca74615
5
5
  SHA512:
6
- metadata.gz: 3d8d0331a351e32cf184a512c155c6d3944bb5bbbb2857aad27636bdc7eca58081d45e6d778eecd50681e1a1c471c75f9cf7d8116b57ba5c5c5b7a5838f3a648
7
- data.tar.gz: ef884f72a85e1457b1d160d2075313df169f895cfe92831d87e77022244db6b6d980f7a36f6c88926886fd67538e916c2e813728ce80aa2897ef24da216d2924
6
+ metadata.gz: 672426fc31d0c6cce4f363509085b40bddf66d6c6516048e40ae1661fefaf2a6a3482acfe9a6dcff8db328675fb2e5ec02c9fe89d91486f551bf029bcb390f6b
7
+ data.tar.gz: 42b693687ddfdf1221c972d902e9249fcec6a947bb48416b4627fbd805859ac8bc5fcdb18ac44e4fb628bfd56f67bf42d028465f6e34c4c679844a7c1027515d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # Release History: opentelemetry-sdk
2
2
 
3
+ ### v0.17.0 / 2021-04-22
4
+
5
+ * BREAKING CHANGE: Replace TextMapInjector/TextMapExtractor pairs with a TextMapPropagator.
6
+
7
+ [Check the propagator documentation](https://open-telemetry.github.io/opentelemetry-ruby/) for the new usage.
8
+
9
+ * ADDED: Add zipkin exporter
10
+ * ADDED: Processors validate exporters on init.
11
+ * ADDED: Add configurable truncation of span and event attribute values
12
+ * ADDED: Add simple 'recording' attr_accessor to InMemorySpanExporter
13
+ * FIXED: Typo in error message
14
+ * FIXED: Improve configuration error reporting
15
+ * FIXED: Refactor propagators to add #fields
16
+
17
+ ### v0.16.0 / 2021-03-17
18
+
19
+ * BREAKING CHANGE: Update SDK BaggageManager to match API
20
+ * BREAKING CHANGE: Implement Exporter#force_flush
21
+
22
+ * ADDED: Add force_flush to SDK's TracerProvider
23
+ * ADDED: Add k8s node to gcp resource detector
24
+ * ADDED: Add console option for OTEL_TRACES_EXPORTER
25
+ * ADDED: Span#add_attributes
26
+ * ADDED: Implement Exporter#force_flush
27
+ * FIXED: Update SDK BaggageManager to match API
28
+ * DOCS: Replace Gitter with GitHub Discussions
29
+
30
+ ### v0.15.0 / 2021-02-18
31
+
32
+ * BREAKING CHANGE: Streamline processor pipeline
33
+
34
+ * ADDED: Add instrumentation config validation
35
+ * FIXED: Streamline processor pipeline
36
+ * FIXED: OTEL_TRACE -> OTEL_TRACES env vars
37
+ * FIXED: Change limits from 1000 to 128
38
+ * FIXED: OTEL_TRACES_EXPORTER and OTEL_PROPAGATORS
39
+ * FIXED: Add thread error handling to the BSP
40
+ * DOCS: Clarify nil attribute values not allowed
41
+
42
+ ### v0.14.0 / 2021-02-03
43
+
44
+ * BREAKING CHANGE: Replace getter and setter callables and remove rack specific propagators
45
+
46
+ * ADDED: Replace getter and setter callables and remove rack specific propagators
47
+
48
+ ### v0.13.1 / 2021-02-01
49
+
50
+ * FIXED: Leaky test
51
+ * FIXED: Allow env var override of service.name
52
+
3
53
  ### v0.13.0 / 2021-01-29
4
54
 
5
55
  * BREAKING CHANGE: Remove MILLIS from BatchSpanProcessor vars
data/README.md CHANGED
@@ -56,7 +56,7 @@ For additional examples, see the [examples on github][examples-github].
56
56
 
57
57
  The `opentelemetry-sdk` gem source is [on github][repo-github], along with related gems including `opentelemetry-api`.
58
58
 
59
- The OpenTelemetry Ruby gems are maintained by the OpenTelemetry-Ruby special interest group (SIG). You can get involved by joining us on our [gitter channel][ruby-gitter] or attending our weekly meeting. See the [meeting calendar][community-meetings] for dates and times. For more information on this and other language SIGs, see the OpenTelemetry [community page][ruby-sig].
59
+ The OpenTelemetry Ruby gems are maintained by the OpenTelemetry-Ruby special interest group (SIG). You can get involved by joining us in [GitHub Discussions][discussions-url] or attending our weekly meeting. See the [meeting calendar][community-meetings] for dates and times. For more information on this and other language SIGs, see the OpenTelemetry [community page][ruby-sig].
60
60
 
61
61
  ## License
62
62
 
@@ -70,4 +70,4 @@ The `opentelemetry-sdk` gem is distributed under the Apache 2.0 license. See [LI
70
70
  [examples-github]: https://github.com/open-telemetry/opentelemetry-ruby/tree/main/examples
71
71
  [ruby-sig]: https://github.com/open-telemetry/community#ruby-sig
72
72
  [community-meetings]: https://github.com/open-telemetry/community#community-meetings
73
- [ruby-gitter]: https://gitter.im/open-telemetry/opentelemetry-ruby
73
+ [discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions
@@ -6,6 +6,7 @@
6
6
 
7
7
  require 'opentelemetry'
8
8
  require 'opentelemetry/common'
9
+ require 'opentelemetry-instrumentation-base'
9
10
 
10
11
  # OpenTelemetry is an open source observability framework, providing a
11
12
  # general-purpose API, SDK, and related tools required for the instrumentation
@@ -66,14 +67,13 @@ module OpenTelemetry
66
67
  begin
67
68
  raise ConfigurationError
68
69
  rescue ConfigurationError => e
69
- OpenTelemetry.handle_error(exception: e, message: 'unexpected configuration error')
70
+ OpenTelemetry.handle_error(exception: e, message: "unexpected configuration error due to #{e.cause}")
70
71
  end
71
72
  end
72
73
  end
73
74
  end
74
75
 
75
76
  require 'opentelemetry/sdk/configurator'
76
- require 'opentelemetry/sdk/baggage'
77
77
  require 'opentelemetry/sdk/internal'
78
78
  require 'opentelemetry/sdk/instrumentation_library'
79
79
  require 'opentelemetry/sdk/resources'
@@ -15,16 +15,12 @@ module OpenTelemetry
15
15
 
16
16
  private_constant :USE_MODE_UNSPECIFIED, :USE_MODE_ONE, :USE_MODE_ALL
17
17
 
18
- attr_writer :logger, :http_extractors, :http_injectors, :text_map_extractors,
19
- :text_map_injectors, :error_handler, :id_generator
18
+ attr_writer :logger, :propagators, :error_handler, :id_generator
20
19
 
21
20
  def initialize
22
21
  @instrumentation_names = []
23
22
  @instrumentation_config_map = {}
24
- @http_extractors = nil
25
- @http_injectors = nil
26
- @text_map_extractors = nil
27
- @text_map_injectors = nil
23
+ @propagators = nil
28
24
  @span_processors = []
29
25
  @use_mode = USE_MODE_UNSPECIFIED
30
26
  @resource = Resources::Resource.default
@@ -138,61 +134,61 @@ module OpenTelemetry
138
134
  def install_instrumentation
139
135
  case @use_mode
140
136
  when USE_MODE_ONE
141
- OpenTelemetry.instrumentation_registry.install(@instrumentation_names, @instrumentation_config_map)
137
+ OpenTelemetry::Instrumentation.registry.install(@instrumentation_names, @instrumentation_config_map)
142
138
  when USE_MODE_ALL
143
- OpenTelemetry.instrumentation_registry.install_all(@instrumentation_config_map)
139
+ OpenTelemetry::Instrumentation.registry.install_all(@instrumentation_config_map)
144
140
  end
145
141
  end
146
142
 
147
143
  def configure_span_processors
148
- processors = @span_processors.empty? ? [default_span_processor] : @span_processors
144
+ processors = @span_processors.empty? ? [wrapped_exporter_from_env].compact : @span_processors
149
145
  processors.each { |p| tracer_provider.add_span_processor(p) }
150
146
  end
151
147
 
152
- def default_span_processor
153
- Trace::Export::SimpleSpanProcessor.new(
154
- Trace::Export::ConsoleSpanExporter.new
155
- )
156
- end
157
-
158
- def configure_propagation
159
- OpenTelemetry.propagation.http = create_propagator(@http_injectors || default_http_injectors,
160
- @http_extractors || default_http_extractors)
161
- OpenTelemetry.propagation.text = create_propagator(@text_map_injectors || default_text_map_injectors,
162
- @text_map_extractors || default_text_map_extractors)
163
- end
164
-
165
- def create_propagator(injectors, extractors)
166
- if injectors.size > 1 || extractors.size > 1
167
- Context::Propagation::CompositePropagator.new(injectors, extractors)
148
+ def wrapped_exporter_from_env
149
+ exporter = ENV.fetch('OTEL_TRACES_EXPORTER', 'otlp')
150
+ case exporter
151
+ when 'none' then nil
152
+ when 'otlp' then fetch_exporter(exporter, 'OpenTelemetry::Exporter::OTLP::Exporter')
153
+ when 'jaeger' then fetch_exporter(exporter, 'OpenTelemetry::Exporter::Jaeger::CollectorExporter')
154
+ when 'zipkin' then fetch_exporter(exporter, 'OpenTelemetry::Exporter::Zipkin::Exporter')
155
+ when 'console' then Trace::Export::SimpleSpanProcessor.new(Trace::Export::ConsoleSpanExporter.new)
168
156
  else
169
- Context::Propagation::Propagator.new(injectors, extractors)
157
+ OpenTelemetry.logger.warn "The #{exporter} exporter is unknown and cannot be configured, spans will not be exported"
158
+ nil
170
159
  end
171
160
  end
172
161
 
173
- def default_http_injectors
174
- default_text_map_injectors
175
- end
176
-
177
- def default_http_extractors
178
- [
179
- OpenTelemetry::Trace::Propagation::TraceContext.rack_extractor,
180
- OpenTelemetry::Baggage::Propagation.rack_extractor
181
- ]
162
+ def configure_propagation # rubocop:disable Metrics/CyclomaticComplexity
163
+ propagators = ENV.fetch('OTEL_PROPAGATORS', 'tracecontext,baggage').split(',').uniq.collect do |propagator|
164
+ case propagator
165
+ when 'tracecontext' then OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator
166
+ when 'baggage' then OpenTelemetry::Baggage::Propagation.text_map_propagator
167
+ when 'b3' then fetch_propagator(propagator, 'OpenTelemetry::Propagator::B3::Single')
168
+ when 'b3multi' then fetch_propagator(propagator, 'OpenTelemetry::Propagator::B3::Multi', 'b3')
169
+ when 'jaeger' then fetch_propagator(propagator, 'OpenTelemetry::Propagator::Jaeger')
170
+ when 'xray' then fetch_propagator(propagator, 'OpenTelemetry::Propagator::XRay')
171
+ when 'ottrace' then fetch_propagator(propagator, 'OpenTelemetry::Propagator::OTTrace')
172
+ else
173
+ OpenTelemetry.logger.warn "The #{propagator} propagator is unknown and cannot be configured"
174
+ Context::Propagation::NoopTextMapPropagator.new
175
+ end
176
+ end
177
+ OpenTelemetry.propagation = Context::Propagation::CompositeTextMapPropagator.compose_propagators((@propagators || propagators).compact)
182
178
  end
183
179
 
184
- def default_text_map_injectors
185
- [
186
- OpenTelemetry::Trace::Propagation::TraceContext.text_map_injector,
187
- OpenTelemetry::Baggage::Propagation.text_map_injector
188
- ]
180
+ def fetch_propagator(name, class_name, gem_suffix = name)
181
+ Kernel.const_get(class_name).text_map_propagator
182
+ rescue NameError
183
+ OpenTelemetry.logger.warn "The #{name} propagator cannot be configured - please add opentelemetry-propagator-#{gem_suffix} to your Gemfile"
184
+ nil
189
185
  end
190
186
 
191
- def default_text_map_extractors
192
- [
193
- OpenTelemetry::Trace::Propagation::TraceContext.text_map_extractor,
194
- OpenTelemetry::Baggage::Propagation.text_map_extractor
195
- ]
187
+ def fetch_exporter(name, class_name)
188
+ Trace::Export::BatchSpanProcessor.new(Kernel.const_get(class_name).new)
189
+ rescue NameError
190
+ OpenTelemetry.logger.warn "The #{name} exporter cannot be configured - please add opentelemetry-exporter-#{name} to your Gemfile, spans will not be exported"
191
+ nil
196
192
  end
197
193
  end
198
194
  end
@@ -47,7 +47,7 @@ module OpenTelemetry
47
47
  def valid_attributes?(attrs)
48
48
  attrs.nil? || attrs.all? do |k, v|
49
49
  if !valid_key?(k)
50
- OpenTelemetry.handle_error(message: "invalid attribute key type #{v.class}")
50
+ OpenTelemetry.handle_error(message: "invalid attribute key type #{k.class}")
51
51
  false
52
52
  elsif !valid_value?(v)
53
53
  OpenTelemetry.handle_error(message: "invalid attribute value type #{v.class}")
@@ -67,14 +67,59 @@ module OpenTelemetry
67
67
  # The name of the cluster that the pod is running in.
68
68
  cluster_name: 'k8s.cluster.name',
69
69
 
70
+ # The name of the Node.
71
+ node_name: 'k8s.node.name',
72
+
73
+ # The UID of the Node.
74
+ node_uid: 'k8s.node.uid',
75
+
70
76
  # The name of the namespace that the pod is running in.
71
77
  namespace_name: 'k8s.namespace.name',
72
78
 
73
79
  # The name of the pod.
74
80
  pod_name: 'k8s.pod.name',
75
81
 
82
+ # The UID of the Pod.
83
+ pod_uid: 'k8s.pod.uid',
84
+
85
+ # The name of the Container in a Pod template.
86
+ container_name: 'k8s.container.name',
87
+
88
+ # The UID of the ReplicaSet.
89
+ replicaset_uid: 'k8s.replicaset.uid',
90
+
91
+ # The name of the ReplicaSet.
92
+ replicaset_name: 'k8s.replicaset.name',
93
+
94
+ # The UID of the Deployment.
95
+ deployment_uid: 'k8s.deployment.uid',
96
+
76
97
  # The name of the deployment.
77
- deployment_name: 'k8s.deployment.name'
98
+ deployment_name: 'k8s.deployment.name',
99
+
100
+ # The UID of the StatefulSet.
101
+ statefulset_uid: 'k8s.statefulset.uid',
102
+
103
+ # The name of the StatefulSet.
104
+ statefulset_name: 'k8s.statefulset.name',
105
+
106
+ # The UID of the DaemonSet.
107
+ daemonset_uid: 'k8s.daemonset.uid',
108
+
109
+ # The name of the DaemonSet.
110
+ daemonset_name: 'k8s.daemonset.name',
111
+
112
+ # The UID of the Job.
113
+ job_uid: 'k8s.job.uid',
114
+
115
+ # The name of the Job.
116
+ job_name: 'k8s.job.name',
117
+
118
+ # The UID of the CronJob.
119
+ cronjob_uid: 'k8s.cronjob.uid',
120
+
121
+ # The name of the CronJob.
122
+ cronjob_name: 'k8s.cronjob.name'
78
123
  }.freeze
79
124
 
80
125
  # Attributes defining an operating system process.
@@ -31,7 +31,7 @@ module OpenTelemetry
31
31
  end
32
32
 
33
33
  def default
34
- @default ||= telemetry_sdk.merge(process).merge(create(Constants::SERVICE_RESOURCE[:name] => 'unknown_service'))
34
+ @default ||= create(Constants::SERVICE_RESOURCE[:name] => 'unknown_service').merge(process).merge(telemetry_sdk)
35
35
  end
36
36
 
37
37
  def telemetry_sdk
@@ -16,6 +16,9 @@ module OpenTelemetry
16
16
  # The global default max number of attributes per {Span}.
17
17
  attr_reader :max_attributes_count
18
18
 
19
+ # The global default max length of attribute value per {Span}.
20
+ attr_reader :max_attributes_length
21
+
19
22
  # The global default max number of {OpenTelemetry::SDK::Trace::Event}s per {Span}.
20
23
  attr_reader :max_events_count
21
24
 
@@ -32,13 +35,15 @@ module OpenTelemetry
32
35
  #
33
36
  # @return [TraceConfig] with the desired values.
34
37
  # @raise [ArgumentError] if any of the max numbers are not positive.
35
- def initialize(sampler: sampler_from_environment(Samplers.parent_based(root: Samplers::ALWAYS_ON)),
36
- max_attributes_count: Integer(ENV.fetch('OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT', 1000)),
37
- max_events_count: Integer(ENV.fetch('OTEL_SPAN_EVENT_COUNT_LIMIT', 1000)),
38
- max_links_count: Integer(ENV.fetch('OTEL_SPAN_LINK_COUNT_LIMIT', 1000)),
38
+ def initialize(sampler: sampler_from_environment(Samplers.parent_based(root: Samplers::ALWAYS_ON)), # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
39
+ max_attributes_count: Integer(ENV.fetch('OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT', 128)),
40
+ max_attributes_length: ENV['OTEL_RUBY_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT'],
41
+ max_events_count: Integer(ENV.fetch('OTEL_SPAN_EVENT_COUNT_LIMIT', 128)),
42
+ max_links_count: Integer(ENV.fetch('OTEL_SPAN_LINK_COUNT_LIMIT', 128)),
39
43
  max_attributes_per_event: max_attributes_count,
40
44
  max_attributes_per_link: max_attributes_count)
41
45
  raise ArgumentError, 'max_attributes_count must be positive' unless max_attributes_count.positive?
46
+ raise ArgumentError, 'max_attributes_length must not be less than 32' unless max_attributes_length.nil? || Integer(max_attributes_length) >= 32
42
47
  raise ArgumentError, 'max_events_count must be positive' unless max_events_count.positive?
43
48
  raise ArgumentError, 'max_links_count must be positive' unless max_links_count.positive?
44
49
  raise ArgumentError, 'max_attributes_per_event must be positive' unless max_attributes_per_event.positive?
@@ -46,6 +51,7 @@ module OpenTelemetry
46
51
 
47
52
  @sampler = sampler
48
53
  @max_attributes_count = max_attributes_count
54
+ @max_attributes_length = max_attributes_length.nil? ? nil : Integer(max_attributes_length)
49
55
  @max_events_count = max_events_count
50
56
  @max_links_count = max_links_count
51
57
  @max_attributes_per_event = max_attributes_per_event
@@ -56,13 +62,13 @@ module OpenTelemetry
56
62
  private
57
63
 
58
64
  def sampler_from_environment(default_sampler) # rubocop:disable Metrics/CyclomaticComplexity
59
- case ENV['OTEL_TRACE_SAMPLER']
65
+ case ENV['OTEL_TRACES_SAMPLER']
60
66
  when 'always_on' then Samplers::ALWAYS_ON
61
67
  when 'always_off' then Samplers::ALWAYS_OFF
62
- when 'traceidratio' then Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACE_SAMPLER_ARG', 1.0)))
68
+ when 'traceidratio' then Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACES_SAMPLER_ARG', 1.0)))
63
69
  when 'parentbased_always_on' then Samplers.parent_based(root: Samplers::ALWAYS_ON)
64
70
  when 'parentbased_always_off' then Samplers.parent_based(root: Samplers::ALWAYS_OFF)
65
- when 'parentbased_traceidratio' then Samplers.parent_based(root: Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACE_SAMPLER_ARG', 1.0))))
71
+ when 'parentbased_traceidratio' then Samplers.parent_based(root: Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACES_SAMPLER_ARG', 1.0))))
66
72
  else default_sampler
67
73
  end
68
74
  rescue StandardError => e
@@ -28,7 +28,8 @@ module OpenTelemetry
28
28
  class BatchSpanProcessor # rubocop:disable Metrics/ClassLength
29
29
  # Returns a new instance of the {BatchSpanProcessor}.
30
30
  #
31
- # @param [SpanExporter] exporter
31
+ # @param [SpanExporter] exporter the (duck type) SpanExporter to where the
32
+ # recorded Spans are pushed after batching.
32
33
  # @param [Numeric] exporter_timeout the delay interval between two
33
34
  # consecutive exports. Defaults to the value of the OTEL_BSP_EXPORT_TIMEOUT
34
35
  # environment variable, if set, or 30,000 (30 seconds).
@@ -43,7 +44,7 @@ module OpenTelemetry
43
44
  # variable, if set, or 512.
44
45
  #
45
46
  # @return a new instance of the {BatchSpanProcessor}.
46
- def initialize(exporter:,
47
+ def initialize(exporter,
47
48
  exporter_timeout: Float(ENV.fetch('OTEL_BSP_EXPORT_TIMEOUT', 30_000)),
48
49
  schedule_delay: Float(ENV.fetch('OTEL_BSP_SCHEDULE_DELAY', 5_000)),
49
50
  max_queue_size: Integer(ENV.fetch('OTEL_BSP_MAX_QUEUE_SIZE', 2048)),
@@ -51,6 +52,7 @@ module OpenTelemetry
51
52
  start_thread_on_boot: String(ENV['OTEL_RUBY_BSP_START_THREAD_ON_BOOT']) !~ /false/i,
52
53
  metrics_reporter: nil)
53
54
  raise ArgumentError if max_export_batch_size > max_queue_size
55
+ raise ArgumentError, "exporter #{exporter.inspect} does not appear to be a valid exporter" unless Common::Utilities.valid_exporter?(exporter)
54
56
 
55
57
  @exporter = exporter
56
58
  @exporter_timeout_seconds = exporter_timeout / 1000.0
@@ -113,7 +115,7 @@ module OpenTelemetry
113
115
  return result_code unless result_code == SUCCESS
114
116
  end
115
117
 
116
- SUCCESS
118
+ @exporter.force_flush(timeout: OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time))
117
119
  ensure
118
120
  # Unshift the remaining spans if we timed out. We drop excess spans from
119
121
  # the snapshot because they're older than any spans in the spans buffer.
@@ -176,6 +178,9 @@ module OpenTelemetry
176
178
  @pid = pid
177
179
  spans.clear
178
180
  @thread = restart_thread ? Thread.new { work } : nil
181
+ rescue ThreadError => e
182
+ @metrics_reporter.add_to_counter('otel.bsp.error', labels: { 'reason' => 'ThreadError' })
183
+ OpenTelemetry.handle_error(exception: e, message: 'unexpected error in BatchSpanProcessor#reset_on_fork')
179
184
  end
180
185
 
181
186
  def export_batch(batch, timeout: @exporter_timeout_seconds)
@@ -26,6 +26,10 @@ module OpenTelemetry
26
26
  SUCCESS
27
27
  end
28
28
 
29
+ def force_flush(timeout: nil)
30
+ SUCCESS
31
+ end
32
+
29
33
  def shutdown(timeout: nil)
30
34
  @stopped = true
31
35
  SUCCESS
@@ -10,30 +10,39 @@ module OpenTelemetry
10
10
  module Export
11
11
  # A SpanExporter implementation that can be used to test OpenTelemetry integration.
12
12
  #
13
- # Example usage:
13
+ # Example usage in a test suite:
14
14
  #
15
15
  # class MyClassTest
16
16
  # def setup
17
17
  # @tracer_provider = TracerProvider.new
18
- # @exporter = InMemorySpanExporter.new
18
+ # # The default is `recording: true`, which is appropriate in non-test environments.
19
+ # @exporter = InMemorySpanExporter.new(recording: false)
19
20
  # @tracer_provider.add_span_processor(SimpleSampledSpansProcessor.new(@exporter))
20
21
  # end
21
22
  #
22
23
  # def test_finished_spans
24
+ # @exporter.recording = true
23
25
  # @tracer_provider.tracer.in_span("span") {}
24
26
  #
25
27
  # spans = @exporter.finished_spans
26
28
  # spans.wont_be_nil
27
29
  # spans.size.must_equal(1)
28
30
  # spans[0].name.must_equal("span")
31
+ #
32
+ # @exporter.recording = false
29
33
  # end
30
34
  class InMemorySpanExporter
35
+ # Controls whether or not the exporter will record spans, or discard them.
36
+ # @return [Boolean] when true, the exporter is recording. By default, this is true.
37
+ attr_accessor :recording
38
+
31
39
  # Returns a new instance of the {InMemorySpanExporter}.
32
40
  #
33
41
  # @return a new instance of the {InMemorySpanExporter}.
34
- def initialize
42
+ def initialize(recording: true)
35
43
  @finished_spans = []
36
44
  @stopped = false
45
+ @recording = recording
37
46
  @mutex = Mutex.new
38
47
  end
39
48
 
@@ -67,11 +76,21 @@ module OpenTelemetry
67
76
  @mutex.synchronize do
68
77
  return FAILURE if @stopped
69
78
 
70
- @finished_spans.concat(span_datas.to_a)
79
+ @finished_spans.concat(span_datas.to_a) if @recording
71
80
  end
72
81
  SUCCESS
73
82
  end
74
83
 
84
+ # Called when {TracerProvider#force_flush} is called, if this exporter is
85
+ # registered to a {TracerProvider} object.
86
+ #
87
+ # @param [optional Numeric] timeout An optional timeout in seconds.
88
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
89
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
90
+ def force_flush(timeout: nil)
91
+ SUCCESS
92
+ end
93
+
75
94
  # Called when {TracerProvider#shutdown} is called, if this exporter is
76
95
  # registered to a {TracerProvider} object.
77
96
  #
@@ -36,6 +36,23 @@ module OpenTelemetry
36
36
  results.uniq.max || SUCCESS
37
37
  end
38
38
 
39
+ # Called when {TracerProvider#force_flush} is called, if this exporter is
40
+ # registered to a {TracerProvider} object.
41
+ #
42
+ # @param [optional Numeric] timeout An optional timeout in seconds.
43
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
44
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
45
+ def force_flush(timeout: nil)
46
+ start_time = Time.now
47
+ results = @span_exporters.map do |processor|
48
+ remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
49
+ return TIMEOUT if remaining_timeout&.zero?
50
+
51
+ processor.force_flush(timeout: remaining_timeout)
52
+ end
53
+ results.uniq.max || SUCCESS
54
+ end
55
+
39
56
  # Called when {TracerProvider#shutdown} is called, if this exporter is
40
57
  # registered to a {TracerProvider} object.
41
58
  #
@@ -31,6 +31,16 @@ module OpenTelemetry
31
31
  FAILURE
32
32
  end
33
33
 
34
+ # Called when {TracerProvider#force_flush} is called, if this exporter is
35
+ # registered to a {TracerProvider} object.
36
+ #
37
+ # @param [optional Numeric] timeout An optional timeout in seconds.
38
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
39
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
40
+ def force_flush(timeout: nil)
41
+ SUCCESS
42
+ end
43
+
34
44
  # Called when {TracerProvider#shutdown} is called, if this exporter is
35
45
  # registered to a {TracerProvider} object.
36
46
  #
@@ -29,6 +29,8 @@ module OpenTelemetry
29
29
  # @return [SimpleSpanProcessor]
30
30
  # @raise ArgumentError if the span_exporter is nil.
31
31
  def initialize(span_exporter)
32
+ raise ArgumentError, "exporter #{span_exporter.inspect} does not appear to be a valid exporter" unless Common::Utilities.valid_exporter?(span_exporter)
33
+
32
34
  @span_exporter = span_exporter
33
35
  end
34
36
 
@@ -61,7 +63,7 @@ module OpenTelemetry
61
63
  end
62
64
 
63
65
  # Export all ended spans to the configured `Exporter` that have not yet
64
- # been exported.
66
+ # been exported, then call {Exporter#force_flush}.
65
67
  #
66
68
  # This method should only be called in cases where it is absolutely
67
69
  # necessary, such as when using some FaaS providers that may suspend
@@ -72,7 +74,7 @@ module OpenTelemetry
72
74
  # @return [Integer] SUCCESS if no error occurred, FAILURE if a
73
75
  # non-specific failure occurred, TIMEOUT if a timeout occurred.
74
76
  def force_flush(timeout: nil)
75
- SUCCESS
77
+ @span_exporter&.force_flush(timeout: timeout) || SUCCESS
76
78
  end
77
79
 
78
80
  # Called when {TracerProvider#shutdown} is called.
@@ -64,6 +64,9 @@ module OpenTelemetry
64
64
  #
65
65
  # @param [String] key
66
66
  # @param [String, Boolean, Numeric, Array<String, Numeric, Boolean>] value
67
+ # Values must be non-nil and (array of) string, boolean or numeric type.
68
+ # Array values must not contain nil elements and all elements must be of
69
+ # the same basic type (string, numeric, boolean).
67
70
  #
68
71
  # @return [self] returns itself
69
72
  def set_attribute(key, value)
@@ -82,6 +85,34 @@ module OpenTelemetry
82
85
  end
83
86
  alias []= set_attribute
84
87
 
88
+ # Add attributes
89
+ #
90
+ # Note that the OpenTelemetry project
91
+ # {https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
92
+ # documents} certain "standard attributes" that have prescribed semantic
93
+ # meanings.
94
+ #
95
+ # @param [Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}] attributes
96
+ # Values must be non-nil and (array of) string, boolean or numeric type.
97
+ # Array values must not contain nil elements and all elements must be of
98
+ # the same basic type (string, numeric, boolean).
99
+ #
100
+ # @return [self] returns itself
101
+ def add_attributes(attributes)
102
+ super
103
+ @mutex.synchronize do
104
+ if @ended
105
+ OpenTelemetry.logger.warn('Calling add_attributes on an ended Span.')
106
+ else
107
+ @attributes ||= {}
108
+ @attributes.merge!(attributes)
109
+ trim_span_attributes(@attributes)
110
+ @total_recorded_attributes += attributes.size
111
+ end
112
+ end
113
+ self
114
+ end
115
+
85
116
  # Add an Event to a {Span}.
86
117
  #
87
118
  # Example:
@@ -96,13 +127,13 @@ module OpenTelemetry
96
127
  # @param [String] name Name of the event.
97
128
  # @param [optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}] attributes
98
129
  # One or more key:value pairs, where the keys must be strings and the
99
- # values may be string, boolean or numeric type.
130
+ # values may be (array of) string, boolean or numeric type.
100
131
  # @param [optional Time] timestamp Optional timestamp for the event.
101
132
  #
102
133
  # @return [self] returns itself
103
134
  def add_event(name, attributes: nil, timestamp: nil)
104
135
  super
105
- event = Event.new(name: name, attributes: attributes, timestamp: timestamp || Time.now)
136
+ event = Event.new(name: name, attributes: truncate_attribute_values(attributes), timestamp: timestamp || Time.now)
106
137
 
107
138
  @mutex.synchronize do
108
139
  if @ended
@@ -285,9 +316,18 @@ module OpenTelemetry
285
316
 
286
317
  excess = attrs.size - @trace_config.max_attributes_count
287
318
  excess.times { attrs.shift } if excess.positive?
319
+ truncate_attribute_values(attrs)
288
320
  nil
289
321
  end
290
322
 
323
+ def truncate_attribute_values(attrs)
324
+ return if attrs.nil?
325
+
326
+ max_attributes_length = @trace_config.max_attributes_length
327
+ attrs.each { |key, value| attrs[key] = OpenTelemetry::Common::Utilities.truncate(value, max_attributes_length) } if max_attributes_length
328
+ attrs
329
+ end
330
+
291
331
  def trim_links(links, max_links_count, max_attributes_per_link) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
292
332
  # Fast path (likely) common cases.
293
333
  return nil if links.nil?
@@ -42,7 +42,7 @@ module OpenTelemetry
42
42
  @mutex.synchronize { @registry[Key.new(name, version)] ||= Tracer.new(name, version, self) }
43
43
  end
44
44
 
45
- # Attempts to stop all the activity for this {Tracer}. Calls
45
+ # Attempts to stop all the activity for this {TracerProvider}. Calls
46
46
  # SpanProcessor#shutdown for all registered SpanProcessors.
47
47
  #
48
48
  # This operation may block until all the Spans are processed. Must be
@@ -63,12 +63,26 @@ module OpenTelemetry
63
63
  end
64
64
  end
65
65
 
66
- # Adds a new SpanProcessor to this {Tracer}.
66
+ # Immediately export all spans that have not yet been exported for all the
67
+ # registered SpanProcessors.
68
+ #
69
+ # This method should only be called in cases where it is absolutely
70
+ # necessary, such as when using some FaaS providers that may suspend
71
+ # the process after an invocation, but before the `Processor` exports
72
+ # the completed spans.
67
73
  #
68
- # Any registered processor causes overhead, consider to use an
69
- # async/batch processor especially for span exporting, and export to
70
- # multiple backends using the
71
- # {io.opentelemetry.sdk.trace.export.MultiSpanExporter}.
74
+ # @param [optional Numeric] timeout An optional timeout in seconds.
75
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
76
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
77
+ def force_flush(timeout: nil)
78
+ @mutex.synchronize do
79
+ return Export::SUCCESS if @stopped
80
+
81
+ @active_span_processor.force_flush(timeout: timeout)
82
+ end
83
+ end
84
+
85
+ # Adds a new SpanProcessor to this {Tracer}.
72
86
  #
73
87
  # @param span_processor the new SpanProcessor to be added.
74
88
  def add_span_processor(span_processor)
@@ -78,7 +92,11 @@ module OpenTelemetry
78
92
  return
79
93
  end
80
94
  @registered_span_processors << span_processor
81
- @active_span_processor = MultiSpanProcessor.new(@registered_span_processors.dup)
95
+ @active_span_processor = if @registered_span_processors.size == 1
96
+ span_processor
97
+ else
98
+ MultiSpanProcessor.new(@registered_span_processors.dup)
99
+ end
82
100
  end
83
101
  end
84
102
  end
@@ -7,6 +7,6 @@
7
7
  module OpenTelemetry
8
8
  module SDK
9
9
  ## Current OpenTelemetry version
10
- VERSION = '0.13.0'
10
+ VERSION = '0.17.0'
11
11
  end
12
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opentelemetry-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenTelemetry Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-30 00:00:00.000000000 Z
11
+ date: 2021-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-api
@@ -16,28 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.13.0
19
+ version: 0.17.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.13.0
26
+ version: 0.17.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: opentelemetry-common
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.13.0
33
+ version: 0.17.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.13.0
40
+ version: 0.17.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: opentelemetry-instrumentation-base
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.17.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.17.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
96
  version: '5.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: opentelemetry-exporter-jaeger
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.17.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.17.0
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: rake
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -163,9 +191,6 @@ files:
163
191
  - README.md
164
192
  - lib/opentelemetry-sdk.rb
165
193
  - lib/opentelemetry/sdk.rb
166
- - lib/opentelemetry/sdk/baggage.rb
167
- - lib/opentelemetry/sdk/baggage/builder.rb
168
- - lib/opentelemetry/sdk/baggage/manager.rb
169
194
  - lib/opentelemetry/sdk/configurator.rb
170
195
  - lib/opentelemetry/sdk/instrumentation_library.rb
171
196
  - lib/opentelemetry/sdk/internal.rb
@@ -201,10 +226,10 @@ homepage: https://github.com/open-telemetry/opentelemetry-ruby
201
226
  licenses:
202
227
  - Apache-2.0
203
228
  metadata:
204
- changelog_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-sdk/v0.13.0/file.CHANGELOG.html
229
+ changelog_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-sdk/v0.17.0/file.CHANGELOG.html
205
230
  source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby/tree/main/sdk
206
231
  bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby/issues
207
- documentation_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-sdk/v0.13.0
232
+ documentation_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-sdk/v0.17.0
208
233
  post_install_message:
209
234
  rdoc_options: []
210
235
  require_paths:
@@ -220,7 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
245
  - !ruby/object:Gem::Version
221
246
  version: '0'
222
247
  requirements: []
223
- rubygems_version: 3.1.4
248
+ rubygems_version: 3.1.6
224
249
  signing_key:
225
250
  specification_version: 4
226
251
  summary: A stats collection and distributed tracing framework
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- require 'opentelemetry/sdk/baggage/builder'
8
- require 'opentelemetry/sdk/baggage/manager'
9
-
10
- module OpenTelemetry
11
- module SDK
12
- # Contains operational implementations of the Baggage::Manager
13
- module Baggage
14
- end
15
- end
16
- end
@@ -1,40 +0,0 @@
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 Baggage
10
- # SDK implementation of Baggage::Builder
11
- class Builder
12
- attr_reader :entries
13
-
14
- def initialize(entries)
15
- @entries = entries
16
- end
17
-
18
- # Set key-value in the to-be-created baggage
19
- #
20
- # @param [String] key The key to store this value under
21
- # @param [String] value String value to be stored under key
22
- def set_value(key, value)
23
- @entries[key] = value.to_s
24
- end
25
-
26
- # Removes key from the to-be-created baggage
27
- #
28
- # @param [String] key The key to remove
29
- def remove_value(key)
30
- @entries.delete(key)
31
- end
32
-
33
- # Clears all baggage from the to-be-created baggage
34
- def clear
35
- @entries.clear
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,97 +0,0 @@
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 Baggage
10
- # Manages baggage
11
- class Manager
12
- BAGGAGE_KEY = OpenTelemetry::Baggage::Propagation::ContextKeys.baggage_key
13
- EMPTY_BAGGAGE = {}.freeze
14
- private_constant(:BAGGAGE_KEY, :EMPTY_BAGGAGE)
15
-
16
- # Used to chain modifications to baggage. The result is a
17
- # context with an updated baggage. If only a single
18
- # modification is being made to baggage, use the other
19
- # methods on +Manager+, if multiple modifications are being made, use
20
- # this one.
21
- #
22
- # @param [optional Context] context The context to update with with new
23
- # modified baggage. Defaults to +Context.current+
24
- # @return [Context]
25
- def build_context(context: Context.current)
26
- builder = Builder.new(baggage_for(context).dup)
27
- yield builder
28
- context.set_value(BAGGAGE_KEY, builder.entries)
29
- end
30
-
31
- # Returns a new context with empty baggage
32
- #
33
- # @param [optional Context] context Context to clear baggage from. Defaults
34
- # to +Context.current+
35
- # @return [Context]
36
- def clear(context: Context.current)
37
- context.set_value(BAGGAGE_KEY, EMPTY_BAGGAGE)
38
- end
39
-
40
- # Returns the corresponding baggage value (or nil) for key
41
- #
42
- # @param [String] key The lookup key
43
- # @param [optional Context] context The context from which to retrieve
44
- # the key.
45
- # Defaults to +Context.current+
46
- # @return [String]
47
- def value(key, context: Context.current)
48
- baggage_for(context)[key]
49
- end
50
-
51
- # Returns the baggage
52
- #
53
- # @param [optional Context] context The context from which to retrieve
54
- # the baggage.
55
- # Defaults to +Context.current+
56
- # @return [Hash]
57
- def values(context: Context.current)
58
- baggage_for(context).dup.freeze
59
- end
60
-
61
- # Returns a new context with new key-value pair
62
- #
63
- # @param [String] key The key to store this value under
64
- # @param [String] value String value to be stored under key
65
- # @param [optional Context] context The context to update with new
66
- # value. Defaults to +Context.current+
67
- # @return [Context]
68
- def set_value(key, value, context: Context.current)
69
- new_baggage = baggage_for(context).dup
70
- new_baggage[key] = value
71
- context.set_value(BAGGAGE_KEY, new_baggage)
72
- end
73
-
74
- # Returns a new context with value at key removed
75
- #
76
- # @param [String] key The key to remove
77
- # @param [optional Context] context The context to remove baggage
78
- # from. Defaults to +Context.current+
79
- # @return [Context]
80
- def remove_value(key, context: Context.current)
81
- baggage = baggage_for(context)
82
- return context unless baggage.key?(key)
83
-
84
- new_baggage = baggage.dup
85
- new_baggage.delete(key)
86
- context.set_value(BAGGAGE_KEY, new_baggage)
87
- end
88
-
89
- private
90
-
91
- def baggage_for(context)
92
- context.value(BAGGAGE_KEY) || EMPTY_BAGGAGE
93
- end
94
- end
95
- end
96
- end
97
- end