opentelemetry-sdk 0.2.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +9 -0
  3. data/CHANGELOG.md +23 -0
  4. data/LICENSE +1 -1
  5. data/README.md +73 -0
  6. data/lib/opentelemetry-sdk.rb +7 -0
  7. data/lib/opentelemetry/sdk.rb +51 -0
  8. data/lib/opentelemetry/sdk/baggage.rb +16 -0
  9. data/lib/opentelemetry/sdk/baggage/builder.rb +40 -0
  10. data/lib/opentelemetry/sdk/baggage/manager.rb +97 -0
  11. data/lib/opentelemetry/sdk/configurator.rb +172 -0
  12. data/lib/opentelemetry/sdk/instrumentation_library.rb +13 -0
  13. data/lib/opentelemetry/sdk/internal.rb +21 -1
  14. data/lib/opentelemetry/sdk/resources.rb +1 -0
  15. data/lib/opentelemetry/sdk/resources/constants.rb +124 -0
  16. data/lib/opentelemetry/sdk/resources/resource.rb +39 -19
  17. data/lib/opentelemetry/sdk/trace.rb +2 -1
  18. data/lib/opentelemetry/sdk/trace/config/trace_config.rb +3 -3
  19. data/lib/opentelemetry/sdk/trace/event.rb +48 -0
  20. data/lib/opentelemetry/sdk/trace/export.rb +2 -7
  21. data/lib/opentelemetry/sdk/trace/export/batch_span_processor.rb +41 -35
  22. data/lib/opentelemetry/sdk/trace/export/console_span_exporter.rb +1 -1
  23. data/lib/opentelemetry/sdk/trace/export/in_memory_span_exporter.rb +7 -7
  24. data/lib/opentelemetry/sdk/trace/export/multi_span_exporter.rb +8 -14
  25. data/lib/opentelemetry/sdk/trace/export/noop_span_exporter.rb +4 -4
  26. data/lib/opentelemetry/sdk/trace/export/simple_span_processor.rb +10 -1
  27. data/lib/opentelemetry/sdk/trace/multi_span_processor.rb +12 -1
  28. data/lib/opentelemetry/sdk/trace/noop_span_processor.rb +10 -1
  29. data/lib/opentelemetry/sdk/trace/samplers.rb +48 -57
  30. data/lib/opentelemetry/sdk/trace/samplers/constant_sampler.rb +33 -0
  31. data/lib/opentelemetry/sdk/trace/samplers/decision.rb +3 -3
  32. data/lib/opentelemetry/sdk/trace/samplers/parent_based.rb +53 -0
  33. data/lib/opentelemetry/sdk/trace/samplers/result.rb +4 -3
  34. data/lib/opentelemetry/sdk/trace/samplers/trace_id_ratio_based.rb +45 -0
  35. data/lib/opentelemetry/sdk/trace/span.rb +39 -28
  36. data/lib/opentelemetry/sdk/trace/span_data.rb +18 -2
  37. data/lib/opentelemetry/sdk/trace/tracer.rb +26 -15
  38. data/lib/opentelemetry/sdk/trace/{tracer_factory.rb → tracer_provider.rb} +9 -9
  39. data/lib/opentelemetry/sdk/version.rb +1 -1
  40. metadata +20 -8
  41. data/lib/opentelemetry/sdk/trace/samplers/probability_sampler.rb +0 -74
@@ -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
@@ -20,10 +20,30 @@ module OpenTelemetry
20
20
  key.instance_of?(String)
21
21
  end
22
22
 
23
- def valid_value?(value)
23
+ def valid_simple_value?(value)
24
24
  value.instance_of?(String) || value == false || value == true || value.is_a?(Numeric)
25
25
  end
26
26
 
27
+ def valid_array_value?(value)
28
+ return false unless value.is_a?(Array)
29
+ return true if value.empty?
30
+
31
+ case value.first
32
+ when String
33
+ value.all? { |v| v.instance_of?(String) }
34
+ when TrueClass, FalseClass
35
+ value.all? { |v| boolean?(v) }
36
+ when Numeric
37
+ value.all? { |v| v.is_a?(Numeric) }
38
+ else
39
+ false
40
+ end
41
+ end
42
+
43
+ def valid_value?(value)
44
+ valid_simple_value?(value) || valid_array_value?(value)
45
+ end
46
+
27
47
  def valid_attributes?(attrs)
28
48
  attrs.nil? || attrs.all? { |k, v| valid_key?(k) && valid_value?(v) }
29
49
  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,124 @@
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
+ # Hostname of the host. It contains what the hostname command returns on the
83
+ # host machine.
84
+ hostname: 'host.hostname',
85
+
86
+ # Unique host id. For Cloud this must be the instance_id assigned by the
87
+ # cloud provider
88
+ id: 'host.id',
89
+
90
+ # Name of the host. It may contain what hostname returns on Unix systems,
91
+ # the fully qualified, or a name specified by the user.
92
+ name: 'host.name',
93
+
94
+ # Type of host. For Cloud this must be the machine type.
95
+ type: 'host.type',
96
+
97
+ # Name of the VM image or OS install the host was instantiated from.
98
+ image_name: 'host.image.name',
99
+
100
+ # VM image id. For Cloud, this value is from the provider.
101
+ image_id: 'host.image.id',
102
+
103
+ # The version string of the VM image.
104
+ image_version: 'host.image.version'
105
+ }.freeze
106
+
107
+ # Attributes defining a running environment (e.g. Cloud, Data Center).
108
+ CLOUD_RESOURCE = {
109
+ # Name of the cloud provider. Example values are aws, azure, gcp.
110
+ provider: 'cloud.provider',
111
+
112
+ # The cloud account id used to identify different entities.
113
+ account_id: 'cloud.account.id',
114
+
115
+ # A specific geographical location where different entities can run.
116
+ region: 'cloud.region',
117
+
118
+ # Zones are a sub set of the region connected through low-latency links.
119
+ zone: 'cloud.zone'
120
+ }.freeze
121
+ end
122
+ end
123
+ end
124
+ end
@@ -13,20 +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>] 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 and values must be strings' unless k.is_a?(String) && v.is_a?(String)
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)
25
26
 
