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
@@ -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
|
-
|
36
|
-
|
37
|
-
|
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
|
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
|
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
|
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::
|
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::
|
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
|
-
|
146
|
-
|
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
|
30
|
+
SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] extract context: #{context.inspect}"}
|
30
31
|
|
31
|
-
context = ::OpenTelemetry::Context.new({})
|
32
|
-
|
33
|
-
|
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
|
-
|
56
|
-
span_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
|
-
|
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
|
-
#
|
66
|
-
trace_state = nil
|
57
|
+
# prepare carrier with carrier's or new tracestate
|
67
58
|
if trace_state_header.nil?
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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__}]
|
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__}]
|
31
|
-
return unless span_context
|
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
|
34
|
-
|
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
|
-
|
41
|
-
|
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
|
-
|
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
|