Skip to content

Storage #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 58 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
bdfb016
wip
jessarcher Jun 7, 2023
2cbdf97
Fix code styling
jessarcher Jun 7, 2023
8ecfb9b
Add non-static redis adapter
timacdonald Jun 8, 2023
e4a5ecb
wip
jessarcher Jun 9, 2023
a208785
Persist aggregates and trim stream
timacdonald Jun 9, 2023
7cf5521
Fix timezone bug
jessarcher Jun 9, 2023
778602c
Remove debugging code
jessarcher Jun 9, 2023
a25f9fc
wip
jessarcher Jun 13, 2023
5a7e20b
wip
jessarcher Jun 14, 2023
6ae7840
Fix queries
jessarcher Jun 14, 2023
33701fb
Use configured timezone
timacdonald Jun 14, 2023
443eb38
Configure duration
timacdonald Jun 14, 2023
0f23ec8
wip
timacdonald Jun 14, 2023
bc5869f
wip
timacdonald Jun 14, 2023
bec81b3
Rename Slow Endpoints to Slow Routes
jessarcher Jun 14, 2023
d95a71e
Add caching to slow routes
jessarcher Jun 14, 2023
350a13b
Add cache and loading to usage
jessarcher Jun 14, 2023
32f2a75
wip
timacdonald Jun 15, 2023
cde856c
wip
timacdonald Jun 15, 2023
f80aa82
wip
timacdonald Jun 16, 2023
f7db780
Improve loading
timacdonald Jun 16, 2023
3a21e3c
Update CSS
timacdonald Jun 16, 2023
236e37c
Extract x-cloak
timacdonald Jun 16, 2023
ba9a5ef
Update slow routes
timacdonald Jun 16, 2023
b4ad1dd
wip
timacdonald Jun 16, 2023
2ef743a
wip
timacdonald Jun 16, 2023
39691b1
capture run at time
timacdonald Jun 16, 2023
5bed7a8
wip: Exceptions
jessarcher Jun 16, 2023
7b1f52f
Update exception handler
jessarcher Jun 16, 2023
26458f1
Remove old code
jessarcher Jun 16, 2023
16b4073
Standardise exceptions
timacdonald Jun 16, 2023
725cadd
wip
timacdonald Jun 16, 2023
34028cb
Camel case
timacdonald Jun 16, 2023
2baeab8
Tidy period selector
timacdonald Jun 16, 2023
c0f4112
Add exception ordering
jessarcher Jun 16, 2023
bc0b535
extract period helper
timacdonald Jun 16, 2023
9ebee27
Update CSS
timacdonald Jun 16, 2023
948e25a
Remove double poll
timacdonald Jun 16, 2023
0bece3f
Add slow query migration and handler
jessarcher Jun 16, 2023
7417e9a
wip
timacdonald Jun 16, 2023
62fa0ae
add todo
timacdonald Jun 16, 2023
434688e
wip slow queries component
timacdonald Jun 16, 2023
4d9d997
Fix DI on handlers
jessarcher Jun 16, 2023
2369e07
Finish slow queries
timacdonald Jun 16, 2023
cadfc6d
Fix period bug
timacdonald Jun 16, 2023
4fff498
wip: server stats
jessarcher Jun 16, 2023
94c67ee
Don't limit slow queries and routes, or exceptions
timacdonald Jun 17, 2023
1bea953
Loading indicator
timacdonald Jun 19, 2023
9298788
Capture stats every 15 seconds
timacdonald Jun 20, 2023
a6f5785
Add server stats to UI
jessarcher Jun 20, 2023
865d634
Job usage
timacdonald Jun 21, 2023
d76d682
Always show current server readings
jessarcher Jun 21, 2023
6c33596
Remove unused code
jessarcher Jun 21, 2023
6820029
Add slow jobs
timacdonald Jun 21, 2023
9e6ed5b
Update period switcher
jessarcher Jun 21, 2023
d1f4679
Drop jobs table
timacdonald Jun 21, 2023
98c14ef
wip
timacdonald Jun 21, 2023
79c5a39
Wip
timacdonald Jun 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"orchestra/testbench": "^8.0",
"pestphp/pest": "^2.0",
"phpstan/phpstan": "^1.10",
"predis/predis": "^2.1"
"predis/predis": "^2.2"
},
"autoload": {
"psr-4": {
Expand Down
3 changes: 3 additions & 0 deletions config/pulse.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
// in milliseconds
'slow_query_threshold' => 1000,

// in milliseconds
'slow_job_threshold' => 1000,

// queues to show stats for
'queues' => [
'default',
Expand Down
83 changes: 83 additions & 0 deletions database/migrations/2023_06_07_000001_create_pulse_tables.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// TODO:
// - Review column types. Most of these likely need to be a text column, even "route".
// - We may need to keep a hashed version of the text columns to index and group by.
// - Do another pass at the indexes to ensure that they are optimized correctly.
Schema::create('pulse_servers', function (Blueprint $table) {
$table->timestamp('date');
$table->string('server');
$table->unsignedTinyInteger('cpu_percent');
$table->unsignedInteger('memory_used');
$table->unsignedInteger('memory_total');
$table->json('storage');

$table->index(['server', 'date']);
});

Schema::create('pulse_requests', function (Blueprint $table) {
$table->timestamp('date');
$table->string('user_id')->nullable();
$table->string('route');
$table->unsignedInteger('duration');

$table->index(['date', 'user_id'], 'user_usage');
$table->index(['date', 'route', 'duration'], 'slow_endpoints');
});

Schema::create('pulse_exceptions', function (Blueprint $table) {
$table->timestamp('date');
$table->string('user_id')->nullable();
$table->string('class');
$table->string('location');

$table->index(['date', 'class', 'location']);
});

Schema::create('pulse_queries', function (Blueprint $table) {
$table->timestamp('date');
$table->string('user_id')->nullable();
$table->string('sql');
$table->unsignedInteger('duration');

$table->index(['date', 'sql', 'duration'], 'slow_queries');
});

Schema::create('pulse_jobs', function (Blueprint $table) {
$table->timestamp('date');
$table->string('user_id')->nullable();
$table->string('job');
$table->string('job_id');
$table->timestamp('processing_started_at', 3)->nullable();
$table->unsignedInteger('duration')->nullable();

// TODO: verify this update index. Needs to find job quickly.
$table->index(['job_id']);
$table->index(['date', 'job', 'duration'], 'slow_jobs');
$table->index(['date', 'user_id'], 'user_usage');
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('pulse_servers');
Schema::dropIfExists('pulse_requests');
Schema::dropIfExists('pulse_exceptions');
Schema::dropIfExists('pulse_queries');
Schema::dropIfExists('pulse_jobs');
}
};
2 changes: 1 addition & 1 deletion dist/pulse.css

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions resources/css/pulse.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

[x-cloak] {
display: none;
}
5 changes: 5 additions & 0 deletions resources/views/components/loading-indicator.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div {{ $attributes }} class="flex flex-col items-center justify-center p-4 py-6">
<div class="animate-pulse bg-gray-50 rounded-full text-xs leading-none px-2 py-1 text-gray-500">
LOADING
</div>
</div>
1 change: 1 addition & 0 deletions resources/views/components/pulse.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
</svg>
<span class="ml-2 text-2xl text-gray-700 font-medium"><b class="font-bold">Laravel</b> Pulse</span>
</div>
<livewire:period-selector />
</div>
</div>
</header>
Expand Down
3 changes: 2 additions & 1 deletion resources/views/dashboard.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
<livewire:servers />
<livewire:usage />
<livewire:exceptions />
<livewire:slow-endpoints />
<livewire:slow-routes />
<livewire:slow-queries />
<livewire:slow-jobs />
<livewire:cache />
<livewire:queues />
</x-pulse>
122 changes: 78 additions & 44 deletions resources/views/livewire/exceptions.blade.php
Original file line number Diff line number Diff line change
@@ -1,56 +1,90 @@
<x-pulse::card
class="col-span-3"
wire:poll=""
>
<x-pulse::card class="col-span-3">
<x-slot:title>
<x-pulse::card-title class="flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-2 stroke-gray-400">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 12.75c1.148 0 2.278.08 3.383.237 1.037.146 1.866.966 1.866 2.013 0 3.728-2.35 6.75-5.25 6.75S6.75 18.728 6.75 15c0-1.046.83-1.867 1.866-2.013A24.204 24.204 0 0112 12.75zm0 0c2.883 0 5.647.508 8.207 1.44a23.91 23.91 0 01-1.152 6.06M12 12.75c-2.883 0-5.647.508-8.208 1.44.125 2.104.52 4.136 1.153 6.06M12 12.75a2.25 2.25 0 002.248-2.354M12 12.75a2.25 2.25 0 01-2.248-2.354M12 8.25c.995 0 1.971-.08 2.922-.236.403-.066.74-.358.795-.762a3.778 3.778 0 00-.399-2.25M12 8.25c-.995 0-1.97-.08-2.922-.236-.402-.066-.74-.358-.795-.762a3.734 3.734 0 01.4-2.253M12 8.25a2.25 2.25 0 00-2.248 2.146M12 8.25a2.25 2.25 0 012.248 2.146M8.683 5a6.032 6.032 0 01-1.155-1.002c.07-.63.27-1.222.574-1.747m.581 2.749A3.75 3.75 0 0115.318 5m0 0c.427-.283.815-.62 1.155-.999a4.471 4.471 0 00-.575-1.752M4.921 6a24.048 24.048 0 00-.392 3.314c1.668.546 3.416.914 5.223 1.082M19.08 6c.205 1.08.337 2.187.392 3.314a23.882 23.882 0 01-5.223 1.082" />
</svg>
<span>
Exceptions
<small class="ml-2 text-gray-400 text-xs font-medium">Past 7 days</small>
<span title="Time: {{ $time }}; Run at: {{ $runAt }};">Exceptions</span>
<small class="ml-2 text-gray-400 text-xs font-medium">past {{ match ($this->period) {
'6_hours' => '6 hours',
'24_hours' => '24 hours',
'7_days' => '7 days',
default => 'hour',
} }}</small>
</span>
</x-pulse::card-title>
<select wire:model="sortBy" class="rounded-md border-gray-200 text-gray-700 py-1 text-sm">
<option value="count">Trending</option>
<option value="last_occurrence">Recent</option>
</select>
<div class="flex items-center gap-2">
<div class="text-sm text-gray-700">Sort by</div>
<select
wire:model="orderBy"
wire:change="$emit('exceptionChanged', $event.target.value)"
class="rounded-md border-gray-200 text-gray-700 py-1 text-sm"
>
<option value="count">count</option>
<option value="last_occurrence">recent</option>
</select>
</div>
</x-slot:title>

<div class="max-h-56 h-full relative overflow-y-auto">
@if (count($exceptions) === 0)
<x-pulse::no-results />
@else
<x-pulse::table>
<x-pulse::thead>
<tr>
<x-pulse::th class="w-full text-left">Type</x-pulse::th>
<x-pulse::th class="text-center">Latest</x-pulse::th>
<x-pulse::th class="text-right">Count</x-pulse::th>
</tr>
</x-pulse::thead>
<tbody>
@foreach ($exceptions as $exception)
<tr>
<x-pulse::td>
<code class="block text-xs text-gray-900">
{{ $exception['class'] }}
</code>
<p class="text-xs text-gray-500">
{{ $exception['location'] }}
</p>
</x-pulse::td>
<x-pulse::td class="text-center text-gray-700 text-sm font-bold whitespace-nowrap">
{{ $exception['last_occurrence'] !== null ? Carbon\Carbon::parse($exception['last_occurrence'])->fromNow() : 'Unknown' }}
</x-pulse::td>
<x-pulse::td class="text-right text-gray-700 text-sm font-bold">
{{ $exception['count'] }}
</x-pulse::td>
</tr>
@endforeach
</tbody>
</x-pulse::table>
@endif
<div class="max-h-56 h-full relative overflow-y-auto" wire:poll.5s>
<script>
const initialExceptionDataLoaded = @js($initialDataLoaded)
</script>
<div x-data="{
initialDataLoaded: initialExceptionDataLoaded,
loadingNewDataset: false,
init() {
['periodChanged', 'exceptionChanged'].forEach(event => Livewire.on(event, () => (this.loadingNewDataset = true)))

window.addEventListener('exceptions:dataLoaded', () => {
this.initialDataLoaded = true
this.loadingNewDataset = false
})

if (! this.initialDataLoaded) {
@this.loadData()
}
}
}">
<x-pulse::loading-indicator x-cloak x-show="! initialDataLoaded" />
<div x-cloak x-show="initialDataLoaded">
<div :class="loadingNewDataset ? 'opacity-25 animate-pulse' : ''">
@if ($initialDataLoaded && count($exceptions) === 0)
<x-pulse::no-results />
@elseif ($initialDataLoaded && count($exceptions) > 0)
<x-pulse::table>
<x-pulse::thead>
<tr>
<x-pulse::th class="w-full text-left">Type</x-pulse::th>
<x-pulse::th class="text-center">Latest</x-pulse::th>
<x-pulse::th class="text-right">Count</x-pulse::th>
</tr>
</x-pulse::thead>
<tbody>
@foreach ($exceptions as $exception)
<tr>
<x-pulse::td>
<code class="block text-xs text-gray-900">
{{ $exception->class }}
</code>
<p class="text-xs text-gray-500">
{{ $exception->location }}
</p>
</x-pulse::td>
<x-pulse::td class="text-center text-gray-700 text-sm font-bold whitespace-nowrap">
{{ $exception->last_occurrence !== null ? Carbon\Carbon::parse($exception->last_occurrence)->fromNow() : 'Unknown' }}
</x-pulse::td>
<x-pulse::td class="text-right text-gray-700 text-sm font-bold">
{{ $exception->count }}
</x-pulse::td>
</tr>
@endforeach
</tbody>
</x-pulse::table>
@endif
</div>
</div>
</div>
</div>
</x-pulse::card>
6 changes: 6 additions & 0 deletions resources/views/livewire/period-selector.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div class="flex gap-2">
<button wire:click="setPeriod('1_hour')" class="font-semibold text-lg {{ $period === '1_hour' ? 'text-gray-700' : 'text-gray-300 hover:text-gray-400'}}">1h</button>
<button wire:click="setPeriod('6_hours')" class="font-semibold text-lg {{ $period === '6_hours' ? 'text-gray-700' : 'text-gray-300 hover:text-gray-400'}}">6h</button>
<button wire:click="setPeriod('24_hours')" class="font-semibold text-lg {{ $period === '24_hours' ? 'text-gray-700' : 'text-gray-300 hover:text-gray-400'}}">24h</button>
<button wire:click="setPeriod('7_days')" class="font-semibold text-lg {{ $period === '7_days' ? 'text-gray-700' : 'text-gray-300 hover:text-gray-400'}}">7d</button>
</div>
Loading