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
@@ -0,0 +1,177 @@
|
|
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_relative 'api'
|
10
|
+
require_relative 'support'
|
11
|
+
require_relative 'opentelemetry'
|
12
|
+
require_relative 'sampling'
|
13
|
+
|
14
|
+
module SolarWindsAPM
|
15
|
+
# OTelNativeConfig module
|
16
|
+
module OTelNativeConfig
|
17
|
+
@@config = {}
|
18
|
+
@@config_map = {}
|
19
|
+
@@agent_enabled = false
|
20
|
+
|
21
|
+
RESOURCE_ATTRIBUTES = 'RESOURCE_ATTRIBUTES'
|
22
|
+
|
23
|
+
def self.initialize
|
24
|
+
return unless defined?(::OpenTelemetry::SDK::Configurator)
|
25
|
+
|
26
|
+
is_lambda = SolarWindsAPM::Utils.determine_lambda
|
27
|
+
|
28
|
+
ENV['OTEL_TRACES_EXPORTER'] = ENV['OTEL_TRACES_EXPORTER'].to_s.split(',').tap { |e| e << 'otlp' unless e.include?('otlp') }.join(',')
|
29
|
+
|
30
|
+
# add response propagator to rack instrumentation
|
31
|
+
resolve_response_propagator
|
32
|
+
|
33
|
+
# dbo: traceparent injection as sql comments
|
34
|
+
require_relative 'patch/tag_sql_patch' if SolarWindsAPM::Config[:tag_sql]
|
35
|
+
|
36
|
+
# endpoint and service_key for non-lambda
|
37
|
+
otlp_endpoint = nil
|
38
|
+
unless is_lambda
|
39
|
+
otlp_endpoint = SolarWindsAPM::OTLPEndPoint.new
|
40
|
+
otlp_endpoint.config_otlp_token_and_endpoint
|
41
|
+
return if otlp_endpoint.token.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
ENV['OTEL_RESOURCE_ATTRIBUTES'] = "sw.apm.version=#{SolarWindsAPM::Version::STRING},sw.data.module=apm,service.name=#{ENV.fetch('OTEL_SERVICE_NAME', nil)}," + ENV['OTEL_RESOURCE_ATTRIBUTES'].to_s
|
45
|
+
|
46
|
+
# resource attributes
|
47
|
+
mandatory_resource = SolarWindsAPM::ResourceDetector.detect
|
48
|
+
additional_attributes = @@config_map[RESOURCE_ATTRIBUTES]
|
49
|
+
if additional_attributes
|
50
|
+
if additional_attributes.instance_of?(::OpenTelemetry::SDK::Resources::Resource)
|
51
|
+
final_attributes = mandatory_resource.merge(additional_attributes)
|
52
|
+
elsif additional_attributes.instance_of?(Hash)
|
53
|
+
final_attributes = mandatory_resource.merge(::OpenTelemetry::SDK::Resources::Resource.create(additional_attributes))
|
54
|
+
end
|
55
|
+
@@config_map.delete(RESOURCE_ATTRIBUTES)
|
56
|
+
else
|
57
|
+
final_attributes = mandatory_resource.merge({})
|
58
|
+
end
|
59
|
+
|
60
|
+
# set gzip compression
|
61
|
+
%w[TRACES METRICS LOGS].each do |signal|
|
62
|
+
ENV["OTEL_EXPORTER_OTLP_#{signal}_COMPRESSION"] = 'gzip' if ENV["OTEL_EXPORTER_OTLP_#{signal}_COMPRESSION"].to_s.empty? && ENV['OTEL_EXPORTER_OTLP_COMPRESSION'].to_s.empty?
|
63
|
+
end
|
64
|
+
|
65
|
+
# set delta temporality
|
66
|
+
ENV['OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE'] = 'delta' if ENV['OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE'].to_s.empty?
|
67
|
+
|
68
|
+
# log level
|
69
|
+
if ENV['OTEL_LOG_LEVEL'].to_s.empty?
|
70
|
+
log_level = (ENV['SW_APM_DEBUG_LEVEL'] || SolarWindsAPM::Config[:debug_level] || 3).to_i
|
71
|
+
ENV['OTEL_LOG_LEVEL'] = SolarWindsAPM::Config::SW_LOG_LEVEL_MAPPING.dig(log_level, :otel)
|
72
|
+
end
|
73
|
+
|
74
|
+
::OpenTelemetry::SDK.configure do |c|
|
75
|
+
c.resource = final_attributes
|
76
|
+
c.use_all(@@config_map)
|
77
|
+
end
|
78
|
+
|
79
|
+
# append our propagators
|
80
|
+
::OpenTelemetry.propagation.instance_variable_get(:@propagators).append(SolarWindsAPM::OpenTelemetry::SolarWindsPropagator::TextMapPropagator.new)
|
81
|
+
|
82
|
+
# add sw metrics processors (only record respone_time)
|
83
|
+
txn_manager = TxnNameManager.new
|
84
|
+
otlp_processor = SolarWindsAPM::OpenTelemetry::OTLPProcessor.new(txn_manager)
|
85
|
+
|
86
|
+
@@config[:metrics_processor] = otlp_processor
|
87
|
+
::OpenTelemetry.tracer_provider.add_span_processor(otlp_processor)
|
88
|
+
|
89
|
+
# collector, service and headers are used for http sampler get settings
|
90
|
+
sampler_config = {
|
91
|
+
tracing_mode: SolarWindsAPM::Config[:tracing_mode],
|
92
|
+
trigger_trace_enabled: SolarWindsAPM::Config[:trigger_tracing_mode],
|
93
|
+
transaction_settings: SolarWindsAPM::Config[:transaction_settings]
|
94
|
+
}
|
95
|
+
|
96
|
+
unless otlp_endpoint.nil?
|
97
|
+
sampler_config.merge!({
|
98
|
+
collector: "https://#{ENV.fetch('SW_APM_COLLECTOR', 'apm.collector.cloud.solarwinds.com:443')}",
|
99
|
+
service: otlp_endpoint.service_name,
|
100
|
+
headers: "Bearer #{otlp_endpoint.token}"
|
101
|
+
})
|
102
|
+
end
|
103
|
+
|
104
|
+
sampler = is_lambda ? JsonSampler.new(sampler_config) : HttpSampler.new(sampler_config)
|
105
|
+
|
106
|
+
::OpenTelemetry.tracer_provider.sampler = ::OpenTelemetry::SDK::Trace::Samplers.parent_based(
|
107
|
+
root: sampler,
|
108
|
+
remote_parent_sampled: sampler,
|
109
|
+
remote_parent_not_sampled: sampler
|
110
|
+
)
|
111
|
+
|
112
|
+
@@agent_enabled = true
|
113
|
+
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.[](key)
|
118
|
+
@@config[key.to_sym]
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.agent_enabled
|
122
|
+
@@agent_enabled
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.resolve_response_propagator
|
126
|
+
response_propagator = SolarWindsAPM::OpenTelemetry::SolarWindsResponsePropagator::TextMapPropagator.new
|
127
|
+
rack_setting = @@config_map['OpenTelemetry::Instrumentation::Rack']
|
128
|
+
|
129
|
+
if rack_setting
|
130
|
+
if rack_setting[:response_propagators].instance_of?(Array)
|
131
|
+
rack_setting[:response_propagators].append(response_propagator)
|
132
|
+
elsif rack_setting[:response_propagators].nil?
|
133
|
+
rack_setting[:response_propagators] = [response_propagator]
|
134
|
+
else
|
135
|
+
SolarWindsAPM.logger.warn do
|
136
|
+
"[#{name}/#{__method__}] Rack response propagator resolve failed. Provided type #{rack_setting[:response_propagators].class}, please provide Array e.g. [#{rack_setting[:response_propagators]}]"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
else
|
140
|
+
@@config_map['OpenTelemetry::Instrumentation::Rack'] = { response_propagators: [response_propagator] }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Allow initialize after set new value to SolarWindsAPM::Config[:key]=value
|
146
|
+
#
|
147
|
+
# Usage:
|
148
|
+
#
|
149
|
+
# Default using the use_all to load all instrumentation
|
150
|
+
# But with specific instrumentation disabled, use {:enabled: false} in config
|
151
|
+
# SolarWindsAPM::OTelNativeConfig.initialize_with_config do |config|
|
152
|
+
# config["OpenTelemetry::Instrumentation::Rack"] = {"a" => "b"}
|
153
|
+
# config["OpenTelemetry::Instrumentation::Dalli"] = {:enabled: false}
|
154
|
+
# config["RESOURCE_ATTRIBUTES"] = ::OpenTelemetry::Resource::Detector::GoogleCloudPlatform.detect
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
def self.initialize_with_config
|
158
|
+
unless block_given?
|
159
|
+
SolarWindsAPM.logger.warn do
|
160
|
+
"[#{name}/#{__method__}] Block not given while doing in-code configuration. Agent disabled."
|
161
|
+
end
|
162
|
+
return
|
163
|
+
end
|
164
|
+
|
165
|
+
yield @@config_map
|
166
|
+
|
167
|
+
if @@config_map.empty?
|
168
|
+
SolarWindsAPM.logger.warn do
|
169
|
+
"[#{name}/#{__method__}] No configuration given for in-code configuration. Agent disabled."
|
170
|
+
end
|
171
|
+
return
|
172
|
+
end
|
173
|
+
|
174
|
+
initialize
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Patch
|
2
|
+
|
3
|
+
## Patch upstream code
|
4
|
+
|
5
|
+
This folder is for storing patch files that apply to upstream code.
|
6
|
+
|
7
|
+
For example, to patch otel ruby sdk `Registry`, and assume you have dummy_patch file that have module `SolarWindsAPM::Patch::DummyPatch`,
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
require_relative './patch/dummy_patch'
|
11
|
+
|
12
|
+
if defined? OpenTelemetry::Instrumentation::Registry && OpenTelemetry::Instrumentation::Registry::VERSION <= '0.3.0'
|
13
|
+
OpenTelemetry::Instrumentation::Registry.prepend(SolarWindsAPM::Patch::DummyPatch)
|
14
|
+
end
|
15
|
+
```
|
@@ -6,27 +6,29 @@
|
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
9
|
+
# Dice is used in oboe_sampler diceRollAlgo
|
10
|
+
module SolarWindsAPM
|
11
|
+
class Dice
|
12
|
+
attr_reader :rate, :scale
|
13
|
+
|
14
|
+
def initialize(settings)
|
15
|
+
@scale = settings[:scale]
|
16
|
+
@rate = settings[:rate] || 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def update(settings)
|
20
|
+
@scale = settings[:scale] if settings[:scale]
|
21
|
+
@rate = settings[:rate] if settings[:rate]
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
# return Boolean
|
25
|
+
def roll
|
26
|
+
(rand * @scale) < @rate
|
26
27
|
end
|
27
28
|
|
28
|
-
def
|
29
|
-
|
29
|
+
def rate=(rate)
|
30
|
+
# Math.max(0, Math.min(this.#scale, n))
|
31
|
+
@rate = rate.clamp(0, @scale)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
@@ -0,0 +1,87 @@
|
|
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
|
+
class HttpSampler < Sampler
|
11
|
+
REQUEST_TIMEOUT = 10 # 10s
|
12
|
+
GET_SETTING_DURAION = 60 # 60s
|
13
|
+
|
14
|
+
# we don't need hostname as it's for separating browser and local env
|
15
|
+
def initialize(config)
|
16
|
+
super(config, SolarWindsAPM.logger)
|
17
|
+
|
18
|
+
@url = config[:collector]
|
19
|
+
@service = URI.encode_www_form_component(config[:service]) # service name "Hello world" -> "Hello%20world"
|
20
|
+
@headers = config[:headers]
|
21
|
+
|
22
|
+
@hostname = hostname
|
23
|
+
@setting_url = URI.join(@url, "./v1/settings/#{@service}/#{@hostname}")
|
24
|
+
|
25
|
+
Thread.new { settings_request }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Node.js equivalent: Retrieve system hostname
|
31
|
+
# e.g. docker -> docker.swo.ubuntu.development; macos -> NHSDFWSSD
|
32
|
+
def hostname
|
33
|
+
host = Socket.gethostname
|
34
|
+
URI.encode_www_form_component(host)
|
35
|
+
end
|
36
|
+
|
37
|
+
def fetch_with_timeout(url, timeout_seconds = nil)
|
38
|
+
uri = url
|
39
|
+
response = nil
|
40
|
+
|
41
|
+
thread = Thread.new do
|
42
|
+
::OpenTelemetry::Common::Utilities.untraced do
|
43
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
44
|
+
request = Net::HTTP::Get.new(uri)
|
45
|
+
request['Authorization'] = @headers
|
46
|
+
|
47
|
+
response = http.request(request)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
rescue StandardError => e
|
51
|
+
@logger.debug { "Error during request: #{e.message}" }
|
52
|
+
end
|
53
|
+
|
54
|
+
thread_join = thread.join(timeout_seconds || REQUEST_TIMEOUT)
|
55
|
+
if thread_join.nil?
|
56
|
+
@logger.debug { "Request timed out after #{timeout_seconds} seconds" }
|
57
|
+
thread.kill
|
58
|
+
end
|
59
|
+
|
60
|
+
response
|
61
|
+
end
|
62
|
+
|
63
|
+
# a endless loop within a thread (non-blocking)
|
64
|
+
def settings_request
|
65
|
+
loop do
|
66
|
+
@logger.debug { "Retrieving sampling settings from #{@setting_url}" }
|
67
|
+
|
68
|
+
response = fetch_with_timeout(@setting_url)
|
69
|
+
parsed = response.nil? ? nil : JSON.parse(response.body)
|
70
|
+
|
71
|
+
@logger.debug { "parsed settings in json: #{parsed.inspect}" }
|
72
|
+
|
73
|
+
if update_settings(parsed)
|
74
|
+
# update the settings before the previous ones expire with some time to spare
|
75
|
+
expiry = (parsed['timestamp'].to_i + parsed['ttl'].to_i)
|
76
|
+
expiry_timeout = expiry - REQUEST_TIMEOUT - Time.now.to_i
|
77
|
+
sleep([0, expiry_timeout].max)
|
78
|
+
else
|
79
|
+
@logger.warn { 'Retrieved sampling settings are invalid. Ensure proper configuration.' }
|
80
|
+
sleep(GET_SETTING_DURAION)
|
81
|
+
end
|
82
|
+
rescue StandardError => e
|
83
|
+
@logger.warn { "Failed to retrieve sampling settings (#{e.message}), tracing will be disabled until valid ones are available." }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,52 @@
|
|
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
|
+
class JsonSampler < Sampler
|
11
|
+
DEFAULT_PATH = File.join(Dir.tmpdir, 'solarwinds-apm-settings.json')
|
12
|
+
|
13
|
+
def initialize(config, path = nil)
|
14
|
+
super(config, SolarWindsAPM.logger)
|
15
|
+
|
16
|
+
@path = path || DEFAULT_PATH
|
17
|
+
@expiry = Time.now.to_i
|
18
|
+
loop_check
|
19
|
+
end
|
20
|
+
|
21
|
+
# only json sampler will need to check if the settings.json file
|
22
|
+
# updated or not from collector extention
|
23
|
+
def should_sample?(params)
|
24
|
+
loop_check
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def loop_check
|
31
|
+
# Update if we're within 10s of expiry
|
32
|
+
return if Time.now.to_i + 10 < @expiry
|
33
|
+
|
34
|
+
begin
|
35
|
+
contents = File.read(@path)
|
36
|
+
unparsed = JSON.parse(contents)
|
37
|
+
rescue StandardError => e
|
38
|
+
@logger.debug { "missing or invalid settings file; Error: #{e.message}" }
|
39
|
+
return
|
40
|
+
end
|
41
|
+
|
42
|
+
unless unparsed.is_a?(Array) && unparsed.length == 1
|
43
|
+
@logger.debug { "invalid settings file : #{unparsed}" }
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
parsed = update_settings(unparsed.first)
|
48
|
+
@logger.debug { "update_settings: #{parsed}" }
|
49
|
+
@expiry = parsed[:timestamp].to_i + parsed[:ttl].to_i if parsed
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,38 @@
|
|
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 Metrics
|
11
|
+
class Counter
|
12
|
+
# counter = Counter.new
|
13
|
+
# counter[:request_count].update(1)
|
14
|
+
def initialize
|
15
|
+
@meter = ::OpenTelemetry.meter_provider.meter('sw.apm.sampling.metrics')
|
16
|
+
|
17
|
+
@counter = {
|
18
|
+
request_count:
|
19
|
+
@meter.create_counter('trace.service.request_count', unit: '{request}', description: 'Count of all requests.'),
|
20
|
+
sample_count:
|
21
|
+
@meter.create_counter('trace.service.samplecount', unit: '{request}', description: 'Count of requests that went through sampling, which excludes those with a valid upstream decision or trigger traced.'),
|
22
|
+
trace_count:
|
23
|
+
@meter.create_counter('trace.service.tracecount', unit: '{trace}', description: 'Count of all traces.'),
|
24
|
+
through_trace_count:
|
25
|
+
@meter.create_counter('trace.service.through_trace_count', unit: '{request}', description: 'Count of requests with a valid upstream decision, thus passed through sampling.'),
|
26
|
+
triggered_trace_count:
|
27
|
+
@meter.create_counter('trace.service.triggered_trace_count', unit: '{trace}', description: 'Count of triggered traces.'),
|
28
|
+
token_bucket_exhaustion_count:
|
29
|
+
@meter.create_counter('trace.service.tokenbucket_exhaustion_count', unit: '{request}', description: 'Count of requests that were not traced due to token bucket rate limiting.')
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def [](key)
|
34
|
+
@counter[key]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|