opentelemetry-sdk 0.4.0 → 0.8.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -2
  3. data/CHANGELOG.md +42 -0
  4. data/README.md +1 -1
  5. data/lib/opentelemetry/sdk.rb +4 -3
  6. data/lib/opentelemetry/sdk/baggage.rb +16 -0
  7. data/lib/opentelemetry/sdk/{correlation_context → baggage}/builder.rb +5 -5
  8. data/lib/opentelemetry/sdk/{correlation_context → baggage}/manager.rb +37 -27
  9. data/lib/opentelemetry/sdk/configurator.rb +73 -39
  10. data/lib/opentelemetry/sdk/instrumentation_library.rb +13 -0
  11. data/lib/opentelemetry/sdk/resources.rb +1 -0
  12. data/lib/opentelemetry/sdk/resources/constants.rb +120 -0
  13. data/lib/opentelemetry/sdk/resources/resource.rb +38 -19
  14. data/lib/opentelemetry/sdk/trace.rb +1 -0
  15. data/lib/opentelemetry/sdk/trace/config/trace_config.rb +3 -3
  16. data/lib/opentelemetry/sdk/trace/event.rb +48 -0
  17. data/lib/opentelemetry/sdk/trace/export.rb +9 -9
  18. data/lib/opentelemetry/sdk/trace/export/batch_span_processor.rb +49 -28
  19. data/lib/opentelemetry/sdk/trace/export/console_span_exporter.rb +3 -6
  20. data/lib/opentelemetry/sdk/trace/export/in_memory_span_exporter.rb +6 -2
  21. data/lib/opentelemetry/sdk/trace/export/multi_span_exporter.rb +7 -8
  22. data/lib/opentelemetry/sdk/trace/export/noop_span_exporter.rb +2 -1
  23. data/lib/opentelemetry/sdk/trace/export/simple_span_processor.rb +13 -3
  24. data/lib/opentelemetry/sdk/trace/multi_span_processor.rb +12 -4
  25. data/lib/opentelemetry/sdk/trace/noop_span_processor.rb +15 -3
  26. data/lib/opentelemetry/sdk/trace/samplers.rb +52 -51
  27. data/lib/opentelemetry/sdk/trace/samplers/constant_sampler.rb +33 -0
  28. data/lib/opentelemetry/sdk/trace/samplers/decision.rb +3 -3
  29. data/lib/opentelemetry/sdk/trace/samplers/parent_based.rb +53 -0
  30. data/lib/opentelemetry/sdk/trace/samplers/result.rb +3 -3
  31. data/lib/opentelemetry/sdk/trace/samplers/trace_id_ratio_based.rb +45 -0
  32. data/lib/opentelemetry/sdk/trace/span.rb +33 -36
  33. data/lib/opentelemetry/sdk/trace/span_data.rb +18 -3
  34. data/lib/opentelemetry/sdk/trace/tracer.rb +36 -20
  35. data/lib/opentelemetry/sdk/trace/tracer_provider.rb +4 -4
  36. data/lib/opentelemetry/sdk/version.rb +1 -1
  37. metadata +19 -10
  38. data/lib/opentelemetry/sdk/correlation_context.rb +0 -16
  39. data/lib/opentelemetry/sdk/trace/samplers/probability_sampler.rb +0 -61
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module SDK
9
+ # InstrumentationLibrary is a struct containing library information for export.
10
+ InstrumentationLibrary = Struct.new(:name,
11
+ :version)
12
+ end
13
+ end
@@ -13,3 +13,4 @@ module OpenTelemetry
13
13
  end
14
14
 
15
15
  require 'opentelemetry/sdk/resources/resource'
