solarwinds_apm 5.1.9 → 6.0.0.preV1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +0 -1
- data/ext/oboe_metal/extconf.rb +19 -23
- data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +1 -1
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +1 -1
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +1 -1
- data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +1 -1
- data/ext/oboe_metal/src/VERSION +1 -1
- data/ext/oboe_metal/src/oboe_debug.h +1 -0
- data/lib/oboe_metal.rb +116 -80
- data/lib/rails/generators/solarwinds_apm/install_generator.rb +1 -2
- data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +44 -260
- data/lib/solarwinds_apm/api/current_trace_info.rb +148 -0
- data/lib/solarwinds_apm/api/tracing.rb +30 -0
- data/lib/solarwinds_apm/api/transaction_name.rb +57 -0
- data/lib/solarwinds_apm/api.rb +8 -15
- data/lib/solarwinds_apm/base.rb +4 -131
- data/lib/solarwinds_apm/config.rb +128 -175
- data/lib/solarwinds_apm/constants.rb +32 -0
- data/lib/solarwinds_apm/logger.rb +1 -1
- data/lib/solarwinds_apm/noop/context.rb +2 -5
- data/lib/solarwinds_apm/noop/metadata.rb +1 -2
- data/lib/solarwinds_apm/noop/profiling.rb +3 -7
- data/lib/solarwinds_apm/oboe_init_options.rb +71 -33
- data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +204 -0
- data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +163 -0
- data/lib/solarwinds_apm/opentelemetry/solarwinds_propagator.rb +92 -0
- data/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +72 -0
- data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +330 -0
- data/lib/solarwinds_apm/opentelemetry.rb +8 -0
- data/lib/solarwinds_apm/otel_config.rb +161 -0
- data/lib/solarwinds_apm/{inst → support}/logger_formatter.rb +5 -6
- data/lib/solarwinds_apm/{inst → support}/logging_log_event.rb +3 -6
- data/lib/solarwinds_apm/{inst → support}/lumberjack_formatter.rb +1 -4
- data/lib/solarwinds_apm/support/oboe_tracing_mode.rb +27 -0
- data/lib/solarwinds_apm/support/swomarginalia/LICENSE +20 -0
- data/lib/solarwinds_apm/support/swomarginalia/README.md +41 -0
- data/lib/solarwinds_apm/support/swomarginalia/comment.rb +205 -0
- data/lib/solarwinds_apm/support/swomarginalia/load_swomarginalia.rb +48 -0
- data/lib/solarwinds_apm/support/swomarginalia/railtie.rb +22 -0
- data/lib/solarwinds_apm/support/swomarginalia/swomarginalia.rb +86 -0
- data/lib/solarwinds_apm/support/transaction_cache.rb +24 -0
- data/lib/solarwinds_apm/support/transaction_settings.rb +26 -209
- data/lib/solarwinds_apm/support/transformer.rb +56 -0
- data/lib/solarwinds_apm/support/txn_name_manager.rb +25 -0
- data/lib/solarwinds_apm/support/x_trace_options.rb +42 -26
- data/lib/solarwinds_apm/support.rb +33 -10
- data/lib/solarwinds_apm/support_report.rb +10 -32
- data/lib/solarwinds_apm/thread_local.rb +1 -1
- data/lib/solarwinds_apm/version.rb +4 -4
- data/lib/solarwinds_apm.rb +31 -26
- metadata +76 -121
- data/.dockerignore +0 -5
- data/.gitignore +0 -58
- data/.rubocop.yml +0 -29
- data/.whitesource +0 -22
- data/.yardopts +0 -7
- data/CHANGELOG-appoptics.md +0 -766
- data/CHANGELOG.md +0 -82
- data/CONFIG.md +0 -31
- data/Gemfile +0 -15
- data/README.md +0 -385
- data/bin/solarwinds_apm_config +0 -15
- data/examples/prepend.rb +0 -13
- data/examples/sdk_examples.rb +0 -158
- data/ext/oboe_metal/README.md +0 -69
- data/ext/oboe_metal/extconf_local.rb +0 -75
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/noop/noop.c +0 -8
- data/ext/oboe_metal/src/README.md +0 -6
- data/ext/oboe_metal/src/frames.cc +0 -247
- data/ext/oboe_metal/src/frames.h +0 -40
- data/ext/oboe_metal/src/logging.cc +0 -97
- data/ext/oboe_metal/src/logging.h +0 -34
- data/ext/oboe_metal/src/profiling.cc +0 -435
- data/ext/oboe_metal/src/profiling.h +0 -78
- data/ext/oboe_metal/test/CMakeLists.txt +0 -53
- data/ext/oboe_metal/test/FindGMock.cmake +0 -43
- data/ext/oboe_metal/test/README.md +0 -56
- data/ext/oboe_metal/test/frames_test.cc +0 -164
- data/ext/oboe_metal/test/profiling_test.cc +0 -93
- data/ext/oboe_metal/test/ruby_inc_dir.rb +0 -8
- data/ext/oboe_metal/test/ruby_prefix.rb +0 -8
- data/ext/oboe_metal/test/ruby_test_helper.rb +0 -67
- data/ext/oboe_metal/test/test.h +0 -11
- data/ext/oboe_metal/test/test_main.cc +0 -32
- data/init.rb +0 -4
- data/lib/solarwinds_apm/api/layerinit.rb +0 -41
- data/lib/solarwinds_apm/api/logging.rb +0 -356
- data/lib/solarwinds_apm/api/memcache.rb +0 -37
- data/lib/solarwinds_apm/api/metrics.rb +0 -63
- data/lib/solarwinds_apm/api/util.rb +0 -98
- data/lib/solarwinds_apm/frameworks/grape.rb +0 -96
- data/lib/solarwinds_apm/frameworks/padrino.rb +0 -78
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +0 -100
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +0 -50
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +0 -50
- data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +0 -88
- data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +0 -26
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +0 -29
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +0 -22
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +0 -103
- data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +0 -14
- data/lib/solarwinds_apm/frameworks/rails.rb +0 -100
- data/lib/solarwinds_apm/frameworks/sinatra.rb +0 -96
- data/lib/solarwinds_apm/inst/bunny-client.rb +0 -157
- data/lib/solarwinds_apm/inst/bunny-consumer.rb +0 -102
- data/lib/solarwinds_apm/inst/curb.rb +0 -289
- data/lib/solarwinds_apm/inst/dalli.rb +0 -89
- data/lib/solarwinds_apm/inst/delayed_job.rb +0 -100
- data/lib/solarwinds_apm/inst/excon.rb +0 -113
- data/lib/solarwinds_apm/inst/faraday.rb +0 -96
- data/lib/solarwinds_apm/inst/graphql.rb +0 -206
- data/lib/solarwinds_apm/inst/grpc_client.rb +0 -147
- data/lib/solarwinds_apm/inst/grpc_server.rb +0 -119
- data/lib/solarwinds_apm/inst/httpclient.rb +0 -182
- data/lib/solarwinds_apm/inst/memcached.rb +0 -86
- data/lib/solarwinds_apm/inst/mongo.rb +0 -246
- data/lib/solarwinds_apm/inst/mongo2.rb +0 -225
- data/lib/solarwinds_apm/inst/moped.rb +0 -466
- data/lib/solarwinds_apm/inst/net_http.rb +0 -60
- data/lib/solarwinds_apm/inst/rack.rb +0 -223
- data/lib/solarwinds_apm/inst/rack_cache.rb +0 -35
- data/lib/solarwinds_apm/inst/redis.rb +0 -280
- data/lib/solarwinds_apm/inst/redis_v4.rb +0 -273
- data/lib/solarwinds_apm/inst/resque.rb +0 -129
- data/lib/solarwinds_apm/inst/rest-client.rb +0 -43
- data/lib/solarwinds_apm/inst/sequel.rb +0 -241
- data/lib/solarwinds_apm/inst/sidekiq-client.rb +0 -63
- data/lib/solarwinds_apm/inst/sidekiq-worker.rb +0 -64
- data/lib/solarwinds_apm/inst/typhoeus.rb +0 -90
- data/lib/solarwinds_apm/instrumentation.rb +0 -22
- data/lib/solarwinds_apm/loading.rb +0 -65
- data/lib/solarwinds_apm/ruby.rb +0 -35
- data/lib/solarwinds_apm/sdk/current_trace_info.rb +0 -123
- data/lib/solarwinds_apm/sdk/custom_metrics.rb +0 -94
- data/lib/solarwinds_apm/sdk/logging.rb +0 -37
- data/lib/solarwinds_apm/sdk/trace_context_headers.rb +0 -69
- data/lib/solarwinds_apm/sdk/tracing.rb +0 -432
- data/lib/solarwinds_apm/support/profiling.rb +0 -25
- data/lib/solarwinds_apm/support/trace_context.rb +0 -53
- data/lib/solarwinds_apm/support/trace_state.rb +0 -69
- data/lib/solarwinds_apm/support/trace_string.rb +0 -89
- data/lib/solarwinds_apm/support/transaction_metrics.rb +0 -67
- data/lib/solarwinds_apm/test.rb +0 -165
- data/lib/solarwinds_apm/util.rb +0 -426
- data/log/.keep +0 -0
- data/log/postgresql/.keep +0 -0
- data/solarwinds_apm.gemspec +0 -55
- data/yardoc_frontpage.md +0 -24
@@ -1,10 +1,8 @@
|
|
1
1
|
# Copyright (c) 2019 SolarWinds, LLC.
|
2
2
|
# All rights reserved.
|
3
|
-
|
4
3
|
require 'singleton'
|
5
|
-
|
6
4
|
module SolarWindsAPM
|
7
|
-
|
5
|
+
# OboeInitOptions
|
8
6
|
class OboeInitOptions
|
9
7
|
include Singleton
|
10
8
|
|
@@ -46,7 +44,7 @@ module SolarWindsAPM
|
|
46
44
|
# custom token bucket rate
|
47
45
|
@token_bucket_rate = (ENV['SW_APM_TOKEN_BUCKET_RATE'] || -1).to_i
|
48
46
|
# use single files in file reporter for each event
|
49
|
-
@file_single =
|
47
|
+
@file_single = ENV['SW_APM_REPORTER_FILE_SINGLE'].to_s.downcase == 'true' ? 1 : 0
|
50
48
|
# timeout for ec2 metadata
|
51
49
|
@ec2_md_timeout = read_and_validate_ec2_md_timeout
|
52
50
|
@grpc_proxy = read_and_validate_proxy
|
@@ -57,7 +55,8 @@ module SolarWindsAPM
|
|
57
55
|
@metric_format = determine_the_metric_model
|
58
56
|
end
|
59
57
|
|
60
|
-
|
58
|
+
# for testing with changed ENV vars
|
59
|
+
def re_init
|
61
60
|
initialize
|
62
61
|
end
|
63
62
|
|
@@ -84,12 +83,12 @@ module SolarWindsAPM
|
|
84
83
|
@ec2_md_timeout, #17
|
85
84
|
@grpc_proxy, #18
|
86
85
|
0, #19 arg for lambda (no lambda for ruby yet)
|
87
|
-
@metric_format #
|
86
|
+
@metric_format #22
|
88
87
|
]
|
89
88
|
end
|
90
89
|
|
91
90
|
def service_key_ok?
|
92
|
-
|
91
|
+
!@service_key.empty? || @reporter != 'ssl'
|
93
92
|
end
|
94
93
|
|
95
94
|
private
|
@@ -106,9 +105,8 @@ module SolarWindsAPM
|
|
106
105
|
when 'ssl', 'file'
|
107
106
|
host = ENV['SW_APM_COLLECTOR'] || ''
|
108
107
|
when 'udp'
|
109
|
-
host = ENV['SW_APM_COLLECTOR'] ||
|
110
|
-
|
111
|
-
# TODO decide what to do
|
108
|
+
host = ENV['SW_APM_COLLECTOR'] || "#{SolarWindsAPM::Config[:reporter_host]}:#{SolarWindsAPM::Config[:reporter_port]}"
|
109
|
+
# TODO: decide what to do
|
112
110
|
# ____ SolarWindsAPM::Config[:reporter_host] and
|
113
111
|
# ____ SolarWindsAPM::Config[:reporter_port] were moved here from
|
114
112
|
# ____ oboe_metal.rb and are not documented anywhere
|
@@ -117,6 +115,7 @@ module SolarWindsAPM
|
|
117
115
|
host = ''
|
118
116
|
end
|
119
117
|
|
118
|
+
host = sanitize_collector_uri(host) unless reporter == 'file'
|
120
119
|
[reporter, host]
|
121
120
|
end
|
122
121
|
|
@@ -125,24 +124,50 @@ module SolarWindsAPM
|
|
125
124
|
|
126
125
|
service_key = ENV['SW_APM_SERVICE_KEY'] || SolarWindsAPM::Config[:service_key]
|
127
126
|
unless service_key
|
128
|
-
SolarWindsAPM.logger.error "[
|
127
|
+
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY not configured."}
|
129
128
|
return ''
|
130
129
|
end
|
131
130
|
|
132
|
-
match = service_key.match(
|
131
|
+
match = service_key.match(/([^:]+)(:{0,1})(.*)/)
|
133
132
|
token = match[1]
|
134
133
|
service_name = match[3]
|
135
134
|
|
136
|
-
return '' unless validate_token(token)
|
135
|
+
return '' unless validate_token(token) # return if token is not even valid
|
136
|
+
|
137
|
+
if service_name.empty?
|
138
|
+
ENV.delete('OTEL_SERVICE_NAME')
|
139
|
+
SolarWindsAPM.logger.warn {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY format problem. Service Name is missing."}
|
140
|
+
return ''
|
141
|
+
end
|
142
|
+
|
143
|
+
# check OTEL_RESOURCE_ATTRIBUTES
|
144
|
+
otel_resource_service_name = nil
|
145
|
+
ENV['OTEL_RESOURCE_ATTRIBUTES']&.split(',')&.each do |pair|
|
146
|
+
key, value = pair.split('=')
|
147
|
+
otel_resource_service_name = value; break if key == 'service.name'
|
148
|
+
end
|
149
|
+
|
150
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] provided otel_resource_service_name #{otel_resource_service_name}"} if otel_resource_service_name
|
151
|
+
service_name = otel_resource_service_name if otel_resource_service_name && validate_transform_service_name(otel_resource_service_name)
|
152
|
+
|
153
|
+
# check OTEL_SERVICE_NAME
|
154
|
+
otel_service_name = ENV['OTEL_SERVICE_NAME']
|
155
|
+
if otel_service_name && validate_transform_service_name(otel_service_name)
|
156
|
+
service_name = otel_service_name
|
157
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] provided otel_service_name #{otel_service_name}"}
|
158
|
+
elsif ENV['OTEL_SERVICE_NAME'].nil?
|
159
|
+
ENV['OTEL_SERVICE_NAME'] = service_name
|
160
|
+
end
|
161
|
+
|
137
162
|
return '' unless validate_transform_service_name(service_name)
|
138
163
|
|
139
|
-
|
164
|
+
"#{token}:#{service_name}"
|
140
165
|
end
|
141
166
|
|
142
167
|
def validate_token(token)
|
143
168
|
if (token !~ /^[0-9a-zA-Z_-]{71}$/) && ENV['SW_APM_COLLECTOR'] !~ /java-collector:1222/
|
144
|
-
masked = "#{token[0..3]}...#{token[-4
|
145
|
-
SolarWindsAPM.logger.error "[
|
169
|
+
masked = "#{token[0..3]}...#{token[-4..]}"
|
170
|
+
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY problem. API Token in wrong format. Masked token: #{masked}"}
|
146
171
|
return false
|
147
172
|
end
|
148
173
|
|
@@ -152,7 +177,7 @@ module SolarWindsAPM
|
|
152
177
|
def validate_transform_service_name(service_name)
|
153
178
|
service_name = 'test_ssl_collector' if ENV['SW_APM_COLLECTOR'] =~ /java-collector:1222/
|
154
179
|
if service_name.empty?
|
155
|
-
SolarWindsAPM.logger.error "[
|
180
|
+
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY problem. Service Name is missing"}
|
156
181
|
return false
|
157
182
|
end
|
158
183
|
|
@@ -162,7 +187,7 @@ module SolarWindsAPM
|
|
162
187
|
name = name[0..254]
|
163
188
|
|
164
189
|
if name != service_name
|
165
|
-
SolarWindsAPM.logger.warn "[
|
190
|
+
SolarWindsAPM.logger.warn {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY problem. Service Name transformed from #{service_name} to #{name}"}
|
166
191
|
service_name = name
|
167
192
|
end
|
168
193
|
@service_name = service_name # instance variable used in testing
|
@@ -172,8 +197,9 @@ module SolarWindsAPM
|
|
172
197
|
def read_and_validate_ec2_md_timeout
|
173
198
|
timeout = ENV['SW_APM_EC2_METADATA_TIMEOUT'] || SolarWindsAPM::Config[:ec2_metadata_timeout]
|
174
199
|
return 1000 unless timeout.is_a?(Integer) || timeout =~ /^\d+$/
|
200
|
+
|
175
201
|
timeout = timeout.to_i
|
176
|
-
|
202
|
+
timeout.between?(0, 3000) ? timeout : 1000
|
177
203
|
end
|
178
204
|
|
179
205
|
def read_and_validate_proxy
|
@@ -181,7 +207,7 @@ module SolarWindsAPM
|
|
181
207
|
return proxy if proxy == ''
|
182
208
|
|
183
209
|
unless proxy =~ /http:\/\/.*:\d+$/
|
184
|
-
SolarWindsAPM.logger.error "[
|
210
|
+
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_PROXY/http_proxy doesn't start with 'http://', #{proxy}"}
|
185
211
|
return '' # try without proxy, it may work, shouldn't crash but may not report
|
186
212
|
end
|
187
213
|
|
@@ -189,31 +215,43 @@ module SolarWindsAPM
|
|
189
215
|
end
|
190
216
|
|
191
217
|
def read_certificates
|
192
|
-
|
193
|
-
file =
|
194
|
-
file =
|
195
|
-
file = ENV['SW_APM_TRUSTEDPATH'] if (!ENV['SW_APM_TRUSTEDPATH'].nil? && !ENV['SW_APM_TRUSTEDPATH']&.empty?)
|
218
|
+
file = String.new
|
219
|
+
file = "#{__dir__}/cert/star.appoptics.com.issuer.crt" if appoptics_collector?
|
220
|
+
file = ENV['SW_APM_TRUSTEDPATH'] if !ENV['SW_APM_TRUSTEDPATH'].nil? && !ENV['SW_APM_TRUSTEDPATH']&.empty?
|
196
221
|
|
197
|
-
return
|
222
|
+
return file if file.empty?
|
198
223
|
|
199
224
|
begin
|
200
225
|
certificate = File.open(file,"r").read
|
201
226
|
rescue StandardError => e
|
202
|
-
SolarWindsAPM.logger.error "[
|
227
|
+
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] certificates: #{file} doesn't exist or caused by #{e.message}."}
|
203
228
|
certificate = String.new
|
204
229
|
end
|
205
230
|
|
206
|
-
|
207
|
-
|
231
|
+
certificate
|
208
232
|
end
|
209
233
|
|
210
234
|
def determine_the_metric_model
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
235
|
+
appoptics_collector? ? 1 : 2
|
236
|
+
end
|
237
|
+
|
238
|
+
def appoptics_collector?
|
239
|
+
allowed_uri = ['collector.appoptics.com', 'collector-stg.appoptics.com',
|
240
|
+
'collector.appoptics.com:443', 'collector-stg.appoptics.com:443']
|
241
|
+
|
242
|
+
(allowed_uri.include? ENV["SW_APM_COLLECTOR"])? true : false
|
243
|
+
end
|
244
|
+
|
245
|
+
def sanitize_collector_uri(uri)
|
246
|
+
return uri if uri.nil? || uri.empty?
|
247
|
+
|
248
|
+
begin
|
249
|
+
sanitized_uri = URI("http://#{uri}").host
|
250
|
+
return sanitized_uri unless sanitized_uri.nil?
|
251
|
+
rescue StandardError => e
|
252
|
+
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] uri for collector #{uri} is malformat. Error: #{e.message}"}
|
215
253
|
end
|
254
|
+
""
|
216
255
|
end
|
217
256
|
end
|
218
257
|
end
|
219
|
-
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# solarwinds_apm will use liboboe to export data to solarwinds swo
|
2
|
+
module SolarWindsAPM
|
3
|
+
module OpenTelemetry
|
4
|
+
# SolarWindsExporter
|
5
|
+
class SolarWindsExporter
|
6
|
+
SUCCESS = ::OpenTelemetry::SDK::Trace::Export::SUCCESS # ::OpenTelemetry #=> the OpenTelemetry at top level (to ignore SolarWindsAPM)
|
7
|
+
FAILURE = ::OpenTelemetry::SDK::Trace::Export::FAILURE
|
8
|
+
|
9
|
+
private_constant(:SUCCESS, :FAILURE)
|
10
|
+
|
11
|
+
def initialize(txn_manager: nil)
|
12
|
+
@shutdown = false
|
13
|
+
@txn_manager = txn_manager
|
14
|
+
@reporter = SolarWindsAPM::Reporter
|
15
|
+
@context = SolarWindsAPM::Context
|
16
|
+
@metadata = SolarWindsAPM::Metadata
|
17
|
+
@version_cache = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def export(span_data, _timeout: nil)
|
21
|
+
return FAILURE if @shutdown
|
22
|
+
|
23
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] span_data: #{span_data}"}
|
24
|
+
span_data.each do |data|
|
25
|
+
log_span_data(data)
|
26
|
+
end
|
27
|
+
SUCCESS
|
28
|
+
end
|
29
|
+
|
30
|
+
def force_flush(timeout: nil) # rubocop:disable Lint/UnusedMethodArgument
|
31
|
+
SUCCESS
|
32
|
+
end
|
33
|
+
|
34
|
+
def shutdown(timeout: nil) # rubocop:disable Lint/UnusedMethodArgument
|
35
|
+
@shutdown = true
|
36
|
+
SUCCESS
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def log_span_data(span_data)
|
42
|
+
|
43
|
+
begin
|
44
|
+
md = build_meta_data(span_data)
|
45
|
+
event = nil
|
46
|
+
|
47
|
+
if span_data.parent_span_id != ::OpenTelemetry::Trace::INVALID_SPAN_ID
|
48
|
+
|
49
|
+
parent_md = build_meta_data(span_data, parent: true)
|
50
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Continue trace from parent. parent_md: #{parent_md}, span_data: #{span_data.inspect}"}
|
51
|
+
event = @context.createEntry(md, (span_data.start_timestamp.to_i / 1000).to_i, parent_md)
|
52
|
+
else
|
53
|
+
|
54
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Start a new trace."}
|
55
|
+
event = @context.createEntry(md, (span_data.start_timestamp.to_i / 1000).to_i)
|
56
|
+
add_info_transaction_name(span_data, event)
|
57
|
+
end
|
58
|
+
|
59
|
+
event.addInfo('Layer', span_data.name)
|
60
|
+
event.addInfo('sw.span_kind', span_data.kind.to_s)
|
61
|
+
event.addInfo('Language', 'Ruby')
|
62
|
+
|
63
|
+
add_info_instrumentation_scope(event, span_data)
|
64
|
+
add_info_instrumented_framework(event, span_data)
|
65
|
+
|
66
|
+
if span_data.attributes
|
67
|
+
if span_data.attributes['http.target']
|
68
|
+
http_target = span_data.attributes['http.target']
|
69
|
+
http_target = http_target.split('?').first if SolarWindsAPM::Config[:log_args] == false # remove url parameters
|
70
|
+
event.addInfo('http.target', http_target)
|
71
|
+
span_data.attributes.each do |k, v|
|
72
|
+
next if k == 'http.target'
|
73
|
+
|
74
|
+
event.addInfo(k, v)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
span_data.attributes.each { |k, v| event.addInfo(k, v) }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
@reporter.send_report(event, with_system_timestamp: false)
|
82
|
+
|
83
|
+
# info / exception event
|
84
|
+
span_data.events&.each do |span_data_event|
|
85
|
+
span_data_event.name == 'exception' ? report_exception_event(span_data_event) : report_info_event(span_data_event)
|
86
|
+
end
|
87
|
+
|
88
|
+
event = @context.createExit((span_data.end_timestamp.to_i / 1000).to_i)
|
89
|
+
event.addInfo('Layer', span_data.name)
|
90
|
+
@reporter.send_report(event, with_system_timestamp: false)
|
91
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Exit a trace: #{event.metadataString}"}
|
92
|
+
rescue StandardError => e
|
93
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] \n #{e.message} #{e.backtrace}\n"}
|
94
|
+
raise
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_info_instrumentation_scope(event, span_data)
|
100
|
+
scope_name = ""
|
101
|
+
scope_version = ""
|
102
|
+
if span_data.instrumentation_scope
|
103
|
+
scope_name = span_data.instrumentation_scope.name if span_data.instrumentation_scope.name
|
104
|
+
scope_version = span_data.instrumentation_scope.version if span_data.instrumentation_scope.version
|
105
|
+
end
|
106
|
+
event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_SCOPE_NAME, scope_name)
|
107
|
+
event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_SCOPE_VERSION, scope_version)
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# get the framework version (the real version not the sdk instrumentation version)
|
112
|
+
#
|
113
|
+
def add_info_instrumented_framework(event, span_data)
|
114
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] add_info_instrumented_framework: #{span_data.instrumentation_scope.name}"}
|
115
|
+
scope_name = span_data.instrumentation_scope.name
|
116
|
+
scope_name = scope_name.downcase if scope_name
|
117
|
+
return unless scope_name&.include? "opentelemetry::instrumentation"
|
118
|
+
|
119
|
+
framework = scope_name.split("::")[2..]&.join("::")
|
120
|
+
return if framework.nil? || framework.empty?
|
121
|
+
|
122
|
+
framework = normalize_framework_name(framework)
|
123
|
+
framework_version = check_framework_version(framework)
|
124
|
+
event.addInfo("Ruby.#{framework}.Version",framework_version) unless framework_version.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
def check_framework_version(framework)
|
128
|
+
framework_version = nil
|
129
|
+
if @version_cache.keys.include? framework
|
130
|
+
|
131
|
+
framework_version = @version_cache[framework]
|
132
|
+
else
|
133
|
+
|
134
|
+
begin
|
135
|
+
require framework
|
136
|
+
framework_version = Gem.loaded_specs[framework].version.to_s
|
137
|
+
rescue LoadError => e
|
138
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] couldn't load #{framework} with error #{e.message}; skip"}
|
139
|
+
rescue StandardError => e
|
140
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] couldn't find #{framework} with error #{e.message}; skip"}
|
141
|
+
ensure
|
142
|
+
@version_cache[framework] = framework_version
|
143
|
+
end
|
144
|
+
end
|
145
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Current framework version cached: #{@version_cache.inspect}"}
|
146
|
+
framework_version
|
147
|
+
end
|
148
|
+
|
149
|
+
def normalize_framework_name(framework)
|
150
|
+
case framework
|
151
|
+
when "net::http"
|
152
|
+
normalized = "net/http"
|
153
|
+
else
|
154
|
+
normalized = framework
|
155
|
+
end
|
156
|
+
normalized
|
157
|
+
end
|
158
|
+
|
159
|
+
# Add transaction name from cache to root span then removes from cache
|
160
|
+
def add_info_transaction_name(span_data, evt)
|
161
|
+
trace_span_id = "#{span_data.hex_trace_id}-#{span_data.hex_span_id}"
|
162
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] #{@txn_manager.inspect},\n span_data: #{span_data.inspect}"}
|
163
|
+
txname = @txn_manager.get(trace_span_id).nil?? "" : @txn_manager.get(trace_span_id)
|
164
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] txname: #{txname}"}
|
165
|
+
evt.addInfo("TransactionName", txname)
|
166
|
+
@txn_manager.del(trace_span_id)
|
167
|
+
end
|
168
|
+
|
169
|
+
def report_exception_event(span_event)
|
170
|
+
evt = @context.createEvent((span_event.timestamp.to_i / 1000).to_i)
|
171
|
+
evt.addInfo('Label', 'error')
|
172
|
+
evt.addInfo('Spec', 'error')
|
173
|
+
|
174
|
+
unless span_event.attributes.nil?
|
175
|
+
evt.addInfo('ErrorClass', span_event.attributes['exception.type'])
|
176
|
+
evt.addInfo('ErrorMsg', span_event.attributes['exception.message'])
|
177
|
+
evt.addInfo('Backtrace', span_event.attributes['exception.stacktrace'])
|
178
|
+
span_event.attributes.each do |key, value|
|
179
|
+
evt.addInfo(key, value) unless ['exception.type', 'exception.message','exception.stacktrace'].include? key
|
180
|
+
end
|
181
|
+
end
|
182
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] exception event #{evt.metadataString}"}
|
183
|
+
@reporter.send_report(evt, with_system_timestamp: false)
|
184
|
+
end
|
185
|
+
|
186
|
+
def report_info_event(span_event)
|
187
|
+
evt = @context.createEvent((span_event.timestamp.to_i / 1000).to_i)
|
188
|
+
evt.addInfo('Label', 'info')
|
189
|
+
span_event.attributes&.each do |key, value|
|
190
|
+
evt.addInfo(key, value)
|
191
|
+
end
|
192
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] info event #{evt.metadataString}"}
|
193
|
+
@reporter.send_report(evt, with_system_timestamp: false)
|
194
|
+
end
|
195
|
+
|
196
|
+
def build_meta_data(span_data, parent: false)
|
197
|
+
flag = span_data.trace_flags.sampled?? 1 : 0
|
198
|
+
version = "00"
|
199
|
+
xtr = parent == false ? "#{version}-#{span_data.hex_trace_id}-#{span_data.hex_span_id}-0#{flag}" : "#{version}-#{span_data.hex_trace_id}-#{span_data.hex_parent_span_id}-0#{flag}"
|
200
|
+
@metadata.fromString(xtr)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module SolarWindsAPM
|
2
|
+
module OpenTelemetry
|
3
|
+
# reference: OpenTelemetry::SDK::Trace::SpanProcessor
|
4
|
+
class SolarWindsProcessor
|
5
|
+
HTTP_METHOD = "http.method".freeze
|
6
|
+
HTTP_ROUTE = "http.route".freeze
|
7
|
+
HTTP_STATUS_CODE = "http.status_code".freeze
|
8
|
+
HTTP_URL = "http.url".freeze
|
9
|
+
LIBOBOE_HTTP_SPAN_STATUS_UNAVAILABLE = 0
|
10
|
+
|
11
|
+
attr_reader :txn_manager
|
12
|
+
|
13
|
+
def initialize(exporter, txn_manager)
|
14
|
+
@exporter = exporter
|
15
|
+
@txn_manager = txn_manager
|
16
|
+
end
|
17
|
+
|
18
|
+
# Called when a {Span} is started, if the {Span#recording?}
|
19
|
+
# returns true.
|
20
|
+
#
|
21
|
+
# This method is called synchronously on the execution thread, should
|
22
|
+
# not throw or block the execution thread.
|
23
|
+
#
|
24
|
+
# @param [Span] span the {Span} that just started.
|
25
|
+
# @param [Context] parent_context the parent {Context} of the newly
|
26
|
+
# started span.
|
27
|
+
def on_start(span, parent_context)
|
28
|
+
|
29
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] processor on_start span: #{span.inspect}, parent_context: #{parent_context.inspect}"}
|
30
|
+
|
31
|
+
parent_span = ::OpenTelemetry::Trace.current_span(parent_context)
|
32
|
+
return if parent_span && parent_span.context != ::OpenTelemetry::Trace::SpanContext::INVALID && parent_span.context.remote? == false
|
33
|
+
|
34
|
+
trace_flags = span.context.trace_flags.sampled? ? '01' : '00'
|
35
|
+
::OpenTelemetry::Context.attach(::OpenTelemetry::Baggage.set_value(::SolarWindsAPM::Constants::INTL_SWO_CURRENT_TRACE_ID, span.context.hex_trace_id))
|
36
|
+
::OpenTelemetry::Context.attach(::OpenTelemetry::Baggage.set_value(::SolarWindsAPM::Constants::INTL_SWO_CURRENT_SPAN_ID, span.context.hex_span_id))
|
37
|
+
::OpenTelemetry::Context.attach(::OpenTelemetry::Baggage.set_value(::SolarWindsAPM::Constants::INTL_SWO_CURRENT_TRACE_FLAG, trace_flags))
|
38
|
+
|
39
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] current baggage values: #{::OpenTelemetry::Baggage.values}"}
|
40
|
+
end
|
41
|
+
|
42
|
+
# Called when a {Span} is ended, if the {Span#recording?}
|
43
|
+
# returns true.
|
44
|
+
#
|
45
|
+
# This method is called synchronously on the execution thread, should
|
46
|
+
# not throw or block the execution thread.
|
47
|
+
# Only calculate inbound metrics for service root spans
|
48
|
+
#
|
49
|
+
# @param [Span] span the {Span} that just ended.
|
50
|
+
def on_finish(span)
|
51
|
+
if span.parent_span_id != ::OpenTelemetry::Trace::INVALID_SPAN_ID
|
52
|
+
@exporter&.export([span.to_span_data]) if span.context.trace_flags.sampled?
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
span_time = calculate_span_time(start_time: span.start_timestamp, end_time: span.end_timestamp)
|
57
|
+
domain = nil
|
58
|
+
has_error = error?(span)
|
59
|
+
trans_name = calculate_transaction_names(span)
|
60
|
+
url_tran = span.attributes[HTTP_URL]
|
61
|
+
|
62
|
+
liboboe_txn_name = nil
|
63
|
+
if span_http?(span)
|
64
|
+
status_code = get_http_status_code(span)
|
65
|
+
request_method = span.attributes[HTTP_METHOD]
|
66
|
+
|
67
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] createHttpSpan with\n
|
68
|
+
trans_name: #{trans_name}\n
|
69
|
+
url_tran: #{url_tran}\n
|
70
|
+
domain: #{domain}\n
|
71
|
+
span_time: #{span_time}\n
|
72
|
+
status_code: #{status_code}\n
|
73
|
+
request_method: #{request_method}\n
|
74
|
+
has_error: #{has_error}"}
|
75
|
+
|
76
|
+
liboboe_txn_name = SolarWindsAPM::Span.createHttpSpan(trans_name,url_tran,domain,span_time,status_code,
|
77
|
+
request_method,has_error)
|
78
|
+
|
79
|
+
else
|
80
|
+
|
81
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] createSpan with \n
|
82
|
+
trans_name: #{trans_name}\n
|
83
|
+
domain: #{domain}\n
|
84
|
+
span_time: #{span_time}\n
|
85
|
+
has_error: #{has_error}"}
|
86
|
+
|
87
|
+
liboboe_txn_name = SolarWindsAPM::Span.createSpan(trans_name, domain, span_time, has_error)
|
88
|
+
end
|
89
|
+
|
90
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] liboboe_txn_name: #{liboboe_txn_name}"}
|
91
|
+
@txn_manager["#{span.context.hex_trace_id}-#{span.context.hex_span_id}"] = liboboe_txn_name if span.context.trace_flags.sampled?
|
92
|
+
|
93
|
+
@exporter&.export([span.to_span_data]) if span.context.trace_flags.sampled?
|
94
|
+
end
|
95
|
+
|
96
|
+
# Export all ended spans to the configured `Exporter` that have not yet
|
97
|
+
# been exported.
|
98
|
+
#
|
99
|
+
# This method should only be called in cases where it is absolutely
|
100
|
+
# necessary, such as when using some FaaS providers that may suspend
|
101
|
+
# the process after an invocation, but before the `Processor` exports
|
102
|
+
# the completed spans.
|
103
|
+
#
|
104
|
+
# @param [optional Numeric] timeout An optional timeout in seconds.
|
105
|
+
# @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
|
106
|
+
# a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
|
107
|
+
def force_flush(timeout: nil)
|
108
|
+
@exporter&.force_flush(timeout: timeout) || ::OpenTelemetry::SDK::Metrics::Export::SUCCESS
|
109
|
+
end
|
110
|
+
|
111
|
+
# Called when {TracerProvider#shutdown} is called.
|
112
|
+
#
|
113
|
+
# @param [optional Numeric] timeout An optional timeout in seconds.
|
114
|
+
# @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
|
115
|
+
# a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
|
116
|
+
def shutdown(timeout: nil)
|
117
|
+
@exporter&.shutdown(timeout: timeout) || ::OpenTelemetry::SDK::Metrics::Export::SUCCESS
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
# This span from inbound HTTP request if from a SERVER by some http.method
|
123
|
+
def span_http?(span)
|
124
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] span.kind #{span.kind} span.attributes: #{span.attributes[HTTP_METHOD]}"}
|
125
|
+
(span.kind == ::OpenTelemetry::Trace::SpanKind::SERVER && !span.attributes[HTTP_METHOD].nil?)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Calculate if this span instance has_error
|
129
|
+
# return [Integer]
|
130
|
+
def error?(span)
|
131
|
+
span.status.code == ::OpenTelemetry::Trace::Status::ERROR ? 1 : 0
|
132
|
+
end
|
133
|
+
|
134
|
+
# Calculate HTTP status_code from span or default to UNAVAILABLE
|
135
|
+
# Something went wrong in OTel or instrumented service crashed early
|
136
|
+
# if no status_code in attributes of HTTP span
|
137
|
+
def get_http_status_code(span)
|
138
|
+
span.attributes[HTTP_STATUS_CODE] || LIBOBOE_HTTP_SPAN_STATUS_UNAVAILABLE
|
139
|
+
end
|
140
|
+
|
141
|
+
# Get trans_name and url_tran of this span instance.
|
142
|
+
def calculate_transaction_names(span)
|
143
|
+
|
144
|
+
trace_span_id = "#{span.context.hex_trace_id}-#{span.context.hex_span_id}"
|
145
|
+
if @txn_manager.get(trace_span_id)
|
146
|
+
trans_name = @txn_manager.get(trace_span_id)
|
147
|
+
else
|
148
|
+
trans_name = span.attributes[HTTP_ROUTE] || nil
|
149
|
+
trans_name = span.name if span.name && (trans_name.nil? || trans_name.empty?)
|
150
|
+
end
|
151
|
+
trans_name
|
152
|
+
end
|
153
|
+
|
154
|
+
# Calculate span time in microseconds (us) using start and end time
|
155
|
+
# in nanoseconds (ns). OTel span start/end_time are optional.
|
156
|
+
def calculate_span_time(start_time: nil, end_time: nil)
|
157
|
+
return 0 if start_time.nil? || end_time.nil?
|
158
|
+
|
159
|
+
((end_time.to_i - start_time.to_i) / 1e3).round
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module SolarWindsAPM
|
2
|
+
module OpenTelemetry
|
3
|
+
module SolarWindsPropagator
|
4
|
+
# TextMapPropagator
|
5
|
+
class TextMapPropagator
|
6
|
+
TRACESTATE_HEADER_NAME = "tracestate".freeze
|
7
|
+
XTRACEOPTIONS_HEADER_NAME = "x-trace-options".freeze
|
8
|
+
XTRACEOPTIONS_SIGNATURE_HEADER_NAME = "x-trace-options-signature".freeze
|
9
|
+
INTL_SWO_X_OPTIONS_KEY = "sw_xtraceoptions".freeze
|
10
|
+
INTL_SWO_SIGNATURE_KEY = "sw_signature".freeze
|
11
|
+
|
12
|
+
private_constant \
|
13
|
+
:TRACESTATE_HEADER_NAME, :XTRACEOPTIONS_HEADER_NAME,
|
14
|
+
:XTRACEOPTIONS_SIGNATURE_HEADER_NAME, :INTL_SWO_X_OPTIONS_KEY, :INTL_SWO_SIGNATURE_KEY
|
15
|
+
|
16
|
+
# Extract trace context from the supplied carrier.
|
17
|
+
#
|
18
|
+
# @param [Carrier] carrier The carrier to get the header from
|
19
|
+
# @param [optional Context] context Context to be updated with the trace context
|
20
|
+
# extracted from the carrier. Defaults to +Context.current+.
|
21
|
+
# @param [optional Getter] getter If the optional getter is provided, it
|
22
|
+
# will be used to read the header from the carrier, otherwise the default
|
23
|
+
# text map getter will be used.
|
24
|
+
#
|
25
|
+
# @return [Context] context updated with extracted baggage, or the original context
|
26
|
+
# if extraction fails
|
27
|
+
def extract(carrier, context: ::OpenTelemetry::Context.current, getter: ::OpenTelemetry::Context::Propagation.text_map_getter)
|
28
|
+
|
29
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] context(before): #{context.inspect} #{context.nil?}"}
|
30
|
+
|
31
|
+
context = ::OpenTelemetry::Context.new({}) if context.nil?
|
32
|
+
|
33
|
+
xtraceoptions_header = getter.get(carrier, XTRACEOPTIONS_HEADER_NAME)
|
34
|
+
context = context.set_value(INTL_SWO_X_OPTIONS_KEY, xtraceoptions_header) if xtraceoptions_header
|
35
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] xtraceoptions_header: #{xtraceoptions_header}"}
|
36
|
+
|
37
|
+
signature_header = getter.get(carrier, XTRACEOPTIONS_SIGNATURE_HEADER_NAME)
|
38
|
+
context = context.set_value(INTL_SWO_SIGNATURE_KEY, signature_header) if signature_header
|
39
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] signature_header: #{signature_header}; propagator extract context: #{context.inspect}"}
|
40
|
+
|
41
|
+
context
|
42
|
+
end
|
43
|
+
|
44
|
+
# Inject trace context into the supplied carrier.
|
45
|
+
#
|
46
|
+
# @param [Carrier] carrier The mutable carrier to inject trace context into
|
47
|
+
# @param [Context] context The context to read trace context from
|
48
|
+
# @param [optional Setter] setter If the optional setter is provided, it
|
49
|
+
# will be used to write context into the carrier, otherwise the default
|
50
|
+
# text map setter will be used.
|
51
|
+
def inject(carrier, context: ::OpenTelemetry::Context.current, setter: ::OpenTelemetry::Context::Propagation.text_map_setter)
|
52
|
+
|
53
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] inject context: #{context.inspect}"}
|
54
|
+
|
55
|
+
cspan = ::OpenTelemetry::Trace.current_span(context)
|
56
|
+
span_context = cspan&.context
|
57
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] cspan #{cspan.inspect}; span_context #{span_context.inspect}"}
|
58
|
+
return unless span_context&.valid?
|
59
|
+
|
60
|
+
sw_value = Transformer.sw_from_context(span_context) # sw_value is a string
|
61
|
+
trace_state_header = carrier[TRACESTATE_HEADER_NAME].nil?? nil : carrier[TRACESTATE_HEADER_NAME]
|
62
|
+
|
63
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] sw_value: #{sw_value}; trace_state_header: #{trace_state_header}"}
|
64
|
+
|
65
|
+
# Prepare carrier with carrier's or new tracestate
|
66
|
+
trace_state = nil
|
67
|
+
if trace_state_header.nil?
|
68
|
+
# Only create new trace state if valid span_id
|
69
|
+
return if span_context.span_id == ::OpenTelemetry::Trace::INVALID_SPAN_ID
|
70
|
+
|
71
|
+
trace_state = ::OpenTelemetry::Trace::Tracestate.create({SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY => sw_value})
|
72
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] creating new trace state: #{trace_state.inspect}"}
|
73
|
+
else
|
74
|
+
trace_state_from_string = ::OpenTelemetry::Trace::Tracestate.from_string(trace_state_header)
|
75
|
+
trace_state = trace_state_from_string.set_value(SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY, sw_value)
|
76
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Updating/Adding trace state for injection #{trace_state.inspect}"}
|
77
|
+
end
|
78
|
+
|
79
|
+
setter.set(carrier, TRACESTATE_HEADER_NAME, Transformer.trace_state_header(trace_state))
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns the predefined propagation fields. If your carrier is reused, you
|
83
|
+
# should delete the fields returned by this method before calling +inject+.
|
84
|
+
#
|
85
|
+
# @return [Array<String>] a list of fields that will be used by this propagator.
|
86
|
+
def fields
|
87
|
+
TRACESTATE_HEADER_NAME
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|