tiden/telemetry-laravel

Tiden error tracking for Laravel — auto-captures reported exceptions and sends them to your Tiden project. Built on tiden/telemetry-php.
1,010 1
Install
composer require tiden/telemetry-laravel
Latest Version:v1.2.0
PHP:^8.3
License:MIT
Last Updated:Oct 2, 2026
Links: GitHub  ·  Packagist
Maintainer: nipisarev

tiden/telemetry-laravel

Laravel integration for Tiden error tracking. Auto-captures every exception Laravel reports and sends it to your Tiden project. Built on tiden/telemetry-php.

Install

composer require tiden/telemetry-laravel

The service provider is auto-discovered. Set your DSN:

TIDEN_DSN=http://<publicKey>@<host:ingestPort>/<projectId>
TIDEN_RELEASE=my-app@1.2.3

That's it — reported exceptions now appear in your Tiden project. environment defaults to APP_ENV.

Configuration (optional)

php artisan vendor:publish --tag=tiden-config

config/tiden.php:

Key Env Default Description
dsn TIDEN_DSN — Project DSN. No DSN → the integration is inert.
release TIDEN_RELEASE — App version.
environment TIDEN_ENVIRONMENT APP_ENV Deployment environment.
send_default_pii TIDEN_SEND_DEFAULT_PII false Send likely-PII (off by default; PII is scrubbed).
http_timeout TIDEN_HTTP_TIMEOUT 5.0 in the console, 2.0 on web requests Seconds one synchronous send may take.
max_breadcrumbs TIDEN_MAX_BREADCRUMBS 100 Breadcrumbs kept per event; the oldest are dropped first. Empty or non-positive values fall back to the default.
before_send — null Hook to change or drop an event. See before_send.
reset_scope TIDEN_RESET_SCOPE true Fresh breadcrumbs per queue job and top-level command. See Scope per job and command.
breadcrumbs.sql TIDEN_BREADCRUMBS_SQL true Record SQL statements (never their bindings).
breadcrumbs.queue TIDEN_BREADCRUMBS_QUEUE true Record queue job processing, completion and failure.
breadcrumbs.logs TIDEN_BREADCRUMBS_LOGS true Record log messages (never their context).
breadcrumbs.max_message_length TIDEN_BREADCRUMBS_MAX_MESSAGE_LENGTH 1024 Cut SQL and log breadcrumb messages to this many bytes, on a UTF-8 character boundary. 0 = no limit; an empty or invalid value means the default.
queue.capture_timeouts TIDEN_QUEUE_CAPTURE_TIMEOUTS true Capture queue jobs that fail because they run past their timeout. See Queue job timeouts.
logs.capture_exceptions TIDEN_LOGS_CAPTURE_EXCEPTIONS false Capture error-level (and higher) log records that carry an exception. See Error-level log records.

before_send

before_send receives the event array and returns it (changed or not), or null to drop the event. Give it in one of two forms, because a closure in a config file breaks php artisan config:cache:

// A static method.
'before_send' => [App\Tiden\Filter::class, 'beforeSend'],

// The class name of an invokable class. The container builds it.
'before_send' => App\Tiden\Filter::class,

The integration ignores a closure or any other value.

Scope per job and command

A queue worker is one long PHP process, so the SDK scope (breadcrumbs, tags, user, extra) would collect data from every job it runs. With reset_scope on (the default):

  • Each queue job starts with no breadcrumbs. Tags, user and extra that you set before the job are kept. Tags that the job sets are discarded when the job completes.
  • When a job throws, its breadcrumbs stay on the scope until the worker has reported the exception. The next job then discards them.
  • Jobs on the sync connection (and deferred / background) run in the caller's request or command and keep its scope.
  • Each top-level Artisan command starts with no breadcrumbs and sets the tag command to the command name. A command called from inside another command (Artisan::call) keeps the breadcrumbs of the outer command.

