opentelemetry-sdk 0.4.0 → 0.8.0

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