Skip to content

Commit 08e1655

Browse files
committed
Refactor CQL performance monitoring integration for improved metrics collection and clarity
1 parent 5db13e9 commit 08e1655

1 file changed

Lines changed: 52 additions & 40 deletions

File tree

src/azu/components/dev_dashboard_component.cr

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,26 @@ module Azu
102102
{% if @top_level.has_constant?("CQL") %}
103103
monitor = CQL::Performance.monitor
104104
metrics = monitor.metrics_summary
105-
stats = monitor.query_profiler.statistics
106-
slow_queries = monitor.query_profiler.slow_queries
107-
n_plus_one_issues = monitor.n_plus_one_detector.issues
105+
profiler = monitor.profiler.not_nil!
106+
detector = monitor.detector.not_nil!
107+
stats = profiler.statistics
108+
slow_queries = profiler.slowest_queries(100)
109+
n_plus_one_issues = detector.issues
108110

109111
# Calculate aggregate stats from query statistics
110-
total_queries = stats.values.sum(&.execution_count)
112+
total_queries = stats.values.sum(&.[:count]).to_i64
111113
slow_query_count = slow_queries.size
112-
avg_time = stats.empty? ? 0.0 : stats.values.sum(&.avg_time.total_milliseconds) / stats.size
113-
min_time = stats.empty? ? 0.0 : stats.values.min_of(&.min_time.total_milliseconds)
114-
max_time = stats.empty? ? 0.0 : stats.values.max_of(&.max_time.total_milliseconds)
114+
avg_time = stats.empty? ? 0.0 : stats.values.sum(&.[:avg_ms]) / stats.size
115+
min_time = stats.empty? ? 0.0 : stats.values.min_of(&.[:min_ms])
116+
max_time = stats.empty? ? 0.0 : stats.values.max_of(&.[:max_ms])
117+
118+
slow_queries_count = (metrics["slow_queries"]?.try(&.as(Int64)) || 0_i64)
119+
n_plus_one_count = (metrics["n_plus_one_patterns"]?.try(&.as(Int64)) || 0_i64)
120+
avg_query_time_ms = (metrics["avg_query_time_ms"]?.try(&.as(Float64)) || 0.0)
121+
uptime_seconds = (metrics["uptime_seconds"]?.try(&.as(Float64)) || 0.0)
115122

116123
{
117-
"total_queries" => total_queries.to_i64,
124+
"total_queries" => total_queries,
118125
"slow_queries" => slow_query_count.to_i64,
119126
"very_slow_queries" => slow_queries.count { |q| q.execution_time.total_milliseconds > 500 }.to_i64,
120127
"error_queries" => 0_i64,
@@ -125,18 +132,18 @@ module Azu
125132
"queries_per_second" => 0.0,
126133
"slow_query_rate" => total_queries > 0 ? (slow_query_count.to_f / total_queries * 100) : 0.0,
127134
"n_plus_one_patterns" => n_plus_one_issues.size,
128-
"critical_n_plus_one" => n_plus_one_issues.count { |i| i.severity == CQL::Performance::PerformanceIssue::Severity::Critical },
129-
"high_n_plus_one" => n_plus_one_issues.count { |i| i.severity == CQL::Performance::PerformanceIssue::Severity::High },
135+
"critical_n_plus_one" => n_plus_one_issues.count { |i| i.severity == :critical },
136+
"high_n_plus_one" => n_plus_one_issues.count { |i| i.severity == :high },
130137
"database_health_score" => begin
131138
# Calculate health score inline
132139
health = 100
133-
health -= [metrics.slow_queries * 2, 30].min
134-
health -= [metrics.n_plus_one_patterns * 5, 25].min
135-
health -= metrics.avg_query_time > 100 ? [((metrics.avg_query_time - 100) / 50).to_i, 20].min : 0
140+
health -= [slow_queries_count * 2, 30].min
141+
health -= [n_plus_one_count * 5, 25].min
142+
health -= avg_query_time_ms > 100 ? [((avg_query_time_ms - 100) / 50).to_i, 20].min : 0
136143
health.clamp(0, 100)
137144
end,
138145
"monitoring_enabled" => monitor.enabled?,
139-
"uptime" => metrics.uptime,
146+
"uptime" => Time::Span.new(seconds: uptime_seconds.to_i64),
140147
}
141148
{% else %}
142149
# CQL not available - return default values
@@ -185,7 +192,10 @@ module Azu
185192
{% if @top_level.has_constant?("CQL") %}
186193
monitor = CQL::Performance.monitor
187194
metrics = monitor.metrics_summary
188-
metrics.total_queries + metrics.slow_queries + metrics.n_plus_one_patterns
195+
total = (metrics["total_queries"]?.try(&.as(Int64)) || 0_i64)
196+
slow = (metrics["slow_queries"]?.try(&.as(Int64)) || 0_i64)
197+
npo = (metrics["n_plus_one_patterns"]?.try(&.as(Int64)) || 0_i64)
198+
(total + slow + npo).to_i32
189199
{% else %}
190200
0 # CQL not available
191201
{% end %}
@@ -196,32 +206,33 @@ module Azu
196206
def collect_query_profiler_data
197207
{% if @top_level.has_constant?("CQL") %}
198208
monitor = CQL::Performance.monitor
199-
stats = monitor.query_profiler.statistics
200-
slowest = monitor.query_profiler.slowest_queries(10)
209+
profiler = monitor.profiler.not_nil!
210+
stats = profiler.statistics
211+
slowest = profiler.slowest_queries(10)
201212

