tiden/telemetry-laravel
| Install | |
|---|---|
composer require tiden/telemetry-laravel |
|
| Latest Version: | v1.2.0 |
| PHP: | ^8.3 |
| License: | MIT |
| Last Updated: | Oct 2, 2026 |
| Links: | GitHub · Packagist |
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
syncconnection (anddeferred/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
commandto 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 callSdk::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_breadcrumbsof 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,alertoremergency. context['exception']is aThrowable.- The exception handler would report it (
shouldReport()), so the classes indontReportstay 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
Related Packages
Graceful, noise-free, and rate-limited exception reporting for Laravel
Organized Laravel exception reports for Slack, with threaded stack traces, dupli...
Version History
| Version | Released | PHP | Laravel | License |
|---|---|---|---|---|
| v1.2.0 | ^8.3 | ^12.0 | | MIT | |
| v1.1.0 | ^8.3 | ^12.0 | | MIT | |
| v1.0.0 | ^8.3 | ^12.0 | | MIT | |
| v0.1.2 | ^8.2 | ^10.0 | | MIT | |
| v0.1.1 | ^8.2 | ^10.0 | | MIT | |
| v0.1.0 | ^8.2 | ^10.0 | | MIT |