Skip to content

Commit abdbe78

Browse files
authored
Merge pull request #5 from laravel/storage
Storage
2 parents 5264eec + 79c5a39 commit abdbe78

40 files changed

+1867
-621
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"orchestra/testbench": "^8.0",
2727
"pestphp/pest": "^2.0",
2828
"phpstan/phpstan": "^1.10",
29-
"predis/predis": "^2.1"
29+
"predis/predis": "^2.2"
3030
},
3131
"autoload": {
3232
"psr-4": {

config/pulse.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
// in milliseconds
1919
'slow_query_threshold' => 1000,
2020

21+
// in milliseconds
22+
'slow_job_threshold' => 1000,
23+
2124
// queues to show stats for
2225
'queues' => [
2326
'default',
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*/
12+
public function up(): void
13+
{
14+
// TODO:
15+
// - Review column types. Most of these likely need to be a text column, even "route".
16+
// - We may need to keep a hashed version of the text columns to index and group by.
17+
// - Do another pass at the indexes to ensure that they are optimized correctly.
18+
Schema::create('pulse_servers', function (Blueprint $table) {
19+
$table->timestamp('date');
20+
$table->string('server');
21+
$table->unsignedTinyInteger('cpu_percent');
22+
$table->unsignedInteger('memory_used');
23+
$table->unsignedInteger('memory_total');
24+
$table->json('storage');
25+
26+
$table->index(['server', 'date']);
27+
});
28+
29+
Schema::create('pulse_requests', function (Blueprint $table) {
30+
$table->timestamp('date');
31+
$table->string('user_id')->nullable();
32+
$table->string('route');
33+
$table->unsignedInteger('duration');
34+
35+
$table->index(['date', 'user_id'], 'user_usage');
36+
$table->index(['date', 'route', 'duration'], 'slow_endpoints');
37+
});
38+
39+
Schema::create('pulse_exceptions', function (Blueprint $table) {
40+
$table->timestamp('date');
41+
$table->string('user_id')->nullable();
42+
$table->string('class');
43+
$table->string('location');
44+
45+
$table->index(['date', 'class', 'location']);
46+
});
47+
48+
Schema::create('pulse_queries', function (Blueprint $table) {
49+
$table->timestamp('date');
50+
$table->string('user_id')->nullable();
51+
$table->string('sql');
52+
$table->unsignedInteger('duration');
53+
54+
$table->index(['date', 'sql', 'duration'], 'slow_queries');
55+
});
56+
57+
Schema::create('pulse_jobs', function (Blueprint $table) {
58+
$table->timestamp('date');
59+
$table->string('user_id')->nullable();
60+
$table->string('job');
61+
$table->string('job_id');
62+
$table->timestamp('processing_started_at', 3)->nullable();
63+
$table->unsignedInteger('duration')->nullable();
64+
65+
// TODO: verify this update index. Needs to find job quickly.
66+
$table->index(['job_id']);
67+
$table->index(['date', 'job', 'duration'], 'slow_jobs');
68+
$table->index(['date', 'user_id'], 'user_usage');
69+
});
70+
}
71+
72+
/**
73+
* Reverse the migrations.
74+
*/
75+
public function down(): void
76+
{
77+
Schema::dropIfExists('pulse_servers');
78+
Schema::dropIfExists('pulse_requests');
79+
Schema::dropIfExists('pulse_exceptions');
80+
Schema::dropIfExists('pulse_queries');
81+
Schema::dropIfExists('pulse_jobs');
82+
}
83+
};

dist/pulse.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/css/pulse.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
@tailwind base;
44
@tailwind components;
55
@tailwind utilities;
6+
7+
[x-cloak] {
8+
display: none;
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div {{ $attributes }} class="flex flex-col items-center justify-center p-4 py-6">
2+
<div class="animate-pulse bg-gray-50 rounded-full text-xs leading-none px-2 py-1 text-gray-500">
3+
LOADING
4+
</div>
5+
</div>

resources/views/components/pulse.blade.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
</svg>
3838
<span class="ml-2 text-2xl text-gray-700 font-medium"><b class="font-bold">Laravel</b> Pulse</span>
3939
</div>
40+
<livewire:period-selector />
4041
</div>
4142
</div>
4243
</header>

resources/views/dashboard.blade.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
<livewire:servers />
33
<livewire:usage />
44
<livewire:exceptions />
5-
<livewire:slow-endpoints />
5+
<livewire:slow-routes />
66
<livewire:slow-queries />
7+
<livewire:slow-jobs />
78
<livewire:cache />
89
<livewire:queues />
910
</x-pulse>
Lines changed: 78 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,90 @@
1-
<x-pulse::card
2-
class="col-span-3"
3-
wire:poll=""
4-
>
1+
<x-pulse::card class="col-span-3">
52
<x-slot:title>
63
<x-pulse::card-title class="flex items-center">
74
<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">
85
<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" />
96
</svg>
107
<span>
11-
Exceptions
12-
<small class="ml-2 text-gray-400 text-xs font-medium">Past 7 days</small>
8+
<span title="Time: {{ $time }}; Run at: {{ $runAt }};">Exceptions</span>
9+
<small class="ml-2 text-gray-400 text-xs font-medium">past {{ match ($this->period) {
10+
'6_hours' => '6 hours',
11+
'24_hours' => '24 hours',
12+
'7_days' => '7 days',
13+
default => 'hour',
14+
} }}</small>
1315
</span>
1416
</x-pulse::card-title>
15-
<select wire:model="sortBy" class="rounded-md border-gray-200 text-gray-700 py-1 text-sm">
16-
<option value="count">Trending</option>
17-
<option value="last_occurrence">Recent</option>
18-
</select>
17+
<div class="flex items-center gap-2">
18+
<div class="text-sm text-gray-700">Sort by</div>
19+
<select
20+
wire:model="orderBy"
21+
wire:change="$emit('exceptionChanged', $event.target.value)"
22+
class="rounded-md border-gray-200 text-gray-700 py-1 text-sm"
23+
>
24+
<option value="count">count</option>
25+
<option value="last_occurrence">recent</option>
26+
</select>
27+
</div>
1928
</x-slot:title>
2029

21-
<div class="max-h-56 h-full relative overflow-y-auto">
22-
@if (count($exceptions) === 0)
23-
<x-pulse::no-results />
24-
@else
25-
<x-pulse::table>
26-
<x-pulse::thead>
27-
<tr>
28-
<x-pulse::th class="w-full text-left">Type</x-pulse::th>
29-
<x-pulse::th class="text-center">Latest</x-pulse::th>
30-
<x-pulse::th class="text-right">Count</x-pulse::th>
31-
</tr>
32-
</x-pulse::thead>
33-
<tbody>
34-
@foreach ($exceptions as $exception)
35-
<tr>
36-
<x-pulse::td>
37-
<code class="block text-xs text-gray-900">
38-
{{ $exception['class'] }}
39-
</code>
40-
<p class="text-xs text-gray-500">
41-
{{ $exception['location'] }}
42-
</p>
43-
</x-pulse::td>
44-
<x-pulse::td class="text-center text-gray-700 text-sm font-bold whitespace-nowrap">
45-
{{ $exception['last_occurrence'] !== null ? Carbon\Carbon::parse($exception['last_occurrence'])->fromNow() : 'Unknown' }}
46-
</x-pulse::td>
47-
<x-pulse::td class="text-right text-gray-700 text-sm font-bold">
48-
{{ $exception['count'] }}
49-
</x-pulse::td>
50-
</tr>
51-
@endforeach
52-
</tbody>
53-
</x-pulse::table>
54-
@endif
30+
<div class="max-h-56 h-full relative overflow-y-auto" wire:poll.5s>
31+
<script>
32+
const initialExceptionDataLoaded = @js($initialDataLoaded)
33+
</script>
34+
<div x-data="{
35+
initialDataLoaded: initialExceptionDataLoaded,
36+
loadingNewDataset: false,
37+
init() {
38+
['periodChanged', 'exceptionChanged'].forEach(event => Livewire.on(event, () => (this.loadingNewDataset = true)))
39+
40+
window.addEventListener('exceptions:dataLoaded', () => {
41+
this.initialDataLoaded = true
42+
this.loadingNewDataset = false
43+
})
44+
45+
if (! this.initialDataLoaded) {
46+
@this.loadData()
47+
}
48+
}
49+
}">
50+
<x-pulse::loading-indicator x-cloak x-show="! initialDataLoaded" />
51+
<div x-cloak x-show="initialDataLoaded">
52+
<div :class="loadingNewDataset ? 'opacity-25 animate-pulse' : ''">
53+
@if ($initialDataLoaded && count($exceptions) === 0)
54+
<x-pulse::no-results />
55+
@elseif ($initialDataLoaded && count($exceptions) > 0)
56+
<x-pulse::table>
57+
<x-pulse::thead>
58+
<tr>
59+
<x-pulse::th class="w-full text-left">Type</x-pulse::th>
60+
<x-pulse::th class="text-center">Latest</x-pulse::th>
61+
<x-pulse::th class="text-right">Count</x-pulse::th>
62+
</tr>
63+
</x-pulse::thead>
64+
<tbody>
65+
@foreach ($exceptions as $exception)
66+
<tr>
67+
<x-pulse::td>
68+
<code class="block text-xs text-gray-900">
69+
{{ $exception->class }}
70+
</code>
71+
<p class="text-xs text-gray-500">
72+
{{ $exception->location }}
73+
</p>
74+
</x-pulse::td>
75+
<x-pulse::td class="text-center text-gray-700 text-sm font-bold whitespace-nowrap">
76+
{{ $exception->last_occurrence !== null ? Carbon\Carbon::parse($exception->last_occurrence)->fromNow() : 'Unknown' }}
77+
</x-pulse::td>
78+
<x-pulse::td class="text-right text-gray-700 text-sm font-bold">
79+
{{ $exception->count }}
80+
</x-pulse::td>
81+
</tr>
82+
@endforeach
83+
</tbody>
84+
</x-pulse::table>
85+
@endif
86+
</div>
87+
</div>
88+
</div>
5589
</div>
5690
</x-pulse::card>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<div class="flex gap-2">
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>
3+
<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>
4+
<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>
5+
<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>
6+
</div>

0 commit comments

Comments
 (0)