202-
total_executions = stats.values.sum(&.execution_count)
203-
max_time = stats.empty? ? 0.0 : stats.values.max_of(&.max_time.total_milliseconds)
204-
most_frequent = stats.values.max_by?(&.execution_count)
213+
total_executions = stats.values.sum(&.[:count]).to_i64
214+
max_time = stats.empty? ? 0.0 : stats.values.max_of(&.[:max_ms])
215+
most_frequent = stats.values.max_by?(&.[:count])
205216

206217
{
207218
"unique_patterns" => stats.size,
208-
"total_executions" => total_executions.to_i64,
219+
"total_executions" => total_executions,
209220
"avg_performance_score" => begin
210221
# Calculate average performance score across all query patterns
211222
if stats.empty?
212223
100.0
213224
else
214225
total_score = stats.values.sum do |stat|
215226
score = 100.0
216-
score -= [(stat.execution_count - 100) / 50.0, 30.0].min if stat.execution_count > 100
217-
score -= [(stat.avg_time.total_milliseconds - 50) / 25.0, 40.0].min if stat.avg_time.total_milliseconds > 50
227+
score -= [(stat[:count] - 100) / 50.0, 30.0].min if stat[:count] > 100
228+
score -= [(stat[:avg_ms] - 50) / 25.0, 40.0].min if stat[:avg_ms] > 50
218229
score.clamp(0.0, 100.0)
219230
end
220231
total_score / stats.size
221232
end
222233
end,
223234
"slowest_pattern_time" => max_time,
224-
"most_frequent_count" => (most_frequent.try(&.execution_count) || 0).to_i64,
235+
"most_frequent_count" => (most_frequent.try(&.[:count]) || 0).to_i64,
225236
}
226237
{% else %}
227238
# CQL not available - return default values
@@ -247,15 +258,15 @@ module Azu
247258
def collect_n_plus_one_data
248259
{% if @top_level.has_constant?("CQL") %}
249260
monitor = CQL::Performance.monitor
250-
issues = monitor.n_plus_one_detector.issues
261+
issues = monitor.detector.not_nil!.issues
251262

252263
{
253264
"issues" => issues.map { |i| {message: i.message, severity: i.severity.to_s, type: i.type}.to_json },
254265
"total_issues" => issues.size,
255-
"critical_count" => issues.count { |i| i.severity == CQL::Performance::PerformanceIssue::Severity::Critical },
256-
"high_count" => issues.count { |i| i.severity == CQL::Performance::PerformanceIssue::Severity::High },
257-
"medium_count" => issues.count { |i| i.severity == CQL::Performance::PerformanceIssue::Severity::Medium },
258-
"low_count" => issues.count { |i| i.severity == CQL::Performance::PerformanceIssue::Severity::Low },
266+
"critical_count" => issues.count { |i| i.severity == :critical },
267+
"high_count" => issues.count { |i| i.severity == :high },
268+
"medium_count" => issues.count { |i| i.severity == :medium },
269+
"low_count" => issues.count { |i| i.severity == :low },
259270
}
260271
{% else %}
261272
# CQL not available - return default values
@@ -283,13 +294,13 @@ module Azu
283294
def collect_slow_queries_data
284295
{% if @top_level.has_constant?("CQL") %}
285296
monitor = CQL::Performance.monitor
286-
slow_queries = monitor.query_profiler.slow_queries(20)
297+
slow_queries = monitor.profiler.not_nil!.slowest_queries(20)
287298

288299
slow_queries.map do |query|
289300
{
290301
"sql" => query.sql,
291302
"normalized_sql" => query.sql.gsub(/\?/, "?").gsub(/\d+/, "?").gsub(/'[^']*'/, "?").gsub(/"[^"]*"/, "?").gsub(/\s+/, " ").strip,
292-
"context" => query.context || "N/A",
303+
"context" => "N/A",
293304
"timestamp" => query.timestamp.to_rfc3339,
294305
"rows_affected" => query.rows_affected || 0_i64,
295306
"error" => "None",
@@ -308,22 +319,23 @@ module Azu
308319
def collect_query_patterns_data
309320
{% if @top_level.has_constant?("CQL") %}
310321
monitor = CQL::Performance.monitor
311-
stats = monitor.query_profiler.statistics
322+
profiler = monitor.profiler.not_nil!
323+
stats = profiler.statistics
312324

313325
# Sort by execution count descending and take top 15
314-
sorted_patterns = stats.values.sort_by(&.execution_count).reverse[0..15]
326+
sorted_patterns = stats.to_a.sort_by { |_, v| v[:count] }.reverse.first(15)
315327

316-
sorted_patterns.map do |stat|
328+
sorted_patterns.map do |sql, stat|
317329
{
318-
"normalized_sql" => stat.normalized_sql,
319-
"execution_count" => stat.execution_count.to_i64,
320-
"avg_time_ms" => stat.avg_time.total_milliseconds,
330+
"normalized_sql" => sql,
331+
"execution_count" => stat[:count].to_i64,
332+
"avg_time_ms" => stat[:avg_ms],
321333
"performance_score" => begin
322334
# Calculate performance score for single query pattern
323335
score = 100.0
324-
score -= [(stat.execution_count - 100) / 50.0, 30.0].min if stat.execution_count > 100
325-
score -= [(stat.avg_time.total_milliseconds - 50) / 25.0, 40.0].min if stat.avg_time.total_milliseconds > 50
326-
score -= [(stat.max_time.total_milliseconds - 200) / 100.0, 20.0].min if stat.max_time.total_milliseconds > 200
336+
score -= [(stat[:count] - 100) / 50.0, 30.0].min if stat[:count] > 100
337+
score -= [(stat[:avg_ms] - 50) / 25.0, 40.0].min if stat[:avg_ms] > 50
338+
score -= [(stat[:max_ms] - 200) / 100.0, 20.0].min if stat[:max_ms] > 200
327339
score.clamp(0.0, 100.0)
328340
end,
329341
}

0 commit comments

Comments
 (0)