26
- memo[-k] = -v
27
+ memo[-k] = v.freeze
27
28
  end.freeze
28
29
 
29
- 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)
30
50
  end
31
51
  end
32
52
 
@@ -35,18 +55,18 @@ module OpenTelemetry
35
55
  # Users should use the {create} factory method to obtain a {Resource}
36
56
  # instance.
37
57
  #
38
- # @param [Hash<String, String>] frozen_labels Frozen-hash of frozen-string
39
- # 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
40
60
  # @return [Resource]
41
- def initialize(frozen_labels)
42
- @labels = frozen_labels
61
+ def initialize(frozen_attributes)
62
+ @attributes = frozen_attributes
43
63
  end
44
64
 
45
- # Returns an enumerator for labels of this {Resource}
65
+ # Returns an enumerator for attributes of this {Resource}
46
66
  #
47
67
  # @return [Enumerator]
48
- def label_enumerator
49
- @label_enumerator ||= labels.to_enum
68
+ def attribute_enumerator
69
+ @attribute_enumerator ||= attributes.to_enum
50
70
  end
51
71
 
52
72
  # Returns a new, merged {Resource} by merging the current {Resource} with
@@ -59,16 +79,16 @@ module OpenTelemetry
59
79
  def merge(other)
60
80
  return self unless other.is_a?(Resource)
61
81
 
62
- merged_labels = labels.merge(other.labels) do |_, old_v, new_v|
82
+ merged_attributes = attributes.merge(other.attributes) do |_, old_v, new_v|
63
83
  old_v.empty? ? new_v : old_v
64
84
  end
65
85
 
66
- self.class.send(:new, merged_labels.freeze)
86
+ self.class.send(:new, merged_attributes.freeze)
67
87
  end
68
88
 
69
89
  protected
70
90
 
71
- attr_reader :labels
91
+ attr_reader :attributes
72
92
  end
73
93
  end
74
94
  end
@@ -15,10 +15,11 @@ 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'
21
22
  require 'opentelemetry/sdk/trace/span_data'
22
23
  require 'opentelemetry/sdk/trace/span'
23
24
  require 'opentelemetry/sdk/trace/tracer'
24
- require 'opentelemetry/sdk/trace/tracer_factory'
25
+ require 'opentelemetry/sdk/trace/tracer_provider'
@@ -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
@@ -15,13 +15,8 @@ module OpenTelemetry
15
15
  # The export 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
21
-
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
18
+ # The export operation finished with an error.
19
+ FAILURE = 1
25
20
  end
26
21
  end
27
22
  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,7 +55,6 @@ 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
59
  @thread = Thread.new { work }
56
60
  end
@@ -72,6 +76,23 @@ module OpenTelemetry
72
76
  end
73
77
  end
74
78
 
79
+ # TODO: test this explicitly.
80
+ # Export all ended spans to the configured `Exporter` that have not yet
81
+ # been exported.
82
+ #
83
+ # This method should only be called in cases where it is absolutely
84
+ # necessary, such as when using some FaaS providers that may suspend
85
+ # the process after an invocation, but before the `Processor` exports
86
+ # the completed spans.
87
+ def force_flush
88
+ snapshot = lock { spans.shift(spans.size) }
89
+ until snapshot.empty?
90
+ batch = snapshot.shift(@batch_size).map!(&:to_span_data)
91
+ result_code = @exporter.export(batch)
92
+ report_result(result_code, batch)
93
+ end
94
+ end
95
+
75
96
  # shuts the consumer thread down and flushes the current accumulated buffer
76
97
  # will block until the thread is finished
77
98
  def shutdown
@@ -81,7 +102,7 @@ module OpenTelemetry
81
102
  end
82
103
 
83
104
  @thread.join
84
- flush
105
+ force_flush
85
106
  @exporter.shutdown
86
107
  end
87
108
 
@@ -104,35 +125,20 @@ module OpenTelemetry
104
125
  end
105
126
 
106
127
  def export_batch(batch)
107
- result_code = nil
108
- @export_attempts.times do |attempts|
109
- result_code = export_with_timeout(batch)
110
- break unless result_code == FAILED_RETRYABLE
111
-
112
- sleep(0.1 * attempts)
113
- end
128
+ result_code = export_with_timeout(batch)
114
129
  report_result(result_code, batch)
115
130
  end
116
131
 
117
132
  def export_with_timeout(batch)
118
133
  Timeout.timeout(@exporter_timeout_seconds) { @exporter.export(batch) }
119
134
  rescue Timeout::Error
120
- FAILED_NOT_RETRYABLE
135
+ FAILURE
121
136
  end
122
137
 
123
138
  def report_result(result_code, batch)
124
139
  OpenTelemetry.logger.error("Unable to export #{batch.size} spans") unless result_code == SUCCESS
125
140
  end
126
141
 
127
- def flush
128
- snapshot = lock { spans.shift(spans.size) }
129
- until snapshot.empty?
130
- batch = snapshot.shift(@batch_size).map!(&:to_span_data)
131
- result_code = @exporter.export(batch)
132
- report_result(result_code, batch)
133
- end
134
- end
135
-
136
142
  def fetch_batch
137
143
  spans.shift(@batch_size).map!(&:to_span_data)
138
144
  end