Skip to content

Commit 8f513b5

Browse files
committed
Added latency hotpots to the dashboard
1 parent 30c2a31 commit 8f513b5

File tree

2 files changed

+97
-16
lines changed

2 files changed

+97
-16
lines changed

lib/VWF/Display/meta_data.pm

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ use warnings;
88
use parent 'VWF::Display';
99

1010
use Filesys::Df;
11-
use Time::Piece;
12-
use Time::Seconds;
11+
use List::Util qw(max);
12+
use POSIX qw(strftime);
1313
use System::Info;
1414
use Sys::Uptime;
1515
use Sys::MemInfo;
1616
use Time::Piece;
17-
use List::Util qw(max);
17+
use Time::Seconds;
1818

1919
sub html {
2020
my $self = shift;
@@ -63,6 +63,7 @@ sub html {
6363
rate_error_pct_dp => $rate_24h->{error_pct_dp},
6464
latency_avg_dp => $latency_24h->{avg_dp},
6565
latency_p95_dp => $latency_24h->{p95_dp},
66+
slow_dp => $self->get_slow_endpoints_24h($vwf_log, $domain_name),
6667
});
6768
}
6869

@@ -204,8 +205,7 @@ sub get_request_rate_24h {
204205
sub get_latency_24h {
205206
my ($self, $vwf_log, $domain_name) = @_;
206207

207-
my $now = time();
208-
my $start = $now - ONE_DAY + _utc_offset();
208+
my $start = time() - ONE_DAY + _utc_offset();
209209

210210
my %buckets;
211211

@@ -251,6 +251,64 @@ sub get_latency_24h {
251251
};
252252
}
253253

254+
sub get_slow_endpoints_24h {
255+
my ($self, $vwf_log, $domain_name) = @_;
256+
257+
my $start = time() - ONE_DAY + _utc_offset();
258+
259+
# Step 1: fetch rows filtered only by equality
260+
my @rows = $vwf_log->selectall_array({ domain_name => $domain_name });
261+
262+
# Step 2: bucket in Perl
263+
my %stats;
264+
265+
foreach my $row (@rows) {
266+
next unless defined $row->{time};
267+
next unless defined $row->{duration_ms};
268+
print __LINE__, "\n";
269+
270+
my $tp;
271+
eval { $tp = Time::Piece->strptime($row->{time}, '%Y-%m-%d %H:%M:%S') };
272+
next unless $tp;
273+
274+
next if $tp->epoch < $start;
275+
276+
my $tpl = $row->{template} // '';
277+
$stats{$tpl}{hits}++;
278+
$stats{$tpl}{total_ms} += $row->{duration_ms};
279+
}
280+
281+
# Step 3: compute averages + threshold
282+
my @ranked;
283+
foreach my $tpl (keys %stats) {
284+
next if $stats{$tpl}{hits} < 5;
285+
286+
push @ranked, {
287+
template => $tpl,
288+
avg_ms => $stats{$tpl}{total_ms} / $stats{$tpl}{hits},
289+
};
290+
}
291+
292+
# Step 4: sort + top 10
293+
@ranked = sort { $b->{avg_ms} <=> $a->{avg_ms} } @ranked;
294+
splice(@ranked, 10) if @ranked > 10;
295+
296+
# Step 5: CanvasJS datapoints
297+
my @dp;
298+
foreach my $row (@ranked) {
299+
my $label = $row->{template};
300+
$label =~ s/"/\\"/g;
301+
302+
push @dp, sprintf(
303+
'{ label: "%s", y: %.0f }',
304+
$label,
305+
$row->{avg_ms}
306+
);
307+
}
308+
309+
return join(', ', @dp);
310+
}
311+
254312
sub _utc_offset
255313
{
256314
my $local_time = time();

templates/default/web/VWF/Display/meta_data.tmpl

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@
3535
});
3636
browserChart.render();
3737

38-
[% IF status_datapoints %]
39-
var statusChart = new CanvasJS.Chart("statusChartContainer", {
40-
animationEnabled: true,
41-
title: { text: "HTTP Status Breakdown" },
42-
data: [{ type:"pie", startAngle:240, yValueFormatString:"##0", indexLabel:"{label} {y}", dataPoints:[[% status_datapoints %]] }]
43-
});
44-
statusChart.render();
45-
[% END %]
38+
[% IF status_datapoints %]
39+
var statusChart = new CanvasJS.Chart("statusChartContainer", {
40+
animationEnabled: true,
41+
title: { text: "HTTP Status Breakdown" },
42+
data: [{ type:"pie", startAngle:240, yValueFormatString:"##0", indexLabel:"{label} {y}", dataPoints:[[% status_datapoints %]] }]
43+
});
44+
statusChart.render();
45+
[% END %]
46+
4647
[% IF rate_total_dp %]
4748
var rateChart = new CanvasJS.Chart("rate24hContainer", {
4849
animationEnabled: true,
@@ -103,6 +104,21 @@
103104
]
104105
});
105106
latencyChart.render();
107+
[% IF slow_dp %]
108+
var slowChart = new CanvasJS.Chart("slowEndpointChart", {
109+
animationEnabled: true,
110+
title: { text: "Slowest Endpoints (avg ms, 24h)" },
111+
axisX: {
112+
title: "Average Response Time (ms)"
113+
}, axisY: {
114+
labelFontSize: 12
115+
}, data: [{
116+
type: "bar",
117+
dataPoints: [ [% slow_dp %] ]
118+
}]
119+
});
120+
slowChart.render();
121+
[% END %]
106122
};
107123
</script>
108124
[% END %]
@@ -178,9 +194,16 @@
178194
[% END %]
179195

180196
<div class="panel">
181-
<h2>Latency (Last 24 Hours)</h2>
182-
<div id="latency24hContainer" style="height:300px; width:100%;"></div>
183-
</div>
197+
<h2>Latency (Last 24 Hours)</h2>
198+
<div id="latency24hContainer" style="height:300px; width:100%;"></div>
199+
</div>
200+
201+
[% IF slow_dp %]
202+
<div class="panel">
203+
<h2>Slow Endpoints</h2>
204+
<div id="slowEndpointChart" style="height: 300px;"></div>
205+
</div>
206+
[% END %]
184207
</div>
185208
</div>
186209
</body>

0 commit comments

Comments
 (0)