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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +28 -54
  3. data/ext/oboe_metal/extconf.rb +23 -23
  4. data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +1 -1
  5. data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +1 -1
  6. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +1 -1
  7. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +1 -1
  8. data/ext/oboe_metal/src/VERSION +1 -2
  9. data/ext/oboe_metal/src/init_solarwinds_apm.cc +0 -6
  10. data/ext/oboe_metal/src/oboe.h +0 -12
  11. data/ext/oboe_metal/src/oboe_swig_wrap.cc +5 -5
  12. data/lib/oboe_metal.rb +3 -3
  13. data/lib/rails/generators/solarwinds_apm/install_generator.rb +0 -3
  14. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +8 -25
  15. data/lib/solarwinds_apm/api/current_trace_info.rb +1 -2
  16. data/lib/solarwinds_apm/api/opentelemetry.rb +39 -0
  17. data/lib/solarwinds_apm/api/transaction_name.rb +18 -17
  18. data/lib/solarwinds_apm/api.rb +2 -0
  19. data/lib/solarwinds_apm/config.rb +21 -63
  20. data/lib/solarwinds_apm/constants.rb +2 -4
  21. data/lib/solarwinds_apm/noop/context.rb +1 -1
  22. data/lib/solarwinds_apm/oboe_init_options.rb +11 -16
  23. data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +92 -87
  24. data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +27 -23
  25. data/lib/solarwinds_apm/opentelemetry/solarwinds_propagator.rb +28 -28
  26. data/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +9 -14
  27. data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +132 -175
  28. data/lib/solarwinds_apm/otel_config.rb +55 -36
  29. data/lib/solarwinds_apm/support/lumberjack_formatter.rb +17 -2
  30. data/lib/solarwinds_apm/support/swomarginalia/comment.rb +2 -2
  31. data/lib/solarwinds_apm/support/swomarginalia/swomarginalia.rb +6 -5
  32. data/lib/solarwinds_apm/support/transaction_cache.rb +27 -2
  33. data/lib/solarwinds_apm/support/transaction_settings.rb +10 -10
  34. data/lib/solarwinds_apm/support/txn_name_manager.rb +34 -17
  35. data/lib/solarwinds_apm/support/utils.rb +24 -0
  36. data/lib/solarwinds_apm/support.rb +4 -2
  37. data/lib/solarwinds_apm/version.rb +1 -1
  38. data/lib/solarwinds_apm.rb +3 -4
  39. metadata +18 -33
  40. data/lib/oboe.rb +0 -7
  41. data/lib/solarwinds_apm/noop/profiling.rb +0 -17
  42. data/lib/solarwinds_apm/support/transformer.rb +0 -56
@@ -32,11 +32,9 @@ module SolarWindsAPM
32
32
  return if parent_span && parent_span.context != ::OpenTelemetry::Trace::SpanContext::INVALID && parent_span.context.remote? == false
33
33
 
34
34
  trace_flags = span.context.trace_flags.sampled? ? '01' : '00'
35
- ::OpenTelemetry::Context.attach(::OpenTelemetry::Baggage.set_value(::SolarWindsAPM::Constants::INTL_SWO_CURRENT_TRACE_ID, span.context.hex_trace_id))
36
- ::OpenTelemetry::Context.attach(::OpenTelemetry::Baggage.set_value(::SolarWindsAPM::Constants::INTL_SWO_CURRENT_SPAN_ID, span.context.hex_span_id))
37
- ::OpenTelemetry::Context.attach(::OpenTelemetry::Baggage.set_value(::SolarWindsAPM::Constants::INTL_SWO_CURRENT_TRACE_FLAG, trace_flags))
38
-
39
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] current baggage values: #{::OpenTelemetry::Baggage.values}"}
35
+ @txn_manager.set_root_context_h(span.context.hex_trace_id,"#{span.context.hex_span_id}-#{trace_flags}")
36
+ rescue StandardError => e
37
+ SolarWindsAPM.logger.info {"[#{self.class}/#{__method__}] processor on_start error: #{e.message}"}
40
38
  end
41
39
 
42
40
  # Called when a {Span} is ended, if the {Span#recording?}
@@ -47,7 +45,9 @@ module SolarWindsAPM
47
45
  # Only calculate inbound metrics for service root spans
48
46
  #
49
47
  # @param [Span] span the {Span} that just ended.
50
- def on_finish(span)
48
+ def on_finish(span)
49
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] processor on_finish span: #{span.inspect}"}
50
+
51
51
  if span.parent_span_id != ::OpenTelemetry::Trace::INVALID_SPAN_ID