16
+ require 'opentelemetry/sdk/resources/constants'
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2020 OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module SDK
9
+ module Resources
10
+ module Constants
11
+ # Attributes describing a service instance.
12
+ SERVICE_RESOURCE = {
13
+ # Logical name of the service.
14
+ name: 'service.name',
15
+
16
+ # A namespace for `service.name`.
17
+ namespace: 'service.namespace',
18
+
19
+ # The string ID of the service instance.
20
+ instance_id: 'service.instance.id',
21
+
22
+ # The version string of the service API or implementation.
23
+ version: 'service.version'
24
+ }.freeze
25
+
26
+ # Attributes describing the telemetry library.
27
+ TELEMETRY_SDK_RESOURCE = {
28
+ # The name of the telemetry library.
29
+ name: 'telemetry.sdk.name',
30
+
31
+ # The language of the telemetry library and of the code instrumented with it.
32
+ language: 'telemetry.sdk.language',
33
+
34
+ # The version string of the telemetry library
35
+ version: 'telemetry.sdk.version'
36
+ }.freeze
37
+
38
+ # Attributes defining a compute unit (e.g. Container, Process, Lambda
39
+ # Function).
40
+ CONTAINER_RESOURCE = {
41
+ # The container name.
42
+ name: 'container.name',
43
+
44
+ # The name of the image the container was built on.
45
+ image_name: 'container.image.name',
46
+
47
+ # The container image tag.
48
+ image_tag: 'container.image.tag'
49
+ }.freeze
50
+
51
+ FAAS_RESOURCE = {
52
+ # The name of the function being executed.
53
+ name: 'faas.name',
54
+
55
+ # The unique name of the function being executed.
56
+ id: 'faas.id',
57
+
58
+ # The version string of the function being executed.
59
+ version: 'faas.version',
60
+
61
+ # The execution environment ID as a string.
62
+ instance: 'faas.instance'
63
+ }.freeze
64
+
65
+ # Attributes defining a deployment service (e.g. Kubernetes).
66
+ K8S_RESOURCE = {
67
+ # The name of the cluster that the pod is running in.
68
+ cluster_name: 'k8s.cluster.name',
69
+
70
+ # The name of the namespace that the pod is running in.
71
+ namespace_name: 'k8s.namespace.name',
72
+
73
+ # The name of the pod.
74
+ pod_name: 'k8s.pod.name',
75
+
76
+ # The name of the deployment.
77
+ deployment_name: 'k8s.deployment.name'
78
+ }.freeze
79
+
80
+ # Attributes defining a computing instance (e.g. host).
81
+ HOST_RESOURCE = {
82
+ # Unique host id. For Cloud this must be the instance_id assigned by the
83
+ # cloud provider
84
+ id: 'host.id',
85
+
86
+ # Name of the host. It may contain what hostname returns on Unix systems,
87
+ # the fully qualified, or a name specified by the user.
88
+ name: 'host.name',
89
+
90
+ # Type of host. For Cloud this must be the machine type.
91
+ type: 'host.type',
92
+
93
+ # Name of the VM image or OS install the host was instantiated from.
94
+ image_name: 'host.image.name',
95
+
96
+ # VM image id. For Cloud, this value is from the provider.
97
+ image_id: 'host.image.id',
98
+
99
+ # The version string of the VM image.
100
+ image_version: 'host.image.version'
101
+ }.freeze
102
+
103
+ # Attributes defining a running environment (e.g. Cloud, Data Center).
104
+ CLOUD_RESOURCE = {
105
+ # Name of the cloud provider. Example values are aws, azure, gcp.
106
+ provider: 'cloud.provider',
107
+
108
+ # The cloud account id used to identify different entities.
109
+ account_id: 'cloud.account.id',
110
+
111
+ # A specific geographical location where different entities can run.
112
+ region: 'cloud.region',
113
+
114
+ # Zones are a sub set of the region connected through low-latency links.
115
+ zone: 'cloud.zone'
116
+ }.freeze
117
+ end
118
+ end
119
+ end
120
+ end
@@ -13,21 +13,40 @@ module OpenTelemetry
13
13
  class << self
14
14
  private :new # rubocop:disable Style/AccessModifierDeclarations
15
15
 
