opentelemetry-sdk 0.13.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
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