Skip to content

Commit

Permalink
[1.x] Allow thresholds of slow queries, jobs and requests to be custo…
Browse files Browse the repository at this point in the history
…mised by regex pattern (#340)

* allow thresholds of slow queries, jobs and requests to be customised by regex pattern

* Fix lint and tests

* Prevent error when Livewire payload contains no components

* Improvements customised thresholds

* Format slow requests

* Revert default config

* slow requests UI

* format slow jobs recorder

* format slow jobs config

* format slow jobs ui

* formatting

* formatting

* format slow outgoing config

* format slow outgoing recorder

* format slow outgoing ui

* format slow queries config

* format slow queries recorder

* Format slow queries threshold

* Format usage UI

* use @js directive

* Remove comment

* Only resolve value once

* Fix CI

* Fix tests

* Formatting

* Formatting

---------

Co-authored-by: Matheus Carvalho <matheus.carvalho@tray.net.br>
Co-authored-by: Jess Archer <jess@jessarcher.com>
Co-authored-by: Tim MacDonald <hello@timacdonald.me>
  • Loading branch information
4 people authored May 9, 2024
1 parent df05d74 commit 7190f4a
Show file tree
Hide file tree
Showing 24 changed files with 275 additions and 32 deletions.
2 changes: 1 addition & 1 deletion resources/views/livewire/cache.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
Str::plural('group', $count)
);
@endphp
<button title="{{ $message }}" @click="alert('{{ str_replace("\n", '\n', $message) }}')">
<button title="{{ $message }}" @click="alert(@js($message))">
<x-pulse::icons.information-circle class="w-5 h-5 stroke-gray-400 dark:stroke-gray-600" />
</button>
</x-slot:actions>
Expand Down
7 changes: 6 additions & 1 deletion resources/views/livewire/slow-jobs.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<x-pulse::card-header
name="Slow Jobs"
title="Time: {{ number_format($time, 0) }}ms; Run at: {{ $runAt }};"
details="{{ $config['threshold'] }}ms threshold, past {{ $this->periodForHumans() }}"
details="{{ is_array($config['threshold']) ? '' : $config['threshold'].'ms threshold, ' }}past {{ $this->periodForHumans() }}"
>
<x-slot:icon>
<x-pulse::icons.command-line />
Expand Down Expand Up @@ -45,6 +45,11 @@
<code class="block text-xs text-gray-900 dark:text-gray-100 truncate" title="{{ $job->job }}">
{{ $job->job }}
</code>
@if (is_array($config['threshold']))
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{{ $job->threshold }}ms threshold
</p>
@endif
</x-pulse::td>
<x-pulse::td numeric class="text-gray-700 dark:text-gray-300 font-bold">
@if ($config['sample_rate'] < 1)
Expand Down
9 changes: 7 additions & 2 deletions resources/views/livewire/slow-outgoing-requests.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<x-pulse::card-header
name="Slow Outgoing Requests"
title="Time: {{ number_format($time) }}ms; Run at: {{ $runAt }};"
details="{{ $config['threshold'] }}ms threshold, past {{ $this->periodForHumans() }}"
details="{{ is_array($config['threshold']) ? '' : $config['threshold'].'ms threshold, ' }}past {{ $this->periodForHumans() }}"
>
<x-slot:icon>
<x-pulse::icons.cloud-arrow-up />
Expand All @@ -20,7 +20,7 @@
Str::plural('group', $count)
);
@endphp
<button title="{{ $message }}" @click="alert('{{ str_replace("\n", '\n', $message) }}')">
<button title="{{ $message }}" @click="alert(@js($message))">
<x-pulse::icons.information-circle class="w-5 h-5 stroke-gray-400 dark:stroke-gray-600" />
</button>