16
- # Returns a newly created {Resource} with the specified labels
16
+ # Returns a newly created {Resource} with the specified attributes
17
17
  #
18
- # @param [Hash{String => String, Numeric, Boolean} labels Hash of key-value pairs to be used
19
- # as labels for this resource
20
- # @raise [ArgumentError] If label keys and values are not strings
18
+ # @param [Hash{String => String, Numeric, Boolean} attributes Hash of key-value pairs to be used
19
+ # as attributes for this resource
20
+ # @raise [ArgumentError] If attribute keys and values are not strings
21
21
  # @return [Resource]
22
- def create(labels = {})
23
- frozen_labels = labels.each_with_object({}) do |(k, v), memo|
24
- raise ArgumentError, 'label keys must be strings' unless k.is_a?(String)
25
- raise ArgumentError, 'label values must be strings, integers, floats, or booleans' unless Internal.valid_value?(v)
22
+ def create(attributes = {})
23
+ frozen_attributes = attributes.each_with_object({}) do |(k, v), memo|
24
+ raise ArgumentError, 'attribute keys must be strings' unless k.is_a?(String)
25
+ raise ArgumentError, 'attribute values must be strings, integers, floats, or booleans' unless Internal.valid_value?(v)
26
26
 
27
27
  memo[-k] = v.freeze
28
28
  end.freeze
29
29
 
30
- new(frozen_labels)
30
+ new(frozen_attributes)
31
+ end
32
+
33
+ def telemetry_sdk
34
+ resource_attributes = {
35
+ Constants::TELEMETRY_SDK_RESOURCE[:name] => 'opentelemetry',
36
+ Constants::TELEMETRY_SDK_RESOURCE[:language] => 'ruby',
37
+ Constants::TELEMETRY_SDK_RESOURCE[:version] => OpenTelemetry::SDK::VERSION
38
+ }
39
+
40
+ resource_pairs = ENV['OTEL_RESOURCE_ATTRIBUTES']
41
+ return create(resource_attributes) unless resource_pairs.is_a?(String)
42
+
43
+ resource_pairs.split(',').each do |pair|
44
+ key, value = pair.split('=')
45
+ resource_attributes[key] = value
46
+ end
47
+
48
+ resource_attributes.delete_if { |_key, value| value.nil? || value.empty? }
49
+ create(resource_attributes)
31
50
  end
32
51
  end
33
52
 
@@ -36,18 +55,18 @@ module OpenTelemetry
36
55
  # Users should use the {create} factory method to obtain a {Resource}
37
56
  # instance.
38
57
  #
39
- # @param [Hash<String, String>] frozen_labels Frozen-hash of frozen-string
40
- # key-value pairs to be used as labels for this resource
58
+ # @param [Hash<String, String>] frozen_attributes Frozen-hash of frozen-string
59
+ # key-value pairs to be used as attributes for this resource
41
60
  # @return [Resource]
42
- def initialize(frozen_labels)
43
- @labels = frozen_labels
61
+ def initialize(frozen_attributes)
62
+ @attributes = frozen_attributes
44
63
  end
45
64
 
46
- # Returns an enumerator for labels of this {Resource}
65
+ # Returns an enumerator for attributes of this {Resource}
47
66
  #
48
67
  # @return [Enumerator]
49
- def label_enumerator
50
- @label_enumerator ||= labels.to_enum
68
+ def attribute_enumerator
69
+ @attribute_enumerator ||= attributes.to_enum
51
70
  end
52
71
 
53
72
  # Returns a new, merged {Resource} by merging the current {Resource} with
@@ -60,16 +79,16 @@ module OpenTelemetry
60
79
  def merge(other)
61
80
  return self unless other.is_a?(Resource)
62
81
 
63
- merged_labels = labels.merge(other.labels) do |_, old_v, new_v|
82
+ merged_attributes = attributes.merge(other.attributes) do |_, old_v, new_v|
64
83
  old_v.empty? ? new_v : old_v
65
84
  end
66
85
 
