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