52
52
  @exporter&.export([span.to_span_data]) if span.context.trace_flags.sampled?
53
53
  return
@@ -57,40 +57,44 @@ module SolarWindsAPM
57
57
  domain = nil
58
58
  has_error = error?(span)
59
59
  trans_name = calculate_transaction_names(span)
60
- url_tran = span.attributes[HTTP_URL]
61
-
62
- liboboe_txn_name = nil
63
60
  if span_http?(span)
64
- status_code = get_http_status_code(span)
61
+ status_code = get_http_status_code(span)
65
62
  request_method = span.attributes[HTTP_METHOD]
63
+ url_tran = span.attributes[HTTP_URL]
66
64
 
67
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] createHttpSpan with\n
65
+ SolarWindsAPM.logger.debug do
66
+ "[#{self.class}/#{__method__}] createHttpSpan with\n
68
67
  trans_name: #{trans_name}\n
69
68
  url_tran: #{url_tran}\n
70
69
  domain: #{domain}\n
71
70
  span_time: #{span_time}\n
72
71
  status_code: #{status_code}\n
73
72
  request_method: #{request_method}\n
74
- has_error: #{has_error}"}
73
+ has_error: #{has_error}"
74
+ end
75
75
 
76
- liboboe_txn_name = SolarWindsAPM::Span.createHttpSpan(trans_name,url_tran,domain,span_time,status_code,
77
- request_method,has_error)
76
+ liboboe_txn_name = SolarWindsAPM::Span.createHttpSpan(trans_name,url_tran,domain,span_time,status_code,request_method,has_error)
78
77
 
79
78
  else
80
79
 
81
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] createSpan with \n
80
+ SolarWindsAPM.logger.debug do
81
+ "[#{self.class}/#{__method__}] createSpan with \n
82
82
  trans_name: #{trans_name}\n
83
83
  domain: #{domain}\n
84
84
  span_time: #{span_time}\n
85
- has_error: #{has_error}"}
85
+ has_error: #{has_error}"
86
+ end
86
87
 
87
88
  liboboe_txn_name = SolarWindsAPM::Span.createSpan(trans_name, domain, span_time, has_error)
88
89
  end
89
90
 
90
91
  SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] liboboe_txn_name: #{liboboe_txn_name}"}
91
92
  @txn_manager["#{span.context.hex_trace_id}-#{span.context.hex_span_id}"] = liboboe_txn_name if span.context.trace_flags.sampled?
92
-
93
+ @txn_manager.delete_root_context_h(span.context.hex_trace_id)
93
94
  @exporter&.export([span.to_span_data]) if span.context.trace_flags.sampled?
95
+ rescue StandardError => e
96
+ SolarWindsAPM.logger.info {"[#{self.class}/#{__method__}] can't flush span to exporter; processor on_finish error: #{e.message}"}
97
+ ::OpenTelemetry::SDK::Trace::Export::FAILURE
94
98
  end
95
99
 
96
100
  # Export all ended spans to the configured `Exporter` that have not yet
@@ -105,7 +109,7 @@ module SolarWindsAPM
105
109
  # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
106
110
  # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
107
111
  def force_flush(timeout: nil)
108
- @exporter&.force_flush(timeout: timeout) || ::OpenTelemetry::SDK::Metrics::Export::SUCCESS
112
+ @exporter&.force_flush(timeout: timeout) || ::OpenTelemetry::SDK::Trace::Export::SUCCESS
109
113
  end
110
114
 
111
115
  # Called when {TracerProvider#shutdown} is called.
@@ -114,14 +118,13 @@ module SolarWindsAPM
114
118
  # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
115
119
  # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
116
120
  def shutdown(timeout: nil)
117
- @exporter&.shutdown(timeout: timeout) || ::OpenTelemetry::SDK::Metrics::Export::SUCCESS
121
+ @exporter&.shutdown(timeout: timeout) || ::OpenTelemetry::SDK::Trace::Export::SUCCESS
118
122
  end
119
123
 
120
124
  private
121
125
 
122
126
  # This span from inbound HTTP request if from a SERVER by some http.method
123
127
  def span_http?(span)
124
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] span.kind #{span.kind} span.attributes: #{span.attributes[HTTP_METHOD]}"}
125
128
  (span.kind == ::OpenTelemetry::Trace::SpanKind::SERVER && !span.attributes[HTTP_METHOD].nil?)
126
129
  end
127
130
 
@@ -140,10 +143,11 @@ module SolarWindsAPM
140
143
 
141
144
  # Get trans_name and url_tran of this span instance.
142
145
  def calculate_transaction_names(span)
