schmeits/pulse-database-table-info
Installation:
composer require schmeits/pulse-database-table-info
Register the Recorder:
Add TableInfoRecorder to the recorders array in config/pulse.php:
'recorders' => [
// ...
\Schmeits\PulseDatabaseTableInfo\TableInfoRecorder::class,
],
Publish Config (Optional):
php artisan vendor:publish --provider="Schmeits\PulseDatabaseTableInfo\PulseDatabaseTableInfoServiceProvider" --tag="config"
Edit config/pulse-database-table-info.php to customize:
migrations, failed_jobs).show_tables_over_kb).First Use Case:
Visit /pulse in your Laravel app. The Database Tables card will appear, showing:
Monitoring Critical Tables:
Exclude transient tables (e.g., sessions, failed_jobs) in config:
'excluded_tables' => [
'migrations',
'failed_jobs',
'sessions',
],
Multi-Database Support: Specify connections to monitor:
'connections' => ['mysql', 'pgsql'], // Default: ['mysql']
Custom Thresholds: Adjust visual alerts for table sizes:
'thresholds' => [
'warning_kb' => 1024, // Yellow if >1MB
'critical_kb' => 5120, // Red if >5MB
],
Integration with Alerts:
Use Pulse’s built-in alerting (e.g., Slack) by combining with PulseAlertRecorder:
'recorders' => [
\Schmeits\PulseDatabaseTableInfo\TableInfoRecorder::class,
\Laravel\Pulse\Recorders\AlertRecorder::class,
],
Scheduled Refresh: Pulse runs on-demand, but cache results for 5–10 minutes to avoid DB load:
'cache_ttl_minutes' => 10,
Dynamic Exclusions:
Override excluded tables per environment (e.g., exclude test_* tables in staging):
'excluded_tables' => env('PULSE_EXCLUDE_TABLES', []),
Custom Table Metadata: Extend the recorder to add columns (e.g., last updated):
use Schmeits\PulseDatabaseTableInfo\TableInfoRecorder;
class CustomTableInfoRecorder extends TableInfoRecorder {
public function getTableInfo() {
$info = parent::getTableInfo();
foreach ($info as &$table) {
$table['last_updated'] = DB::select("SELECT updated_at FROM information_schema.tables WHERE table_name = ?", [$table['name']]);
}
return $info;
}
}
Performance Overhead:
cache_ttl_minutes or exclude non-critical tables.Connection Errors:
try {
return parent::getTableInfo();
} catch (\Exception $e) {
\Log::error("Pulse DB info failed: " . $e->getMessage());
return [];
}
Schema Changes:
schema:dump to validate table names before deployment.MySQL vs. PostgreSQL:
DATA_LENGTH vs. pg_total_relation_size).getTableSize() in a custom recorder for non-MySQL:
protected function getTableSize(string $tableName): int {
return DB::select("SELECT pg_total_relation_size(?)", [$tableName])[0]->pg_total_relation_size;
}
Verify Data: Check raw SQL queries by enabling Pulse debug mode:
'debug' => env('APP_DEBUG', false),
Inspect logs in storage/logs/pulse.log.
Test Locally:
Use pulse:test to simulate Pulse cards:
php artisan pulse:test --recorder=TableInfoRecorder
Add Custom Columns:
Extend TableInfoRecorder and override formatTableInfo():
public function formatTableInfo(array $tables): array {
foreach ($tables as &$table) {
$table['custom_metric'] = $this->calculateCustomMetric($table['name']);
}
return parent::formatTableInfo($tables);
}
Filter Tables Dynamically: Use a closure in config:
'table_filter' => function (string $tableName) {
return !str_starts_with($tableName, 'temp_');
},
Localization: Translate table names/sizes by extending the view:
// resources/views/vendor/pulse/cards/table-info.blade.php
@foreach($tables as $table)
<tr>
<td>{{ __('pulse::table-info.tables.'.$table['name']) ?: $table['name'] }}</td>
<td>{{ $table['rows'] }} {{ __('pulse::table-info.rows') }}</td>
<td>{{ $table['size_human'] }} {{ __('pulse::table-info.size') }}</td>
</tr>
@endforeach
Compare Over Time: Use Pulse’s built-in history to track table growth:
'history_enabled' => true, // Default: false
Exclude Views: Filter out database views (not tables) in config:
'excluded_tables' => [
'*_view', // Regex pattern
],
Dark Mode Compatibility: Ensure color thresholds work in dark mode by using CSS variables:
/* resources/css/pulse.css */
.pulse-table-critical {
background-color: var(--pulse-danger);
}
How can I help you explore Laravel packages today?