solarwinds_apm 6.0.0.preV1 → 6.0.0.preV3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|