apm_bro 0.1.11 → 0.1.13
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/error_middleware.rb +2 -1
- data/lib/apm_bro/job_sql_tracking_middleware.rb +12 -0
- data/lib/apm_bro/job_subscriber.rb +64 -2
- data/lib/apm_bro/logger.rb +128 -0
- data/lib/apm_bro/sql_subscriber.rb +72 -14
- data/lib/apm_bro/sql_tracking_middleware.rb +3 -0
- data/lib/apm_bro/subscriber.rb +4 -2
- data/lib/apm_bro/version.rb +1 -1
- data/lib/apm_bro.rb +6 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1104f9fc59e6d12b981c8c9dbd646ccf0e4199afaf2a5792a40e7a928ebc2ac9
|
|
4
|
+
data.tar.gz: b6798ce81a4e61cfd7e05cdf5974cbf0475610b0355686fbd5fad538eb5a0ea6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 233bdd3ec6fe51292f331da900f3fbde862a4e78db6a3bceb1d6b2caeeef28bf9611f382ca0f0052baaa255a39f1fb2f3da57dc915c7def3a42d974df4f451e5
|
|
7
|
+
data.tar.gz: edff2e3c6da3985dab9b176387dafd65c315b7428e29e72231191c2d495831ba6ca69b74e085a882c614a712a9576b72c8f7fa757edfa5ebcd50ed417cf367ab
|
|
@@ -5,7 +5,19 @@ module ApmBro
|
|
|
5
5
|
def self.subscribe!
|
|
6
6
|
# Start SQL tracking when a job begins - use the start event, not the complete event
|
|
7
7
|
ActiveSupport::Notifications.subscribe("perform_start.active_job") do |name, started, finished, _unique_id, data|
|
|
8
|
+
# Clear logs for this job
|
|
9
|
+
ApmBro.logger.clear
|
|
8
10
|
ApmBro::SqlSubscriber.start_request_tracking
|
|
11
|
+
|
|
12
|
+
# Start lightweight memory tracking for this job
|
|
13
|
+
if defined?(ApmBro::LightweightMemoryTracker)
|
|
14
|
+
ApmBro::LightweightMemoryTracker.start_request_tracking
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Start detailed memory tracking when allocation tracking is enabled
|
|
18
|
+
if ApmBro.configuration.allocation_tracking_enabled && defined?(ApmBro::MemoryTrackingSubscriber)
|
|
19
|
+
ApmBro::MemoryTrackingSubscriber.start_request_tracking
|
|
20
|
+
end
|
|
9
21
|
end
|
|
10
22
|
rescue StandardError
|
|
11
23
|
# Never raise from instrumentation install
|
|
@@ -23,6 +23,34 @@ module ApmBro
|
|
|
23
23
|
# Get SQL queries executed during this job
|
|
24
24
|
sql_queries = ApmBro::SqlSubscriber.stop_request_tracking
|
|
25
25
|
|
|
26
|
+
# Stop memory tracking and get collected memory data
|
|
27
|
+
if ApmBro.configuration.allocation_tracking_enabled && defined?(ApmBro::MemoryTrackingSubscriber)
|
|
28
|
+
detailed_memory = ApmBro::MemoryTrackingSubscriber.stop_request_tracking
|
|
29
|
+
memory_performance = ApmBro::MemoryTrackingSubscriber.analyze_memory_performance(detailed_memory)
|
|
30
|
+
# Keep memory_events compact and user-friendly (no large raw arrays)
|
|
31
|
+
memory_events = {
|
|
32
|
+
memory_before: detailed_memory[:memory_before],
|
|
33
|
+
memory_after: detailed_memory[:memory_after],
|
|
34
|
+
duration_seconds: detailed_memory[:duration_seconds],
|
|
35
|
+
allocations_count: (detailed_memory[:allocations] || []).length,
|
|
36
|
+
memory_snapshots_count: (detailed_memory[:memory_snapshots] || []).length,
|
|
37
|
+
large_objects_count: (detailed_memory[:large_objects] || []).length
|
|
38
|
+
}
|
|
39
|
+
else
|
|
40
|
+
lightweight_memory = ApmBro::LightweightMemoryTracker.stop_request_tracking
|
|
41
|
+
# Separate raw readings from derived performance metrics to avoid duplicating data
|
|
42
|
+
memory_events = {
|
|
43
|
+
memory_before: lightweight_memory[:memory_before],
|
|
44
|
+
memory_after: lightweight_memory[:memory_after]
|
|
45
|
+
}
|
|
46
|
+
memory_performance = {
|
|
47
|
+
memory_growth_mb: lightweight_memory[:memory_growth_mb],
|
|
48
|
+
gc_count_increase: lightweight_memory[:gc_count_increase],
|
|
49
|
+
heap_pages_increase: lightweight_memory[:heap_pages_increase],
|
|
50
|
+
duration_seconds: lightweight_memory[:duration_seconds]
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
26
54
|
payload = {
|
|
27
55
|
job_class: data[:job].class.name,
|
|
28
56
|
job_id: data[:job].job_id,
|
|
@@ -34,7 +62,10 @@ module ApmBro
|
|
|
34
62
|
rails_env: safe_rails_env,
|
|
35
63
|
host: safe_host,
|
|
36
64
|
memory_usage: memory_usage_mb,
|
|
37
|
-
gc_stats: gc_stats
|
|
65
|
+
gc_stats: gc_stats,
|
|
66
|
+
memory_events: memory_events,
|
|
67
|
+
memory_performance: memory_performance,
|
|
68
|
+
logs: ApmBro.logger.logs
|
|
38
69
|
}
|
|
39
70
|
|
|
40
71
|
client.post_metric(event_name: name, payload: payload)
|
|
@@ -56,6 +87,34 @@ module ApmBro
|
|
|
56
87
|
# Get SQL queries executed during this job
|
|
57
88
|
sql_queries = ApmBro::SqlSubscriber.stop_request_tracking
|
|
58
89
|
|
|
90
|
+
# Stop memory tracking and get collected memory data
|
|
91
|
+
if ApmBro.configuration.allocation_tracking_enabled && defined?(ApmBro::MemoryTrackingSubscriber)
|
|
92
|
+
detailed_memory = ApmBro::MemoryTrackingSubscriber.stop_request_tracking
|
|
93
|
+
memory_performance = ApmBro::MemoryTrackingSubscriber.analyze_memory_performance(detailed_memory)
|
|
94
|
+
# Keep memory_events compact and user-friendly (no large raw arrays)
|
|
95
|
+
memory_events = {
|
|
96
|
+
memory_before: detailed_memory[:memory_before],
|
|
97
|
+
memory_after: detailed_memory[:memory_after],
|
|
98
|
+
duration_seconds: detailed_memory[:duration_seconds],
|
|
99
|
+
allocations_count: (detailed_memory[:allocations] || []).length,
|
|
100
|
+
memory_snapshots_count: (detailed_memory[:memory_snapshots] || []).length,
|
|
101
|
+
large_objects_count: (detailed_memory[:large_objects] || []).length
|
|
102
|
+
}
|
|
103
|
+
else
|
|
104
|
+
lightweight_memory = ApmBro::LightweightMemoryTracker.stop_request_tracking
|
|
105
|
+
# Separate raw readings from derived performance metrics to avoid duplicating data
|
|
106
|
+
memory_events = {
|
|
107
|
+
memory_before: lightweight_memory[:memory_before],
|
|
108
|
+
memory_after: lightweight_memory[:memory_after]
|
|
109
|
+
}
|
|
110
|
+
memory_performance = {
|
|
111
|
+
memory_growth_mb: lightweight_memory[:memory_growth_mb],
|
|
112
|
+
gc_count_increase: lightweight_memory[:gc_count_increase],
|
|
113
|
+
heap_pages_increase: lightweight_memory[:heap_pages_increase],
|
|
114
|
+
duration_seconds: lightweight_memory[:duration_seconds]
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
|
|
59
118
|
payload = {
|
|
60
119
|
job_class: data[:job].class.name,
|
|
61
120
|
job_id: data[:job].job_id,
|
|
@@ -70,7 +129,10 @@ module ApmBro
|
|
|
70
129
|
rails_env: safe_rails_env,
|
|
71
130
|
host: safe_host,
|
|
72
131
|
memory_usage: memory_usage_mb,
|
|
73
|
-
gc_stats: gc_stats
|
|
132
|
+
gc_stats: gc_stats,
|
|
133
|
+
memory_events: memory_events,
|
|
134
|
+
memory_performance: memory_performance,
|
|
135
|
+
logs: ApmBro.logger.logs
|
|
74
136
|
}
|
|
75
137
|
|
|
76
138
|
event_name = exception&.class&.name || "ActiveJob::Exception"
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ApmBro
|
|
4
|
+
class Logger
|
|
5
|
+
SEVERITY_LEVELS = {
|
|
6
|
+
debug: 0,
|
|
7
|
+
info: 1,
|
|
8
|
+
warn: 2,
|
|
9
|
+
error: 3,
|
|
10
|
+
fatal: 4
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
# ANSI color codes
|
|
14
|
+
COLOR_RESET = "\033[0m".freeze
|
|
15
|
+
COLOR_DEBUG = "\033[36m".freeze # Cyan
|
|
16
|
+
COLOR_INFO = "\033[32m".freeze # Green
|
|
17
|
+
COLOR_WARN = "\033[33m".freeze # Yellow
|
|
18
|
+
COLOR_ERROR = "\033[31m".freeze # Red
|
|
19
|
+
COLOR_FATAL = "\033[35m".freeze # Magenta
|
|
20
|
+
|
|
21
|
+
def initialize
|
|
22
|
+
@thread_logs_key = :apm_bro_logs
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def debug(message)
|
|
26
|
+
log(:debug, message)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def info(message)
|
|
30
|
+
log(:info, message)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def warn(message)
|
|
34
|
+
log(:warn, message)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def error(message)
|
|
38
|
+
log(:error, message)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def fatal(message)
|
|
42
|
+
log(:fatal, message)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Get all logs for the current thread
|
|
46
|
+
def logs
|
|
47
|
+
Thread.current[@thread_logs_key] || []
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Clear logs for the current thread
|
|
51
|
+
def clear
|
|
52
|
+
Thread.current[@thread_logs_key] = []
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def log(severity, message)
|
|
58
|
+
timestamp = Time.now.utc
|
|
59
|
+
log_entry = {
|
|
60
|
+
sev: severity.to_s,
|
|
61
|
+
msg: message.to_s,
|
|
62
|
+
time: timestamp.iso8601(3) # Include milliseconds for better precision
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Store in thread-local storage
|
|
66
|
+
Thread.current[@thread_logs_key] ||= []
|
|
67
|
+
Thread.current[@thread_logs_key] << log_entry
|
|
68
|
+
|
|
69
|
+
# Print the message immediately
|
|
70
|
+
print_log(severity, message, timestamp)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def print_log(severity, message, timestamp)
|
|
74
|
+
formatted_message = format_log_message(severity, message, timestamp)
|
|
75
|
+
|
|
76
|
+
if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
|
77
|
+
# Use Rails logger if available (Rails handles its own color formatting)
|
|
78
|
+
case severity
|
|
79
|
+
when :debug
|
|
80
|
+
Rails.logger.debug(formatted_message)
|
|
81
|
+
when :info
|
|
82
|
+
Rails.logger.info(formatted_message)
|
|
83
|
+
when :warn
|
|
84
|
+
Rails.logger.warn(formatted_message)
|
|
85
|
+
when :error
|
|
86
|
+
Rails.logger.error(formatted_message)
|
|
87
|
+
when :fatal
|
|
88
|
+
Rails.logger.fatal(formatted_message)
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
# Fallback to stdout with colors
|
|
92
|
+
colored_message = format_log_message_with_color(severity, message, timestamp)
|
|
93
|
+
$stdout.puts(colored_message)
|
|
94
|
+
end
|
|
95
|
+
rescue StandardError
|
|
96
|
+
# Never let logging break the application
|
|
97
|
+
$stdout.puts("[ApmBro] #{severity.to_s.upcase}: #{message}")
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def format_log_message(severity, message, timestamp)
|
|
101
|
+
"[ApmBro] #{timestamp.iso8601(3)} #{severity.to_s.upcase}: #{message}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def format_log_message_with_color(severity, message, timestamp)
|
|
105
|
+
color = color_for_severity(severity)
|
|
106
|
+
severity_str = severity.to_s.upcase
|
|
107
|
+
"#{color}[ApmBro] #{timestamp.iso8601(3)} #{severity_str}: #{message}#{COLOR_RESET}"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def color_for_severity(severity)
|
|
111
|
+
case severity
|
|
112
|
+
when :debug
|
|
113
|
+
COLOR_DEBUG
|
|
114
|
+
when :info
|
|
115
|
+
COLOR_INFO
|
|
116
|
+
when :warn
|
|
117
|
+
COLOR_WARN
|
|
118
|
+
when :error
|
|
119
|
+
COLOR_ERROR
|
|
120
|
+
when :fatal
|
|
121
|
+
COLOR_FATAL
|
|
122
|
+
else
|
|
123
|
+
COLOR_RESET
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
@@ -9,6 +9,7 @@ module ApmBro
|
|
|
9
9
|
THREAD_LOCAL_KEY = :apm_bro_sql_queries
|
|
10
10
|
THREAD_LOCAL_ALLOC_START_KEY = :apm_bro_sql_alloc_start
|
|
11
11
|
THREAD_LOCAL_ALLOC_RESULTS_KEY = :apm_bro_sql_alloc_results
|
|
12
|
+
THREAD_LOCAL_BACKTRACE_KEY = :apm_bro_sql_backtraces
|
|
12
13
|
|
|
13
14
|
def self.subscribe!
|
|
14
15
|
# Subscribe with a start/finish listener to measure allocations per query
|
|
@@ -20,13 +21,19 @@ module ApmBro
|
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
ActiveSupport::Notifications.subscribe(SQL_EVENT_NAME) do |name, started, finished, _unique_id, data|
|
|
24
|
+
next if data[:name] == "SCHEMA"
|
|
23
25
|
# Only track queries that are part of the current request
|
|
24
26
|
next unless Thread.current[THREAD_LOCAL_KEY]
|
|
25
27
|
unique_id = _unique_id
|
|
26
28
|
allocations = nil
|
|
29
|
+
captured_backtrace = nil
|
|
27
30
|
begin
|
|
28
31
|
alloc_results = Thread.current[THREAD_LOCAL_ALLOC_RESULTS_KEY]
|
|
29
32
|
allocations = alloc_results && alloc_results.delete(unique_id)
|
|
33
|
+
|
|
34
|
+
# Get the captured backtrace from when the query started
|
|
35
|
+
backtrace_map = Thread.current[THREAD_LOCAL_BACKTRACE_KEY]
|
|
36
|
+
captured_backtrace = backtrace_map && backtrace_map.delete(unique_id)
|
|
30
37
|
rescue StandardError
|
|
31
38
|
end
|
|
32
39
|
|
|
@@ -36,7 +43,7 @@ module ApmBro
|
|
|
36
43
|
duration_ms: ((finished - started) * 1000.0).round(2),
|
|
37
44
|
cached: data[:cached] || false,
|
|
38
45
|
connection_id: data[:connection_id],
|
|
39
|
-
trace: safe_query_trace(data),
|
|
46
|
+
trace: safe_query_trace(data, captured_backtrace),
|
|
40
47
|
allocations: allocations
|
|
41
48
|
}
|
|
42
49
|
# Add to thread-local storage
|
|
@@ -49,6 +56,7 @@ module ApmBro
|
|
|
49
56
|
Thread.current[THREAD_LOCAL_KEY] = []
|
|
50
57
|
Thread.current[THREAD_LOCAL_ALLOC_START_KEY] = {}
|
|
51
58
|
Thread.current[THREAD_LOCAL_ALLOC_RESULTS_KEY] = {}
|
|
59
|
+
Thread.current[THREAD_LOCAL_BACKTRACE_KEY] = {}
|
|
52
60
|
end
|
|
53
61
|
|
|
54
62
|
def self.stop_request_tracking
|
|
@@ -56,6 +64,7 @@ module ApmBro
|
|
|
56
64
|
Thread.current[THREAD_LOCAL_KEY] = nil
|
|
57
65
|
Thread.current[THREAD_LOCAL_ALLOC_START_KEY] = nil
|
|
58
66
|
Thread.current[THREAD_LOCAL_ALLOC_RESULTS_KEY] = nil
|
|
67
|
+
Thread.current[THREAD_LOCAL_BACKTRACE_KEY] = nil
|
|
59
68
|
queries || []
|
|
60
69
|
end
|
|
61
70
|
|
|
@@ -75,7 +84,7 @@ module ApmBro
|
|
|
75
84
|
sql.length > 1000 ? sql[0..1000] + "..." : sql
|
|
76
85
|
end
|
|
77
86
|
|
|
78
|
-
def self.safe_query_trace(data)
|
|
87
|
+
def self.safe_query_trace(data, captured_backtrace = nil)
|
|
79
88
|
return [] unless data.is_a?(Hash)
|
|
80
89
|
|
|
81
90
|
# Build trace from available data fields
|
|
@@ -86,24 +95,64 @@ module ApmBro
|
|
|
86
95
|
trace << "#{data[:filename]}:#{data[:line]}:in `#{data[:method]}'"
|
|
87
96
|
end
|
|
88
97
|
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
#
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
# Use the captured backtrace from when the query started (most accurate)
|
|
99
|
+
if captured_backtrace && captured_backtrace.is_a?(Array) && !captured_backtrace.empty?
|
|
100
|
+
# Filter to only include frames that contain "app/" (application code)
|
|
101
|
+
app_frames = captured_backtrace.select do |frame|
|
|
102
|
+
frame.include?('/app/')
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
caller_trace = app_frames.map do |line|
|
|
94
106
|
# Remove any potential sensitive information from file paths
|
|
95
107
|
line.gsub(/\/[^\/]*(password|secret|key|token)[^\/]*\//i, '/[FILTERED]/')
|
|
96
108
|
end
|
|
97
109
|
|
|
98
|
-
# Combine the immediate location with the call stack
|
|
99
110
|
trace.concat(caller_trace)
|
|
100
|
-
|
|
101
|
-
#
|
|
111
|
+
else
|
|
112
|
+
# Fallback: try to get backtrace from current context
|
|
113
|
+
begin
|
|
114
|
+
# Get all available frames - we'll filter to find application code
|
|
115
|
+
all_frames = Thread.current.backtrace || []
|
|
116
|
+
|
|
117
|
+
if all_frames.empty?
|
|
118
|
+
# Fallback to caller_locations if backtrace is empty
|
|
119
|
+
locations = caller_locations(1, 50)
|
|
120
|
+
all_frames = locations.map { |loc| "#{loc.path}:#{loc.lineno}:in `#{loc.label}'" } if locations
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Filter to only include frames that contain "app/" (application code)
|
|
124
|
+
app_frames = all_frames.select do |frame|
|
|
125
|
+
frame.include?('/app/')
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
caller_trace = app_frames.map do |line|
|
|
129
|
+
line.gsub(/\/[^\/]*(password|secret|key|token)[^\/]*\//i, '/[FILTERED]/')
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
trace.concat(caller_trace)
|
|
133
|
+
rescue StandardError
|
|
134
|
+
# If backtrace fails, try caller as fallback
|
|
135
|
+
begin
|
|
136
|
+
caller_stack = caller(20, 50) # Get more frames to find app/ frames
|
|
137
|
+
app_frames = caller_stack.select { |frame| frame.include?('/app/') }
|
|
138
|
+
caller_trace = app_frames.map do |line|
|
|
139
|
+
line.gsub(/\/[^\/]*(password|secret|key|token)[^\/]*\//i, '/[FILTERED]/')
|
|
140
|
+
end
|
|
141
|
+
trace.concat(caller_trace)
|
|
142
|
+
rescue StandardError
|
|
143
|
+
# If caller also fails, we still have the immediate location
|
|
144
|
+
end
|
|
145
|
+
end
|
|
102
146
|
end
|
|
103
147
|
|
|
104
|
-
# If we have a backtrace, use it (but it's usually nil for SQL events)
|
|
148
|
+
# If we have a backtrace in the data, use it (but it's usually nil for SQL events)
|
|
105
149
|
if data[:backtrace] && data[:backtrace].is_a?(Array)
|
|
106
|
-
|
|
150
|
+
# Filter to only include frames that contain "app/"
|
|
151
|
+
app_backtrace = data[:backtrace].select do |line|
|
|
152
|
+
line.is_a?(String) && line.include?('/app/')
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
backtrace_trace = app_backtrace.map do |line|
|
|
107
156
|
case line
|
|
108
157
|
when String
|
|
109
158
|
line.gsub(/\/[^\/]*(password|secret|key|token)[^\/]*\//i, '/[FILTERED]/')
|
|
@@ -114,8 +163,8 @@ module ApmBro
|
|
|
114
163
|
trace.concat(backtrace_trace)
|
|
115
164
|
end
|
|
116
165
|
|
|
117
|
-
# Remove duplicates and
|
|
118
|
-
trace.uniq.
|
|
166
|
+
# Remove duplicates and return all app/ frames (no limit)
|
|
167
|
+
trace.uniq.map do |line|
|
|
119
168
|
case line
|
|
120
169
|
when String
|
|
121
170
|
# Remove any potential sensitive information from file paths
|
|
@@ -138,6 +187,15 @@ module ApmBro
|
|
|
138
187
|
begin
|
|
139
188
|
map = (Thread.current[ApmBro::SqlSubscriber::THREAD_LOCAL_ALLOC_START_KEY] ||= {})
|
|
140
189
|
map[id] = GC.stat[:total_allocated_objects] if defined?(GC) && GC.respond_to?(:stat)
|
|
190
|
+
|
|
191
|
+
# Capture the backtrace at query start time (before notification system processes it)
|
|
192
|
+
# This gives us the actual call stack where the SQL was executed
|
|
193
|
+
backtrace_map = (Thread.current[ApmBro::SqlSubscriber::THREAD_LOCAL_BACKTRACE_KEY] ||= {})
|
|
194
|
+
captured_backtrace = Thread.current.backtrace
|
|
195
|
+
if captured_backtrace && captured_backtrace.is_a?(Array)
|
|
196
|
+
# Skip the first few frames (our listener code) to get to the actual query execution
|
|
197
|
+
backtrace_map[id] = captured_backtrace[5..-1] || captured_backtrace
|
|
198
|
+
end
|
|
141
199
|
rescue StandardError
|
|
142
200
|
end
|
|
143
201
|
end
|
|
@@ -7,6 +7,9 @@ module ApmBro
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def call(env)
|
|
10
|
+
# Clear logs for this request
|
|
11
|
+
ApmBro.logger.clear
|
|
12
|
+
|
|
10
13
|
# Start SQL tracking for this request
|
|
11
14
|
if defined?(ApmBro::SqlSubscriber)
|
|
12
15
|
puts "Starting SQL tracking for request: #{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
|
data/lib/apm_bro/subscriber.rb
CHANGED
|
@@ -95,7 +95,8 @@ module ApmBro
|
|
|
95
95
|
exception_class: (exception_class || exception_obj&.class&.name),
|
|
96
96
|
message: (exception_message || exception_obj&.message).to_s[0, 1000],
|
|
97
97
|
backtrace: backtrace,
|
|
98
|
-
error: true
|
|
98
|
+
error: true,
|
|
99
|
+
logs: ApmBro.logger.logs
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
event_name = (exception_class || exception_obj&.class&.name || "exception").to_s
|
|
@@ -134,7 +135,8 @@ module ApmBro
|
|
|
134
135
|
view_events: view_events,
|
|
135
136
|
view_performance: view_performance,
|
|
136
137
|
memory_events: memory_events,
|
|
137
|
-
memory_performance: memory_performance
|
|
138
|
+
memory_performance: memory_performance,
|
|
139
|
+
logs: ApmBro.logger.logs
|
|
138
140
|
}
|
|
139
141
|
client.post_metric(event_name: name, payload: payload)
|
|
140
142
|
end
|
data/lib/apm_bro/version.rb
CHANGED
data/lib/apm_bro.rb
CHANGED
|
@@ -18,6 +18,7 @@ module ApmBro
|
|
|
18
18
|
autoload :MemoryHelpers, "apm_bro/memory_helpers"
|
|
19
19
|
autoload :JobSubscriber, "apm_bro/job_subscriber"
|
|
20
20
|
autoload :JobSqlTrackingMiddleware, "apm_bro/job_sql_tracking_middleware"
|
|
21
|
+
autoload :Logger, "apm_bro/logger"
|
|
21
22
|
begin
|
|
22
23
|
require "apm_bro/railtie"
|
|
23
24
|
rescue LoadError
|
|
@@ -45,4 +46,9 @@ module ApmBro
|
|
|
45
46
|
SecureRandom.uuid
|
|
46
47
|
end
|
|
47
48
|
end
|
|
49
|
+
|
|
50
|
+
# Returns the logger instance for storing and retrieving log messages
|
|
51
|
+
def self.logger
|
|
52
|
+
@logger ||= Logger.new
|
|
53
|
+
end
|
|
48
54
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: apm_bro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emanuel Comsa
|
|
@@ -29,6 +29,7 @@ files:
|
|
|
29
29
|
- lib/apm_bro/job_sql_tracking_middleware.rb
|
|
30
30
|
- lib/apm_bro/job_subscriber.rb
|
|
31
31
|
- lib/apm_bro/lightweight_memory_tracker.rb
|
|
32
|
+
- lib/apm_bro/logger.rb
|
|
32
33
|
- lib/apm_bro/memory_helpers.rb
|
|
33
34
|
- lib/apm_bro/memory_leak_detector.rb
|
|
34
35
|
- lib/apm_bro/memory_tracking_subscriber.rb
|