Expand Down Expand Up @@ -71,6 +71,11 @@
{{ $request->uri }}
</code>
</div>
@if (is_array($config['threshold']))
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{{ $request->threshold }}ms threshold
</p>
@endif
</x-pulse::td>
<x-pulse::td numeric class="text-gray-700 dark:text-gray-300 font-bold">
@if ($config['sample_rate'] < 1)
Expand Down
7 changes: 6 additions & 1 deletion resources/views/livewire/slow-queries.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<x-pulse::card-header
name="Slow Queries"
title="Time: {{ number_format($time) }}ms; Run at: {{ $runAt }};"
details="{{ $config['threshold'] }}ms threshold, past {{ $this->periodForHumans() }}"
details="{{ is_array($config['threshold']) ? '' : $config['threshold'].'ms threshold, ' }}past {{ $this->periodForHumans() }}"
>
<x-slot:icon>
<x-pulse::icons.circle-stack />
Expand Down Expand Up @@ -68,6 +68,11 @@
{{ $query->location }}
</p>
@endif
@if (is_array($config['threshold']))
<p class="px-3 mt-3 text-xs leading-none text-gray-400 dark:text-gray-500">
{{ $query->threshold }}ms threshold
</p>
@endif
</div>
<div class="absolute top-0 right-0 bottom-0 rounded-r-md w-3 bg-gradient-to-r from-transparent to-gray-700 dark:to-gray-800 pointer-events-none"></div>
</div>
Expand Down
7 changes: 6 additions & 1 deletion resources/views/livewire/slow-requests.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<x-pulse::card-header
name="Slow Requests"
title="Time: {{ number_format($time) }}ms; Run at: {{ $runAt }};"
details="{{ $config['threshold'] }}ms threshold, past {{ $this->periodForHumans() }}"
details="{{ is_array($config['threshold']) ? '' : $config['threshold'].'ms threshold, ' }}past {{ $this->periodForHumans() }}"
>
<x-slot:icon>
<x-pulse::icons.arrows-left-right />
Expand Down Expand Up @@ -55,6 +55,11 @@
{{ $slowRequest->action }}
</p>
@endif
@if (is_array($config['threshold']))
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{{ $slowRequest->threshold }}ms threshold
</p>
@endif
</x-pulse::td>
<x-pulse::td numeric class="text-gray-700 dark:text-gray-300 font-bold">
@if ($config['sample_rate'] < 1)
Expand Down
10 changes: 9 additions & 1 deletion resources/views/livewire/usage.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
default => 'Application Usage'
}"
title="Time: {{ number_format($time) }}ms; Run at: {{ $runAt }};"
details="{{ $this->usage === 'slow_requests' ? ($slowRequestsConfig['threshold'].'ms threshold, ') : '' }}past {{ $this->periodForHumans() }}"
details="{{ $this->usage === 'slow_requests' ? (is_array($slowRequestsConfig['threshold']) ? '' : $slowRequestsConfig['threshold'].'ms threshold, ') : '' }}past {{ $this->periodForHumans() }}"
>
<x-slot:icon>
<x-dynamic-component :component="'pulse::icons.' . match ($this->type) {
Expand All @@ -31,6 +31,14 @@ class="flex-1"
@change="loading = true"
/>
@endif
@if ($this->usage === 'slow_requests' && is_array($slowRequestsConfig['threshold']))
@php
$message = 'You have per-route thresholds configured.';
@endphp
<button title="{{ $message }}" @click="alert(@js($message))">
<x-pulse::icons.information-circle class="w-5 h-5 stroke-gray-400 dark:stroke-gray-600" />
</button>
@endif
</x-slot:actions>
</x-pulse::card-header>

