tailcove / laravel
Monolog handler and Laravel service provider for sending application logs to Tailcove.
Requires
- php: ^8.2
- illuminate/bus: ^11.0 || ^12.0 || ^13.0
- illuminate/console: ^11.0 || ^12.0 || ^13.0
- illuminate/contracts: ^11.0 || ^12.0 || ^13.0
- illuminate/database: ^11.0 || ^12.0 || ^13.0
- illuminate/queue: ^11.0 || ^12.0 || ^13.0
- illuminate/support: ^11.0 || ^12.0 || ^13.0
- monolog/monolog: ^3.0
Requires (Dev)
- orchestra/testbench: ^9.0 || ^10.0
- pestphp/pest: ^3.0 || ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Documentation · Get started free · View on Packagist · Report a bug
Send your Laravel logs to Tailcove with one composer require.
Install
composer require tailcove/laravel
Requires PHP 8.2+ and Laravel 11, 12 or 13. Laravel's package auto-discovery registers the service provider for you.
Quick start
1. Get a token. Create a source in your Tailcove dashboard and copy its ingest token. It is shown only once, so save it straight into your .env.
2. Add two lines to .env.
TAILCOVE_TOKEN=your-source-ingest-token LOG_STACK=single,tailcove
3. Add the channel to config/logging.php.
'channels' => [ // ... 'tailcove' => [ 'driver' => 'tailcove', 'level' => env('LOG_LEVEL', 'debug'), ], ],
That's it. Log::info(...), Log::error(...) and any exception you report now appear in Tailcove search and live tail within a couple of seconds.
Configuration
Publish the config file if you want to edit it:
php artisan vendor:publish --tag=tailcove-config
Every option lives in config/tailcove.php and can be set with an environment variable. To run more than one Tailcove channel, set the same key directly on a channel in config/logging.php to override it for that channel.
| Environment variable | Default | What it does |
|---|---|---|
TAILCOVE_TOKEN |
— | Your source's ingest token. Required. Never commit it. |
TAILCOVE_ENDPOINT |
https://ingest.tailcove.dev/api/v1/logs |
The ingest URL. Only change this if you self-host. |
TAILCOVE_ENABLED |
true |
Set false to keep the channel registered but silent. |
TAILCOVE_LEVEL |
debug |
Lowest Monolog level the handler processes. |
TAILCOVE_BATCH_SIZE |
50 |
Send once this many records are buffered. |
TAILCOVE_BATCH_SECONDS |
2.0 |
Send once this many seconds have passed since the first buffered record. |
TAILCOVE_DISPATCH |
shutdown |
shutdown sends after the response. queue uses a queued job. See Sending modes. |
TAILCOVE_QUEUE_CONNECTION |
— | Queue connection to use when TAILCOVE_DISPATCH=queue. |
TAILCOVE_HTTP_TIMEOUT |
2.0 |
Seconds a delivery attempt may take before giving up. |
TAILCOVE_EXCEPTION_TRACE_LIMIT |
10 |
Most stack frames kept when an exception is logged. |
TAILCOVE_LOG_SLOW_QUERIES |
false |
Log slow queries. See Extras. |
TAILCOVE_SLOW_QUERY_THRESHOLD_MS |
500 |
How slow a query must be to be logged. |
TAILCOVE_LOG_FAILED_JOBS |
false |
Log failed queue jobs. |
TAILCOVE_LOG_SCHEDULE_FAILURES |
false |
Log failed scheduled tasks. |
What gets added automatically
| Field | Value |
|---|---|
environment |
app()->environment() |
hostname |
gethostname() |
user_id |
The signed-in user's id, when a guard has one |
request_id |
Shared by every line in one request. Reuses an incoming X-Request-Id header, or creates a UUID. |
If adding any of these fails, for example when no auth guard exists in that context, the line is still sent without that field. It never breaks the log call.
When a line's context has an exception key, as with report($e) or Log::error('...', ['exception' => $e]), it is sent as structured data:
'exception' => [ 'class' => 'RuntimeException', 'message' => 'Something broke', 'location' => '/app/Http/Controllers/OrderController.php:42', 'trace' => ['#0 /app/...', '#1 /app/...'], // up to TAILCOVE_EXCEPTION_TRACE_LIMIT frames ],
Sending modes
shutdown (default). Sends from a shutdown function, right after the response. No queue worker needed.
queue. Dispatches a Tailcove\Laravel\Jobs\SendLogBatch job instead, for apps that want sending off the web worker completely. A failed delivery uses your queue's own retries (3 tries, waiting 5, 30 and 120 seconds) and isn't dropped straight away.
TAILCOVE_DISPATCH=queue TAILCOVE_QUEUE_CONNECTION=redis
Security note: in queue mode the ingest token travels inside the serialized job on your queue backend, and is stored in
failed_jobsif every retry fails. Anyone who can read that store can read the token. If that matters, stay onshutdown, or lock down your queue store as you would any table holding secrets.
Extras
Each is off by default and logs through the tailcove channel, so the data ships even if you never call Log:: yourself. A failure in any of them is caught and dropped.
TAILCOVE_LOG_SLOW_QUERIES=true TAILCOVE_SLOW_QUERY_THRESHOLD_MS=500 TAILCOVE_LOG_FAILED_JOBS=true TAILCOVE_LOG_SCHEDULE_FAILURES=true
| Setting | What is logged |
|---|---|
| Slow queries | Queries at or above the threshold, with sql, bindings, time_ms and connection. |
| Failed queue jobs | Each JobFailed event, with the job name, connection and the exception. |
| Scheduled task failures | Each ScheduledTaskFailed event, with the command and the exception. |
When delivery fails
A failed delivery never throws into your app. It is caught and written to PHP's error_log() as a local fallback. Logging is best-effort by design.
Help and feedback
- Docs: tailcove.dev/docs/sending-logs/laravel-package
- Bugs and feature requests: open an issue
- Security problems: please email security@tailcove.dev instead of opening a public issue.
Documentation · Get started free · Report a bug · MIT License