solarwinds_apm 6.0.0.preV1 → 6.0.0.preV3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +28 -54
- data/ext/oboe_metal/extconf.rb +23 -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 -2
- data/ext/oboe_metal/src/init_solarwinds_apm.cc +0 -6
- data/ext/oboe_metal/src/oboe.h +0 -12
- data/ext/oboe_metal/src/oboe_swig_wrap.cc +5 -5
- data/lib/oboe_metal.rb +3 -3
- data/lib/rails/generators/solarwinds_apm/install_generator.rb +0 -3
- data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +8 -25
- data/lib/solarwinds_apm/api/current_trace_info.rb +1 -2
- data/lib/solarwinds_apm/api/opentelemetry.rb +39 -0
- data/lib/solarwinds_apm/api/transaction_name.rb +18 -17
- data/lib/solarwinds_apm/api.rb +2 -0
- data/lib/solarwinds_apm/config.rb +21 -63
- data/lib/solarwinds_apm/constants.rb +2 -4
- data/lib/solarwinds_apm/noop/context.rb +1 -1
- data/lib/solarwinds_apm/oboe_init_options.rb +11 -16
- data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +92 -87
- data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +27 -23
- data/lib/solarwinds_apm/opentelemetry/solarwinds_propagator.rb +28 -28
- data/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +9 -14
- data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +132 -175
- data/lib/solarwinds_apm/otel_config.rb +55 -36
- data/lib/solarwinds_apm/support/lumberjack_formatter.rb +17 -2
- data/lib/solarwinds_apm/support/swomarginalia/comment.rb +2 -2
- data/lib/solarwinds_apm/support/swomarginalia/swomarginalia.rb +6 -5
- data/lib/solarwinds_apm/support/transaction_cache.rb +27 -2
- data/lib/solarwinds_apm/support/transaction_settings.rb +10 -10
- data/lib/solarwinds_apm/support/txn_name_manager.rb +34 -17
- data/lib/solarwinds_apm/support/utils.rb +24 -0
- data/lib/solarwinds_apm/support.rb +4 -2
- data/lib/solarwinds_apm/version.rb +1 -1
- data/lib/solarwinds_apm.rb +3 -4
- metadata +18 -33
- data/lib/oboe.rb +0 -7
- data/lib/solarwinds_apm/noop/profiling.rb +0 -17
- data/lib/solarwinds_apm/support/transformer.rb +0 -56
@@ -11,13 +11,13 @@ module SolarWindsAPM
|
|
11
11
|
module Config
|
12
12
|
@@config = {}
|
13
13
|
@@instrumentation = [:action_controller, :action_controller_api, :action_view,
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
:active_record, :bunnyclient, :bunnyconsumer, :curb,
|
15
|
+
:dalli, :delayed_jobclient, :delayed_jobworker,
|
16
|
+
:excon, :faraday, :graphql, :grpc_client, :grpc_server, :grape,
|
17
|
+
:httpclient, :nethttp, :memcached, :mongo, :moped, :padrino, :rack, :redis,
|
18
|
+
:resqueclient, :resqueworker, :rest_client,
|
19
|
+
:sequel, :sidekiqclient, :sidekiqworker, :sinatra, :typhoeus,
|
20
|
+
:curb, :excon, :faraday, :httpclient, :nethttp, :rest_client, :typhoeus]
|
21
21
|
|
22
22
|
##
|
23
23
|
# load_config_file
|
@@ -47,28 +47,21 @@ module SolarWindsAPM
|
|
47
47
|
config_file = File.join(Dir.pwd, 'solarwinds_apm_config.rb')
|
48
48
|
config_files << config_file if File.exist?(config_file)
|
49
49
|
|
50
|
-
SolarWindsAPM.logger.warn {"[#{
|
50
|
+
SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] Multiple configuration files configured, using the first one listed: #{config_files.join(', ')}"} if config_files.size > 1
|
51
51
|
load(config_files[0]) if config_files.size > 0
|
52
52
|
|
53
53
|
set_log_level # sets SolarWindsAPM::Config[:debug_level], SolarWindsAPM.logger.level
|
54
|
-
set_verbose_level # the verbose setting is only relevant for ruby, ENV['SW_APM_GEM_VERBOSE'] overrides
|
55
54
|
end
|
56
55
|
|
57
56
|
def self.config_from_env
|
58
|
-
config_files = []
|
59
57
|
if File.exist?(ENV['SW_APM_CONFIG_RUBY']) && !File.directory?(ENV['SW_APM_CONFIG_RUBY'])
|
60
|
-
|
58
|
+
config_file = ENV['SW_APM_CONFIG_RUBY']
|
61
59
|
elsif File.exist?(File.join(ENV['SW_APM_CONFIG_RUBY'], 'solarwinds_apm_config.rb'))
|
62
|
-
|
60
|
+
config_file = File.join(ENV['SW_APM_CONFIG_RUBY'], 'solarwinds_apm_config.rb')
|
63
61
|
else
|
64
|
-
SolarWindsAPM.logger.warn {"[#{
|
62
|
+
SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] Could not find the configuration file set by the SW_APM_CONFIG_RUBY environment variable: #{ENV['SW_APM_CONFIG_RUBY']}"}
|
65
63
|
end
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.set_verbose_level
|
70
|
-
verbose = ENV.has_key?('SW_APM_GEM_VERBOSE')? ENV['SW_APM_GEM_VERBOSE'].downcase == 'true' : nil
|
71
|
-
SolarWindsAPM::Config[:verbose] = verbose
|
64
|
+
config_file
|
72
65
|
end
|
73
66
|
|
74
67
|
def self.set_log_level
|
@@ -86,9 +79,9 @@ module SolarWindsAPM
|
|
86
79
|
# to create an output similar to the content of the config file
|
87
80
|
#
|
88
81
|
def self.print_config
|
89
|
-
SolarWindsAPM.logger.warn {"[#{
|
82
|
+
SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] General configurations list blow:"}
|
90
83
|
@@config.each do |k,v|
|
91
|
-
SolarWindsAPM.logger.warn {"[#{
|
84
|
+
SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] Config Key/Value: #{k}, #{v.inspect}"}
|
92
85
|
end
|
93
86
|
end
|
94
87
|
|
@@ -99,9 +92,6 @@ module SolarWindsAPM
|
|
99
92
|
# The defaults are read from the template configuration file.
|
100
93
|
#
|
101
94
|
def self.initialize(_data={})
|
102
|
-
@@config[:profiling] = :disabled
|
103
|
-
@@config[:profiling_interval] = 5
|
104
|
-
|
105
95
|
# for config file backward compatibility
|
106
96
|
@@instrumentation.each {|inst| @@config[inst] = {}}
|
107
97
|
@@config[:transaction_name] = {}
|
@@ -137,40 +127,24 @@ module SolarWindsAPM
|
|
137
127
|
|
138
128
|
case key
|
139
129
|
when :sampling_rate
|
140
|
-
SolarWindsAPM.logger.warn {"[#{
|
130
|
+
SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] sampling_rate is not a supported setting for SolarWindsAPM::Config. Please use :sample_rate."}
|
141
131
|
|
142
132
|
when :sample_rate
|
143
133
|
unless value.is_a?(Integer) || value.is_a?(Float)
|
144
|
-
SolarWindsAPM.logger.warn {"[#{
|
134
|
+
SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] :sample_rate must be a number between 0 and 1000000 (1m) (provided: #{value}), corrected to 0"}
|
145
135
|
value = 0
|
146
136
|
end
|
147
137
|
|
148
138
|
# Validate :sample_rate value
|
149
139
|
unless value.between?(0, 1e6)
|
150
140
|
new_value = value < 0 ? 0 : 1_000_000
|
151
|
-
SolarWindsAPM.logger.warn {"[#{
|
141
|
+
SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] :sample_rate must be between 0 and 1000000 (1m) (provided: #{value}), corrected to #{new_value}"}
|
152
142
|
end
|
153
143
|
|
154
144
|
# Assure value is an integer
|
155
145
|
@@config[key.to_sym] = new_value.to_i
|
156
146
|
SolarWindsAPM.sample_rate(new_value) if SolarWindsAPM.loaded
|
157
147
|
|
158
|
-
when :profiling
|
159
|
-
SolarWindsAPM.logger.warn {"[#{self.name}/#{__method__}] Profiling feature is currently not available." }
|
160
|
-
@@config[:profiling] = :disabled
|
161
|
-
|
162
|
-
when :profiling_interval
|
163
|
-
SolarWindsAPM.logger.warn {"[#{self.name}/#{__method__}] Profiling feature is currently not available. :profiling_interval setting is not configured."}
|
164
|
-
value = if value.is_a?(Integer) && value > 0
|
165
|
-
[100, value].min
|
166
|
-
else
|
167
|
-
10
|
168
|
-
end
|
169
|
-
@@config[:profiling_interval] = value
|
170
|
-
# CProfiler may not be loaded yet, the profiler will send the value
|
171
|
-
# after it is loaded
|
172
|
-
SolarWindsAPM::CProfiler.interval_setup(value) if defined? SolarWindsAPM::CProfiler
|
173
|
-
|
174
148
|
when :transaction_settings
|
175
149
|
compile_settings(value)
|
176
150
|
|
@@ -202,7 +176,7 @@ module SolarWindsAPM
|
|
202
176
|
|
203
177
|
# `tracing: disabled` is the default
|
204
178
|
disabled = settings.select { |v| !v.has_key?(:tracing) || v[:tracing] == :disabled }
|
205
|
-
enabled
|
179
|
+
enabled = settings.select { |v| v[:tracing] == :enabled }
|
206
180
|
|
207
181
|
SolarWindsAPM::Config[:enabled_regexps] = compile_regexp(enabled)
|
208
182
|
SolarWindsAPM::Config[:disabled_regexps] = compile_regexp(disabled)
|
@@ -210,11 +184,8 @@ module SolarWindsAPM
|
|
210
184
|
private_class_method :compile_settings
|
211
185
|
|
212
186
|
def self.compile_regexp(settings)
|
213
|
-
regexp_regexp
|
214
|
-
|
215
|
-
|
216
|
-
regexps = [regexp_regexp, extensions_regexp].flatten.compact
|
217
|
-
|
187
|
+
regexp_regexp = compile_settings_regexp(settings)
|
188
|
+
regexps = [regexp_regexp].flatten.compact
|
218
189
|
regexps.empty? ? nil : regexps
|
219
190
|
end
|
220
191
|
private_class_method :compile_regexp
|
@@ -230,7 +201,7 @@ module SolarWindsAPM
|
|
230
201
|
begin
|
231
202
|
v[:regexp].is_a?(String) ? Regexp.new(v[:regexp], v[:opts]) : Regexp.new(v[:regexp])
|
232
203
|
rescue StandardError => e
|
233
|
-
SolarWindsAPM.logger.warn {"[#{
|
204
|
+
SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] Problem compiling transaction_settings item #{v}, will ignore. Error: #{e.message}"}
|
234
205
|
nil
|
235
206
|
end
|
236
207
|
end
|
@@ -239,19 +210,6 @@ module SolarWindsAPM
|
|
239
210
|
end
|
240
211
|
private_class_method :compile_settings_regexp
|
241
212
|
|
242
|
-
def self.compile_settings_extensions(value)
|
243
|
-
extensions = value.select do |v|
|
244
|
-
v.has_key?(:extensions) &&
|
245
|
-
v[:extensions].is_a?(Array) &&
|
246
|
-
!v[:extensions].empty?
|
247
|
-
end
|
248
|
-
extensions = extensions.map { |v| v[:extensions] }.flatten
|
249
|
-
extensions.keep_if { |v| v.is_a?(String) }
|
250
|
-
|
251
|
-
extensions.empty? ? nil : Regexp.new("(#{Regexp.union(extensions).source})(\\?.+){0,1}$")
|
252
|
-
end
|
253
|
-
private_class_method :compile_settings_extensions
|
254
|
-
|
255
213
|
def self.reset_regexps
|
256
214
|
SolarWindsAPM::Config[:enabled_regexps] = nil
|
257
215
|
SolarWindsAPM::Config[:disabled_regexps] = nil
|
@@ -20,12 +20,10 @@ module SolarWindsAPM
|
|
20
20
|
INTL_SWO_PROPAGATOR = "solarwinds_propagator".freeze
|
21
21
|
INTL_SWO_DEFAULT_PROPAGATORS = [INTL_SWO_TRACECONTEXT_PROPAGATOR, "baggage",INTL_SWO_PROPAGATOR].freeze
|
22
22
|
INTL_SWO_SUPPORT_EMAIL = "SWO-support@solarwinds.com".freeze
|
23
|
-
INTL_SWO_CURRENT_SPAN_ID = "sw-current-entry-span-id".freeze
|
24
|
-
INTL_SWO_CURRENT_TRACE_ID = "sw-current-trace-id".freeze
|
25
|
-
INTL_SWO_CURRENT_TRACE_FLAG = "sw-current-trace-flag".freeze
|
26
|
-
|
27
23
|
INTL_SWO_OTEL_SCOPE_NAME = "otel.scope.name".freeze
|
28
24
|
INTL_SWO_OTEL_SCOPE_VERSION = "otel.scope.version".freeze
|
25
|
+
INTL_SWO_OTEL_STATUS = "otel.status".freeze
|
26
|
+
INTL_SWO_OTEL_STATUS_DESCRIPTION = "otel.status_description".freeze
|
29
27
|
|
30
28
|
INTERNAL_TRIGGERED_TRACE = "TriggeredTrace".freeze
|
31
29
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# Copyright (c) 2019 SolarWinds, LLC.
|
2
2
|
# All rights reserved.
|
3
3
|
require 'singleton'
|
4
|
+
require 'uri'
|
4
5
|
module SolarWindsAPM
|
5
6
|
# OboeInitOptions
|
6
7
|
class OboeInitOptions
|
@@ -96,9 +97,6 @@ module SolarWindsAPM
|
|
96
97
|
def reporter_and_host
|
97
98
|
|
98
99
|
reporter = ENV['SW_APM_REPORTER'] || 'ssl'
|
99
|
-
# override with 'file', e.g. when running tests
|
100
|
-
# changed my mind => set the right reporter in the env when running tests !!!
|
101
|
-
# reporter = 'file' if ENV.key?('SW_APM_GEM_TEST')
|
102
100
|
|
103
101
|
host = ''
|
104
102
|
case reporter
|
@@ -123,7 +121,7 @@ module SolarWindsAPM
|
|
123
121
|
return '' unless @reporter == 'ssl'
|
124
122
|
|
125
123
|
service_key = ENV['SW_APM_SERVICE_KEY'] || SolarWindsAPM::Config[:service_key]
|
126
|
-
|
124
|
+
if service_key.nil? || service_key == ''
|
127
125
|
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY not configured."}
|
128
126
|
return ''
|
129
127
|
end
|
@@ -133,7 +131,7 @@ module SolarWindsAPM
|
|
133
131
|
service_name = match[3]
|
134
132
|
|
135
133
|
return '' unless validate_token(token) # return if token is not even valid
|
136
|
-
|
134
|
+
|
137
135
|
if service_name.empty?
|
138
136
|
ENV.delete('OTEL_SERVICE_NAME')
|
139
137
|
SolarWindsAPM.logger.warn {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY format problem. Service Name is missing."}
|
@@ -197,7 +195,7 @@ module SolarWindsAPM
|
|
197
195
|
def read_and_validate_ec2_md_timeout
|
198
196
|
timeout = ENV['SW_APM_EC2_METADATA_TIMEOUT'] || SolarWindsAPM::Config[:ec2_metadata_timeout]
|
199
197
|
return 1000 unless timeout.is_a?(Integer) || timeout =~ /^\d+$/
|
200
|
-
|
198
|
+
|
201
199
|
timeout = timeout.to_i
|
202
200
|
timeout.between?(0, 3000) ? timeout : 1000
|
203
201
|
end
|
@@ -215,19 +213,16 @@ module SolarWindsAPM
|
|
215
213
|
end
|
216
214
|
|
217
215
|
def read_certificates
|
218
|
-
file =
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
return file if file.empty?
|
223
|
-
|
216
|
+
file = appoptics_collector?? "#{__dir__}/cert/star.appoptics.com.issuer.crt" : ENV['SW_APM_TRUSTEDPATH']
|
217
|
+
return String.new if file.nil? || file&.empty?
|
218
|
+
|
224
219
|
begin
|
225
220
|
certificate = File.open(file,"r").read
|
226
221
|
rescue StandardError => e
|
227
222
|
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] certificates: #{file} doesn't exist or caused by #{e.message}."}
|
228
223
|
certificate = String.new
|
229
224
|
end
|
230
|
-
|
225
|
+
|
231
226
|
certificate
|
232
227
|
end
|
233
228
|
|
@@ -236,7 +231,7 @@ module SolarWindsAPM
|
|
236
231
|
end
|
237
232
|
|
238
233
|
def appoptics_collector?
|
239
|
-
allowed_uri = ['collector.appoptics.com', 'collector-stg.appoptics.com',
|
234
|
+
allowed_uri = ['collector.appoptics.com', 'collector-stg.appoptics.com',
|
240
235
|
'collector.appoptics.com:443', 'collector-stg.appoptics.com:443']
|
241
236
|
|
242
237
|
(allowed_uri.include? ENV["SW_APM_COLLECTOR"])? true : false
|
@@ -246,12 +241,12 @@ module SolarWindsAPM
|
|
246
241
|
return uri if uri.nil? || uri.empty?
|
247
242
|
|
248
243
|
begin
|
249
|
-
sanitized_uri = URI("http://#{uri}").host
|
244
|
+
sanitized_uri = ::URI.parse("http://#{uri}").host
|
250
245
|
return sanitized_uri unless sanitized_uri.nil?
|
251
246
|
rescue StandardError => e
|
252
247
|
SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] uri for collector #{uri} is malformat. Error: #{e.message}"}
|
253
248
|
end
|
254
|
-
""
|
249
|
+
""
|
255
250
|
end
|
256
251
|
end
|
257
252
|
end
|
@@ -19,12 +19,13 @@ module SolarWindsAPM
|
|
19
19
|
|
20
20
|
def export(span_data, _timeout: nil)
|
21
21
|
return FAILURE if @shutdown
|
22
|
-
|
23
|
-
|
22
|
+
|
23
|
+
status = SUCCESS
|
24
24
|
span_data.each do |data|
|
25
|
-
log_span_data(data)
|
25
|
+
status = log_span_data(data)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
|
+
status
|
28
29
|
end
|
29
30
|
|
30
31
|
def force_flush(timeout: nil) # rubocop:disable Lint/UnusedMethodArgument
|
@@ -39,64 +40,63 @@ module SolarWindsAPM
|
|
39
40
|
private
|
40
41
|
|
41
42
|
def log_span_data(span_data)
|
43
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] span_data: #{span_data.inspect}\n"}
|
44
|
+
|
45
|
+
md = build_meta_data(span_data)
|
46
|
+
event = nil
|
47
|
+
if span_data.parent_span_id != ::OpenTelemetry::Trace::INVALID_SPAN_ID
|
48
|
+
parent_md = build_meta_data(span_data, parent: true)
|
49
|
+
event = @context.createEntry(md, (span_data.start_timestamp.to_i / 1000).to_i, parent_md)
|
50
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Continue trace from parent metadata: #{parent_md.toString}."}
|
51
|
+
else
|
52
|
+
event = @context.createEntry(md, (span_data.start_timestamp.to_i / 1000).to_i)
|
53
|
+
add_info_transaction_name(span_data, event)
|
54
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Start a new trace."}
|
55
|
+
end
|
56
|
+
|
57
|
+
layer_name = "#{span_data.kind}:#{span_data.name}"
|
58
|
+
event.addInfo('Layer', layer_name)
|
59
|
+
event.addInfo('sw.span_kind', span_data.kind.to_s)
|
60
|
+
event.addInfo('Language', 'Ruby')
|
61
|
+
|
62
|
+
add_instrumentation_scope(event, span_data)
|
63
|
+
add_instrumented_framework(event, span_data)
|
64
|
+
add_span_data_attributes(event, span_data.attributes) if span_data.attributes
|
42
65
|
|
43
|
-
|
44
|
-
|
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)
|
66
|
+
event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_STATUS, span_data.status.ok?? 'OK' : 'ERROR')
|
67
|
+
event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_STATUS_DESCRIPTION, span_data.status.description) unless span_data.status.description.empty?
|
82
68
|
|
83
|
-
|
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
|
69
|
+
@reporter.send_report(event, with_system_timestamp: false)
|
87
70
|
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
71
|
+
# info / exception event
|
72
|
+
span_data.events&.each do |span_data_event|
|
73
|
+
span_data_event.name == 'exception' ? report_exception_event(span_data_event) : report_info_event(span_data_event)
|
95
74
|
end
|
96
75
|
|
76
|
+
event = @context.createExit((span_data.end_timestamp.to_i / 1000).to_i)
|
77
|
+
event.addInfo('Layer', layer_name)
|
78
|
+
@reporter.send_report(event, with_system_timestamp: false)
|
79
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Exit a trace: #{event.metadataString}"}
|
80
|
+
SUCCESS
|
81
|
+
rescue StandardError => e
|
82
|
+
SolarWindsAPM.logger.info {"[#{self.class}/#{__method__}] exporter error: \n #{e.message} #{e.backtrace}\n"}
|
83
|
+
FAILURE
|
97
84
|
end
|
98
85
|
|
99
|
-
|
86
|
+
##
|
87
|
+
# extract the span_data.attributes (OpenTelemetry::SDK::Trace::SpanData.attributes)
|
88
|
+
def add_span_data_attributes(event, span_attributes)
|
89
|
+
target = 'http.target'
|
90
|
+
attributes = span_attributes.dup
|
91
|
+
attributes[target] = attributes[target].split('?').first if attributes[target] && SolarWindsAPM::Config[:log_args] == false # remove url parameters
|
92
|
+
attributes.each { |k, v| event.addInfo(k, v) }
|
93
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] span_data attributes added: #{attributes.inspect}"}
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# get instrumentation scope data: scope name and version.
|
98
|
+
# the version if the opentelemetry-instrumentation-* gem version
|
99
|
+
def add_instrumentation_scope(event, span_data)
|
100
100
|
scope_name = ""
|
101
101
|
scope_version = ""
|
102
102
|
if span_data.instrumentation_scope
|
@@ -104,14 +104,13 @@ module SolarWindsAPM
|
|
104
104
|
scope_version = span_data.instrumentation_scope.version if span_data.instrumentation_scope.version
|
105
105
|
end
|
106
106
|
event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_SCOPE_NAME, scope_name)
|
107
|
-
event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_SCOPE_VERSION, scope_version)
|
107
|
+
event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_SCOPE_VERSION, scope_version)
|
108
108
|
end
|
109
109
|
|
110
|
-
|
111
|
-
#
|
112
|
-
#
|
113
|
-
def
|
114
|
-
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] add_info_instrumented_framework: #{span_data.instrumentation_scope.name}"}
|
110
|
+
##
|
111
|
+
# add the gem library version to event
|
112
|
+
# p.s. gem library version is not same as the opentelemetry-instrumentation-* gem version
|
113
|
+
def add_instrumented_framework(event, span_data)
|
115
114
|
scope_name = span_data.instrumentation_scope.name
|
116
115
|
scope_name = scope_name.downcase if scope_name
|
117
116
|
return unless scope_name&.include? "opentelemetry::instrumentation"
|
@@ -121,9 +120,12 @@ module SolarWindsAPM
|
|
121
120
|
|
122
121
|
framework = normalize_framework_name(framework)
|
123
122
|
framework_version = check_framework_version(framework)
|
123
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] #{span_data.instrumentation_scope.name} with #{framework} and version #{framework_version}"}
|
124
124
|
event.addInfo("Ruby.#{framework}.Version",framework_version) unless framework_version.nil?
|
125
125
|
end
|
126
126
|
|
127
|
+
##
|
128
|
+
# helper function that extract gem library version for func add_instrumented_framework
|
127
129
|
def check_framework_version(framework)
|
128
130
|
framework_version = nil
|
129
131
|
if @version_cache.keys.include? framework
|
@@ -142,10 +144,12 @@ module SolarWindsAPM
|
|
142
144
|
@version_cache[framework] = framework_version
|
143
145
|
end
|
144
146
|
end
|
145
|
-
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}]
|
147
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] current framework version cached: #{@version_cache.inspect}"}
|
146
148
|
framework_version
|
147
149
|
end
|
148
150
|
|
151
|
+
##
|
152
|
+
# helper function that convert opentelemetry instrumentation name to gem library understandable
|
149
153
|
def normalize_framework_name(framework)
|
150
154
|
case framework
|
151
155
|
when "net::http"
|
@@ -156,47 +160,48 @@ module SolarWindsAPM
|
|
156
160
|
normalized
|
157
161
|
end
|
158
162
|
|
163
|
+
##
|
159
164
|
# Add transaction name from cache to root span then removes from cache
|
160
|
-
def add_info_transaction_name(span_data,
|
165
|
+
def add_info_transaction_name(span_data, event)
|
166
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] transaction manager: #{@txn_manager.inspect}."}
|
161
167
|
trace_span_id = "#{span_data.hex_trace_id}-#{span_data.hex_span_id}"
|
162
|
-
|
163
|
-
|
164
|
-
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] txname: #{txname}"}
|
165
|
-
evt.addInfo("TransactionName", txname)
|
168
|
+
txname = @txn_manager.get(trace_span_id) || ''
|
169
|
+
event.addInfo("TransactionName", txname)
|
166
170
|
@txn_manager.del(trace_span_id)
|
167
171
|
end
|
168
172
|
|
173
|
+
##
|
174
|
+
# report exception event
|
169
175
|
def report_exception_event(span_event)
|
170
|
-
|
171
|
-
|
172
|
-
|
176
|
+
event = @context.createEvent((span_event.timestamp.to_i / 1000).to_i)
|
177
|
+
event.addInfo('Label', 'error')
|
178
|
+
event.addInfo('Spec', 'error')
|
173
179
|
|
174
180
|
unless span_event.attributes.nil?
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
end
|
181
|
+
attributes = span_event.attributes.dup
|
182
|
+
attributes.delete('exception.type') if event.addInfo('ErrorClass', attributes['exception.type'])
|
183
|
+
attributes.delete('exception.message') if event.addInfo('ErrorMsg', attributes['exception.message'])
|
184
|
+
attributes.delete('exception.stacktrace') if event.addInfo('Backtrace', attributes['exception.stacktrace'])
|
185
|
+
attributes.each { |key, value| event.addInfo(key, value) }
|
181
186
|
end
|
182
|
-
|
183
|
-
|
187
|
+
|
188
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] exception event #{event.metadataString}"}
|
189
|
+
@reporter.send_report(event, with_system_timestamp: false)
|
184
190
|
end
|
185
191
|
|
192
|
+
##
|
193
|
+
# report non-exception/info event
|
186
194
|
def report_info_event(span_event)
|
187
|
-
|
188
|
-
|
189
|
-
span_event.attributes&.each
|
190
|
-
|
191
|
-
|
192
|
-
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] info event #{evt.metadataString}"}
|
193
|
-
@reporter.send_report(evt, with_system_timestamp: false)
|
195
|
+
event = @context.createEvent((span_event.timestamp.to_i / 1000).to_i)
|
196
|
+
event.addInfo('Label', 'info')
|
197
|
+
span_event.attributes&.each { |key, value| event.addInfo(key, value) }
|
198
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] info event #{event.metadataString}"}
|
199
|
+
@reporter.send_report(event, with_system_timestamp: false)
|
194
200
|
end
|
195
201
|
|
196
202
|
def build_meta_data(span_data, parent: false)
|
197
203
|
flag = span_data.trace_flags.sampled?? 1 : 0
|
198
|
-
|
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}"
|
204
|
+
xtr = parent == false ? "00-#{span_data.hex_trace_id}-#{span_data.hex_span_id}-0#{flag}" : "00-#{span_data.hex_trace_id}-#{span_data.hex_parent_span_id}-0#{flag}"
|
200
205
|
@metadata.fromString(xtr)
|
201
206
|
end
|
202
207
|
end
|