143
-
144
146
  trace_span_id = "#{span.context.hex_trace_id}-#{span.context.hex_span_id}"
145
- if @txn_manager.get(trace_span_id)
146
- trans_name = @txn_manager.get(trace_span_id)
147
+ trans_name = @txn_manager.get(trace_span_id)
148
+ if trans_name
149
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] found trans name from txn_manager: #{trans_name} by #{trace_span_id}"}
150
+ @txn_manager.del(trace_span_id)
147
151
  else
148
152
  trans_name = span.attributes[HTTP_ROUTE] || nil
149
153
  trans_name = span.name if span.name && (trans_name.nil? || trans_name.empty?)
@@ -2,6 +2,7 @@ module SolarWindsAPM
2
2
  module OpenTelemetry
3
3
  module SolarWindsPropagator
4
4
  # TextMapPropagator
5
+ # propagator error will be rescued by OpenTelemetry::Context::Propagation::TextMapPropagator
5
6
  class TextMapPropagator
6
7
  TRACESTATE_HEADER_NAME = "tracestate".freeze
7
8
  XTRACEOPTIONS_HEADER_NAME = "x-trace-options".freeze
@@ -26,19 +27,11 @@ module SolarWindsAPM
26
27
  # if extraction fails
27
28
  def extract(carrier, context: ::OpenTelemetry::Context.current, getter: ::OpenTelemetry::Context::Propagation.text_map_getter)
28
29
 
29
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] context(before): #{context.inspect} #{context.nil?}"}
30
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] extract context: #{context.inspect}"}
30
31
 
31
- context = ::OpenTelemetry::Context.new({}) if context.nil?
32
-
33
- xtraceoptions_header = getter.get(carrier, XTRACEOPTIONS_HEADER_NAME)
34
- context = context.set_value(INTL_SWO_X_OPTIONS_KEY, xtraceoptions_header) if xtraceoptions_header
35
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] xtraceoptions_header: #{xtraceoptions_header}"}
36
-
37
- signature_header = getter.get(carrier, XTRACEOPTIONS_SIGNATURE_HEADER_NAME)
38
- context = context.set_value(INTL_SWO_SIGNATURE_KEY, signature_header) if signature_header
39
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] signature_header: #{signature_header}; propagator extract context: #{context.inspect}"}
40
-
41
- context
32
+ context = context.nil?? ::OpenTelemetry::Context.new({}) : context
33
+ context = inject_extracted_header(carrier, context, getter, XTRACEOPTIONS_HEADER_NAME, INTL_SWO_X_OPTIONS_KEY)
34
+ inject_extracted_header(carrier, context, getter, XTRACEOPTIONS_SIGNATURE_HEADER_NAME, INTL_SWO_SIGNATURE_KEY)
42
35
  end
43
36
 
44
37
  # Inject trace context into the supplied carrier.
@@ -51,32 +44,30 @@ module SolarWindsAPM
51
44
  def inject(carrier, context: ::OpenTelemetry::Context.current, setter: ::OpenTelemetry::Context::Propagation.text_map_setter)
52
45
 
53
46
  SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] inject context: #{context.inspect}"}
54
-
55
- cspan = ::OpenTelemetry::Trace.current_span(context)
56
- span_context = cspan&.context
57
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] cspan #{cspan.inspect}; span_context #{span_context.inspect}"}
47
+
48
+ span_context = ::OpenTelemetry::Trace.current_span(context)&.context
49
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] span_context #{span_context.inspect}"}
58
50
  return unless span_context&.valid?
59
51
 
60
- sw_value = Transformer.sw_from_context(span_context) # sw_value is a string
52
+ trace_flag = span_context.trace_flags.sampled?? 1 : 0
53
+ sw_value = "#{span_context.hex_span_id}-0#{trace_flag}"
61
54
  trace_state_header = carrier[TRACESTATE_HEADER_NAME].nil?? nil : carrier[TRACESTATE_HEADER_NAME]
62
-
63
55
  SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] sw_value: #{sw_value}; trace_state_header: #{trace_state_header}"}
64
56
 
65
- # Prepare carrier with carrier's or new tracestate
66
- trace_state = nil
57
+ # prepare carrier with carrier's or new tracestate
67
58
  if trace_state_header.nil?
