apm_bro 0.1.17 → 0.1.19
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/lib/apm_bro/client.rb +8 -18
- data/lib/apm_bro/configuration.rb +62 -294
- data/lib/apm_bro/error_middleware.rb +2 -2
- data/lib/apm_bro/http_instrumentation.rb +2 -2
- data/lib/apm_bro/railtie.rb +14 -21
- data/lib/apm_bro/sql_tracking_middleware.rb +0 -6
- data/lib/apm_bro/subscriber.rb +4 -2
- data/lib/apm_bro/version.rb +1 -1
- data/lib/apm_bro.rb +8 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0c2d1fa177a670e4c599968669d284408d8e4e07feeae007bc3a7b4039dd3f69
|
|
4
|
+
data.tar.gz: a02724bba6a69bd2e66d1a8d893ee22d932d1f0bd2996f83b40cf0a0e4d6b257
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 44ef00e740c200bc47b45b032bed321a33e82f16973a695b19018226e57f879f11c4675cb082cbf324dfb441d298293555d43cfad1b0fb0421df661f6aeb2e7c
|
|
7
|
+
data.tar.gz: d907473bfbec4779f0658c27908ddd26551f175c61f26bac8661820d4ead6f8c963d9e1714e4d8161832076207cbcc09794bc854c2a67e54b336273079251e26
|
data/lib/apm_bro/client.rb
CHANGED
|
@@ -13,21 +13,12 @@ module ApmBro
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def post_metric(event_name:, payload:)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
end
|
|
16
|
+
return if @configuration.api_key.nil?
|
|
17
|
+
return unless @configuration.enabled
|
|
19
18
|
|
|
20
19
|
# Check sampling rate - skip if not selected for sampling
|
|
21
|
-
unless @configuration.should_sample?
|
|
22
|
-
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
api_key = @configuration.resolve_api_key
|
|
26
|
-
|
|
27
|
-
if api_key.nil?
|
|
28
|
-
return
|
|
29
|
-
end
|
|
30
|
-
|
|
20
|
+
return unless @configuration.should_sample?
|
|
21
|
+
|
|
31
22
|
# Check circuit breaker before making request
|
|
32
23
|
if @circuit_breaker && @configuration.circuit_breaker_enabled
|
|
33
24
|
if @circuit_breaker.state == :open
|
|
@@ -41,7 +32,7 @@ module ApmBro
|
|
|
41
32
|
end
|
|
42
33
|
|
|
43
34
|
# Make the HTTP request (async)
|
|
44
|
-
make_http_request(event_name, payload, api_key)
|
|
35
|
+
make_http_request(event_name, payload, @configuration.api_key)
|
|
45
36
|
|
|
46
37
|
nil
|
|
47
38
|
end
|
|
@@ -59,10 +50,9 @@ module ApmBro
|
|
|
59
50
|
end
|
|
60
51
|
|
|
61
52
|
def make_http_request(event_name, payload, api_key)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
use_staging = ENV["USE_STAGING_ENDPOINT"] && !ENV["USE_STAGING_ENDPOINT"].empty?
|
|
54
|
+
production_url = use_staging ? "https://deadbro.aberatii.com/apm/v1/metrics" : "https://www.deadbro.com/apm/v1/metrics"
|
|
55
|
+
endpoint_url = @configuration.ruby_dev ? "http://localhost:3100/apm/v1/metrics" : production_url
|
|
66
56
|
uri = URI.parse(endpoint_url)
|
|
67
57
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
68
58
|
http.use_ssl = (uri.scheme == "https")
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module ApmBro
|
|
4
4
|
class Configuration
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
attr_accessor :api_key, :open_timeout, :read_timeout, :enabled, :ruby_dev, :memory_tracking_enabled,
|
|
6
|
+
:allocation_tracking_enabled, :circuit_breaker_enabled, :circuit_breaker_failure_threshold, :circuit_breaker_recovery_timeout,
|
|
7
|
+
:circuit_breaker_retry_timeout, :sample_rate, :excluded_controllers, :excluded_jobs,
|
|
8
|
+
:exclusive_controllers, :exclusive_jobs, :deploy_id, :slow_query_threshold_ms, :explain_analyze_enabled
|
|
8
9
|
|
|
9
10
|
def initialize
|
|
10
11
|
@api_key = nil
|
|
@@ -19,238 +20,62 @@ module ApmBro
|
|
|
19
20
|
@circuit_breaker_failure_threshold = 3
|
|
20
21
|
@circuit_breaker_recovery_timeout = 60 # seconds
|
|
21
22
|
@circuit_breaker_retry_timeout = 300 # seconds
|
|
22
|
-
@sample_rate = 100
|
|
23
|
+
@sample_rate = 100
|
|
23
24
|
@excluded_controllers = []
|
|
24
25
|
@excluded_jobs = []
|
|
25
|
-
@
|
|
26
|
-
@exclusive_controller_actions = []
|
|
26
|
+
@exclusive_controllers = []
|
|
27
27
|
@exclusive_jobs = []
|
|
28
28
|
@deploy_id = resolve_deploy_id
|
|
29
29
|
@slow_query_threshold_ms = 500 # Default: 500ms
|
|
30
30
|
@explain_analyze_enabled = false # Enable EXPLAIN ANALYZE for slow queries by default
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
return @api_key if present?(@api_key)
|
|
36
|
-
|
|
37
|
-
if defined?(Rails)
|
|
38
|
-
key = fetch_from_rails_settings
|
|
39
|
-
return key if present?(key)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
env_key = ENV["APM_BRO_API_KEY"]
|
|
43
|
-
return env_key if present?(env_key)
|
|
44
|
-
|
|
45
|
-
nil
|
|
33
|
+
def resolve_deploy_id
|
|
34
|
+
ENV["APM_BRO_DEPLOY_ID"] || ENV["GIT_REV"] || ENV["HEROKU_SLUG_COMMIT"] || ApmBro.process_deploy_id
|
|
46
35
|
end
|
|
47
36
|
|
|
48
|
-
def
|
|
49
|
-
return
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
37
|
+
def excluded_controller?(controller_name, action_name = nil)
|
|
38
|
+
return false if @excluded_controllers.empty?
|
|
39
|
+
|
|
40
|
+
# If action_name is provided, check both controller#action patterns and controller-only patterns
|
|
41
|
+
if action_name
|
|
42
|
+
target = "#{controller_name}##{action_name}"
|
|
43
|
+
# Check controller#action patterns (patterns containing '#')
|
|
44
|
+
action_patterns = @excluded_controllers.select { |pat| pat.to_s.include?("#") }
|
|
45
|
+
if action_patterns.any? { |pat| match_name_or_pattern?(target, pat) }
|
|
46
|
+
return true
|
|
55
47
|
end
|
|
48
|
+
# Check controller-only patterns (patterns without '#')
|
|
49
|
+
# If the controller itself is excluded, all its actions are excluded
|
|
50
|
+
controller_patterns = @excluded_controllers.reject { |pat| pat.to_s.include?("#") }
|
|
51
|
+
if controller_patterns.any? { |pat| match_name_or_pattern?(controller_name, pat) }
|
|
52
|
+
return true
|
|
53
|
+
end
|
|
54
|
+
return false
|
|
56
55
|
end
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# Priority: explicit config -> Rails credentials/settings -> ENV -> default
|
|
63
|
-
return @sample_rate if present?(@sample_rate)
|
|
64
|
-
|
|
65
|
-
if defined?(Rails)
|
|
66
|
-
rate = fetch_from_rails_settings(%w[apm_bro sample_rate])
|
|
67
|
-
return rate if present?(rate)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
env_rate = ENV["APM_BRO_SAMPLE_RATE"]
|
|
71
|
-
return env_rate.to_i if present?(env_rate) && env_rate.match?(/^\d+$/)
|
|
72
|
-
|
|
73
|
-
100 # default
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def resolve_deploy_id
|
|
77
|
-
# Priority: explicit config -> Rails settings/credentials -> ENV -> random UUID
|
|
78
|
-
return @deploy_id if present?(@deploy_id)
|
|
79
|
-
|
|
80
|
-
if defined?(Rails)
|
|
81
|
-
val = fetch_from_rails_settings(%w[apm_bro deploy_id])
|
|
82
|
-
return val if present?(val)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Prefer explicit env var, then common platform-specific var
|
|
86
|
-
apm_bro_deploy_id = ENV["APM_BRO_DEPLOY_ID"]
|
|
87
|
-
return apm_bro_deploy_id if present?(apm_bro_deploy_id)
|
|
88
|
-
|
|
89
|
-
env_val = ENV["GIT_REV"]
|
|
90
|
-
return env_val if present?(env_val)
|
|
91
|
-
|
|
92
|
-
heroku_val = ENV["HEROKU_SLUG_COMMIT"]
|
|
93
|
-
return heroku_val if present?(heroku_val)
|
|
94
|
-
|
|
95
|
-
# Fall back to a process-stable ID
|
|
96
|
-
ApmBro.process_deploy_id
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def excluded_controller?(controller_name)
|
|
100
|
-
list = resolve_excluded_controllers
|
|
101
|
-
return false if list.nil? || list.empty?
|
|
102
|
-
list.any? { |pat| match_name_or_pattern?(controller_name, pat) }
|
|
56
|
+
|
|
57
|
+
# When action_name is nil, only check controller-only patterns (no #)
|
|
58
|
+
controller_patterns = @excluded_controllers.reject { |pat| pat.to_s.include?("#") }
|
|
59
|
+
return false if controller_patterns.empty?
|
|
60
|
+
controller_patterns.any? { |pat| match_name_or_pattern?(controller_name, pat) }
|
|
103
61
|
end
|
|
104
62
|
|
|
105
63
|
def excluded_job?(job_class_name)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
list.any? { |pat| match_name_or_pattern?(job_class_name, pat) }
|
|
64
|
+
return false if @excluded_jobs.empty?
|
|
65
|
+
@excluded_jobs.any? { |pat| match_name_or_pattern?(job_class_name, pat) }
|
|
109
66
|
end
|
|
110
67
|
|
|
111
68
|
def exclusive_job?(job_class_name)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
list.any? { |pat| match_name_or_pattern?(job_class_name, pat) }
|
|
69
|
+
return true if @exclusive_jobs.empty? # If not defined, allow all (default behavior)
|
|
70
|
+
@exclusive_jobs.any? { |pat| match_name_or_pattern?(job_class_name, pat) }
|
|
115
71
|
end
|
|
116
72
|
|
|
117
|
-
def
|
|
118
|
-
|
|
119
|
-
return false if list.nil? || list.empty?
|
|
73
|
+
def exclusive_controller?(controller_name, action_name)
|
|
74
|
+
return true if @exclusive_controllers.empty? # If not defined, allow all (default behavior)
|
|
120
75
|
target = "#{controller_name}##{action_name}"
|
|
121
|
-
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def exclusive_controller_action?(controller_name, action_name)
|
|
125
|
-
list = resolve_exclusive_controller_actions
|
|
126
|
-
return true if list.nil? || list.empty? # If not defined, allow all (default behavior)
|
|
127
|
-
target = "#{controller_name}##{action_name}"
|
|
128
|
-
list.any? { |pat| match_name_or_pattern?(target, pat) }
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def resolve_excluded_controller_actions
|
|
132
|
-
# Collect patterns from @excluded_controller_actions
|
|
133
|
-
patterns = []
|
|
134
|
-
if @excluded_controller_actions && !@excluded_controller_actions.empty?
|
|
135
|
-
patterns.concat(Array(@excluded_controller_actions))
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
# Also check @excluded_controllers for patterns containing '#' (controller action patterns)
|
|
139
|
-
if @excluded_controllers && !@excluded_controllers.empty?
|
|
140
|
-
action_patterns = Array(@excluded_controllers).select { |pat| pat.to_s.include?("#") }
|
|
141
|
-
patterns.concat(action_patterns)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
return patterns if !patterns.empty?
|
|
145
|
-
|
|
146
|
-
if defined?(Rails)
|
|
147
|
-
list = fetch_from_rails_settings(%w[apm_bro excluded_controller_actions])
|
|
148
|
-
if list
|
|
149
|
-
rails_patterns = Array(list)
|
|
150
|
-
# Also check excluded_controllers from Rails settings for action patterns
|
|
151
|
-
controllers_list = fetch_from_rails_settings(%w[apm_bro excluded_controllers])
|
|
152
|
-
if controllers_list
|
|
153
|
-
action_patterns = Array(controllers_list).select { |pat| pat.to_s.include?("#") }
|
|
154
|
-
rails_patterns.concat(action_patterns)
|
|
155
|
-
end
|
|
156
|
-
return rails_patterns if !rails_patterns.empty?
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
env = ENV["APM_BRO_EXCLUDED_CONTROLLER_ACTIONS"]
|
|
161
|
-
if env && !env.strip.empty?
|
|
162
|
-
env_patterns = env.split(",").map(&:strip)
|
|
163
|
-
# Also check excluded_controllers env var for action patterns
|
|
164
|
-
controllers_env = ENV["APM_BRO_EXCLUDED_CONTROLLERS"]
|
|
165
|
-
if controllers_env && !controllers_env.strip.empty?
|
|
166
|
-
action_patterns = controllers_env.split(",").map(&:strip).select { |pat| pat.include?("#") }
|
|
167
|
-
env_patterns.concat(action_patterns)
|
|
168
|
-
end
|
|
169
|
-
return env_patterns if !env_patterns.empty?
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
[]
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def resolve_excluded_controllers
|
|
176
|
-
return @excluded_controllers if @excluded_controllers && !@excluded_controllers.empty?
|
|
177
|
-
|
|
178
|
-
if defined?(Rails)
|
|
179
|
-
list = fetch_from_rails_settings(%w[apm_bro excluded_controllers])
|
|
180
|
-
return Array(list) if list
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
env = ENV["APM_BRO_EXCLUDED_CONTROLLERS"]
|
|
184
|
-
return env.split(",").map(&:strip) if env && !env.strip.empty?
|
|
185
|
-
|
|
186
|
-
[]
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def resolve_excluded_jobs
|
|
190
|
-
return @excluded_jobs if @excluded_jobs && !@excluded_jobs.empty?
|
|
191
|
-
|
|
192
|
-
if defined?(Rails)
|
|
193
|
-
list = fetch_from_rails_settings(%w[apm_bro excluded_jobs])
|
|
194
|
-
return Array(list) if list
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
env = ENV["APM_BRO_EXCLUDED_JOBS"]
|
|
198
|
-
return env.split(",").map(&:strip) if env && !env.strip.empty?
|
|
199
|
-
|
|
200
|
-
[]
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def resolve_exclusive_controller_actions
|
|
204
|
-
# Collect patterns from @exclusive_controller_actions
|
|
205
|
-
patterns = []
|
|
206
|
-
if @exclusive_controller_actions && !@exclusive_controller_actions.empty?
|
|
207
|
-
patterns.concat(Array(@exclusive_controller_actions))
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
return patterns if !patterns.empty?
|
|
211
|
-
|
|
212
|
-
if defined?(Rails)
|
|
213
|
-
list = fetch_from_rails_settings(%w[apm_bro exclusive_controller_actions])
|
|
214
|
-
if list
|
|
215
|
-
rails_patterns = Array(list)
|
|
216
|
-
return rails_patterns if !rails_patterns.empty?
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
env = ENV["APM_BRO_EXCLUSIVE_CONTROLLER_ACTIONS"]
|
|
221
|
-
if env && !env.strip.empty?
|
|
222
|
-
env_patterns = env.split(",").map(&:strip)
|
|
223
|
-
return env_patterns if !env_patterns.empty?
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
[]
|
|
76
|
+
@exclusive_controllers.any? { |pat| match_name_or_pattern?(target, pat) }
|
|
227
77
|
end
|
|
228
78
|
|
|
229
|
-
def resolve_exclusive_jobs
|
|
230
|
-
# Collect patterns from @exclusive_jobs
|
|
231
|
-
patterns = []
|
|
232
|
-
if @exclusive_jobs && !@exclusive_jobs.empty?
|
|
233
|
-
patterns.concat(Array(@exclusive_jobs))
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
return patterns if !patterns.empty?
|
|
237
|
-
|
|
238
|
-
if defined?(Rails)
|
|
239
|
-
list = fetch_from_rails_settings(%w[apm_bro exclusive_jobs])
|
|
240
|
-
if list
|
|
241
|
-
rails_patterns = Array(list)
|
|
242
|
-
return rails_patterns if !rails_patterns.empty?
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
env = ENV["APM_BRO_EXCLUSIVE_JOBS"]
|
|
247
|
-
if env && !env.strip.empty?
|
|
248
|
-
env_patterns = env.split(",").map(&:strip)
|
|
249
|
-
return env_patterns if !env_patterns.empty?
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
[]
|
|
253
|
-
end
|
|
254
79
|
|
|
255
80
|
def should_sample?
|
|
256
81
|
sample_rate = resolve_sample_rate
|
|
@@ -260,13 +85,34 @@ module ApmBro
|
|
|
260
85
|
# Generate random number 1-100 and check if it's within sample rate
|
|
261
86
|
rand(1..100) <= sample_rate
|
|
262
87
|
end
|
|
88
|
+
|
|
89
|
+
def resolve_sample_rate
|
|
90
|
+
return @sample_rate unless @sample_rate.nil?
|
|
91
|
+
|
|
92
|
+
if ENV["APM_BRO_SAMPLE_RATE"]
|
|
93
|
+
env_value = ENV["APM_BRO_SAMPLE_RATE"].to_s.strip
|
|
94
|
+
# Validate that it's a valid integer string
|
|
95
|
+
if env_value.match?(/^\d+$/)
|
|
96
|
+
parsed = env_value.to_i
|
|
97
|
+
# Ensure it's in valid range (0-100)
|
|
98
|
+
(parsed >= 0 && parsed <= 100) ? parsed : 100
|
|
99
|
+
else
|
|
100
|
+
100 # Invalid format, fall back to default
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
100 # default
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def resolve_api_key
|
|
108
|
+
return @api_key unless @api_key.nil?
|
|
109
|
+
|
|
110
|
+
ENV["APM_BRO_API_KEY"]
|
|
111
|
+
end
|
|
263
112
|
|
|
264
113
|
def sample_rate=(value)
|
|
265
114
|
# Allow nil to use default/resolved value
|
|
266
|
-
if value.nil?
|
|
267
|
-
@sample_rate = nil
|
|
268
|
-
return
|
|
269
|
-
end
|
|
115
|
+
return @sample_rate = nil if value.nil?
|
|
270
116
|
|
|
271
117
|
# Allow 0 to disable sampling, or 1-100 for percentage
|
|
272
118
|
unless value.is_a?(Integer) && value >= 0 && value <= 100
|
|
@@ -277,10 +123,6 @@ module ApmBro
|
|
|
277
123
|
|
|
278
124
|
private
|
|
279
125
|
|
|
280
|
-
def present?(value)
|
|
281
|
-
!(value.nil? || (value.respond_to?(:empty?) && value.empty?))
|
|
282
|
-
end
|
|
283
|
-
|
|
284
126
|
def match_name_or_pattern?(name, pattern)
|
|
285
127
|
return false if name.nil? || pattern.nil?
|
|
286
128
|
pat = pattern.to_s
|
|
@@ -300,79 +142,5 @@ module ApmBro
|
|
|
300
142
|
false
|
|
301
143
|
end
|
|
302
144
|
|
|
303
|
-
def fetch_from_rails_settings(path_keys = ["apm_bro", "api_key"])
|
|
304
|
-
# Try Rails.application.config_for(:apm_bro)
|
|
305
|
-
begin
|
|
306
|
-
if Rails.respond_to?(:application) && Rails.application.respond_to?(:config_for)
|
|
307
|
-
config = begin
|
|
308
|
-
Rails.application.config_for(:apm_bro)
|
|
309
|
-
rescue
|
|
310
|
-
nil
|
|
311
|
-
end
|
|
312
|
-
if config && config.is_a?(Hash)
|
|
313
|
-
return dig_hash(config, *Array(path_keys))
|
|
314
|
-
end
|
|
315
|
-
end
|
|
316
|
-
rescue
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
# Try Rails.application.credentials
|
|
320
|
-
begin
|
|
321
|
-
creds = Rails.application.credentials if Rails.respond_to?(:application)
|
|
322
|
-
if creds
|
|
323
|
-
# credentials.apm_bro[:api_key] or credentials[:apm_bro][:api_key]
|
|
324
|
-
value = dig_credentials(creds, *Array(path_keys))
|
|
325
|
-
return value if present?(value)
|
|
326
|
-
end
|
|
327
|
-
rescue
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
# Try Rails.application.config.x.apm_bro.api_key
|
|
331
|
-
begin
|
|
332
|
-
x = Rails.application.config.x if Rails.respond_to?(:application)
|
|
333
|
-
if x && x.respond_to?(:apm_bro)
|
|
334
|
-
config_x = x.apm_bro
|
|
335
|
-
return config_x.public_send(Array(path_keys).last) if config_x.respond_to?(Array(path_keys).last)
|
|
336
|
-
end
|
|
337
|
-
rescue
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
nil
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
def dig_hash(hash, *keys)
|
|
344
|
-
keys.reduce(hash) do |memo, key|
|
|
345
|
-
break nil unless memo.is_a?(Hash)
|
|
346
|
-
memo[key.to_s] || memo[key.to_sym]
|
|
347
|
-
end
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
def dig_credentials(creds, *keys)
|
|
351
|
-
# Rails credentials can behave like hashes or use methods
|
|
352
|
-
current = creds
|
|
353
|
-
keys.each do |key|
|
|
354
|
-
if current.respond_to?(:[]) && current[key].nil? && current[key.to_sym].nil?
|
|
355
|
-
if current.respond_to?(key)
|
|
356
|
-
current = current.public_send(key)
|
|
357
|
-
elsif current.respond_to?(key.to_sym)
|
|
358
|
-
current = current.public_send(key.to_sym)
|
|
359
|
-
else
|
|
360
|
-
return nil
|
|
361
|
-
end
|
|
362
|
-
else
|
|
363
|
-
current = current[key] || current[key.to_sym]
|
|
364
|
-
end
|
|
365
|
-
return nil if current.nil?
|
|
366
|
-
end
|
|
367
|
-
current
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
def join_url(base, path)
|
|
371
|
-
base = base.to_s
|
|
372
|
-
path = path.to_s
|
|
373
|
-
base = base.chomp("/")
|
|
374
|
-
path = "/#{path}" unless path.start_with?("/")
|
|
375
|
-
base + path
|
|
376
|
-
end
|
|
377
145
|
end
|
|
378
146
|
end
|
|
@@ -38,7 +38,7 @@ module ApmBro
|
|
|
38
38
|
|
|
39
39
|
# Skip instrumentation for our own APM endpoint to prevent infinite loops,
|
|
40
40
|
# but do NOT alter the original method's return value/control flow.
|
|
41
|
-
skip_instrumentation = uri && (uri.to_s.include?("localhost") || uri.to_s.include?("
|
|
41
|
+
skip_instrumentation = uri && (uri.to_s.include?("localhost") || uri.to_s.include?("aberatii.com"))
|
|
42
42
|
|
|
43
43
|
unless skip_instrumentation
|
|
44
44
|
payload = {
|
|
@@ -85,7 +85,7 @@ module ApmBro
|
|
|
85
85
|
|
|
86
86
|
# Skip instrumentation for our own APM endpoint to prevent infinite loops,
|
|
87
87
|
# but do NOT alter the original method's return value/control flow.
|
|
88
|
-
skip_instrumentation = req_url && req_url.include?("localhost:3100/apm/v1/metrics")
|
|
88
|
+
skip_instrumentation = req_url && (req_url.include?("localhost:3100/apm/v1/metrics") || req_url.include?("deadbro.aberatii.com/apm/v1/metrics"))
|
|
89
89
|
|
|
90
90
|
unless skip_instrumentation
|
|
91
91
|
payload = {
|
data/lib/apm_bro/railtie.rb
CHANGED
|
@@ -10,26 +10,16 @@ end
|
|
|
10
10
|
if defined?(Rails) && defined?(Rails::Railtie)
|
|
11
11
|
module ApmBro
|
|
12
12
|
class Railtie < ::Rails::Railtie
|
|
13
|
-
initializer "apm_bro.configure" do |_app|
|
|
14
|
-
# Allow host app to set config in Rails config, credentials, or ENV.
|
|
15
|
-
# If host app sets config.x.apm_bro, mirror into gem configuration.
|
|
16
|
-
|
|
17
|
-
if Rails.application.config.x.respond_to?(:apm_bro)
|
|
18
|
-
xcfg = Rails.application.config.x.apm_bro
|
|
19
|
-
ApmBro.configure do |cfg|
|
|
20
|
-
cfg.api_key = xcfg.api_key if xcfg.respond_to?(:api_key)
|
|
21
|
-
cfg.enabled = xcfg.enabled if xcfg.respond_to?(:enabled)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
rescue
|
|
25
|
-
end
|
|
26
13
|
|
|
27
14
|
initializer "apm_bro.subscribe" do |app|
|
|
28
15
|
app.config.after_initialize do
|
|
29
|
-
|
|
16
|
+
# Use the shared Client instance for all subscribers
|
|
17
|
+
shared_client = ApmBro.client
|
|
18
|
+
|
|
19
|
+
ApmBro::Subscriber.subscribe!(client: shared_client)
|
|
30
20
|
# Install outgoing HTTP instrumentation
|
|
31
21
|
require "apm_bro/http_instrumentation"
|
|
32
|
-
ApmBro::HttpInstrumentation.install!(client:
|
|
22
|
+
ApmBro::HttpInstrumentation.install!(client: shared_client)
|
|
33
23
|
|
|
34
24
|
# Install SQL query tracking
|
|
35
25
|
require "apm_bro/sql_subscriber"
|
|
@@ -45,7 +35,7 @@ if defined?(Rails) && defined?(Rails::Railtie)
|
|
|
45
35
|
|
|
46
36
|
# Install view rendering tracking
|
|
47
37
|
require "apm_bro/view_rendering_subscriber"
|
|
48
|
-
ApmBro::ViewRenderingSubscriber.subscribe!(client:
|
|
38
|
+
ApmBro::ViewRenderingSubscriber.subscribe!(client: shared_client)
|
|
49
39
|
|
|
50
40
|
# Install lightweight memory tracking (default)
|
|
51
41
|
require "apm_bro/lightweight_memory_tracker"
|
|
@@ -55,7 +45,7 @@ if defined?(Rails) && defined?(Rails::Railtie)
|
|
|
55
45
|
# Install detailed memory tracking only if enabled
|
|
56
46
|
if ApmBro.configuration.allocation_tracking_enabled
|
|
57
47
|
require "apm_bro/memory_tracking_subscriber"
|
|
58
|
-
ApmBro::MemoryTrackingSubscriber.subscribe!(client:
|
|
48
|
+
ApmBro::MemoryTrackingSubscriber.subscribe!(client: shared_client)
|
|
59
49
|
end
|
|
60
50
|
|
|
61
51
|
# Install job tracking if ActiveJob is available
|
|
@@ -63,7 +53,7 @@ if defined?(Rails) && defined?(Rails::Railtie)
|
|
|
63
53
|
require "apm_bro/job_subscriber"
|
|
64
54
|
require "apm_bro/job_sql_tracking_middleware"
|
|
65
55
|
ApmBro::JobSqlTrackingMiddleware.subscribe!
|
|
66
|
-
ApmBro::JobSubscriber.subscribe!(client:
|
|
56
|
+
ApmBro::JobSubscriber.subscribe!(client: shared_client)
|
|
67
57
|
end
|
|
68
58
|
rescue
|
|
69
59
|
# Never raise in Railtie init
|
|
@@ -73,13 +63,16 @@ if defined?(Rails) && defined?(Rails::Railtie)
|
|
|
73
63
|
# Insert Rack middleware early enough to observe uncaught exceptions
|
|
74
64
|
initializer "apm_bro.middleware" do |app|
|
|
75
65
|
require "apm_bro/error_middleware"
|
|
66
|
+
|
|
67
|
+
# Use the shared Client instance for the middleware
|
|
68
|
+
shared_client = ApmBro.client
|
|
76
69
|
|
|
77
70
|
if defined?(::ActionDispatch::DebugExceptions)
|
|
78
|
-
app.config.middleware.insert_before(::ActionDispatch::DebugExceptions, ::ApmBro::ErrorMiddleware)
|
|
71
|
+
app.config.middleware.insert_before(::ActionDispatch::DebugExceptions, ::ApmBro::ErrorMiddleware, shared_client)
|
|
79
72
|
elsif defined?(::ActionDispatch::ShowExceptions)
|
|
80
|
-
app.config.middleware.insert_before(::ActionDispatch::ShowExceptions, ::ApmBro::ErrorMiddleware)
|
|
73
|
+
app.config.middleware.insert_before(::ActionDispatch::ShowExceptions, ::ApmBro::ErrorMiddleware, shared_client)
|
|
81
74
|
else
|
|
82
|
-
app.config.middleware.use(::ApmBro::ErrorMiddleware)
|
|
75
|
+
app.config.middleware.use(::ApmBro::ErrorMiddleware, shared_client)
|
|
83
76
|
end
|
|
84
77
|
rescue
|
|
85
78
|
# Never raise in Railtie init
|
|
@@ -12,37 +12,31 @@ module ApmBro
|
|
|
12
12
|
|
|
13
13
|
# Start SQL tracking for this request
|
|
14
14
|
if defined?(ApmBro::SqlSubscriber)
|
|
15
|
-
puts "Starting SQL tracking for request: #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}"
|
|
16
15
|
ApmBro::SqlSubscriber.start_request_tracking
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
# Start cache tracking for this request
|
|
20
19
|
if defined?(ApmBro::CacheSubscriber)
|
|
21
|
-
puts "Starting cache tracking for request: #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}"
|
|
22
20
|
ApmBro::CacheSubscriber.start_request_tracking
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
# Start Redis tracking for this request
|
|
26
24
|
if defined?(ApmBro::RedisSubscriber)
|
|
27
|
-
puts "Starting redis tracking for request: #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}"
|
|
28
25
|
ApmBro::RedisSubscriber.start_request_tracking
|
|
29
26
|
end
|
|
30
27
|
|
|
31
28
|
# Start view rendering tracking for this request
|
|
32
29
|
if defined?(ApmBro::ViewRenderingSubscriber)
|
|
33
|
-
puts "Starting view rendering tracking for request: #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}"
|
|
34
30
|
ApmBro::ViewRenderingSubscriber.start_request_tracking
|
|
35
31
|
end
|
|
36
32
|
|
|
37
33
|
# Start lightweight memory tracking for this request
|
|
38
34
|
if defined?(ApmBro::LightweightMemoryTracker)
|
|
39
|
-
puts "Starting lightweight memory tracking for request: #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}"
|
|
40
35
|
ApmBro::LightweightMemoryTracker.start_request_tracking
|
|
41
36
|
end
|
|
42
37
|
|
|
43
38
|
# Start detailed memory tracking when allocation tracking is enabled
|
|
44
39
|
if ApmBro.configuration.allocation_tracking_enabled && defined?(ApmBro::MemoryTrackingSubscriber)
|
|
45
|
-
puts "Starting detailed memory tracking for request: #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}"
|
|
46
40
|
ApmBro::MemoryTrackingSubscriber.start_request_tracking
|
|
47
41
|
end
|
|
48
42
|
|
data/lib/apm_bro/subscriber.rb
CHANGED
|
@@ -13,11 +13,13 @@ module ApmBro
|
|
|
13
13
|
begin
|
|
14
14
|
controller_name = data[:controller].to_s
|
|
15
15
|
action_name = data[:action].to_s
|
|
16
|
-
if ApmBro.configuration.
|
|
16
|
+
if ApmBro.configuration.excluded_controller?(controller_name, action_name)
|
|
17
|
+
puts "excluded controller"
|
|
17
18
|
next
|
|
18
19
|
end
|
|
19
20
|
# If exclusive_controller_actions is defined and not empty, only track matching actions
|
|
20
|
-
unless ApmBro.configuration.
|
|
21
|
+
unless ApmBro.configuration.exclusive_controller?(controller_name, action_name)
|
|
22
|
+
puts "exclusive controller"
|
|
21
23
|
next
|
|
22
24
|
end
|
|
23
25
|
rescue
|
data/lib/apm_bro/version.rb
CHANGED
data/lib/apm_bro.rb
CHANGED
|
@@ -33,9 +33,15 @@ module ApmBro
|
|
|
33
33
|
def self.configuration
|
|
34
34
|
@configuration ||= Configuration.new
|
|
35
35
|
end
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
def self.reset_configuration!
|
|
38
|
-
@configuration =
|
|
38
|
+
@configuration = nil
|
|
39
|
+
@client = nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns a shared Client instance for use across the application
|
|
43
|
+
def self.client
|
|
44
|
+
@client ||= Client.new
|
|
39
45
|
end
|
|
40
46
|
|
|
41
47
|
# Returns a process-stable deploy identifier used when none is configured.
|