Set TIDEN_RESET_SCOPE=false to keep one scope for the whole process.

Two things to know:

  • When a job completes, the integration pops exactly one scope level. If a job calls Sdk::pushScope() itself, it must call Sdk::popScope() before it finishes.
  • The "processed" queue breadcrumb and the SQL the worker runs to poll for jobs are recorded outside any job scope. Events from jobs never see them, because each job starts with no breadcrumbs. An event that you capture from the worker loop outside a job can carry up to max_breadcrumbs of them.

Transport failures

Sends are synchronous and never throw. When a send fails, the integration writes one debug log record, tiden.transport.send.failed, with the reason, the HTTP status, the envelope size in bytes and the curl error number. The record never contains the ingest URL (it includes the DSN key) or the event payload. If logging that record causes another failed send, the second failure is not logged, so the integration cannot loop.

Queue job timeouts

When a queue job runs past its timeout, the worker marks the job as failed and then kills the process. It does not call report(), so the reportable callback never sees the exception. The integration listens for the JobFailed event and captures the exception when it is an Illuminate\Queue\TimeoutExceededException. A timeout fails the job only on its last attempt, when it uses up the job's maxExceptions, or when the job sets failOnTimeout. A timeout that does not fail the job releases it for a retry, and the integration does not capture it.

With Worker::$killOnTimeout = false (Laravel 13) the worker does not kill the process: it throws the same TimeoutExceededException and reports it. Tiden sends the same exception object once, so this is still one event.

The capture runs inside the worker's timeout handler, before the process is killed, and sends synchronously. A timed-out job therefore holds the process for up to http_timeout (5 s in the console by default, plus a connect timeout of at most 1 s) beyond its configured timeout. Set TIDEN_HTTP_TIMEOUT lower if a supervisor enforces a hard deadline right after the job's timeout.

The worker reports every other job failure itself, so the integration does not capture those failures again.

On by default. Set TIDEN_QUEUE_CAPTURE_TIMEOUTS=false to turn it off.

Error-level log records

Some code catches an exception and only logs it:

try {
    $gateway->charge($order);
} catch (PaymentFailed $e) {
    Log::error('Charge failed', ['exception' => $e]);
}

Set TIDEN_LOGS_CAPTURE_EXCEPTIONS=true to capture these exceptions too. The integration then captures a log record when all of these conditions are true:

  • The level is error, critical, alert or emergency.
  • context['exception'] is a Throwable.
  • The exception handler would report it (shouldReport()), so the classes in dontReport stay out.

Laravel's exception handler logs every exception that it reports. The integration skips that log record (the exception is already captured), so report($e) still makes one event when this option is on, and report throttling (throttle()) works as it does without Tiden.

Off by default.

Manual capture

use Tiden\Sdk;

Sdk::captureException($e);
Sdk::captureMessage('checkout completed', 'info');

License

MIT

Related Packages

nikolaynesov/laravel-serene

Graceful, noise-free, and rate-limited exception reporting for Laravel

1,601 0
zereflab/laravel-bug-bot

Organized Laravel exception reports for Slack, with threaded stack traces, dupli...

3,346 2
overtrue/laravel-wechat

微信 SDK for Laravel

1,889,804 2,900
santigraviano/laravel-mercadopago

Mercado Pago SDK v0.5.2 for Laravel

160,040 47
zgldh/qiniu-laravel-storage

Qiniu Resource (Cloud) Storage SDK for Laravel 5/6/7/8/9

408,208 516

Version History

Version Released PHP Laravel License
v1.2.0 ^8.3 ^12.0 || ^13.0 MIT
v1.1.0 ^8.3 ^12.0 || ^13.0 MIT
v1.0.0 ^8.3 ^12.0 || ^13.0 MIT
v0.1.2 ^8.2 ^10.0 || ^11.0 || ^12.0 MIT
v0.1.1 ^8.2 ^10.0 || ^11.0 || ^12.0 MIT