67
- self.class.send(:new, merged_labels.freeze)
86
+ self.class.send(:new, merged_attributes.freeze)
68
87
  end
69
88
 
70
89
  protected
71
90
 
72
- attr_reader :labels
91
+ attr_reader :attributes
73
92
  end
74
93
  end
75
94
  end
@@ -15,6 +15,7 @@ end
15
15
 
16
16
  require 'opentelemetry/sdk/trace/samplers'
17
17
  require 'opentelemetry/sdk/trace/config'
18
+ require 'opentelemetry/sdk/trace/event'
18
19
  require 'opentelemetry/sdk/trace/export'
19
20
  require 'opentelemetry/sdk/trace/multi_span_processor'
20
21
  require 'opentelemetry/sdk/trace/noop_span_processor'
@@ -10,7 +10,7 @@ module OpenTelemetry
10
10
  module Config
11
11
  # Class that holds global trace parameters.
12
12
  class TraceConfig
13
- DEFAULT_SAMPLER = Samplers::ALWAYS_ON
13
+ DEFAULT_SAMPLER = Samplers.parent_based(root: Samplers::ALWAYS_ON)
14
14
  DEFAULT_MAX_ATTRIBUTES_COUNT = 32
15
15
  DEFAULT_MAX_EVENTS_COUNT = 128
16
16
  DEFAULT_MAX_LINKS_COUNT = 32
@@ -30,13 +30,13 @@ module OpenTelemetry
30
30
  # The global default max number of attributes per {Span}.
31
31
  attr_reader :max_attributes_count
32
32
 
33
- # The global default max number of {OpenTelemetry::Trace::Event}s per {Span}.
33
+ # The global default max number of {OpenTelemetry::SDK::Trace::Event}s per {Span}.
34
34
  attr_reader :max_events_count
35
35
 
36
36
  # The global default max number of {OpenTelemetry::Trace::Link} entries per {Span}.
37
37
  attr_reader :max_links_count
38
38
 
39
- # The global default max number of attributes per {OpenTelemetry::Trace::Event}.
39
+ # The global default max number of attributes per {OpenTelemetry::SDK::Trace::Event}.
40
40
  attr_reader :max_attributes_per_event
41
41
 
42
42
  # The global default max number of attributes per {OpenTelemetry::Trace::Link}.
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module SDK
9
+ module Trace
10
+ # A text annotation with a set of attributes and a timestamp.
11
+ class Event
12
+ EMPTY_ATTRIBUTES = {}.freeze
13
+
14
+ private_constant :EMPTY_ATTRIBUTES
15
+
16
+ # Returns the name of this event
17
+ #
18
+ # @return [String]
19
+ attr_reader :name
20
+
21
+ # Returns the frozen attributes for this event
22
+ #
23
+ # @return [Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}]
24
+ attr_reader :attributes
25
+
26
+ # Returns the timestamp for this event
27
+ #
28
+ # @return [Time]
29
+ attr_reader :timestamp
30
+
31
+ # Returns a new immutable {Event}.
32
+ #
33
+ # @param [String] name The name of this event
34
+ # @param [optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}]
35
+ # attributes A hash of attributes for this event. Attributes will be
36
+ # frozen during Event initialization.
37
+ # @param [optional Time] timestamp The timestamp for this event.
38
+ # Defaults to Time.now.
39
+ # @return [Event]
40
+ def initialize(name:, attributes: nil, timestamp: nil)
41
+ @name = name
42
+ @attributes = attributes.freeze || EMPTY_ATTRIBUTES
43
+ @timestamp = timestamp || Time.now
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -7,21 +7,21 @@
7
7
  module OpenTelemetry
8
8
  module SDK
9
9
  module Trace
10
- # The Export module contains the built-in exporters for the OpenTelemetry
10
+ # The Export module contains the built-in exporters and span processors for the OpenTelemetry
11
11
  # reference implementation.
12
12
  module Export