68
- # Only create new trace state if valid span_id
69
- return if span_context.span_id == ::OpenTelemetry::Trace::INVALID_SPAN_ID
70
-
71
- trace_state = ::OpenTelemetry::Trace::Tracestate.create({SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY => sw_value})
72
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] creating new trace state: #{trace_state.inspect}"}
59
+ # only create new trace state if valid span_id
60
+ unless span_context.span_id == ::OpenTelemetry::Trace::INVALID_SPAN_ID
61
+ trace_state = ::OpenTelemetry::Trace::Tracestate.create({SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY => sw_value})
62
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] creating new trace state: #{trace_state.inspect}"}
63
+ setter.set(carrier, TRACESTATE_HEADER_NAME, Utils.trace_state_header(trace_state))
64
+ end
73
65
  else
74
66
  trace_state_from_string = ::OpenTelemetry::Trace::Tracestate.from_string(trace_state_header)
75
67
  trace_state = trace_state_from_string.set_value(SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY, sw_value)
76
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] Updating/Adding trace state for injection #{trace_state.inspect}"}
68
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] updating/adding trace state for injection #{trace_state.inspect}"}
69
+ setter.set(carrier, TRACESTATE_HEADER_NAME, Utils.trace_state_header(trace_state))
77
70
  end
78
-
79
- setter.set(carrier, TRACESTATE_HEADER_NAME, Transformer.trace_state_header(trace_state))
80
71
  end
81
72
 
82
73
  # Returns the predefined propagation fields. If your carrier is reused, you
@@ -86,6 +77,15 @@ module SolarWindsAPM
86
77
  def fields
87
78
  TRACESTATE_HEADER_NAME
88
79
  end
80
+
81
+ private
82
+
83
+ def inject_extracted_header(carrier, context, getter, header, inject_key)
84
+ extracted_header = getter.get(carrier, header)
85
+ context = context.set_value(inject_key, extracted_header) if extracted_header
86
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] #{header}: #{inject_key} = #{extracted_header}"}
87
+ context
88
+ end
89
89
  end
90
90
  end
91
91
  end
@@ -2,6 +2,7 @@ module SolarWindsAPM
2
2
  module OpenTelemetry
3
3
  module SolarWindsResponsePropagator
4
4
  # ResponsePropagator
5
+ # response propagator error will be rescued by OpenTelemetry::Instrumentation::Rack::Middlewares::EventHandler
5
6
  class TextMapPropagator
6
7
  HTTP_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers".freeze
7
8
  XTRACE_HEADER_NAME = "x-trace".freeze
@@ -25,26 +26,20 @@ module SolarWindsAPM
25
26
  # text map setter will be used.
26
27
  def inject(carrier, context: ::OpenTelemetry::Context.current, setter: ::OpenTelemetry::Context::Propagation.text_map_setter)
27
28
 
28
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] response propagator context: #{context.inspect}"}
29
29
  span_context = ::OpenTelemetry::Trace.current_span(context).context
30
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] response propagator span_context: #{span_context.inspect}"}
31
- return unless span_context.valid?
30
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] context: #{context.inspect}; span_context: #{span_context.inspect}"}
31
+ return unless span_context&.valid?
32
32
 
33
- x_trace = Transformer.traceparent_from_context(span_context)
34
- setter.set(carrier, XTRACE_HEADER_NAME, x_trace)
35
- exposed_headers = [XTRACE_HEADER_NAME]
36
-
37
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] response propagator span_context.tracestate: #{span_context.tracestate.inspect}"}
33
+ x_trace = Utils.traceparent_from_context(span_context)
34
+ exposed_headers = [XTRACE_HEADER_NAME]
38
35
  xtraceoptions_response = recover_response_from_tracestate(span_context.tracestate)
39
36
 
40
- unless xtraceoptions_response.empty?
41
- exposed_headers << XTRACEOPTIONS_RESPONSE_HEADER_NAME
42
- setter.set(carrier, XTRACEOPTIONS_RESPONSE_HEADER_NAME, xtraceoptions_response)
43
- end
37
+ SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] x-trace: #{x_trace}; exposed headers: #{exposed_headers.inspect}; x-trace-options-response: #{xtraceoptions_response}"}
38
+ exposed_headers.append(XTRACEOPTIONS_RESPONSE_HEADER_NAME) unless xtraceoptions_response.empty?
44
39
 
45
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] response propagator exposed_headers: #{exposed_headers.inspect}"}
40
+ setter.set(carrier, XTRACE_HEADER_NAME, x_trace)
41
+ setter.set(carrier, XTRACEOPTIONS_RESPONSE_HEADER_NAME, xtraceoptions_response) unless xtraceoptions_response.empty?
46
42
  setter.set(carrier, HTTP_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS, exposed_headers.join(","))
47
-
48
43
  end
49
44
 
50
45
  # Returns the predefined propagation fields. If your carrier is reused, you