spatie/laravel-ray
Send Laravel debug output to Ray, Spatie’s desktop debugger. Use a consistent “ray()” API to inspect variables, arrays, HTML, queries, and more, measure performance, and pause execution. Works alongside PHP, JS, and other integrations.
Installation:
composer require spatie/laravel-ray
php artisan ray:install
This publishes the config file and installs the Ray CLI tool.
First Use Case:
Replace dd() or dump() with Ray’s directives in your Laravel app:
ray('User data', $user); // Logs user data to Ray
ray(new User); // Auto-detects Eloquent models
Launch Ray:
php artisan serve).RAY_APP_ID in .env (generated during installation).ray('Test message') in a route or controller to verify integration.Replace dd() with ray() for non-destructive inspection:
// Before
dd($request->all());
// After
ray('Request data', $request->all());
ray()->table($data) for tabular data (e.g., query results).Log raw SQL or Eloquent queries:
ray()->query($query); // Logs the query and its bindings
ray()->sql($query->toSql(), $query->getBindings()); // Manual SQL logging
app()->booted(function () {
\Spatie\Ray\Ray::captureQueries();
});
Use ray()->measure() to track execution time:
ray()->measure('Process order', function () {
// Code to measure
Order::find($id)->process();
});
ray()->measure('User profile load', function () {
return view('profile', ['user' => User::find(1)]);
});
Add @ray directives in views:
@ray($user) <!-- Logs the $user variable -->
@ray('Current route', route()->current())
@xray to log all Blade variables:
@xray
Enhance error logs with additional context:
try {
// Risky code
} catch (\Exception $e) {
ray()->exception($e, [
'user_id' => auth()->id(),
'request_data' => $request->all(),
]);
throw $e;
}
Log outgoing emails (works with any mail driver):
ray()->mail($mailable); // Logs the raw email content
config/ray.php:
'mail' => true,
Use Ray’s context to filter logs:
ray()->withContext(['user_id' => auth()->id()])->info('User action');
Log requests/responses globally:
public function handle($request, Closure $next)
{
ray()->info('Incoming request', [
'method' => $request->method(),
'path' => $request->path(),
]);
$response = $next($request);
ray()->info('Response', [
'status' => $response->status(),
'headers' => $response->headers->all(),
]);
return $response;
}
Log events with context:
public function handle(OrderPlaced $event)
{
ray()->event($event, [
'user' => $event->user,
'total' => $event->order->total,
]);
}
Mock Ray in tests to avoid clutter:
public function testSomething()
{
Ray::shouldReceive('info')->once();
// Test code
}
Disable Ray in production by setting:
RAY_ENABLED=false
Performance Overhead:
ray() calls can slow down development.APP_DEBUG mode):
if (app()->environment('local')) {
ray('Debug data', $data);
}
ray()->debug() for local-only logs.Sensitive Data Leaks:
ray('User', [
'id' => $user->id,
'email' => $user->email,
// Omit sensitive fields
]);
ray()->mask() to redact sensitive values:
ray()->mask('password', $user->toArray());
Query Logging Overhead:
captureQueries() can impact performance.if ($request->has('debug')) {
Ray::captureQueries();
}
Blade @ray in Production:
@ray directives may expose data in production.'blade' => [
'enabled' => env('APP_DEBUG', false),
],
Ray App ID Mismatch:
RAY_APP_ID in .env matches the one in the Ray app settings.Large Payloads:
ray()->file() for large content:
ray()->file(storage_path('logs/large-data.log'));
Ray Not Receiving Logs:
RAY_APP_ID.config/app.php under providers).Logs Not Formatting Correctly:
composer update spatie/laravel-ray).php artisan ray:clean
Query Logs Missing:
captureQueries() is called and the database connection is active.storage/logs/laravel.log.Blade @ray Not Working:
php artisan view:clear).@ray directive is not inside a @once or @stack directive.Custom Loggers: Extend Ray’s functionality by creating custom loggers:
Ray::extend('custom', function ($message, $data = []) {
// Custom logic
return [
'type' => 'custom',
'message' => $message,
'data' => $data,
];
});
Use it like:
ray()->custom('My message', ['key' => 'value']);
Ray Directives:
Add custom directives to the RayServiceProvider:
public function boot()
{
Ray::directive('measure', function ($name, $callable) {
$start = microtime(true);
$result = $callable();
$duration = microtime(true) - $start;
return [
'type' => 'measure',
'name' => $name,
'duration' => $duration,
'result' => $result,
];
});
}
Use in Blade:
@measure('Load data', App\DataLoader::fetch())
Ray Middleware: Create middleware to log specific request/response data:
public function handle($request, Closure $next)
{
ray()->info('API Request', [
'headers' => $request->header(),
'input' => $request->all(),
]);
return $next($request);
}
Ray Commands: Extend the `ray:
How can I help you explore Laravel packages today?