13
- # Result codes for the SpanExporter#export method.
13
+ # Result codes for the SpanExporter#export method and the SpanProcessor#force_flush and SpanProcessor#shutdown methods.
14
14
 
15
- # The export operation finished successfully.
15
+ # The operation finished successfully.
16
16
  SUCCESS = 0
17
17
 
18
- # The export operation finished with an error, but retrying may
19
- # succeed.
20
- FAILED_RETRYABLE = 1
18
+ # The operation finished with an error.
19
+ FAILURE = 1
21
20
 
22
- # The export operation finished with an error, the caller should not
23
- # try to export the same data again.
24
- FAILED_NOT_RETRYABLE = 2
21
+ # Additional result code for the SpanProcessor#force_flush and SpanProcessor#shutdown methods.
22
+
23
+ # The operation timed out.
24
+ TIMEOUT = 2
25
25
  end
26
26
  end
27
27
  end
@@ -22,24 +22,29 @@ module OpenTelemetry
22
22
  # If the queue gets half full a preemptive notification is sent to the
23
23
  # worker thread that exports the spans to wake up and start a new
24
24
  # export cycle.
25
- #
26
- # max_export_attempts attempts are made to export each batch, while
27
- # export fails with {FAILED_RETRYABLE}, backing off linearly in 100ms
28
- # increments.
29
25
  class BatchSpanProcessor
30
- EXPORTER_TIMEOUT_MILLIS = 30_000
31
- SCHEDULE_DELAY_MILLIS = 5_000
32
- MAX_QUEUE_SIZE = 2048
33
- MAX_EXPORT_BATCH_SIZE = 512
34
- MAX_EXPORT_ATTEMPTS = 5
35
- private_constant(:SCHEDULE_DELAY_MILLIS, :MAX_QUEUE_SIZE, :MAX_EXPORT_BATCH_SIZE, :MAX_EXPORT_ATTEMPTS)
36
-
26
+ # Returns a new instance of the {BatchSpanProcessor}.
27
+ #
28
+ # @param [SpanExporter] exporter
29
+ # @param [Numeric] exporter_timeout_millis the delay interval between two
30
+ # consecutive exports. Defaults to the value of the OTEL_BSP_EXPORT_TIMEOUT_MILLIS
31
+ # environment variable, if set, or 30,000 (30 seconds).
32
+ # @param [Numeric] schedule_delay_millis the maximum allowed time to export data.
33
+ # Defaults to the value of the OTEL_BSP_SCHEDULE_DELAY_MILLIS environment
34
+ # variable, if set, or 5,000 (5 seconds).
35
+ # @param [Integer] max_queue_size the maximum queue size in spans.
36
+ # Defaults to the value of the OTEL_BSP_MAX_QUEUE_SIZE environment
37
+ # variable, if set, or 2048.
38
+ # @param [Integer] max_export_batch_size the maximum batch size in spans.
39
+ # Defaults to the value of the OTEL_BSP_MAX_EXPORT_BATCH_SIZE environment
40
+ # variable, if set, or 512.
41
+ #
42
+ # @return a new instance of the {BatchSpanProcessor}.
37
43
  def initialize(exporter:,
38
- exporter_timeout_millis: EXPORTER_TIMEOUT_MILLIS,
39
- schedule_delay_millis: SCHEDULE_DELAY_MILLIS,
40
- max_queue_size: MAX_QUEUE_SIZE,
41
- max_export_batch_size: MAX_EXPORT_BATCH_SIZE,
42
- max_export_attempts: MAX_EXPORT_ATTEMPTS)
44
+ exporter_timeout_millis: Float(ENV.fetch('OTEL_BSP_EXPORT_TIMEOUT_MILLIS', 30_000)),
45
+ schedule_delay_millis: Float(ENV.fetch('OTEL_BSP_SCHEDULE_DELAY_MILLIS', 5_000)),
46
+ max_queue_size: Integer(ENV.fetch('OTEL_BSP_MAX_QUEUE_SIZE', 2048)),
47
+ max_export_batch_size: Integer(ENV.fetch('OTEL_BSP_MAX_EXPORT_BATCH_SIZE', 512)))
43
48
  raise ArgumentError if max_export_batch_size > max_queue_size
