solarwinds_apm 6.1.2 → 7.0.0.prev2
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.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +1 -30
- data/lib/solarwinds_apm/api/current_trace_info.rb +10 -6
- data/lib/solarwinds_apm/api/custom_metrics.rb +8 -25
- data/lib/solarwinds_apm/api/tracing.rb +12 -27
- data/lib/solarwinds_apm/api/transaction_name.rb +6 -10
- data/lib/solarwinds_apm/config.rb +7 -1
- data/lib/solarwinds_apm/constants.rb +1 -0
- data/lib/solarwinds_apm/noop/api.rb +5 -2
- data/lib/solarwinds_apm/noop.rb +0 -24
- data/lib/solarwinds_apm/opentelemetry/otlp_processor.rb +116 -66
- data/lib/solarwinds_apm/opentelemetry/solarwinds_propagator.rb +0 -2
- data/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +5 -4
- data/lib/solarwinds_apm/opentelemetry.rb +5 -7
- data/lib/solarwinds_apm/otel_native_config.rb +180 -0
- data/lib/solarwinds_apm/patch/README.md +15 -0
- data/lib/solarwinds_apm/{noop/metadata.rb → sampling/dice.rb} +19 -17
- data/lib/solarwinds_apm/sampling/http_sampler.rb +87 -0
- data/lib/solarwinds_apm/sampling/json_sampler.rb +52 -0
- data/lib/solarwinds_apm/sampling/metrics.rb +38 -0
- data/lib/solarwinds_apm/sampling/oboe_sampler.rb +348 -0
- data/lib/solarwinds_apm/sampling/sampler.rb +197 -0
- data/lib/solarwinds_apm/sampling/sampling_constants.rb +127 -0
- data/lib/solarwinds_apm/sampling/sampling_patch.rb +49 -0
- data/lib/solarwinds_apm/sampling/setting_example.txt +1 -0
- data/lib/solarwinds_apm/{noop/context.rb → sampling/settings.rb} +14 -25
- data/lib/solarwinds_apm/sampling/token_bucket.rb +126 -0
- data/lib/solarwinds_apm/sampling/trace_options.rb +100 -0
- data/lib/solarwinds_apm/{patch.rb → sampling.rb} +20 -4
- data/lib/solarwinds_apm/support/logger_formatter.rb +1 -1
- data/lib/solarwinds_apm/support/logging_log_event.rb +1 -1
- data/lib/solarwinds_apm/support/lumberjack_formatter.rb +1 -1
- data/lib/solarwinds_apm/support/otlp_endpoint.rb +99 -0
- data/lib/solarwinds_apm/support/resource_detector.rb +192 -0
- data/lib/solarwinds_apm/support/service_key_checker.rb +12 -6
- data/lib/solarwinds_apm/support/transaction_settings.rb +6 -0
- data/lib/solarwinds_apm/support/txn_name_manager.rb +54 -9
- data/lib/solarwinds_apm/support/utils.rb +9 -0
- data/lib/solarwinds_apm/support.rb +2 -4
- data/lib/solarwinds_apm/version.rb +4 -4
- data/lib/solarwinds_apm.rb +27 -73
- metadata +107 -40
- data/ext/oboe_metal/extconf.rb +0 -168
- data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +0 -1
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +0 -1
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +0 -1
- data/ext/oboe_metal/lib/liboboe-1.0-lambda-aarch64.so.sha256 +0 -1
- data/ext/oboe_metal/lib/liboboe-1.0-lambda-x86_64.so.sha256 +0 -1
- data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +0 -1
- data/ext/oboe_metal/src/VERSION +0 -1
- data/ext/oboe_metal/src/bson/bson.h +0 -220
- data/ext/oboe_metal/src/bson/platform_hacks.h +0 -91
- data/ext/oboe_metal/src/init_solarwinds_apm.cc +0 -18
- data/ext/oboe_metal/src/oboe.h +0 -930
- data/ext/oboe_metal/src/oboe_api.cpp +0 -793
- data/ext/oboe_metal/src/oboe_api.h +0 -621
- data/ext/oboe_metal/src/oboe_debug.h +0 -17
- data/ext/oboe_metal/src/oboe_swig_wrap.cc +0 -11045
- data/lib/oboe_metal.rb +0 -187
- data/lib/solarwinds_apm/cert/star.appoptics.com.issuer.crt +0 -24
- data/lib/solarwinds_apm/noop/span.rb +0 -25
- data/lib/solarwinds_apm/oboe_init_options.rb +0 -222
- data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +0 -239
- data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +0 -174
- data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +0 -333
- data/lib/solarwinds_apm/otel_config.rb +0 -174
- data/lib/solarwinds_apm/otel_lambda_config.rb +0 -56
- data/lib/solarwinds_apm/patch/dummy_patch.rb +0 -12
- data/lib/solarwinds_apm/support/oboe_tracing_mode.rb +0 -33
- data/lib/solarwinds_apm/support/support_report.rb +0 -99
- data/lib/solarwinds_apm/support/transaction_cache.rb +0 -57
- data/lib/solarwinds_apm/support/x_trace_options.rb +0 -138
@@ -1,333 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# © 2023 SolarWinds Worldwide, LLC. All rights reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:http://www.apache.org/licenses/LICENSE-2.0
|
6
|
-
#
|
7
|
-
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
8
|
-
|
9
|
-
module SolarWindsAPM
|
10
|
-
module OpenTelemetry
|
11
|
-
# SolarWindsSampler
|
12
|
-
class SolarWindsSampler
|
13
|
-
INTERNAL_BUCKET_CAPACITY = 'BucketCapacity'
|
14
|
-
INTERNAL_BUCKET_RATE = 'BucketRate'
|
15
|
-
INTERNAL_SAMPLE_RATE = 'SampleRate'
|
16
|
-
INTERNAL_SAMPLE_SOURCE = 'SampleSource'
|
17
|
-
INTERNAL_SW_KEYS = 'SWKeys'
|
18
|
-
LIBOBOE_CONTINUED = -1
|
19
|
-
SW_TRACESTATE_CAPTURE_KEY = 'sw.w3c.tracestate'
|
20
|
-
SW_TRACESTATE_ROOT_KEY = 'sw.tracestate_parent_id'
|
21
|
-
UNSET = -1
|
22
|
-
SWO_TRACING_ENABLED = 1
|
23
|
-
SWO_TRACING_DISABLED = 0
|
24
|
-
SWO_TRACING_UNSET = -1
|
25
|
-
XTRACEOPTIONS_RESP_AUTH = 'auth'
|
26
|
-
XTRACEOPTIONS_RESP_IGNORED = 'ignored'
|
27
|
-
XTRACEOPTIONS_RESP_TRIGGER_IGNORED = 'ignored'
|
28
|
-
XTRACEOPTIONS_RESP_TRIGGER_NOT_REQUESTED = 'not-requested'
|
29
|
-
XTRACEOPTIONS_RESP_TRIGGER_TRACE = 'trigger-trace'
|
30
|
-
|
31
|
-
attr_reader :description
|
32
|
-
|
33
|
-
def initialize(config = {})
|
34
|
-
@config = config
|
35
|
-
end
|
36
|
-
|
37
|
-
def ==(other)
|
38
|
-
@decision == other.decision && @description == other.description
|
39
|
-
end
|
40
|
-
|
41
|
-
# @api private
|
42
|
-
#
|
43
|
-
# See {Samplers}.
|
44
|
-
# trace_id
|
45
|
-
# parent_context: OpenTelemetry::Context
|
46
|
-
def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:)
|
47
|
-
SolarWindsAPM.logger.debug do
|
48
|
-
"[#{self.class}/#{__method__}] should_sample? start parameters \n
|
49
|
-
trace_id: #{trace_id.unpack1('H*')}\n
|
50
|
-
parent_context: #{parent_context}\n
|
51
|
-
parent_context.inspect: #{parent_context.inspect}\n
|
52
|
-
links: #{links}\n
|
53
|
-
name: #{name}\n
|
54
|
-
kind: #{kind}\n
|
55
|
-
attributes: #{attributes}"
|
56
|
-
end
|
57
|
-
|
58
|
-
SolarWindsAPM::Reporter.send(:report_init) # This only happens if after_fork enabled
|
59
|
-
|
60
|
-
parent_span_context = ::OpenTelemetry::Trace.current_span(parent_context).context
|
61
|
-
xtraceoptions = ::SolarWindsAPM::XTraceOptions.new(parent_context)
|
62
|
-
SolarWindsAPM.logger.debug do
|
63
|
-
"[#{self.class}/#{__method__}] parent_span_context: #{parent_span_context.inspect}\n xtraceoptions: #{xtraceoptions.inspect}"
|
64
|
-
end
|
65
|
-
|
66
|
-
liboboe_decision = calculate_liboboe_decision(parent_span_context, xtraceoptions, name, kind, attributes)
|
67
|
-
otel_decision = otel_decision_from_liboboe(liboboe_decision)
|
68
|
-
new_trace_state = calculate_trace_state(liboboe_decision, parent_span_context, xtraceoptions)
|
69
|
-
new_attributes = if otel_sampled?(otel_decision)
|
70
|
-
calculate_attributes(attributes, liboboe_decision,
|
71
|
-
new_trace_state, parent_span_context, xtraceoptions)
|
72
|
-
end
|
73
|
-
sampling_result = ::OpenTelemetry::SDK::Trace::Samplers::Result.new(decision: otel_decision,
|
74
|
-
attributes: new_attributes,
|
75
|
-
tracestate: new_trace_state)
|
76
|
-
|
77
|
-
SolarWindsAPM.logger.debug do
|
78
|
-
"[#{self.class}/#{__method__}] should_sample? end with sampling_result: #{sampling_result.inspect} from otel_decision: #{otel_decision.inspect} and new_attributes: #{new_attributes.inspect}"
|
79
|
-
end
|
80
|
-
sampling_result
|
81
|
-
rescue StandardError => e
|
82
|
-
SolarWindsAPM.logger.info { "[#{self.class}/#{__method__}] sampler error: #{e.message}" }
|
83
|
-
::OpenTelemetry::SDK::Trace::Samplers::Result.new(decision: ::OpenTelemetry::SDK::Trace::Samplers::Decision::DROP,
|
84
|
-
attributes: attributes,
|
85
|
-
tracestate: ::OpenTelemetry::Trace::Tracestate::DEFAULT)
|
86
|
-
end
|
87
|
-
|
88
|
-
protected
|
89
|
-
|
90
|
-
attr_reader :decision
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
##
|
95
|
-
# use parent_span_context and xtraceoptions object to feed to liboboe function getDecisions that get liboboe_decision
|
96
|
-
# name, kind and attributes are used for transaction filter caching (to avoid continous calculate_trace_mode calculation)
|
97
|
-
# return decision Hash
|
98
|
-
def calculate_liboboe_decision(parent_span_context, xtraceoptions, name, kind, attributes)
|
99
|
-
tracestring = Utils.traceparent_from_context(parent_span_context) if parent_span_context.valid? && parent_span_context.remote?
|
100
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] tracestring: #{tracestring}" }
|
101
|
-
|
102
|
-
# otel-ruby contrib use different key to store url info, currently it's using http.target for path
|
103
|
-
url_path = attributes.nil? ? '' : attributes['http.target']
|
104
|
-
transaction_naming_key = "#{url_path}-#{name}-#{kind}"
|
105
|
-
tracing_mode = SolarWindsAPM::TransactionCache.get(transaction_naming_key)
|
106
|
-
SolarWindsAPM.logger.debug do
|
107
|
-
"[#{self.class}/#{__method__}] transaction cache: #{transaction_naming_key}; tracing_mode: #{tracing_mode}."
|
108
|
-
end
|
109
|
-
|
110
|
-
unless tracing_mode
|
111
|
-
trans_settings = SolarWindsAPM::TransactionSettings.new(url_path: url_path, name: name, kind: kind)
|
112
|
-
tracing_mode = trans_settings.calculate_trace_mode == 1 ? SWO_TRACING_ENABLED : SWO_TRACING_DISABLED
|
113
|
-
SolarWindsAPM::TransactionCache.set(transaction_naming_key, tracing_mode)
|
114
|
-
end
|
115
|
-
|
116
|
-
sw_member_value = parent_span_context.tracestate[SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY]
|
117
|
-
trigger_trace_mode = SolarWindsAPM::OboeTracingMode.get_oboe_trigger_trace_mode(@config['trigger_trace'])
|
118
|
-
sample_rate = UNSET
|
119
|
-
options = xtraceoptions&.options
|
120
|
-
trigger_trace = xtraceoptions&.intify_trigger_trace || 0
|
121
|
-
signature = xtraceoptions&.signature
|
122
|
-
timestamp = xtraceoptions&.timestamp
|
123
|
-
|
124
|
-
SolarWindsAPM.logger.debug do
|
125
|
-
"[#{self.class}/#{__method__}] get liboboe decision parameters: \n
|
126
|
-
tracestring: #{tracestring}\n
|
127
|
-
sw_member_value: #{sw_member_value}\n
|
128
|
-
tracing_mode: #{tracing_mode}\n
|
129
|
-
sample_rate: #{sample_rate}\n
|
130
|
-
trigger_trace: #{trigger_trace}\n
|
131
|
-
trigger_trace_mode: #{trigger_trace_mode}\n
|
132
|
-
options: #{options}\n
|
133
|
-
signature: #{signature}\n
|
134
|
-
timestamp: #{timestamp}"
|
135
|
-
end
|
136
|
-
|
137
|
-
args = [tracestring, sw_member_value, tracing_mode, sample_rate,
|
138
|
-
trigger_trace, trigger_trace_mode, options, signature, timestamp]
|
139
|
-
|
140
|
-
if SolarWindsAPM::OboeInitOptions.instance.lambda_env
|
141
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] get decision from oboe_api" }
|
142
|
-
# trigger trace disabled at this point (https://swicloud.atlassian.net/wiki/spaces/NIT/pages/3753116438/AWS+Lambda+Instrumentation+POC#Concerns)
|
143
|
-
do_metrics, do_sample, rate, source, bucket_rate,
|
144
|
-
bucket_cap, decision_type, auth, status_msg, auth_msg,
|
145
|
-
status = SolarWindsAPM.oboe_api.getTracingDecision(*args)
|
146
|
-
else
|
147
|
-
do_metrics, do_sample, rate, source, bucket_rate,
|
148
|
-
bucket_cap, decision_type, auth, status_msg, auth_msg,
|
149
|
-
status = SolarWindsAPM::Context.getDecisions(*args)
|
150
|
-
end
|
151
|
-
|
152
|
-
{
|
153
|
-
'do_metrics' => do_metrics.positive?,
|
154
|
-
'do_sample' => do_sample.positive?,
|
155
|
-
'rate' => rate,
|
156
|
-
'source' => source,
|
157
|
-
'bucket_rate' => bucket_rate,
|
158
|
-
'bucket_cap' => bucket_cap,
|
159
|
-
'decision_type' => decision_type,
|
160
|
-
'auth' => auth,
|
161
|
-
'status_msg' => status_msg,
|
162
|
-
'auth_msg' => auth_msg,
|
163
|
-
'status' => status
|
164
|
-
}
|
165
|
-
end
|
166
|
-
|
167
|
-
def otel_decision_from_liboboe(liboboe_decision)
|
168
|
-
decision = ::OpenTelemetry::SDK::Trace::Samplers::Decision::DROP
|
169
|
-
if liboboe_decision['do_sample']
|
170
|
-
decision = ::OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD_AND_SAMPLE # even if not do_metrics
|
171
|
-
elsif liboboe_decision['do_metrics']
|
172
|
-
decision = ::OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD_ONLY
|
173
|
-
end
|
174
|
-
SolarWindsAPM.logger.debug { "otel decision: #{decision} created from liboboe_decision: #{liboboe_decision}" }
|
175
|
-
decision
|
176
|
-
end
|
177
|
-
|
178
|
-
##
|
179
|
-
# add sw=value and xtrace_options_response=value into the old/new tracestate
|
180
|
-
# the returned value tracestate will be used in propagating to next services
|
181
|
-
def calculate_trace_state(liboboe_decision, parent_span_context, xtraceoptions)
|
182
|
-
if !parent_span_context.valid? || parent_span_context.tracestate.nil?
|
183
|
-
trace_state = create_new_trace_state(parent_span_context, liboboe_decision)
|
184
|
-
else
|
185
|
-
trace_state = parent_span_context.tracestate.set_value(SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY,
|
186
|
-
sw_from_span_and_decision(parent_span_context,
|
187
|
-
liboboe_decision))
|
188
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] updated trace_state: #{trace_state.inspect}" }
|
189
|
-
end
|
190
|
-
|
191
|
-
# for setting up the xtrace_options_response
|
192
|
-
if xtraceoptions&.options
|
193
|
-
trace_state = trace_state.set_value(XTraceOptions.sw_xtraceoptions_response_key.to_s,
|
194
|
-
create_xtraceoptions_response_value(liboboe_decision,
|
195
|
-
parent_span_context, xtraceoptions))
|
196
|
-
end
|
197
|
-
trace_state
|
198
|
-
end
|
199
|
-
|
200
|
-
##
|
201
|
-
#
|
202
|
-
def create_new_trace_state(parent_span_context, liboboe_decision)
|
203
|
-
decision = sw_from_span_and_decision(parent_span_context, liboboe_decision)
|
204
|
-
trace_state = ::OpenTelemetry::Trace::Tracestate.from_hash({ SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY => decision }) # e.g. sw=3e222c863a04123a-01
|
205
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] created new trace_state: #{trace_state.inspect}" }
|
206
|
-
trace_state
|
207
|
-
end
|
208
|
-
|
209
|
-
##
|
210
|
-
#
|
211
|
-
def create_xtraceoptions_response_value(liboboe_decision, parent_span_context, xtraceoptions)
|
212
|
-
response = []
|
213
|
-
w3c_sanitized = SolarWindsAPM::Constants::INTL_SWO_EQUALS_W3C_SANITIZED
|
214
|
-
w3c_sanitized_comma = SolarWindsAPM::Constants::INTL_SWO_COMMA_W3C_SANITIZED
|
215
|
-
if xtraceoptions.signature && liboboe_decision['auth_msg']
|
216
|
-
response << [XTRACEOPTIONS_RESP_AUTH,
|
217
|
-
liboboe_decision['auth_msg']].join(w3c_sanitized)
|
218
|
-
end
|
219
|
-
|
220
|
-
if !liboboe_decision['auth'] || liboboe_decision['auth'] < 1
|
221
|
-
if xtraceoptions.trigger_trace
|
222
|
-
# If a traceparent header was provided then oboe does not generate the message
|
223
|
-
tracestring = Utils.traceparent_from_context(parent_span_context) if parent_span_context.valid? && parent_span_context.remote?
|
224
|
-
trigger_msg = tracestring && (liboboe_decision['decision_type']).zero? ? XTRACEOPTIONS_RESP_TRIGGER_IGNORED : liboboe_decision['status_msg']
|
225
|
-
SolarWindsAPM.logger.debug do
|
226
|
-
"[#{self.class}/#{__method__}] tracestring: #{tracestring}; trigger_msg: #{trigger_msg}"
|
227
|
-
end
|
228
|
-
else
|
229
|
-
trigger_msg = XTRACEOPTIONS_RESP_TRIGGER_NOT_REQUESTED
|
230
|
-
end
|
231
|
-
|
232
|
-
response << [XTRACEOPTIONS_RESP_TRIGGER_TRACE, trigger_msg].join(w3c_sanitized) # e.g. response << trigger-trace####ok
|
233
|
-
end
|
234
|
-
|
235
|
-
# appending ignored value from xtraceoptions to response. e.g. response << ignored####invalidkeys,invalidkeys,invalidkeys
|
236
|
-
unless xtraceoptions.ignored.empty?
|
237
|
-
response << [XTRACEOPTIONS_RESP_IGNORED,
|
238
|
-
xtraceoptions.ignored.join(w3c_sanitized_comma)].join(w3c_sanitized)
|
239
|
-
end
|
240
|
-
joined_response = response.join(';')
|
241
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] final response_value: #{joined_response}" }
|
242
|
-
joined_response
|
243
|
-
end
|
244
|
-
|
245
|
-
##
|
246
|
-
# calculate_attributes is used for getting the otel Result class in last step of sampler should_sample?
|
247
|
-
# e.g. result = Result.new(decision: otel_decision, attributes: new_attributes, tracestate: new_trace_state)
|
248
|
-
# calculate_attributes use new_trace_state that is derived from current span information and old tracestate from parent_span_context.tracestate
|
249
|
-
# the sw.w3c.tracestate should perserve the old tracestate value for debugging purpose
|
250
|
-
def calculate_attributes(attributes, liboboe_decision, trace_state, parent_span_context, xtraceoptions)
|
251
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] new_trace_state: #{trace_state.inspect}" }
|
252
|
-
new_attributes = attributes.dup || {}
|
253
|
-
|
254
|
-
# Always (root or is_remote) set _INTERNAL_SW_KEYS if injected
|
255
|
-
new_attributes[INTERNAL_SW_KEYS] = xtraceoptions.sw_keys if xtraceoptions.sw_keys
|
256
|
-
|
257
|
-
# Always (root or is_remote) set custom KVs if extracted from x-trace-options
|
258
|
-
xtraceoptions.custom_kvs&.each { |k, v| new_attributes[k] = v }
|
259
|
-
|
260
|
-
# Always (root or is_remote) set service entry internal KVs
|
261
|
-
new_attributes[INTERNAL_BUCKET_CAPACITY] = liboboe_decision['bucket_cap'].to_s
|
262
|
-
new_attributes[INTERNAL_BUCKET_RATE] = liboboe_decision['bucket_rate'].to_s
|
263
|
-
new_attributes[INTERNAL_SAMPLE_RATE] = liboboe_decision['rate']
|
264
|
-
new_attributes[INTERNAL_SAMPLE_SOURCE] = liboboe_decision['source']
|
265
|
-
|
266
|
-
# set sw.tracestate_parent_id if its tracestate contains "sw"
|
267
|
-
sw_value = parent_span_context.tracestate.value(SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY)
|
268
|
-
new_attributes[SW_TRACESTATE_ROOT_KEY] = sw_value.split('-')[0] if sw_value && parent_span_context.remote?
|
269
|
-
|
270
|
-
# If unsigned or signed TT (root or is_remote), set TriggeredTrace
|
271
|
-
new_attributes[SolarWindsAPM::Constants::INTERNAL_TRIGGERED_TRACE] = true if xtraceoptions.trigger_trace
|
272
|
-
|
273
|
-
# Trace's root span has no valid traceparent nor tracestate so we can't calculate remaining attributes
|
274
|
-
if !parent_span_context.valid? || trace_state.nil?
|
275
|
-
SolarWindsAPM.logger.debug do
|
276
|
-
"[#{self.class}/#{__method__}] No valid traceparent or no tracestate - returning attributes: #{new_attributes}"
|
277
|
-
end
|
278
|
-
return new_attributes.freeze || nil
|
279
|
-
end
|
280
|
-
|
281
|
-
new_attributes = add_tracestate_capture_to_new_attributes(new_attributes, liboboe_decision, trace_state,
|
282
|
-
parent_span_context)
|
283
|
-
new_attributes.freeze
|
284
|
-
end
|
285
|
-
|
286
|
-
##
|
287
|
-
#
|
288
|
-
def add_tracestate_capture_to_new_attributes(new_attributes, liboboe_decision, trace_state, parent_span_context)
|
289
|
-
tracestate_capture = new_attributes[SW_TRACESTATE_CAPTURE_KEY]
|
290
|
-
SolarWindsAPM.logger.debug do
|
291
|
-
"[#{self.class}/#{__method__}] tracestate_capture #{tracestate_capture.inspect}; new_attributes #{new_attributes.inspect}"
|
292
|
-
end
|
293
|
-
|
294
|
-
if tracestate_capture.nil?
|
295
|
-
trace_state_no_response = trace_state.delete(XTraceOptions.sw_xtraceoptions_response_key)
|
296
|
-
else
|
297
|
-
# retain all potential tracestate pairs for attributes and generate new sw=key for tracestate based on root parent_span_id
|
298
|
-
attr_trace_state = ::OpenTelemetry::Trace::Tracestate.from_string(tracestate_capture)
|
299
|
-
new_attr_trace_state = attr_trace_state.set_value(SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY,
|
300
|
-
sw_from_span_and_decision(parent_span_context,
|
301
|
-
liboboe_decision))
|
302
|
-
trace_state_no_response = new_attr_trace_state.delete(XTraceOptions.sw_xtraceoptions_response_key)
|
303
|
-
end
|
304
|
-
SolarWindsAPM.logger.debug do
|
305
|
-
"[#{self.class}/#{__method__}] trace_state_no_response #{trace_state_no_response.inspect}"
|
306
|
-
end
|
307
|
-
|
308
|
-
trace_state_no_response = parent_span_context.tracestate.delete(XTraceOptions.sw_xtraceoptions_response_key)
|
309
|
-
no_sw_count = trace_state_no_response.to_h.count { |k, _v| k != 'sw' }
|
310
|
-
|
311
|
-
if no_sw_count.positive?
|
312
|
-
new_attributes[SW_TRACESTATE_CAPTURE_KEY] =
|
313
|
-
Utils.trace_state_header(trace_state_no_response)
|
314
|
-
end
|
315
|
-
SolarWindsAPM.logger.debug do
|
316
|
-
"[#{self.class}/#{__method__}] new_attributes after add_tracestate_capture_to_new_attributes: #{new_attributes.inspect}"
|
317
|
-
end
|
318
|
-
|
319
|
-
new_attributes
|
320
|
-
end
|
321
|
-
|
322
|
-
# formats tracestate sw value from span_id and liboboe decision as 16-byte span_id with 8-bit trace_flags e.g. 1a2b3c4d5e6f7g8h-01
|
323
|
-
def sw_from_span_and_decision(parent_span_context, liboboe_decision)
|
324
|
-
trace_flag = liboboe_decision['do_sample'] == true ? '01' : '00'
|
325
|
-
[parent_span_context.hex_span_id, trace_flag].join('-')
|
326
|
-
end
|
327
|
-
|
328
|
-
def otel_sampled?(otel_decision)
|
329
|
-
otel_decision == ::OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD_AND_SAMPLE
|
330
|
-
end
|
331
|
-
end
|
332
|
-
end
|
333
|
-
end
|
@@ -1,174 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# © 2023 SolarWinds Worldwide, LLC. All rights reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:http://www.apache.org/licenses/LICENSE-2.0
|
6
|
-
#
|
7
|
-
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
8
|
-
|
9
|
-
module SolarWindsAPM
|
10
|
-
# OTelConfig module
|
11
|
-
# For configure otel component: configurable: propagator, exporter
|
12
|
-
# non-config: sampler, processor, response_propagator
|
13
|
-
# Level of this configuration: SolarWindsOTel::Config -> OboeOption -> SolarWindsOTel::OTelConfig
|
14
|
-
module OTelConfig
|
15
|
-
@@config = {}
|
16
|
-
@@config_map = {}
|
17
|
-
|
18
|
-
@@agent_enabled = true
|
19
|
-
|
20
|
-
def self.disable_agent(reason: nil)
|
21
|
-
return unless @@agent_enabled # only show the msg once
|
22
|
-
|
23
|
-
@@agent_enabled = false
|
24
|
-
SolarWindsAPM.logger.warn { "[#{name}/#{__method__}] SolarWindsAPM disabled. No Trace exported. Reason: #{reason}" }
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.resolve_sampler
|
28
|
-
sampler_config = { 'trigger_trace' => SolarWindsAPM::Config[:trigger_tracing_mode] }
|
29
|
-
@@config[:sampler] =
|
30
|
-
::OpenTelemetry::SDK::Trace::Samplers.parent_based(
|
31
|
-
root: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(sampler_config),
|
32
|
-
remote_parent_sampled: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(sampler_config),
|
33
|
-
remote_parent_not_sampled: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(sampler_config)
|
34
|
-
)
|
35
|
-
end
|
36
|
-
|
37
|
-
#
|
38
|
-
# append/add solarwinds_response_propagator into rack instrumentation
|
39
|
-
#
|
40
|
-
def self.resolve_response_propagator
|
41
|
-
response_propagator = SolarWindsAPM::OpenTelemetry::SolarWindsResponsePropagator::TextMapPropagator.new
|
42
|
-
rack_setting = @@config_map['OpenTelemetry::Instrumentation::Rack']
|
43
|
-
|
44
|
-
if rack_setting
|
45
|
-
if rack_setting[:response_propagators].instance_of?(Array)
|
46
|
-
rack_setting[:response_propagators].append(response_propagator)
|
47
|
-
elsif rack_setting[:response_propagators].nil?
|
48
|
-
rack_setting[:response_propagators] = [response_propagator]
|
49
|
-
else
|
50
|
-
SolarWindsAPM.logger.warn do
|
51
|
-
"[#{name}/#{__method__}] Rack response propagator resolve failed. Provided type #{rack_setting[:response_propagators].class}, please provide Array e.g. [#{rack_setting[:response_propagators]}]"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
else
|
55
|
-
@@config_map['OpenTelemetry::Instrumentation::Rack'] = { response_propagators: [response_propagator] }
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.[](key)
|
60
|
-
@@config[key.to_sym]
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.print_config
|
64
|
-
@@config.each do |k, v|
|
65
|
-
SolarWindsAPM.logger.debug { "[#{name}/#{__method__}] Config Key/Value: #{k}, #{v.class}" }
|
66
|
-
end
|
67
|
-
@@config_map.each do |k, v|
|
68
|
-
SolarWindsAPM.logger.debug { "[#{name}/#{__method__}] Config Key/Value: #{k}, #{v}" }
|
69
|
-
end
|
70
|
-
nil
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.resolve_solarwinds_processor
|
74
|
-
txn_manager = SolarWindsAPM::TxnNameManager.new
|
75
|
-
exporter = SolarWindsAPM::OpenTelemetry::SolarWindsExporter.new(txn_manager: txn_manager)
|
76
|
-
@@config[:metrics_processor] = SolarWindsAPM::OpenTelemetry::SolarWindsProcessor.new(txn_manager)
|
77
|
-
@@config[:span_processor] = ::OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(exporter)
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.resolve_solarwinds_propagator
|
81
|
-
@@config[:propagators] = SolarWindsAPM::OpenTelemetry::SolarWindsPropagator::TextMapPropagator.new
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.validate_propagator(propagators)
|
85
|
-
if propagators.nil?
|
86
|
-
disable_agent(reason: 'propagators are invaliad.')
|
87
|
-
return
|
88
|
-
end
|
89
|
-
|
90
|
-
SolarWindsAPM.logger.debug { "[#{name}/#{__method__}] propagators: #{propagators.map(&:class)}" }
|
91
|
-
disable_agent(reason: 'Missing tracecontext propagator.') unless ([::OpenTelemetry::Trace::Propagation::TraceContext::TextMapPropagator, ::OpenTelemetry::Baggage::Propagation::TextMapPropagator] - propagators.map(&:class)).empty?
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.initialize
|
95
|
-
unless defined?(::OpenTelemetry::SDK::Configurator)
|
96
|
-
disable_agent(reason: 'missing OpenTelemetry::SDK::Configurator; opentelemetry seems not loaded.')
|
97
|
-
return
|
98
|
-
end
|
99
|
-
|
100
|
-
resolve_sampler
|
101
|
-
resolve_solarwinds_propagator
|
102
|
-
resolve_solarwinds_processor
|
103
|
-
resolve_response_propagator
|
104
|
-
|
105
|
-
print_config if SolarWindsAPM.logger.level.zero?
|
106
|
-
|
107
|
-
# resolve OTEL environmental variables
|
108
|
-
ENV['OTEL_TRACES_EXPORTER'] = 'none' if ENV['OTEL_TRACES_EXPORTER'].to_s.empty?
|
109
|
-
if ENV['OTEL_LOG_LEVEL'].to_s.empty?
|
110
|
-
log_level = (ENV['SW_APM_DEBUG_LEVEL'] || SolarWindsAPM::Config[:debug_level] || 3).to_i
|
111
|
-
ENV['OTEL_LOG_LEVEL'] = SolarWindsAPM::Config::SW_LOG_LEVEL_MAPPING.dig(log_level, :otel)
|
112
|
-
end
|
113
|
-
|
114
|
-
# for dbo, traceparent injection as comments
|
115
|
-
require_relative 'patch/tag_sql_patch' if SolarWindsAPM::Config[:tag_sql]
|
116
|
-
|
117
|
-
::OpenTelemetry::SDK.configure { |c| c.use_all(@@config_map) }
|
118
|
-
|
119
|
-
validate_propagator(::OpenTelemetry.propagation.instance_variable_get(:@propagators))
|
120
|
-
|
121
|
-
return unless @@agent_enabled
|
122
|
-
|
123
|
-
# append our propagators
|
124
|
-
::OpenTelemetry.propagation.instance_variable_get(:@propagators).append(@@config[:propagators])
|
125
|
-
|
126
|
-
# append our processors (with our exporter)
|
127
|
-
::OpenTelemetry.tracer_provider.add_span_processor(@@config[:metrics_processor])
|
128
|
-
::OpenTelemetry.tracer_provider.add_span_processor(@@config[:span_processor])
|
129
|
-
|
130
|
-
# configure sampler afterwards
|
131
|
-
::OpenTelemetry.tracer_provider.sampler = @@config[:sampler]
|
132
|
-
|
133
|
-
if ENV['SW_APM_AUTO_CONFIGURE'] == 'false'
|
134
|
-
SolarWindsAPM.logger.info '==================================================================='
|
135
|
-
SolarWindsAPM.logger.info "\e[1mSolarWindsAPM manual initialization was successful.\e[0m"
|
136
|
-
SolarWindsAPM.logger.info '==================================================================='
|
137
|
-
end
|
138
|
-
|
139
|
-
nil
|
140
|
-
end
|
141
|
-
|
142
|
-
#
|
143
|
-
# Allow initialize after set new value to SolarWindsAPM::Config[:key]=value
|
144
|
-
#
|
145
|
-
# Usage:
|
146
|
-
#
|
147
|
-
# Default using the use_all to load all instrumentation
|
148
|
-
# But with specific instrumentation disabled, use {:enabled: false} in config
|
149
|
-
# SolarWindsAPM::OTelConfig.initialize_with_config do |config|
|
150
|
-
# config["OpenTelemetry::Instrumentation::Rack"] = {"a" => "b"}
|
151
|
-
# config["OpenTelemetry::Instrumentation::Dalli"] = {:enabled: false}
|
152
|
-
# end
|
153
|
-
#
|
154
|
-
def self.initialize_with_config
|
155
|
-
unless block_given?
|
156
|
-
SolarWindsAPM.logger.warn do
|
157
|
-
"[#{name}/#{__method__}] Block not given while doing in-code configuration. Agent disabled."
|
158
|
-
end
|
159
|
-
return
|
160
|
-
end
|
161
|
-
|
162
|
-
yield @@config_map
|
163
|
-
|
164
|
-
if @@config_map.empty?
|
165
|
-
SolarWindsAPM.logger.warn do
|
166
|
-
"[#{name}/#{__method__}] No configuration given for in-code configuration. Agent disabled."
|
167
|
-
end
|
168
|
-
return
|
169
|
-
end
|
170
|
-
|
171
|
-
initialize
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# © 2023 SolarWinds Worldwide, LLC. All rights reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:http://www.apache.org/licenses/LICENSE-2.0
|
6
|
-
#
|
7
|
-
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
8
|
-
|
9
|
-
require 'solarwinds_apm/constants'
|
10
|
-
require 'solarwinds_apm/api'
|
11
|
-
require 'solarwinds_apm/support'
|
12
|
-
require 'solarwinds_apm/opentelemetry'
|
13
|
-
|
14
|
-
module SolarWindsAPM
|
15
|
-
# OTelLambdaConfig module
|
16
|
-
module OTelLambdaConfig
|
17
|
-
def self.initialize
|
18
|
-
return unless defined?(::OpenTelemetry::SDK::Configurator)
|
19
|
-
|
20
|
-
if ENV['OTEL_TRACES_EXPORTER'].to_s.empty?
|
21
|
-
ENV['OTEL_TRACES_EXPORTER'] = 'otlp'
|
22
|
-
elsif !ENV['OTEL_TRACES_EXPORTER'].include? 'otlp'
|
23
|
-
ENV['OTEL_TRACES_EXPORTER'] += ',otlp'
|
24
|
-
end
|
25
|
-
|
26
|
-
ENV['OTEL_RESOURCE_ATTRIBUTES'] = "sw.apm.version=#{SolarWindsAPM::Version::STRING},sw.data.module=apm,service.name=#{ENV['OTEL_SERVICE_NAME'] || ENV.fetch('AWS_LAMBDA_FUNCTION_NAME', nil)}," + ENV['OTEL_RESOURCE_ATTRIBUTES'].to_s
|
27
|
-
::OpenTelemetry::SDK.configure(&:use_all)
|
28
|
-
|
29
|
-
# append our propagators
|
30
|
-
::OpenTelemetry.propagation.instance_variable_get(:@propagators).append(SolarWindsAPM::OpenTelemetry::SolarWindsPropagator::TextMapPropagator.new)
|
31
|
-
|
32
|
-
# register metrics_exporter to meter_provider
|
33
|
-
::OpenTelemetry.meter_provider.add_metric_reader(::OpenTelemetry::Exporter::OTLP::Metrics::MetricsExporter.new)
|
34
|
-
|
35
|
-
# append our processors
|
36
|
-
::OpenTelemetry.tracer_provider.add_span_processor(SolarWindsAPM::OpenTelemetry::OTLPProcessor.new)
|
37
|
-
|
38
|
-
# configure sampler afterwards
|
39
|
-
::OpenTelemetry.tracer_provider.sampler = ::OpenTelemetry::SDK::Trace::Samplers.parent_based(
|
40
|
-
root: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new,
|
41
|
-
remote_parent_sampled: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new,
|
42
|
-
remote_parent_not_sampled: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new
|
43
|
-
)
|
44
|
-
|
45
|
-
SolarWindsAPM.logger.info do
|
46
|
-
"[#{name}/#{__method__}] SolarWindsAPM lambda configuration initialized \
|
47
|
-
\n Installed instrumentation: #{::OpenTelemetry.tracer_provider.instance_variable_get(:@registry).keys} \
|
48
|
-
\n SpanProcessor: #{::OpenTelemetry.tracer_provider.instance_variable_get(:@span_processors).map(&:class)} \
|
49
|
-
\n Sampler: #{::OpenTelemetry.tracer_provider.instance_variable_get(:@sampler).inspect} \
|
50
|
-
\n Resource: #{::OpenTelemetry.tracer_provider.instance_variable_get(:@resource).inspect}"
|
51
|
-
end
|
52
|
-
|
53
|
-
nil
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# © 2023 SolarWinds Worldwide, LLC. All rights reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:http://www.apache.org/licenses/LICENSE-2.0
|
6
|
-
#
|
7
|
-
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
8
|
-
|
9
|
-
module SolarWindsAPM
|
10
|
-
# OboeTracingMode
|
11
|
-
# Used in solarwinds_sampler
|
12
|
-
class OboeTracingMode
|
13
|
-
OBOE_SETTINGS_UNSET = -1
|
14
|
-
OBOE_TRACE_DISABLED = 0
|
15
|
-
OBOE_TRACE_ENABLED = 1
|
16
|
-
OBOE_TRIGGER_DISABLED = 0
|
17
|
-
OBOE_TRIGGER_ENABLED = 1
|
18
|
-
|
19
|
-
def self.get_oboe_trace_mode(tracing_mode)
|
20
|
-
mode = OBOE_SETTINGS_UNSET
|
21
|
-
mode = OBOE_TRACE_ENABLED if tracing_mode == :enabled
|
22
|
-
mode = OBOE_TRACE_DISABLED if tracing_mode == :disabled
|
23
|
-
mode
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.get_oboe_trigger_trace_mode(trigger_trace_mode)
|
27
|
-
mode = OBOE_SETTINGS_UNSET
|
28
|
-
mode = OBOE_TRIGGER_ENABLED if trigger_trace_mode == :enabled
|
29
|
-
mode = OBOE_TRIGGER_DISABLED if trigger_trace_mode == :disabled
|
30
|
-
mode
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|