solarwinds_apm 6.0.0.preV2 → 6.0.0.preV4

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.
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