solarwinds_apm 6.0.0.preV2 → 6.0.0.preV4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +1 -1
  3. data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +1 -1
  4. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +1 -1
  5. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +1 -1
  6. data/ext/oboe_metal/src/VERSION +1 -2
  7. data/ext/oboe_metal/src/oboe.h +0 -12
  8. data/ext/oboe_metal/src/oboe_swig_wrap.cc +5 -5
  9. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +1 -9
  10. data/lib/solarwinds_apm/api/current_trace_info.rb +0 -1
  11. data/lib/solarwinds_apm/api/opentelemetry.rb +39 -0
  12. data/lib/solarwinds_apm/api/transaction_name.rb +17 -17
  13. data/lib/solarwinds_apm/api.rb +2 -0
  14. data/lib/solarwinds_apm/config.rb +3 -19
  15. data/lib/solarwinds_apm/constants.rb +2 -4
  16. data/lib/solarwinds_apm/noop/context.rb +1 -1
  17. data/lib/solarwinds_apm/oboe_init_options.rb +2 -5
  18. data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +92 -87
  19. data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +18 -17
  20. data/lib/solarwinds_apm/opentelemetry/solarwinds_propagator.rb +28 -28
  21. data/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +9 -14
  22. data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +122 -170
  23. data/lib/solarwinds_apm/otel_config.rb +47 -28
  24. data/lib/solarwinds_apm/support/lumberjack_formatter.rb +17 -2
  25. data/lib/solarwinds_apm/support/swomarginalia/swomarginalia.rb +5 -4
  26. data/lib/solarwinds_apm/support/transaction_cache.rb +27 -2
  27. data/lib/solarwinds_apm/support/transaction_settings.rb +2 -2
  28. data/lib/solarwinds_apm/support/txn_name_manager.rb +34 -17
  29. data/lib/solarwinds_apm/support/utils.rb +24 -0
  30. data/lib/solarwinds_apm/support.rb +2 -4
  31. data/lib/solarwinds_apm/version.rb +1 -1
  32. data/lib/solarwinds_apm.rb +2 -2
  33. metadata +13 -13
  34. data/lib/oboe.rb +0 -7
  35. data/lib/solarwinds_apm/support/transformer.rb +0 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f218890396745c5ba75f0819fa07e3717014fe7aa4072136cf62c23bcbadf34
4
- data.tar.gz: b02cde4d6b896bc60da7fe2c1ab67fd01500a97073d6b67cae497eca70773fa7
3
+ metadata.gz: 713296dd9c5976499e32444e7746b7c340aa49a8cbd34df63308451f39c83615
4
+ data.tar.gz: 8efaffed12d27beb7144ea55e3180bd49eedf10075f77573591272645fe975ea
5
5
  SHA512:
6
- metadata.gz: f699da24367449958aaff9900c3a0e6ef312917a98df5eda9fd7694a7ccf0f4b27a4f9ff02c3b855d89f2360215b6b0e0b3cfcb541f3b34cc05f7c6de468520f
7
- data.tar.gz: 65b88f0502aadd4e1e0fda69e39c73350efc100c5a64d226ccd474aa11409af8fd40a5ee1f5735516a2fd7ac5fc20fb16e5f8140c2550029bf8fafdd049d0002
6
+ metadata.gz: 9c2a125a6991e69089af608f6d8c37d2716b083bd47f28c4c7d9610f8d02be31e6024107e91ad09a4e78c6200b9d608de9bd56d5b67b098a8a4a7cdd4a2a1c19
7
+ data.tar.gz: 61d4b4e5805eefe3dee96567509c4eb2378c226f38df35dabc93df999ec3a209ac8a61a4d578d7710819618e21af2701f8acb327bb684b641d2f5ede6878cbdb
@@ -1 +1 @@
1
- b931c715d8ddaa9f2b91c72ad708ed3467e6e68ee4255756123b2ca96f1b98d0
1
+ 86a0c98301b157fd2ec184e585d70e40753c721c52fbc596ab09aa3d422d5f1f
@@ -1 +1 @@
1
- c8189fe6f5b31c15c31d3b005aebcff90f97ff82e92d9e0d3b254bbbe2a7367d
1
+ 534122daed4a1a81a9e66828f206662ea8f6bf891fb84438cc3daef5f78a7af4
@@ -1 +1 @@
1
- 2824ba630ba794ff6280358922b54e8e1be4ccdb145376f90601e6652d149525
1
+ 89936e04f0b8cddf3fb94c8a4c21d16aa780d6e4fbf4bb66eba42eb33fe15cc6
@@ -1 +1 @@
1
- 82a003ec82e3703260cdc215ef4c0c0bc7bc916cef27ef509034b60fd5ef9b35
1
+ 623f5b308759754c8d771567d5346c46e1d9b53739995a9b5594cc08f8bc6e54
@@ -1,2 +1 @@
1
- 12.4.0
2
-
1
+ 13.0.0
@@ -432,16 +432,6 @@ int oboe_init_reporter(const char *protocol, oboe_init_options_t *options);
432
432
  */