Expand Down
4 changes: 4 additions & 0 deletions src/Livewire/SlowJobs.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\View;
use Laravel\Pulse\Recorders\Concerns\Thresholds;
use Laravel\Pulse\Recorders\SlowJobs as SlowJobsRecorder;
use Livewire\Attributes\Lazy;
use Livewire\Attributes\Url;
Expand All @@ -15,6 +16,8 @@
#[Lazy]
class SlowJobs extends Card
{
use Thresholds;

/**
* Ordering.
*
Expand All @@ -40,6 +43,7 @@ public function render(): Renderable
'job' => $row->key,
'slowest' => $row->max,
'count' => $row->count,
'threshold' => $this->threshold($row->key, SlowJobsRecorder::class),
]),
$this->orderBy,
);
Expand Down
4 changes: 4 additions & 0 deletions src/Livewire/SlowOutgoingRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\View;
use Laravel\Pulse\Recorders\Concerns\Thresholds;
use Laravel\Pulse\Recorders\SlowOutgoingRequests as SlowOutgoingRequestsRecorder;
use Livewire\Attributes\Lazy;
use Livewire\Attributes\Url;
Expand All @@ -15,6 +16,8 @@
#[Lazy]
class SlowOutgoingRequests extends Card
{
use Thresholds;

/**
* Ordering.
*
Expand Down Expand Up @@ -44,6 +47,7 @@ public function render(): Renderable
'uri' => $uri,
'slowest' => $row->max,
'count' => $row->count,
'threshold' => $this->threshold($uri, SlowOutgoingRequestsRecorder::class),
];
}),
$this->orderBy,
Expand Down
4 changes: 4 additions & 0 deletions src/Livewire/SlowQueries.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\View;
use Laravel\Pulse\Recorders\Concerns\Thresholds;
use Laravel\Pulse\Recorders\SlowQueries as SlowQueriesRecorder;
use Livewire\Attributes\Lazy;
use Livewire\Attributes\Url;
Expand All @@ -15,6 +16,8 @@
#[Lazy]
class SlowQueries extends Card
{
use Thresholds;

/**
* Ordering.
*
Expand Down Expand Up @@ -56,6 +59,7 @@ public function render(): Renderable
'location' => $location,
'slowest' => $row->max,
'count' => $row->count,
'threshold' => $this->threshold($sql, SlowQueriesRecorder::class),
];
}),
$this->orderBy,
Expand Down
4 changes: 4 additions & 0 deletions src/Livewire/SlowRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\View;
use Laravel\Pulse\Recorders\Concerns\Thresholds;
use Laravel\Pulse\Recorders\SlowRequests as SlowRequestsRecorder;
use Livewire\Attributes\Lazy;
use Livewire\Attributes\Url;
Expand All @@ -15,6 +16,8 @@
#[Lazy]
class SlowRequests extends Card
{
use Thresholds;

/**
* Ordering.
*
Expand Down Expand Up @@ -45,6 +48,7 @@ public function render(): Renderable
'action' => $action,
'count' => $row->count,
'slowest' => $row->max,
'threshold' => $this->threshold($uri, SlowRequestsRecorder::class),
];
}),
$this->orderBy,
Expand Down
4 changes: 2 additions & 2 deletions src/Recorders/Concerns/LivewireRoutes.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ protected function resolveRoutePath(Request $request): array
$path = $route->getDomain().Str::start($route->uri(), '/');
$via = $route->getActionName();

if ($route->named('*livewire.update')) {
$snapshot = json_decode($request->input('components.0.snapshot'), flags: JSON_THROW_ON_ERROR);
if ($route->named('*livewire.update') && ($snapshot = $request->input('components.0.snapshot'))) {
$snapshot = json_decode($snapshot, flags: JSON_THROW_ON_ERROR);

if (isset($snapshot->memo->path)) {
$via = 'via '.$path;
Expand Down
27 changes: 25 additions & 2 deletions src/Recorders/Concerns/Thresholds.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,36 @@

namespace Laravel\Pulse\Recorders\Concerns;

use Illuminate\Support\Facades\Config;

trait Thresholds
{
/**
* Determine if the duration is under the configured threshold.
*/
protected function underThreshold(int|float $duration): bool
protected function underThreshold(int|float $duration, string $key): bool
{
return $duration < $this->threshold($key);
}

/**
* Get the threshold for the given key.
*/
protected function threshold(string $key, ?string $recorder = null): int
{
return $duration < $this->config->get('pulse.recorders.'.static::class.'.threshold');
$recorder ??= static::class;

$config = Config::get("pulse.recorders.{$recorder}.threshold");

if (! is_array($config)) {
return $config;
}

// @phpstan-ignore argument.templateType, argument.templateType
$custom = collect($config)
->except(['default'])
->first(fn ($threshold, $pattern) => preg_match($pattern, $key) === 1);

return $custom ?? $config['default'] ?? 1_000;
}
}
4 changes: 2 additions & 2 deletions src/Recorders/SlowJobs.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ public function record(JobReleasedAfterException|JobFailed|JobProcessed|JobProce

$this->pulse->lazy(function () use ($timestamp, $timestampMs, $name, $lastJobStartedProcessingAt) {
if (
$this->underThreshold($duration = $timestampMs - $lastJobStartedProcessingAt) ||
! $this->shouldSample() ||
$this->shouldIgnore($name)
$this->shouldIgnore($name) ||
$this->underThreshold($duration = $timestampMs - $lastJobStartedProcessingAt, $name)
) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Recorders/SlowOutgoingRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ public function record(RequestInterface $request, int $startedAt): void

$this->pulse->lazy(function () use ($startedAt, $timestamp, $endedAt, $method, $uri) {
if (
$this->underThreshold($duration = $endedAt - $startedAt) ||
! $this->shouldSample() ||
$this->shouldIgnore($uri)
$this->shouldIgnore($uri) ||
$this->underThreshold($duration = $endedAt - $startedAt, $uri)
) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Recorders/SlowQueries.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public function record(QueryExecuted $event): void

$this->pulse->lazy(function () use ($timestampMs, $duration, $sql, $location) {
if (
$this->underThreshold($duration) ||
! $this->shouldSample() ||
$this->shouldIgnore($sql)
$this->shouldIgnore($sql) ||
$this->underThreshold($duration, $sql)
) {
return;
}
Expand Down
11 changes: 5 additions & 6 deletions src/Recorders/SlowRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,16 @@ public function register(callable $record, Application $app): void
*/
public function record(Carbon $startedAt, Request $request, Response $response): void
{
if (
! $request->route() instanceof Route ||
$this->underThreshold($duration = ((int) $startedAt->diffInMilliseconds())) ||
! $this->shouldSample()
) {
if (! $request->route() instanceof Route || ! $this->shouldSample()) {
return;
}

[$path, $via] = $this->resolveRoutePath($request);

if ($this->shouldIgnore($path)) {
if (
$this->shouldIgnore($path) ||
$this->underThreshold($duration = ((int) $startedAt->diffInMilliseconds()), $path)
) {
return;
}

Expand Down
4 changes: 2 additions & 2 deletions tests/Feature/Livewire/SlowJobsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

Livewire::test(SlowJobs::class, ['lazy' => false])
->assertViewHas('slowJobs', collect([
(object) ['job' => 'App\Jobs\MyJob', 'count' => 4, 'slowest' => 2468],
(object) ['job' => 'App\Jobs\MyOtherJob', 'count' => 2, 'slowest' => 1234],
(object) ['job' => 'App\Jobs\MyJob', 'count' => 4, 'slowest' => 2468, 'threshold' => 1_000],
(object) ['job' => 'App\Jobs\MyOtherJob', 'count' => 2, 'slowest' => 1234, 'threshold' => 1_000],
]));
});
4 changes: 2 additions & 2 deletions tests/Feature/Livewire/SlowOutgoingRequestsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

Livewire::test(SlowOutgoingRequests::class, ['lazy' => false])
->assertViewHas('slowOutgoingRequests', collect([
(object) ['method' => 'GET', 'uri' => 'http://example.com', 'count' => 4, 'slowest' => 2468],
(object) ['method' => 'GET', 'uri' => 'http://example.org', 'count' => 2, 'slowest' => 1234],
(object) ['method' => 'GET', 'uri' => 'http://example.com', 'count' => 4, 'slowest' => 2468, 'threshold' => 1_000],
(object) ['method' => 'GET', 'uri' => 'http://example.org', 'count' => 2, 'slowest' => 1234, 'threshold' => 1_000],
]));
});
4 changes: 2 additions & 2 deletions tests/Feature/Livewire/SlowQueriesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@

Livewire::test(SlowQueries::class, ['lazy' => false])
->assertViewHas('slowQueries', collect([
(object) ['sql' => 'select * from `users`', 'location' => 'app/Foo.php:123', 'count' => 4, 'slowest' => 2468],
(object) ['sql' => 'select * from `users` where `id` = ?', 'location' => 'app/Bar.php:456', 'count' => 2, 'slowest' => 1234],
(object) ['sql' => 'select * from `users`', 'location' => 'app/Foo.php:123', 'count' => 4, 'slowest' => 2468, 'threshold' => 1_000],
(object) ['sql' => 'select * from `users` where `id` = ?', 'location' => 'app/Bar.php:456', 'count' => 2, 'slowest' => 1234, 'threshold' => 1_000],
]));
});

Expand Down
4 changes: 2 additions & 2 deletions tests/Feature/Livewire/SlowRequestsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

Livewire::test(SlowRequests::class, ['lazy' => false])
->assertViewHas('slowRequests', collect([
(object) ['method' => 'GET', 'uri' => '/users', 'action' => 'FooController@index', 'count' => 4, 'slowest' => 2468],
(object) ['method' => 'GET', 'uri' => '/users/{user}', 'action' => 'Closure', 'count' => 2, 'slowest' => 1234],
(object) ['method' => 'GET', 'uri' => '/users', 'action' => 'FooController@index', 'count' => 4, 'slowest' => 2468, 'threshold' => 1_000],
(object) ['method' => 'GET', 'uri' => '/users/{user}', 'action' => 'Closure', 'count' => 2, 'slowest' => 1234, 'threshold' => 1_000],
]));
});
Loading

0 comments on commit 7190f4a

Please sign in to comment.