aspecto-opentelemetry 0.1.6 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -10
- data/lib/aspecto/opentelemetry/config/remote_config.rb +22 -6
- data/lib/aspecto/opentelemetry/configurator.rb +15 -3
- data/lib/aspecto/opentelemetry/propagator/aspecto.rb +30 -0
- data/lib/aspecto/opentelemetry/sampler/message_process_sampler.rb +1 -1
- data/lib/aspecto/opentelemetry/version.rb +1 -1
- data/lib/aspecto/opentelemetry.rb +7 -2
- metadata +31 -3
- data/lib/aspecto/opentelemetry/resource/detectors/deployment.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 005e783e20aa54623dca0a11daae40ef3e3d8a6d9b83a13b6fd44f11a0a7f00b
|
4
|
+
data.tar.gz: 9edaffde8afa0cbfb8f3547aec3fd4ab3fc236395e70e6ecb1e60b83f5d563b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a220142b3826b3cf0d95e73c559e0ac5ce0e29828f98883fd6e7f8e7a9c4a486bfe6620a49f73cbc938d23c3b0c48f8782147a69779256719520532112ef1b6d
|
7
|
+
data.tar.gz: fd9e2c8b3513d25599411f2718ff1f3aa79b75425fd9d81f75f32e1ceb7b69c4228dfc46abc1f0dc64a7f020c2916ed47f1bc29d11539cabf87e91945ce38851
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Aspecto::OpenTelemetry
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/aspecto-opentelemetry.svg)](https://badge.fury.io/rb/aspecto-opentelemetry)
|
4
|
+
|
3
5
|
Aspecto's SDK for ruby.
|
4
6
|
This gem is a distribution of OpenTelemetry pre-configured to use all available instrumentations and export trace data to Aspecto.
|
5
7
|
|
@@ -97,16 +99,18 @@ The only required config options are [`aspecto_auth`](https://app.aspecto.io/app
|
|
97
99
|
|
98
100
|
### Configuration Options
|
99
101
|
|
100
|
-
| Option Name
|
101
|
-
|
|
102
|
-
| `aspecto_auth`
|
103
|
-
| `service_name`
|
104
|
-
| `env`
|
105
|
-
| `log_level`
|
106
|
-
| `sampling_ratio`
|
107
|
-
| `otel_exporter_otlp_traces_endpoint` | `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | URL
|
108
|
-
| `require_config_for_traces` | `ASPECTO_REQUIRE_CONFIG_FOR_TRACES` | boolean
|
109
|
-
|
102
|
+
| Option Name | Environment Variable | Type | Default | Description |
|
103
|
+
| --- | --- | --- | --- | --- |
|
104
|
+
| `aspecto_auth` | `ASPECTO_AUTH` | UUID string | - | Aspecto's [API key](https://app.aspecto.io/app/integration/api-key) for authentication |
|
105
|
+
| `service_name` | `OTEL_SERVICE_NAME` | string | - | Name of the service which is sending telemetry|
|
106
|
+
| `env` | `ASPECTO_ENV` | string | Extracted from Rails or Sinatra if used | Deployment environment: `production` / `staging` / `development`, etc. |
|
107
|
+
| `log_level` | `OTEL_LOG_LEVEL` | string | `ERROR` | `ERROR` / `WARN` / `INFO`, etc. |
|
108
|
+
| `sampling_ratio` | `ASPECTO_SAMPLING_RATIO` | float | 1.0| How many of the traces starting in this service should be sampled. set to number in range [0.0, 1.0] where 0.0 is no sampling, and 1.0 is sample all |
|
109
|
+
| `otel_exporter_otlp_traces_endpoint` | `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | URL | `https://otelcol.aspecto.io/v1/trace` | Url |
|
110
|
+
| `require_config_for_traces` | `ASPECTO_REQUIRE_CONFIG_FOR_TRACES` | boolean | `false` | When `true`, the SDK will not trace anything until remote sampling configuration arrives (few hundreds ms). Can be used to enforce sampling configuration is always applied, with the cost of losing traces generated during service startup. |
|
111
|
+
| `extract_b3_context` | `ASPECTO_EXTRACT_B3_CONTEXT` | boolean | `false` | Set to `true` when the service receives requests from another instrumented component that propagate context via B3 protocol multi or single header. For example: Envoy Proxy, Ambassador and Istio |
|
112
|
+
| `inject_b3_context_single_header` | `ASPECTO_INJECT_B3_CONTEXT_SINGLE_HEADER` | boolean | `false` | Set to `true` when the service send traffic to another instrumented component that propagate context via B3 **single header** protocol |
|
113
|
+
| `inject_b3_context_multi_header` | `ASPECTO_INJECT_B3_CONTEXT_MULTI_HEADER` | boolean | `false` | Set to `true` when the service send traffic to another instrumented component that propagate context via B3 **multi header** protocol. For example: Envoy Proxy, Istio |
|
110
114
|
|
111
115
|
## Contributing
|
112
116
|
|
@@ -16,6 +16,8 @@ module Aspecto
|
|
16
16
|
def initialize(aspecto_auth, service_name, env, fallback_sampler)
|
17
17
|
@service_name = service_name
|
18
18
|
@env = env
|
19
|
+
@error_reported = false
|
20
|
+
@got_remote_config = false
|
19
21
|
@fallback_sampler = fallback_sampler
|
20
22
|
aspecto_config_host = ENV.fetch("ASPECTO_CONFIG_HOST", "https://config.aspecto.io")
|
21
23
|
@aspecto_config_url = URI("#{aspecto_config_host}/config/#{aspecto_auth}")
|
@@ -27,7 +29,10 @@ module Aspecto
|
|
27
29
|
update_config
|
28
30
|
end
|
29
31
|
|
30
|
-
::OpenTelemetry.logger.info "[Aspecto]
|
32
|
+
::OpenTelemetry.logger.info "[Aspecto] initialized remote config polling"
|
33
|
+
rescue StandardError => e
|
34
|
+
::OpenTelemetry.logger.error "[Aspecto] failed to initialize remote config polling"
|
35
|
+
::OpenTelemetry.logger.error e
|
31
36
|
end
|
32
37
|
|
33
38
|
def shutdown
|
@@ -50,7 +55,7 @@ module Aspecto
|
|
50
55
|
@http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
51
56
|
end
|
52
57
|
|
53
|
-
def update_config
|
58
|
+
def update_config
|
54
59
|
::OpenTelemetry::Common::Utilities.untraced do
|
55
60
|
request = Net::HTTP::Get.new(@aspecto_config_url.path)
|
56
61
|
request["If-None-Match"] = @latest_config_etag unless @latest_config_etag.nil?
|
@@ -60,7 +65,7 @@ module Aspecto
|
|
60
65
|
return if response_code == 304
|
61
66
|
|
62
67
|
if response_code >= 400
|
63
|
-
|
68
|
+
log_config_error "failed to get remote config with http response #{response_code}."
|
64
69
|
return
|
65
70
|
end
|
66
71
|
|
@@ -68,13 +73,14 @@ module Aspecto
|
|
68
73
|
handle_new_config JSON.parse(response.body) if response_code < 300
|
69
74
|
end
|
70
75
|
rescue StandardError => e
|
71
|
-
|
72
|
-
::OpenTelemetry.logger.debug e
|
76
|
+
log_config_error "updating remote config failed with exception.", e
|
73
77
|
end
|
74
78
|
|
75
79
|
def handle_new_config(config)
|
76
|
-
::OpenTelemetry.logger.info("[Aspecto] successfully received remote configuration")
|
77
80
|
update_sampler config["samplingRules"]
|
81
|
+
@error_reported = false
|
82
|
+
@got_remote_config = true
|
83
|
+
::OpenTelemetry.logger.info("[Aspecto] successfully updated remote configuration")
|
78
84
|
end
|
79
85
|
|
80
86
|
def update_sampler(sampler_config)
|
@@ -84,6 +90,16 @@ module Aspecto
|
|
84
90
|
# updating the sampler should be thread safe as it's an atomic setter on a global value
|
85
91
|
::OpenTelemetry.tracer_provider.sampler = message_process_sampler
|
86
92
|
end
|
93
|
+
|
94
|
+
def log_config_error(msg, err = nil)
|
95
|
+
return if @error_reported # report every issue only once
|
96
|
+
|
97
|
+
retry_msg = "will try again until success every #{@remote_config_poll_frequency}."
|
98
|
+
previous_config_msg = @got_remote_config ? "using previous remote config" : "no previous config is avialable"
|
99
|
+
::OpenTelemetry.logger.info("[Aspecto]: #{msg} #{retry_msg} #{previous_config_msg}")
|
100
|
+
::OpenTelemetry.logger.info(err) if err
|
101
|
+
@error_reported = true
|
102
|
+
end
|
87
103
|
end
|
88
104
|
end
|
89
105
|
end
|
@@ -6,7 +6,7 @@ module Aspecto
|
|
6
6
|
class Configurator
|
7
7
|
TRUTHY_VALUES = %w[1 T t true TRUE True].freeze
|
8
8
|
|
9
|
-
def initialize
|
9
|
+
def initialize # rubocop:disable Metrics/AbcSize
|
10
10
|
# initialize config options from environment variables.
|
11
11
|
# they can later be overwritten with configurator attribute setters
|
12
12
|
# that have precedence over env
|
@@ -16,7 +16,12 @@ module Aspecto
|
|
16
16
|
self.env = ENV["ASPECTO_ENV"] if ENV["ASPECTO_ENV"]
|
17
17
|
self.sampling_ratio = Float(ENV.fetch("ASPECTO_SAMPLING_RATIO", 1.0))
|
18
18
|
self.otel_exporter_otlp_traces_endpoint = ENV.fetch("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "https://otelcol.aspecto.io/v1/trace")
|
19
|
-
self.require_config_for_traces =
|
19
|
+
self.require_config_for_traces = self.class.bool_env_variable "ASPECTO_REQUIRE_CONFIG_FOR_TRACES", false
|
20
|
+
|
21
|
+
# b3 propagattor
|
22
|
+
self.extract_b3_context = self.class.bool_env_variable "ASPECTO_EXTRACT_B3_CONTEXT", false
|
23
|
+
self.inject_b3_context_single_header = self.class.bool_env_variable "ASPECTO_INJECT_B3_CONTEXT_SINGLE_HEADER", false
|
24
|
+
self.inject_b3_context_multi_header = self.class.bool_env_variable "ASPECTO_INJECT_B3_CONTEXT_MULTI_HEADER", false
|
20
25
|
end
|
21
26
|
|
22
27
|
def service_name=(service_name)
|
@@ -27,7 +32,7 @@ module Aspecto
|
|
27
32
|
@override_resource_attributes[::OpenTelemetry::SemanticConventions::Resource::DEPLOYMENT_ENVIRONMENT] = env
|
28
33
|
end
|
29
34
|
|
30
|
-
attr_accessor :sampling_ratio, :log_level, :otel_exporter_otlp_traces_endpoint, :require_config_for_traces
|
35
|
+
attr_accessor :sampling_ratio, :log_level, :otel_exporter_otlp_traces_endpoint, :require_config_for_traces, :extract_b3_context, :inject_b3_context_single_header, :inject_b3_context_multi_header
|
31
36
|
attr_reader :aspecto_auth
|
32
37
|
|
33
38
|
def aspecto_auth=(aspecto_auth)
|
@@ -38,6 +43,13 @@ module Aspecto
|
|
38
43
|
def config_override_resource
|
39
44
|
::OpenTelemetry::SDK::Resources::Resource.create(@override_resource_attributes)
|
40
45
|
end
|
46
|
+
|
47
|
+
def self.bool_env_variable(env_variable_name, default_value)
|
48
|
+
env_value = ENV[env_variable_name]
|
49
|
+
return default_value if env_value.nil?
|
50
|
+
|
51
|
+
TRUTHY_VALUES.include?(env_value.strip)
|
52
|
+
end
|
41
53
|
end
|
42
54
|
end
|
43
55
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "opentelemetry"
|
4
|
+
require "opentelemetry-propagator-b3"
|
5
|
+
|
6
|
+
module Aspecto
|
7
|
+
module OpenTelemetry
|
8
|
+
module Propagator
|
9
|
+
# Aspecto OpenTelemetry Propagator Configuration
|
10
|
+
module Aspecto
|
11
|
+
extend self
|
12
|
+
|
13
|
+
W3C_PROPAGATOR = ::OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator
|
14
|
+
B3_SINGLE_PROPAGATOR = ::OpenTelemetry::Propagator::B3::Single.text_map_propagator
|
15
|
+
B3_MULTI_PROPAGATOR = ::OpenTelemetry::Propagator::B3::Multi.text_map_propagator
|
16
|
+
|
17
|
+
def from_configurator(configurator)
|
18
|
+
injectors = [W3C_PROPAGATOR]
|
19
|
+
injectors.push(B3_SINGLE_PROPAGATOR) if configurator.inject_b3_context_single_header
|
20
|
+
injectors.push(B3_MULTI_PROPAGATOR) if configurator.inject_b3_context_multi_header
|
21
|
+
|
22
|
+
extractors = [W3C_PROPAGATOR]
|
23
|
+
extractors.push(B3_SINGLE_PROPAGATOR, B3_MULTI_PROPAGATOR) if configurator.extract_b3_context
|
24
|
+
|
25
|
+
::OpenTelemetry::Context::Propagation::CompositeTextMapPropagator.compose(injectors: injectors, extractors: extractors)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -2,14 +2,15 @@
|
|
2
2
|
|
3
3
|
require_relative "opentelemetry/version"
|
4
4
|
require_relative "opentelemetry/configurator"
|
5
|
+
require_relative "opentelemetry/propagator/aspecto"
|
5
6
|
require_relative "opentelemetry/resource/detectors/aspecto"
|
6
|
-
require_relative "opentelemetry/resource/detectors/deployment"
|
7
7
|
require_relative "opentelemetry/config/remote_config"
|
8
8
|
|
9
9
|
require "opentelemetry/sdk"
|
10
10
|
require "opentelemetry/exporter/otlp"
|
11
11
|
require "opentelemetry/instrumentation/all"
|
12
12
|
require "opentelemetry-instrumentation-aws_sdk"
|
13
|
+
require "opentelemetry-resource-detector-deployment"
|
13
14
|
|
14
15
|
module Aspecto
|
15
16
|
# Aspecto OpenTelemetry Distro
|
@@ -27,7 +28,7 @@ module Aspecto
|
|
27
28
|
::OpenTelemetry::SDK.configure do |c|
|
28
29
|
c.logger = Logger.new($stdout, level: configurator.log_level)
|
29
30
|
c.resource = Aspecto::OpenTelemetry::Resource::Detectors::Aspecto.detect
|
30
|
-
c.resource =
|
31
|
+
c.resource = ::OpenTelemetry::Resource::Detector::Deployment.detect
|
31
32
|
c.resource = configurator.config_override_resource # must be last
|
32
33
|
c.use_all "OpenTelemetry::Instrumentation::ActionPack" => { enable_recognize_route: true },
|
33
34
|
"OpenTelemetry::Instrumentation::AwsSdk" => {
|
@@ -50,6 +51,10 @@ module Aspecto
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
54
|
+
# Propagation
|
55
|
+
::OpenTelemetry.propagation = ::Aspecto::OpenTelemetry::Propagator::Aspecto.from_configurator configurator
|
56
|
+
|
57
|
+
# Sampling
|
53
58
|
if configurator.require_config_for_traces
|
54
59
|
::OpenTelemetry.logger.info "[Aspecto] Require config for traces. Applying ALWAYS_OFF sampler"
|
55
60
|
::OpenTelemetry.tracer_provider.sampler = ::OpenTelemetry::SDK::Trace::Samplers::ALWAYS_OFF
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aspecto-opentelemetry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aspecto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aspecto-opentelemetry-instrumentation-aws_sdk
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.22.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: opentelemetry-propagator-b3
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.19.2
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.19.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: opentelemetry-resource-detector-deployment
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.0.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.0.1
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: opentelemetry-sdk
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -167,8 +195,8 @@ files:
|
|
167
195
|
- lib/aspecto/opentelemetry.rb
|
168
196
|
- lib/aspecto/opentelemetry/config/remote_config.rb
|
169
197
|
- lib/aspecto/opentelemetry/configurator.rb
|
198
|
+
- lib/aspecto/opentelemetry/propagator/aspecto.rb
|
170
199
|
- lib/aspecto/opentelemetry/resource/detectors/aspecto.rb
|
171
|
-
- lib/aspecto/opentelemetry/resource/detectors/deployment.rb
|
172
200
|
- lib/aspecto/opentelemetry/sampler/condition.rb
|
173
201
|
- lib/aspecto/opentelemetry/sampler/message_process_sampler.rb
|
174
202
|
- lib/aspecto/opentelemetry/sampler/operator.rb
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Aspecto
|
4
|
-
module OpenTelemetry
|
5
|
-
module Resource
|
6
|
-
module Detectors
|
7
|
-
# Deployment contains detect class method for determining deployment resource attributes
|
8
|
-
module Deployment
|
9
|
-
extend self
|
10
|
-
|
11
|
-
def detect
|
12
|
-
resource_attributes = {}
|
13
|
-
deployment_environment = rails_env || sinatra_env || rack_env
|
14
|
-
resource_attributes[::OpenTelemetry::SemanticConventions::Resource::DEPLOYMENT_ENVIRONMENT] = deployment_environment if deployment_environment
|
15
|
-
::OpenTelemetry::SDK::Resources::Resource.create(resource_attributes)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def rails_env
|
21
|
-
# rails extract env like this:
|
22
|
-
# https://github.com/rails/rails/blob/5647a9c1ced68d20338552d47a3b755e10a271c4/railties/lib/rails.rb#L74
|
23
|
-
# ActiveSupport::EnvironmentInquirer.new(ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development")
|
24
|
-
::Rails.env.to_s if defined?(::Rails.env)
|
25
|
-
end
|
26
|
-
|
27
|
-
def rack_env
|
28
|
-
ENV["RACK_ENV"]
|
29
|
-
end
|
30
|
-
|
31
|
-
def sinatra_env
|
32
|
-
# https://github.com/sinatra/sinatra/blob/e69b6b9dee7165d3a583fc8a6af10ceee1ea687d/lib/sinatra/base.rb#L1801
|
33
|
-
# cases:
|
34
|
-
#
|
35
|
-
# 1. if sinatra is "require"d before the detector, then we return the value from the library
|
36
|
-
# this case will return the default "development" fallback if not env variable is set which is good.
|
37
|
-
#
|
38
|
-
# 2. if sinatra is "require"d after the detector, then:
|
39
|
-
# 2.1 if user is setting environment via 'APP_ENV' or 'RACK_ENV' then those value will be picked up and reported
|
40
|
-
# 2.2 else, the sinatra environment will fallback to "development", but detector will return nil for it.
|
41
|
-
# this issue is not covered, as when detector initialize the immutable resource, it has no way
|
42
|
-
# of knowing if "sinatra" will be required later or not.
|
43
|
-
(::Sinatra::Base.environment.to_s if defined?(::Sinatra::Base.environment)) || ENV["APP_ENV"]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|