44
49
 
45
50
  @exporter = exporter
@@ -50,13 +55,14 @@ module OpenTelemetry
50
55
  @delay_seconds = schedule_delay_millis / 1000.0
51
56
  @max_queue_size = max_queue_size
52
57
  @batch_size = max_export_batch_size
53
- @export_attempts = max_export_attempts
54
58
  @spans = []
55
- @thread = Thread.new { work }
59
+ @pid = nil
60
+ @thread = nil
61
+ reset_on_fork
56
62
  end
57
63
 
58
64
  # does nothing for this processor
59
- def on_start(span)
65
+ def on_start(span, parent_context)
60
66
  # noop
61
67
  end
62
68
 
@@ -65,6 +71,7 @@ module OpenTelemetry
65
71
  return unless span.context.trace_flags.sampled?
66
72
 
67
73
  lock do
74
+ reset_on_fork
68
75
  n = spans.size + 1 - max_queue_size
69
76
  spans.shift(n) if n.positive?
70
77
  spans << span
@@ -80,17 +87,27 @@ module OpenTelemetry
80
87
  # necessary, such as when using some FaaS providers that may suspend
81
88
  # the process after an invocation, but before the `Processor` exports
82
89
  # the completed spans.
90
+ #
91
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
92
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
83
93
  def force_flush
84
- snapshot = lock { spans.shift(spans.size) }
94
+ snapshot = lock do
95
+ reset_on_fork(restart_thread: false) if @keep_running
96
+ spans.shift(spans.size)
97
+ end
85
98
  until snapshot.empty?
86
99
  batch = snapshot.shift(@batch_size).map!(&:to_span_data)
87
100
  result_code = @exporter.export(batch)
88
101
  report_result(result_code, batch)
89
102
  end
103
+ SUCCESS
90
104
  end
91
105
 
92
106
  # shuts the consumer thread down and flushes the current accumulated buffer
93
107
  # will block until the thread is finished
108
+ #
109
+ # @return [Integer] SUCCESS if no error occurred, FAILURE if a
110
+ # non-specific failure occurred, TIMEOUT if a timeout occurred.
94
111
  def shutdown
95
112
  lock do
96
113
  @keep_running = false
@@ -109,6 +126,7 @@ module OpenTelemetry
109
126
  def work
110
127
  loop do
111
128
  batch = lock do
129
+ reset_on_fork(restart_thread: false)
112
130
  @condition.wait(@mutex, @delay_seconds) if spans.size < batch_size && @keep_running
113
131
  @condition.wait(@mutex, @delay_seconds) while spans.empty? && @keep_running
114
132
  return unless @keep_running
@@ -120,21 +138,24 @@ module OpenTelemetry
120
138
  end
121
139
  end
122
140
 
123
- def export_batch(batch)
124
- result_code = nil
125
- @export_attempts.times do |attempts|
126
- result_code = export_with_timeout(batch)
127
- break unless result_code == FAILED_RETRYABLE
141
+ def reset_on_fork(restart_thread: true)
142
+ pid = Process.pid
143
+ return if @pid == pid
128
144
 
129
- sleep(0.1 * attempts)
130
- end
145
+ @pid = pid
146
+ spans.clear
147
+ @thread = Thread.new { work } if restart_thread
148
+ end
149
+
150
+ def export_batch(batch)
151
+ result_code = export_with_timeout(batch)
131
152
  report_result(result_code, batch)
132
153
  end
133
154
 
134
155
  def export_with_timeout(batch)
135
156
  Timeout.timeout(@exporter_timeout_seconds) { @exporter.export(batch) }
136
157
  rescue Timeout::Error
137
- FAILED_NOT_RETRYABLE
158
+ FAILURE
138
159
  end
139
160
 
140
161
  def report_result(result_code, batch)