Skip to content

Error Tracking

Learn how to capture and report errors with the Laravel SDK.

Automatic Error Capturing

The Laravel SDK automatically captures all unhandled exceptions. Once installed, exceptions thrown in your application are reported to Nadi without any additional code.

php
// This is automatically captured
public function show($id)
{
    $user = User::findOrFail($id); // 404 exceptions are captured
}

Manual Error Capturing

Capturing Exceptions

Capture exceptions while still handling them in your code:

php
use Nadi\Laravel\Facades\Nadi;

try {
    $this->processPayment($order);
} catch (PaymentException $e) {
    Nadi::captureException($e);

    // Continue handling the exception
    return back()->withError('Payment failed. Please try again.');
}

Capturing with Context

Add context when capturing:

php
use Nadi\Laravel\Facades\Nadi;

try {
    $this->processPayment($order);
} catch (PaymentException $e) {
    Nadi::captureException($e, [
        'extra' => [
            'order_id' => $order->id,
            'amount' => $order->total,
            'gateway' => $order->payment_gateway,
        ],
        'tags' => [
            'payment_type' => 'credit_card',
        ],
    ]);
}

Capturing Messages

Log important events without exceptions:

php
use Nadi\Laravel\Facades\Nadi;

// Info level message
Nadi::captureMessage('User upgraded to premium');

// With explicit level
Nadi::captureMessage('API rate limit approaching', 'warning');

// With context
Nadi::captureMessage('Large export completed', 'info', [
    'extra' => [
        'records' => 50000,
        'duration_ms' => 12500,
    ],
]);

Available levels: debug, info, warning, error, fatal

Error Levels

Automatic Level Assignment

The SDK assigns levels based on exception type:

Exception TypeLevel
ErrorException (E_ERROR, E_PARSE)fatal
ErrorException (E_WARNING)warning
ErrorException (E_NOTICE)info
Other exceptionserror

Custom Level Mapping

Override levels for specific exceptions in config/nadi.php:

php
'exception_levels' => [
    \App\Exceptions\MinorException::class => 'warning',
    \App\Exceptions\DeprecationException::class => 'info',
    \App\Exceptions\CriticalException::class => 'fatal',
],

Filtering Exceptions

Ignoring Exceptions

Don't report certain exception types:

php
// config/nadi.php
'dont_report' => [
    \Illuminate\Auth\AuthenticationException::class,
    \Illuminate\Validation\ValidationException::class,
    \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class,
    \App\Exceptions\ExpectedException::class,
],

Allowlist Mode

Only report specific exceptions (ignores dont_report):

php
// config/nadi.php
'report_only' => [
    \App\Exceptions\CriticalException::class,
    \App\Exceptions\PaymentException::class,
],

Dynamic Filtering

Filter exceptions at runtime:

php
// AppServiceProvider.php
use Nadi\Laravel\Facades\Nadi;

public function boot()
{
    Nadi::beforeCapture(function ($event, $hint) {
        // Don't report exceptions from bots
        if (request()->header('User-Agent') === 'Bot/1.0') {
            return null; // Returning null prevents capture
        }

        return $event;
    });
}

Exception Handler Integration

Laravel 11+

The SDK integrates automatically. For custom behavior, modify bootstrap/app.php:

php
use Nadi\Laravel\Facades\Nadi;

return Application::configure(basePath: dirname(__DIR__))
    ->withExceptions(function (Exceptions $exceptions) {
        $exceptions->report(function (Throwable $e) {
            Nadi::captureException($e);
        });
    })
    ->create();

Laravel 9-10

Modify app/Exceptions/Handler.php:

php
use Nadi\Laravel\Facades\Nadi;

public function register()
{
    $this->reportable(function (Throwable $e) {
        Nadi::captureException($e);
    });
}

Queue Job Exceptions

Queue job exceptions are automatically captured. Configure in config/nadi.php:

php
'capture_queue_exceptions' => true,

Additional context is included:

  • Job class name
  • Queue name
  • Attempt number
  • Job payload (filtered)

Manual Queue Exception Handling

php
use Nadi\Laravel\Facades\Nadi;

class ProcessOrder implements ShouldQueue
{
    public function handle()
    {
        try {
            $this->process();
        } catch (\Exception $e) {
            Nadi::captureException($e, [
                'tags' => ['job' => 'process_order'],
                'extra' => ['order_id' => $this->order->id],
            ]);
            throw $e; // Re-throw for retry logic
        }
    }
}

Console Command Exceptions

Exceptions in Artisan commands are automatically captured:

php
class ImportData extends Command
{
    public function handle()
    {
        // Exceptions here are captured with command context
        $this->import();
    }
}

Scheduled Task Exceptions

Enable scheduled task exception capturing:

php
// config/nadi.php
'capture_schedule_exceptions' => true,

Breadcrumbs provide a trail of events leading up to an error:

php
use Nadi\Laravel\Facades\Nadi;

// Add a breadcrumb
Nadi::addBreadcrumb('Loaded user profile', 'navigation', [
    'user_id' => $user->id,
]);

// Later, when an error occurs, breadcrumbs are included
throw new \Exception('Failed to update profile');

Automatic Breadcrumbs

The SDK automatically records:

  • Route navigation
  • Database queries (optional)
  • Log messages
  • HTTP requests
  • User authentication events

Configure in config/nadi.php:

php
'breadcrumbs' => [
    'sql_queries' => true,
    'log_messages' => true,
    'http_requests' => true,
    'auth_events' => true,
    'max_breadcrumbs' => 100,
],

Error Grouping

Nadi automatically groups similar errors. The grouping is based on:

  1. Exception class
  2. Error message (with dynamic values normalized)
  3. Stack trace signature

Custom Fingerprinting

Override the default grouping:

php
use Nadi\Laravel\Facades\Nadi;

Nadi::beforeCapture(function ($event, $hint) {
    // Group all timeout errors together
    if ($hint['exception'] instanceof TimeoutException) {
        $event['fingerprint'] = ['timeout-exception'];
    }

    return $event;
});

Next Steps

Released under the MIT License.