solarwinds_apm 6.1.2 → 7.0.0.prev1
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 +4 -2
- 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 +1 -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 +90 -69
- 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 +177 -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/{noop/span.rb → support/aws_resource_detector.rb} +5 -18
- 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/aws/beanstalk.rb +51 -0
- data/lib/solarwinds_apm/support/resource_detector/aws/ec2.rb +145 -0
- data/lib/solarwinds_apm/support/resource_detector/aws/ecs.rb +173 -0
- data/lib/solarwinds_apm/support/resource_detector/aws/eks.rb +174 -0
- data/lib/solarwinds_apm/support/resource_detector/aws/lambda.rb +66 -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 +3 -4
- data/lib/solarwinds_apm/version.rb +4 -4
- data/lib/solarwinds_apm.rb +27 -73
- metadata +99 -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/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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d66514bebfccf2f3c5a2b2e6924fe7fc7abe6a33fa90ce2dcc94de968e64018
|
4
|
+
data.tar.gz: 55cd6df597c8db22130b6322ede1deae4911c1409674734cb11ccf9223734dcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa5dd5bb46399211d816833f257b69fec64a325cb6ee3c256d612d64be0e4cb50e5b1e195025afad69dee4d5c79726d9e5b6ff8f5a25d952724b01521e8d9331
|
7
|
+
data.tar.gz: 6b9e3f5bc1e8e35b419d9a2c04c43bca23268ea9fed3832368d5f0c708925abd1e46d9f2e215833fae5e6154fa77c7ec696e3819a0ff37188c1c407aa4965522
|
data/README.md
CHANGED
@@ -89,6 +89,7 @@ add_tracer :method_name, 'custom_span_name', { attributes: { 'any' => 'attribute
|
|
89
89
|
For example, if you want to instrument class or instance method `create_session` inside an application controller:
|
90
90
|
|
91
91
|
To instrument instance method
|
92
|
+
|
92
93
|
```ruby
|
93
94
|
class SessionsController < ApplicationController
|
94
95
|
include SolarWindsAPM::API::Tracer
|
@@ -107,6 +108,7 @@ end
|
|
107
108
|
```
|
108
109
|
|
109
110
|
To instrument class method
|
111
|
+
|
110
112
|
```ruby
|
111
113
|
class SessionsController < ApplicationController
|
112
114
|
def create
|
@@ -142,10 +144,10 @@ trace.trace_flags # 01
|
|
142
144
|
|
143
145
|
On startup, this library initializes and maintains a connection to a SolarWinds Observability collector, and receives settings used for making tracing decisions. This process can take up to a few seconds depending on the connection. If the application receives requests before initialization has completed, these requests will not be traced. While this is not critical for long-running server processes, it might be a problem for short-running apps such as cron jobs or CLI apps.
|
144
146
|
|
145
|
-
A call to the `solarwinds_ready
|
147
|
+
A call to the `solarwinds_ready?` method allows the application to block until initialization has completed and the library is ready for tracing. The method accepts an optional timeout parameter in milliseconds.
|
146
148
|
|
147
149
|
```ruby
|
148
|
-
SolarWindsAPM::API.solarwinds_ready(wait_milliseconds=3000)
|
150
|
+
SolarWindsAPM::API.solarwinds_ready?(wait_milliseconds=3000)
|
149
151
|
```
|
150
152
|
|
151
153
|
#### Set a Custom Transaction Name
|
@@ -111,12 +111,16 @@ module SolarWindsAPM
|
|
111
111
|
private
|
112
112
|
|
113
113
|
def current_span
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
114
|
+
if defined?(::OpenTelemetry::Trace)
|
115
|
+
span = ::OpenTelemetry::Trace.current_span
|
116
|
+
trace_id = span.context.hex_trace_id
|
117
|
+
span_id = span.context.hex_span_id
|
118
|
+
trace_flags = span.context.trace_flags.sampled? ? '01' : '00'
|
119
|
+
tracestring = "00-#{trace_id}-#{span_id}-#{trace_flags}"
|
120
|
+
[trace_id, span_id, trace_flags, tracestring]
|
121
|
+
else
|
122
|
+
%w[00000000000000000000000000000000 00000000 00 00-00000000000000000000000000000000-00000000-00]
|
123
|
+
end
|
120
124
|
end
|
121
125
|
|
122
126
|
# if true the trace info should be added to the log message
|
@@ -32,12 +32,9 @@ module SolarWindsAPM
|
|
32
32
|
# === Returns:
|
33
33
|
# * Boolean
|
34
34
|
#
|
35
|
-
def increment_metric(
|
36
|
-
|
37
|
-
|
38
|
-
with_hostname = with_hostname ? 1 : 0
|
39
|
-
tags, tags_count = make_tags(tags_kvs)
|
40
|
-
SolarWindsAPM::CustomMetrics.increment(name.to_s, count, with_hostname, nil, tags, tags_count).zero?
|
35
|
+
def increment_metric(_name, _count = 1, _with_hostname = false, _tags_kvs = {}) # rubocop:disable Style/OptionalBooleanParameter
|
36
|
+
SolarWindsAPM.logger.warn { 'increment_metric have been deprecated. Please use opentelemetry metrics-sdk to log metrics data.' }
|
37
|
+
false
|
41
38
|
end
|
42
39
|
|
43
40
|
# Send values with counts
|
@@ -66,29 +63,15 @@ module SolarWindsAPM
|
|
66
63
|
# === Returns:
|
67
64
|
# * Boolean
|
68
65
|
#
|
69
|
-
def summary_metric(
|
70
|
-
|
71
|
-
|
72
|
-
with_hostname = with_hostname ? 1 : 0
|
73
|
-
tags, tags_count = make_tags(tags_kvs)
|
74
|
-
SolarWindsAPM::CustomMetrics.summary(name.to_s, value, count, with_hostname, nil, tags, tags_count).zero?
|
66
|
+
def summary_metric(_name, _value, _count = 1, _with_hostname = false, _tags_kvs = {}) # rubocop:disable Style/OptionalBooleanParameter
|
67
|
+
SolarWindsAPM.logger.warn { 'summary_metric have been deprecated. Please use opentelemetry metrics-sdk to log metrics data.' }
|
68
|
+
false
|
75
69
|
end
|
76
70
|
|
77
71
|
private
|
78
72
|
|
79
|
-
def make_tags(
|
80
|
-
|
81
|
-
SolarWindsAPM.logger.warn("[solarwinds_apm/metrics] CustomMetrics received tags_kvs that are not a Hash (found #{tags_kvs.class}), setting tags_kvs = {}")
|
82
|
-
tags_kvs = {}
|
83
|
-
end
|
84
|
-
count = tags_kvs.size
|
85
|
-
tags = SolarWindsAPM::MetricTags.new(count)
|
86
|
-
|
87
|
-
tags_kvs.each_with_index do |(k, v), i|
|
88
|
-
tags.add(i, k.to_s, v.to_s)
|
89
|
-
end
|
90
|
-
|
91
|
-
[tags, count]
|
73
|
+
def make_tags(_tags_kvs)
|
74
|
+
nil
|
92
75
|
end
|
93
76
|
end
|
94
77
|
end
|
@@ -12,22 +12,12 @@ module SolarWindsAPM
|
|
12
12
|
# Wait for SolarWinds to be ready to send traces.
|
13
13
|
#
|
14
14
|
# This may be useful in short lived background processes when it is important to capture
|
15
|
-
# information during the whole time the process is running.
|
16
|
-
# and it will return integer if setting <tt>integer_response</tt> as true.
|
15
|
+
# information during the whole time the process is running.
|
17
16
|
# Usually SolarWinds doesn't block an application while it is starting up.
|
18
17
|
#
|
19
|
-
# For status code reference:
|
20
|
-
# 0: unknown error
|
21
|
-
# 1: is ready
|
22
|
-
# 2: not ready yet, try later
|
23
|
-
# 3: limit exceeded
|
24
|
-
# 4: invalid API key
|
25
|
-
# 5: connection error
|
26
|
-
#
|
27
18
|
# === Argument:
|
28
19
|
#
|
29
20
|
# * +wait_milliseconds+ - (int, default 3000) the maximum time to wait in milliseconds
|
30
|
-
# * +integer_response+ - (boolean, default false) determine whether return status code of reporter or not
|
31
21
|
#
|
32
22
|
# === Example:
|
33
23
|
#
|
@@ -35,24 +25,19 @@ module SolarWindsAPM
|
|
35
25
|
# Logger.info "SolarWindsAPM not ready after 10 seconds, no metrics will be sent"
|
36
26
|
# end
|
37
27
|
#
|
38
|
-
# # with status code print out
|
39
|
-
# status = SolarWindsAPM::API.solarwinds_ready?(10_000, integer_response: true)
|
40
|
-
# unless status == 1
|
41
|
-
# Logger.info "SolarWindsAPM not ready after 10 seconds, no metrics will be sent. Error code "#{status}"
|
42
|
-
# end
|
43
|
-
#
|
44
28
|
# === Returns:
|
45
|
-
# * Boolean
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
return is_ready if integer_response
|
29
|
+
# * Boolean
|
30
|
+
#
|
31
|
+
def solarwinds_ready?(wait_milliseconds = 3000, integer_response: nil)
|
32
|
+
unless integer_response.nil?
|
33
|
+
SolarWindsAPM.logger.warn do
|
34
|
+
'Deprecation: solarwinds_ready? no longer accepts integer_response, this parameter will be removed in the next release.'
|
35
|
+
end
|
36
|
+
end
|
54
37
|
|
55
|
-
|
38
|
+
root_sampler = ::OpenTelemetry.tracer_provider.sampler.instance_variable_get(:@root)
|
39
|
+
is_ready = root_sampler.wait_until_ready(wait_milliseconds / 1000)
|
40
|
+
!!is_ready
|
56
41
|
end
|
57
42
|
end
|
58
43
|
end
|
@@ -39,23 +39,19 @@ module SolarWindsAPM
|
|
39
39
|
#
|
40
40
|
def set_transaction_name(custom_name = nil)
|
41
41
|
status = true
|
42
|
-
if ENV.fetch('SW_APM_ENABLED', 'true') == 'false'
|
43
|
-
SolarWindsAPM::Context.toString == '99-00000000000000000000000000000000-0000000000000000-00'
|
44
|
-
# library disabled or noop, just log and skip work.
|
45
|
-
# TODO: can we have a single indicator that the API is in noop mode?
|
42
|
+
if ENV.fetch('SW_APM_ENABLED', 'true') == 'false'
|
46
43
|
SolarWindsAPM.logger.debug { "[#{name}/#{__method__}] SolarWindsAPM is in disabled or noop mode." }
|
47
|
-
elsif
|
44
|
+
elsif SolarWindsAPM::OTelNativeConfig[:metrics_processor].nil?
|
48
45
|
SolarWindsAPM.logger.warn do
|
49
|
-
"[#{name}/#{__method__}] Set transaction name failed:
|
46
|
+
"[#{name}/#{__method__}] Set transaction name failed: Solarwinds processor is missing. Noop mode."
|
50
47
|
end
|
51
|
-
|
52
|
-
elsif SolarWindsAPM::OTelConfig[:metrics_processor].nil?
|
48
|
+
elsif custom_name.nil? || custom_name.empty?
|
53
49
|
SolarWindsAPM.logger.warn do
|
54
|
-
"[#{name}/#{__method__}] Set transaction name failed:
|
50
|
+
"[#{name}/#{__method__}] Set transaction name failed: custom_name is either nil or empty string."
|
55
51
|
end
|
56
52
|
status = false
|
57
53
|
else
|
58
|
-
solarwinds_processor = SolarWindsAPM::
|
54
|
+
solarwinds_processor = SolarWindsAPM::OTelNativeConfig[:metrics_processor]
|
59
55
|
current_span = ::OpenTelemetry::Trace.current_span
|
60
56
|
|
61
57
|
if current_span.context.valid?
|
@@ -212,7 +212,7 @@ module SolarWindsAPM
|
|
212
212
|
|
213
213
|
# Assure value is an integer
|
214
214
|
@@config[key.to_sym] = new_value.to_i
|
215
|
-
SolarWindsAPM.sample_rate(new_value)
|
215
|
+
SolarWindsAPM.sample_rate(new_value)
|
216
216
|
|
217
217
|
when :transaction_settings
|
218
218
|
compile_settings(value)
|
@@ -19,8 +19,9 @@ module NoopAPI
|
|
19
19
|
# Tracing
|
20
20
|
module Tracing
|
21
21
|
# (wait_milliseconds=3000, integer_response: false)
|
22
|
-
def solarwinds_ready?(
|
23
|
-
|
22
|
+
def solarwinds_ready?(_wait_milliseconds = 3000, integer_response: false)
|
23
|
+
_noop = integer_response
|
24
|
+
false
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
@@ -55,10 +56,12 @@ module NoopAPI
|
|
55
56
|
# CustomMetrics
|
56
57
|
module CustomMetrics
|
57
58
|
def increment_metric(*)
|
59
|
+
SolarWindsAPM.logger.warn { 'increment_metric have been deprecated. Please use opentelemetry metrics-sdk to log metrics data.' }
|
58
60
|
false
|
59
61
|
end
|
60
62
|
|
61
63
|
def summary_metric(*)
|
64
|
+
SolarWindsAPM.logger.warn { 'summary_metric have been deprecated. Please use opentelemetry metrics-sdk to log metrics data.' }
|
62
65
|
false
|
63
66
|
end
|
64
67
|
end
|
data/lib/solarwinds_apm/noop.rb
CHANGED
@@ -6,28 +6,4 @@
|
|
6
6
|
#
|
7
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
8
|
|
9
|
-
require_relative 'noop/context'
|
10
|
-
require_relative 'noop/metadata'
|
11
|
-
require_relative 'noop/span'
|
12
9
|
require_relative 'noop/api'
|
13
|
-
|
14
|
-
module SolarWindsAPM
|
15
|
-
include Oboe_metal
|
16
|
-
# Reporter noop
|
17
|
-
class Reporter
|
18
|
-
##
|
19
|
-
# noop version of :send_report
|
20
|
-
#
|
21
|
-
def self.send_report(event, with_system_timestamp: false); end
|
22
|
-
|
23
|
-
##
|
24
|
-
# noop version of :send_status
|
25
|
-
#
|
26
|
-
def self.send_status(event, context = nil, with_system_timestamp: false); end
|
27
|
-
|
28
|
-
##
|
29
|
-
# noop version of :start
|
30
|
-
#
|
31
|
-
def self.start; end
|
32
|
-
end
|
33
|
-
end
|
@@ -8,41 +8,60 @@
|
|
8
8
|
|
9
9
|
module SolarWindsAPM
|
10
10
|
module OpenTelemetry
|
11
|
-
# reference: OpenTelemetry::SDK::Trace::SpanProcessor
|
12
|
-
class OTLPProcessor
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
# reference: OpenTelemetry::SDK::Trace::SpanProcessor
|
12
|
+
class OTLPProcessor
|
13
|
+
attr_reader :txn_manager
|
14
|
+
|
15
|
+
SW_TRANSACTION_NAME = 'sw.transaction'
|
16
|
+
SW_IS_ENTRY_SPAN = 'sw.is_entry_span'
|
17
|
+
SW_IS_ERROR = 'sw.is_error'
|
18
|
+
|
19
|
+
HTTP_METHOD = 'http.method'
|
20
|
+
HTTP_ROUTE = 'http.route'
|
21
|
+
HTTP_STATUS_CODE = 'http.status_code'
|
22
|
+
HTTP_URL = 'http.url'
|
23
|
+
|
24
|
+
INVALID_HTTP_STATUS_CODE = 0
|
25
|
+
|
26
|
+
def initialize(txn_manager)
|
27
|
+
@txn_manager = txn_manager
|
28
|
+
@meters = { 'sw.apm.request.metrics' => ::OpenTelemetry.meter_provider.meter('sw.apm.request.metrics') }
|
29
|
+
@metrics = { response_time: @meters['sw.apm.request.metrics'].create_histogram('trace.service.response_time', unit: 'ms', description: 'Duration of each entry span for the service, typically meaning the time taken to process an inbound request.') }
|
30
|
+
@transaction_name = nil
|
19
31
|
end
|
20
32
|
|
21
|
-
# @param [Span] span the {Span} that just started.
|
22
|
-
# @param [Context] parent_context the
|
23
|
-
# started span.
|
33
|
+
# @param [Span] span the (mutable) {Span} that just started.
|
34
|
+
# @param [Context] parent_context of the started span.
|
24
35
|
def on_start(span, parent_context)
|
25
36
|
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] processor on_start span: #{span.to_span_data.inspect}" }
|
26
37
|
|
27
38
|
return if non_entry_span(parent_context: parent_context)
|
28
39
|
|
29
|
-
span.
|
30
|
-
span.
|
40
|
+
trace_flags = span.context.trace_flags.sampled? ? '01' : '00'
|
41
|
+
@txn_manager&.set_root_context_h(span.context.hex_trace_id, "#{span.context.hex_span_id}-#{trace_flags}")
|
42
|
+
span.add_attributes({ SW_IS_ENTRY_SPAN => true })
|
31
43
|
rescue StandardError => e
|
32
44
|
SolarWindsAPM.logger.info { "[#{self.class}/#{__method__}] processor on_start error: #{e.message}" }
|
33
45
|
end
|
34
46
|
|
35
|
-
|
47
|
+
def on_finishing(span)
|
48
|
+
@transaction_name = calculate_transaction_names(span)
|
49
|
+
span.set_attribute(SW_TRANSACTION_NAME, @transaction_name)
|
50
|
+
@txn_manager.delete_root_context_h(span.context.hex_trace_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param [Span] span the (immutable) {Span} that just ended.
|
36
54
|
def on_finish(span)
|
37
55
|
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] processor on_finish span: #{span.to_span_data.inspect}" }
|
38
|
-
|
39
|
-
# return if span is non-entry span
|
40
56
|
return if non_entry_span(span: span)
|
41
57
|
|
42
58
|
record_request_metrics(span)
|
43
|
-
record_sampling_metrics
|
44
59
|
|
45
|
-
|
60
|
+
# pull should work on any instrument from oboe_sampler
|
61
|
+
::OpenTelemetry.meter_provider.metric_readers.each do |reader|
|
62
|
+
reader.pull if reader.respond_to? :pull
|
63
|
+
end
|
64
|
+
|
46
65
|
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] processor on_finish succeed" }
|
47
66
|
rescue StandardError => e
|
48
67
|
SolarWindsAPM.logger.info { "[#{self.class}/#{__method__}] error processing span on_finish: #{e.message}" }
|
@@ -50,24 +69,10 @@ module SolarWindsAPM
|
|
50
69
|
|
51
70
|
private
|
52
71
|
|
53
|
-
# Create two meters for sampling and request count
|
54
|
-
def init_meters
|
55
|
-
{
|
56
|
-
'sw.apm.sampling.metrics' => ::OpenTelemetry.meter_provider.meter('sw.apm.sampling.metrics'),
|
57
|
-
'sw.apm.request.metrics' => ::OpenTelemetry.meter_provider.meter('sw.apm.request.metrics')
|
58
|
-
}
|
59
|
-
end
|
60
|
-
|
61
|
-
def span_attributes(span)
|
62
|
-
span_attrs = { 'sw.transaction' => calculate_lambda_transaction_name(span) }
|
63
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] span_attrs: #{span_attrs.inspect}" }
|
64
|
-
span_attrs
|
65
|
-
end
|
66
|
-
|
67
72
|
def meter_attributes(span)
|
68
73
|
meter_attrs = {
|
69
|
-
|
70
|
-
|
74
|
+
SW_IS_ERROR => error?(span) == 1,
|
75
|
+
SW_TRANSACTION_NAME => @transaction_name
|
71
76
|
}
|
72
77
|
|
73
78
|
if span_http?(span)
|
@@ -76,26 +81,33 @@ module SolarWindsAPM
|
|
76
81
|
meter_attrs['http.method'] = span.attributes[HTTP_METHOD] if span.attributes[HTTP_METHOD]
|
77
82
|
end
|
78
83
|
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] meter_attrs: #{meter_attrs.inspect}" }
|
84
|
+
meter_attrs.compact!
|
79
85
|
meter_attrs
|
80
86
|
end
|
81
87
|
|
82
|
-
def calculate_lambda_transaction_name(
|
83
|
-
(ENV['SW_APM_TRANSACTION_NAME'] || ENV['AWS_LAMBDA_FUNCTION_NAME'] ||
|
88
|
+
def calculate_lambda_transaction_name(span_name)
|
89
|
+
(ENV['SW_APM_TRANSACTION_NAME'] || ENV['AWS_LAMBDA_FUNCTION_NAME'] || span_name || 'unknown').slice(0, SolarWindsAPM::Constants::MAX_TXN_NAME_LENGTH)
|
84
90
|
end
|
85
91
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
92
|
+
# Get trans_name and url_tran of this span instance.
|
93
|
+
# Predecessor order: custom SDK > env var SW_APM_TRANSACTION_NAME > automatic naming
|
94
|
+
def calculate_transaction_names(span)
|
95
|
+
return calculate_lambda_transaction_name(span.name) if SolarWindsAPM::Utils.determine_lambda
|
96
|
+
|
97
|
+
trace_span_id = "#{span.context.hex_trace_id}-#{span.context.hex_span_id}"
|
98
|
+
trans_name = @txn_manager.get(trace_span_id)
|
99
|
+
if trans_name
|
100
|
+
SolarWindsAPM.logger.debug do
|
101
|
+
"[#{self.class}/#{__method__}] found trans name from txn_manager: #{trans_name} by #{trace_span_id}"
|
102
|
+
end
|
103
|
+
@txn_manager.del(trace_span_id)
|
104
|
+
elsif !ENV['SW_APM_TRANSACTION_NAME'].to_s.empty?
|
105
|
+
trans_name = ENV.fetch('SW_APM_TRANSACTION_NAME', nil)
|
106
|
+
else
|
107
|
+
trans_name = span.attributes[HTTP_ROUTE] || nil
|
108
|
+
trans_name = span.name if trans_name.to_s.empty? && span.name
|
109
|
+
end
|
110
|
+
trans_name.to_s.slice(0, SolarWindsAPM::Constants::MAX_TXN_NAME_LENGTH)
|
99
111
|
end
|
100
112
|
|
101
113
|
def record_request_metrics(span)
|
@@ -106,31 +118,40 @@ module SolarWindsAPM
|
|
106
118
|
@metrics[:response_time].record(span_time, attributes: meter_attrs)
|
107
119
|
end
|
108
120
|
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
@metrics[:tracecount].add(trace_count)
|
121
|
+
# Calculate span time in microseconds (us) using start and end time
|
122
|
+
# in nanoseconds (ns). OTel span start/end_time are optional.
|
123
|
+
def calculate_span_time(start_time: nil, end_time: nil)
|
124
|
+
return 0 if start_time.nil? || end_time.nil?
|
114
125
|
|
115
|
-
|
116
|
-
|
117
|
-
@metrics[:samplecount].add(sample_count)
|
126
|
+
((end_time.to_i - start_time.to_i) / 1e3).round
|
127
|
+
end
|
118
128
|
|
119
|
-
|
120
|
-
|
121
|
-
|
129
|
+
# Calculate if this span instance has_error
|
130
|
+
# return [Integer]
|
131
|
+
def error?(span)
|
132
|
+
span.status.code == ::OpenTelemetry::Trace::Status::ERROR ? 1 : 0
|
133
|
+
end
|
122
134
|
|
123
|
-
|
124
|
-
|
125
|
-
|
135
|
+
# This span from inbound HTTP request if from a SERVER by some http.method
|
136
|
+
def span_http?(span)
|
137
|
+
span.kind == ::OpenTelemetry::Trace::SpanKind::SERVER && !span.attributes[HTTP_METHOD].nil?
|
138
|
+
end
|
126
139
|
|
127
|
-
|
128
|
-
|
129
|
-
|
140
|
+
# Calculate HTTP status_code from span or default to UNAVAILABLE
|
141
|
+
# Something went wrong in OTel or instrumented service crashed early
|
142
|
+
# if no status_code in attributes of HTTP span
|
143
|
+
def get_http_status_code(span)
|
144
|
+
span.attributes[HTTP_STATUS_CODE] || INVALID_HTTP_STATUS_CODE
|
145
|
+
end
|
130
146
|
|
131
|
-
|
132
|
-
|
133
|
-
|
147
|
+
# check if it's entry span based on no parent or parent is remote
|
148
|
+
def non_entry_span(span: nil, parent_context: nil)
|
149
|
+
if parent_context
|
150
|
+
parent_span = ::OpenTelemetry::Trace.current_span(parent_context)
|
151
|
+
parent_span && parent_span.context != ::OpenTelemetry::Trace::SpanContext::INVALID && parent_span.context.remote? == false
|
152
|
+
elsif span
|
153
|
+
span.attributes['sw.is_entry_span'] != true
|
154
|
+
end
|
134
155
|
end
|
135
156
|
end
|
136
157
|
end
|
@@ -51,8 +51,6 @@ module SolarWindsAPM
|
|
51
51
|
# text map setter will be used.
|
52
52
|
def inject(carrier, context: ::OpenTelemetry::Context.current,
|
53
53
|
setter: ::OpenTelemetry::Context::Propagation.text_map_setter)
|
54
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] inject context: #{context.inspect}" }
|
55
|
-
|
56
54
|
span_context = ::OpenTelemetry::Trace.current_span(context)&.context
|
57
55
|
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] span_context #{span_context.inspect}" }
|
58
56
|
return unless span_context&.valid?
|
@@ -16,6 +16,7 @@ module SolarWindsAPM
|
|
16
16
|
XTRACE_HEADER_NAME = 'x-trace'
|
17
17
|
XTRACEOPTIONS_RESPONSE_HEADER_NAME = 'x-trace-options-response'
|
18
18
|
INTL_SWO_EQUALS = '='
|
19
|
+
SW_XTRACEOPTIONS_RESPONSE_KEY = 'xtrace_options_response'
|
19
20
|
|
20
21
|
private_constant \
|
21
22
|
:HTTP_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS, :XTRACE_HEADER_NAME,
|
@@ -36,14 +37,13 @@ module SolarWindsAPM
|
|
36
37
|
setter: ::OpenTelemetry::Context::Propagation.text_map_setter)
|
37
38
|
span_context = ::OpenTelemetry::Trace.current_span(context).context
|
38
39
|
|
39
|
-
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] context current_span: #{context.instance_variable_get(:@entries)&.values&.first.inspect}" }
|
40
40
|
SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] span_context: #{span_context.inspect}" }
|
41
41
|
|
42
42
|
return unless span_context&.valid?
|
43
43
|
|
44
44
|
x_trace = Utils.traceparent_from_context(span_context)
|
45
45
|
exposed_headers = [XTRACE_HEADER_NAME]
|
46
|
-
xtraceoptions_response = recover_response_from_tracestate(span_context
|
46
|
+
xtraceoptions_response = recover_response_from_tracestate(span_context)
|
47
47
|
|
48
48
|
SolarWindsAPM.logger.debug do
|
49
49
|
"[#{self.class}/#{__method__}] x-trace: #{x_trace}; exposed headers: #{exposed_headers.inspect}; x-trace-options-response: #{xtraceoptions_response}"
|
@@ -69,11 +69,12 @@ module SolarWindsAPM
|
|
69
69
|
private
|
70
70
|
|
71
71
|
# sw_xtraceoptions_response_key -> xtrace_options_response
|
72
|
-
def recover_response_from_tracestate(
|
73
|
-
sanitized = tracestate.value(
|
72
|
+
def recover_response_from_tracestate(span_context)
|
73
|
+
sanitized = span_context.tracestate.value(SW_XTRACEOPTIONS_RESPONSE_KEY)
|
74
74
|
sanitized = '' if sanitized.nil?
|
75
75
|
sanitized = sanitized.gsub(SolarWindsAPM::Constants::INTL_SWO_EQUALS_W3C_SANITIZED,
|
76
76
|
SolarWindsAPM::Constants::INTL_SWO_EQUALS)
|
77
|
+
sanitized = sanitized.gsub(':', SolarWindsAPM::Constants::INTL_SWO_EQUALS)
|
77
78
|
sanitized = sanitized.gsub(SolarWindsAPM::Constants::INTL_SWO_COMMA_W3C_SANITIZED,
|
78
79
|
SolarWindsAPM::Constants::INTL_SWO_COMMA)
|
79
80
|
SolarWindsAPM.logger.debug do
|
@@ -6,14 +6,12 @@
|
|
6
6
|
#
|
7
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
8
|
|
9
|
-
require 'opentelemetry
|
10
|
-
require 'opentelemetry
|
11
|
-
|
12
|
-
|
9
|
+
require 'opentelemetry-sdk'
|
10
|
+
require 'opentelemetry-metrics-sdk'
|
11
|
+
require 'opentelemetry-exporter-otlp'
|
12
|
+
require 'opentelemetry-exporter-otlp-metrics'
|
13
|
+
require 'opentelemetry-instrumentation-all'
|
13
14
|
|
14
15
|
require_relative 'opentelemetry/solarwinds_propagator'
|
15
|
-
require_relative 'opentelemetry/solarwinds_processor'
|
16
|
-
require_relative 'opentelemetry/solarwinds_sampler'
|
17
|
-
require_relative 'opentelemetry/solarwinds_exporter'
|
18
16
|
require_relative 'opentelemetry/solarwinds_response_propagator'
|
19
17
|
require_relative 'opentelemetry/otlp_processor'
|