433
433
  int oboe_init_options_set_defaults(oboe_init_options_t *options);
434
434
 
435
- /**
436
- * Disconnect or shut down the Oboe reporter, but allow it to be reconnect()ed.
437
- */
438
- void oboe_reporter_disconnect(); /* TODO: Need implementation. */
439
-
440
- /**
441
- * Reconnect or restart the Oboe reporter.
442
- */
443
- void oboe_reporter_reconnect(); /* TODO: Need implementation. */
444
-
445
435
  /**
446
436
  * tell reporter to flush all messages that are currently buffered
447
437
  */
@@ -712,8 +702,6 @@ void oboe_settings_rate_set(int sample_rate);
712
702
  void oboe_settings_mode_set(int tracing_mode);
713
703
  void oboe_settings_trigger_set(int trigger_mode);
714
704
 
715
- int oboe_rand_get_value();
716
-
717
705
  /**
718
706
  * Convert a tracing mode to a printable string.
719
707
  */
@@ -1932,7 +1932,7 @@ SWIG_ruby_failed(VALUE SWIGUNUSEDPARM(arg1), VALUE SWIGUNUSEDPARM(arg2))
1932
1932
  }
1933
1933
 
1934
1934
 
1935
- /*@SWIG:/usr/local/share/swig/4.0.2/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
1935
+ /*@SWIG:/usr/share/swig4.0/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
1936
1936
  SWIGINTERN VALUE SWIG_AUX_NUM2LONG(VALUE arg)
1937
1937
  {
1938
1938
  VALUE *args = (VALUE *)arg;
@@ -2120,7 +2120,7 @@ SWIG_From_std_string (const std::string& s)
2120
2120
  #define SWIG_From_double rb_float_new
2121
2121
 
2122
2122
 
2123
- /*@SWIG:/usr/local/share/swig/4.0.2/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
2123
+ /*@SWIG:/usr/share/swig4.0/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
2124
2124
  SWIGINTERN VALUE SWIG_AUX_NUM2ULONG(VALUE arg)
2125
2125
  {
2126
2126
  VALUE *args = (VALUE *)arg;
@@ -2172,7 +2172,7 @@ SWIG_AsVal_unsigned_SS_int (VALUE obj, unsigned int *val)
2172
2172
 
2173
2173
 
2174
2174
  #ifdef SWIG_LONG_LONG_AVAILABLE
2175
- /*@SWIG:/usr/local/share/swig/4.0.2/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
2175
+ /*@SWIG:/usr/share/swig4.0/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
2176
2176
  SWIGINTERN VALUE SWIG_AUX_NUM2LL(VALUE arg)
2177
2177
  {
2178
2178
  VALUE *args = (VALUE *)arg;
@@ -2203,7 +2203,7 @@ SWIG_AsVal_long_SS_long (VALUE obj, long long *val)
2203
2203
  #endif
2204
2204
 
2205
2205
 
2206
- /*@SWIG:/usr/local/share/swig/4.0.2/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
2206
+ /*@SWIG:/usr/share/swig4.0/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
2207
2207
  SWIGINTERN VALUE SWIG_AUX_NUM2DBL(VALUE arg)
2208
2208
  {
2209
2209
  VALUE *args = (VALUE *)arg;
@@ -2234,7 +2234,7 @@ SWIG_AsVal_double (VALUE obj, double *val)
2234
2234
 
2235
2235
 
2236
2236
  #ifdef SWIG_LONG_LONG_AVAILABLE
2237
- /*@SWIG:/usr/local/share/swig/4.0.2/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
2237
+ /*@SWIG:/usr/share/swig4.0/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
2238
2238
  SWIGINTERN VALUE SWIG_AUX_NUM2ULL(VALUE arg)
2239
2239
  {
2240
2240
  VALUE *args = (VALUE *)arg;
@@ -107,11 +107,7 @@ if defined?(SolarWindsAPM::Config)
107
107
  #
108
108
  # Currently allowed array of hash
109
109
  #
110
- # and the hashes within the :url list either:
111
- # :extensions takes an array of strings for filtering (not regular expressions!)
112
- # :tracing defaults to :disabled, can be set to :enabled to override
113
- # the global :disabled setting
114
- # or:
110
+ # and the hashes within the :transaction_settings list:
115
111
  # :regexp is a regular expression that is applied to the incoming path
116
112
  # :opts (optional) nil(default) or Regexp::IGNORECASE (options for regexp)
117
113
  # :tracing defaults to :disabled, can be set to :enabled to override
@@ -121,10 +117,6 @@ if defined?(SolarWindsAPM::Config)
121
117
  # down execution.
122
118
  #
123
119
  SolarWindsAPM::Config[:transaction_settings] = [
124
- # {
125
- # extensions: %w[long_job],
126
- # tracing: :disabled
127
- # },
128
120
  # {
129
121
  # regexp: '^.*\/long_job\/.*$',
130
122
  # opts: Regexp::IGNORECASE,
@@ -108,7 +108,6 @@ module SolarWindsAPM
108
108
  span_id = span.context.hex_span_id
109
109
  trace_flags = span.context.trace_flags.sampled?? '01' : '00'
110
110
  tracestring = "00-#{trace_id}-#{span_id}-#{trace_flags}"
111
-
112
111
  [trace_id, span_id, trace_flags, tracestring]
113
112
  end
114
113
 
@@ -0,0 +1,39 @@
1
+ module SolarWindsAPM
2
+ module API
3
+ module OpenTelemetry
4
+ # Create custom span based on current last span
5
+ #
6
+ # Wrap OpenTelemetry function OpenTelemetry.tracer_provider.tracer.in_span
7
+ #
8
+ # === Argument:
9
+ #
10
+ # * +name+ - (int, default 3000) the maximum time to wait in milliseconds
11
+ # * +attributes+ - (hash, default nil)
12
+ # * +links+ - (string, default nil)
13
+ # * +start_timestamp+ - (int, default nil)
14
+ # * +kind+ - (symbol, default nil)
15
+ #
16
+ # === Example:
17
+ #
18
+ # SolarWindsAPM::API.in_span('custom_span') do |span|
19
+ # url = URI.parse("http://www.google.ca/")
20
+ # req = Net::HTTP::Get.new(url.to_s)
21
+ # res = Net::HTTP.start(url.host, url.port) {|http| http.request(req)}
22
+ # end
23
+ #
24
+ # === Returns:
25
+ # * Objective
26
+ #
27
+ def in_span(name, attributes: nil, links: nil, start_timestamp: nil, kind: nil, &block)
28
+ if block.nil?
29
+ SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] please provide block when using in_span function"}
30
+ return
31
+ end
32
+
33
+ SolarWindsAPM.logger.debug {"[#{name}/#{__method__}] solarwinds_apm in_span with OTEL_SERVICE_NAME #{ENV['OTEL_SERVICE_NAME']}"}
34
+ current_tracer = ::OpenTelemetry.tracer_provider.tracer(ENV['OTEL_SERVICE_NAME'])
35
+ current_tracer.in_span(name, attributes: attributes, links: links, start_timestamp: start_timestamp, kind: kind, &block)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -31,27 +31,27 @@ module SolarWindsAPM
31
31
  #
32
32
  def set_transaction_name(custom_name=nil)
33
33
 
34
- return false if custom_name.nil? || custom_name.empty?
35
- return true if SolarWindsAPM::Context.toString == '00-00000000000000000000000000000000-0000000000000000-00' # noop
36
-
37
- solarwinds_processor = SolarWindsAPM::OTelConfig.class_variable_get(:@@config)[:span_processor]
38
- if solarwinds_processor.nil?
34
+ status = true
35
+ if custom_name.nil? || custom_name.empty?
36
+ status = false
37
+ elsif SolarWindsAPM::Context.toString == '99-00000000000000000000000000000000-0000000000000000-00' # noop
38
+ status = true
39
+ elsif SolarWindsAPM::OTelConfig.class_variable_get(:@@config)[:span_processor].nil?
39
40
  SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] Solarwinds processor is missing. Set transaction name failed."}
40
- return false
41
- end
41
+ status = false
42
+ else
43
+ solarwinds_processor = SolarWindsAPM::OTelConfig.class_variable_get(:@@config)[:span_processor]
44
+ current_span = ::OpenTelemetry::Trace.current_span
45
+ entry_trace_id = current_span.context.hex_trace_id
46
+ entry_span_id, trace_flags = solarwinds_processor.txn_manager.get_root_context_h(entry_trace_id)&.split('-')
42
47
 
43
- entry_trace_id = ::OpenTelemetry::Baggage.value(::SolarWindsAPM::Constants::INTL_SWO_CURRENT_TRACE_ID)
44
- entry_span_id = ::OpenTelemetry::Baggage.value(::SolarWindsAPM::Constants::INTL_SWO_CURRENT_SPAN_ID)
48
+ status = false if entry_trace_id.nil? || entry_span_id.nil? || trace_flags.nil?
49
+ status = false if entry_trace_id == '0'*32 || entry_span_id == '0'*16 || trace_flags == '00' # not sampled
45
50
 
46
- if entry_trace_id.nil? || entry_span_id.nil?
47
- SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] Cannot cache custom transaction name #{custom_name} because OTel service entry span not started; ignoring"}
48
- return false
51
+ solarwinds_processor.txn_manager.set("#{entry_trace_id}-#{entry_span_id}",custom_name)
52
+ SolarWindsAPM.logger.debug {"[#{name}/#{__method__}] Cached custom transaction name for #{entry_trace_id}-#{entry_span_id} as #{custom_name}"}
49
53
  end
50
-
51
- trace_span_id = "#{entry_trace_id}-#{entry_span_id}"
52
- solarwinds_processor.txn_manager.set(trace_span_id,custom_name)
53
- SolarWindsAPM.logger.debug {"[#{name}/#{__method__}] Cached custom transaction name for #{trace_span_id} as #{custom_name}"}
54
- true
54
+ status
55
55
  end
56
56
  end
57
57
  end
@@ -4,11 +4,13 @@
4
4
  require_relative './api/transaction_name'
5
5
  require_relative './api/current_trace_info'
6
6
  require_relative './api/tracing'
7
+ require_relative './api/opentelemetry'
7
8
 
8
9
  module SolarWindsAPM
9
10
  module API
10
11
  extend SolarWindsAPM::API::TransactionName
11
12
  extend SolarWindsAPM::API::CurrentTraceInfo
12
13
  extend SolarWindsAPM::API::Tracing
14
+ extend SolarWindsAPM::API::OpenTelemetry
13
15
  end
14
16
  end
@@ -176,7 +176,7 @@ module SolarWindsAPM
176
176
 
177
177
  # `tracing: disabled` is the default
178
178
  disabled = settings.select { |v| !v.has_key?(:tracing) || v[:tracing] == :disabled }
179
- enabled = settings.select { |v| v[:tracing] == :enabled }
179
+ enabled = settings.select { |v| v[:tracing] == :enabled }
180
180
 
181
181
  SolarWindsAPM::Config[:enabled_regexps] = compile_regexp(enabled)
182
182
  SolarWindsAPM::Config[:disabled_regexps] = compile_regexp(disabled)
@@ -184,11 +184,8 @@ module SolarWindsAPM
184
184
  private_class_method :compile_settings
185
185
 
186
186
  def self.compile_regexp(settings)
187
- regexp_regexp = compile_settings_regexp(settings)
188
- extensions_regexp = compile_settings_extensions(settings)
189
-
190
- regexps = [regexp_regexp, extensions_regexp].flatten.compact
191
-
187
+ regexp_regexp = compile_settings_regexp(settings)
188
+ regexps = [regexp_regexp].flatten.compact
192
189
  regexps.empty? ? nil : regexps
193
190
  end
194
191
  private_class_method :compile_regexp
@@ -213,19 +210,6 @@ module SolarWindsAPM
213
210
  end
214
211
  private_class_method :compile_settings_regexp
215
212
 
216
- def self.compile_settings_extensions(value)
217
- extensions = value.select do |v|
218
- v.has_key?(:extensions) &&
219
- v[:extensions].is_a?(Array) &&
220
- !v[:extensions].empty?
221
- end
222
- extensions = extensions.map { |v| v[:extensions] }.flatten
223
- extensions.keep_if { |v| v.is_a?(String) }
224
-
225
- extensions.empty? ? nil : Regexp.new("(#{Regexp.union(extensions).source})(\\?.+){0,1}$")
226
- end
227
- private_class_method :compile_settings_extensions
228
-
229
213
  def self.reset_regexps
230
214
  SolarWindsAPM::Config[:enabled_regexps] = nil
231
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
@@ -12,7 +12,7 @@ module SolarWindsAPM
12
12
  # toString would return the current trace context as string
13
13
  #
14
14
  def self.toString
15
- '00-00000000000000000000000000000000-0000000000000000-00'
15
+ '99-00000000000000000000000000000000-0000000000000000-00'
16
16
  end
17
17
 
18
18
  ##
@@ -213,11 +213,8 @@ module SolarWindsAPM
213
213
  end
214
214
 
215
215
  def read_certificates
216
- file = String.new
217
- file = "#{__dir__}/cert/star.appoptics.com.issuer.crt" if appoptics_collector?
218
- file = ENV['SW_APM_TRUSTEDPATH'] if !ENV['SW_APM_TRUSTEDPATH'].nil? && !ENV['SW_APM_TRUSTEDPATH']&.empty?
219
-
220
- return file if file.empty?
216
+ file = appoptics_collector?? "#{__dir__}/cert/star.appoptics.com.issuer.crt" : ENV['SW_APM_TRUSTEDPATH']
217
+ return String.new if file.nil? || file&.empty?
221
218
 
222
219
  begin
223
220
  certificate = File.open(file,"r").read
@@ -19,12 +19,13 @@ module SolarWindsAPM
19
19
 
20
20
  def export(span_data, _timeout: nil)
21
21
  return FAILURE if @shutdown
22
-
23
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] span_data: #{span_data}"}
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
- SUCCESS
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
- 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)
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
- # 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
69
+ @reporter.send_report(event, with_system_timestamp: false)
87
70
 
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
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
- def add_info_instrumentation_scope(event, span_data)
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
- # 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}"}
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__}] Current framework version cached: #{@version_cache.inspect}"}
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, evt)
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
- 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)
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
- evt = @context.createEvent((span_event.timestamp.to_i / 1000).to_i)
171
- evt.addInfo('Label', 'error')
172
- evt.addInfo('Spec', 'error')
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
- 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
+ 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
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] exception event #{evt.metadataString}"}
183
- @reporter.send_report(evt, with_system_timestamp: false)
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
- 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)
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
- 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}"
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