Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Flare Debug Sender Laravel Package

spatie/flare-debug-sender

A debug sender for Flare payloads, intended mainly for internal testing. It lets Laravel apps route error, trace, and Zipkin payloads through a configurable channel, with options to pass through data, alter tracing IDs and times, print payload details, and customize curl sender settings.

View on GitHub
Deep Wiki
Context7

Getting Started

Install as a dev dependency and publish the Flare config so you have a sender key to override:

composer require --dev spatie/flare-debug-sender
php artisan vendor:publish --tag=flare-config

Where to look first: the entire package is one config array. Read the Options list in the README top to bottom, then open vendor/spatie/flare-debug-sender/src/Channels/ — the three channels (RayDebugChannel, LaravelLogDebugChannel, FileDebugChannel) tell you more about real usage than the docs do. Check the installed Flare SDK version first: 2.x of this package only exists to follow the Flare v3 packages, so on an older SDK you want 1.x.

Minimal, Ray-free starting point — write to a log file, send nothing to Flare:

// config/flare.php
'sender' => [
    'class' => \Spatie\FlareDebugSender\FlareDebugSender::class,
    'config' => [
        'passthrough_errors' => false,
        'passthrough_traces' => false,
        'passthrough_zipkin' => false,
        'channel' => \Spatie\FlareDebugSender\Channels\FileDebugChannel::class,
        'channel_config' => [
            'file' => storage_path('logs/flare-debug.log'),
        ],
        'print_endpoint' => true,
    ],
],

Be explicit about every flag rather than relying on defaults — only channel (RayDebugChannel) and sender (CurlSender) have documented defaults, and you do not want an accidental passthrough.

First use case — verify an exception's context without a browser. You don't need a failing request; report the exception directly:

php artisan tinker
>>> report(new App\Exceptions\OrderSyncFailed($order));

Then tail -f storage/logs/flare-debug.log. You now see the exact payload Flare would have received: exception class, message, stack, the context fields you attached, the request/user/resource blocks, and the endpoint. That's the loop — trigger, read, delete the sender block, move on.

Implementation Patterns

Gate it behind an env flag, not a committed config. The safest shape is to only inject the sender key when explicitly enabled locally, so the class name never appears in a cached production config:

// config/flare.php
'sender' => env('FLARE_DEBUG_SENDER')
    ? [ /* the debug sender array */ ]
    : null,

Put FLARE_DEBUG_SENDER=true in your local .env only. Never true in .env.example.

Choose your channel by team, not by default. If the team already runs Ray, RayDebugChannel is the fastest feedback loop. If not, don't make Ray a prerequisite for debugging — use FileDebugChannel with an explicit path (or LaravelLogDebugChannel if you route it to a dedicated log channel rather than the default stack).

Passthrough is the main dial. The three passthrough_* flags decide whether the payload also goes to the real Flare/Zipkin. Combinations worth memorizing:

Goal Setting
Inspect payload, still get real reports passthrough_errors => true
Full suppression, no outbound traffic all three false
Trace/span debugging only passthrough_errors => false, passthrough_traces => true

Verify payload-mutating code. If you have middleware, a report() override, or a custom exception handler that rewrites context, this is how you prove the rewrite lands. Capture the payload once with the handler disabled, once with it enabled, and diff the two files — far more convincing than reading the handler source.

Upgrade gate for Flare majors. Before and after bumping Flare, run the same failing request through this sender and diff the captured payloads. Set replace_tracing_ids and replace_tracing_times to true for both runs so the IDs/timestamps don't drown the signal. Treat "readable" as readable — capture twice and confirm the output is actually stable before you trust a clean diff.

Slice instead of scrolling. print_full_payload => true produces a lot. Redirect it and query it:

tail -f storage/logs/flare-debug.log | jq '.context' 2>/dev/null
# or
rg -n '"user_id"|"headers"|"session"' storage/logs/flare-debug.log

Start with print_endpoint and print_resource alone; they're the cheap, low-noise toggles. Add print_full_payload only when you need the whole envelope.

Onboarding demo. The single highest-leverage non-debug use: show a new engineer a real payload instead of the Flare dashboard abstraction. Five minutes and they understand what the team is actually paying for.

Extension points, used sparingly. channel and sender are both swappable. A custom channel is the right hook if you want output somewhere the three built-ins don't cover (a Slack webhook locally, an in-memory buffer for a targeted assertion). The nested sender (default CurlSender) is where you'd intercept below the payload layer — note the changelog entry "Allow defining an alternative sender" is exactly this seam.

Gotchas and Tips

  • A misconfigured debug sender silently eats your errors. This is the number one risk. If passthrough_errors is false in a shared environment, real exceptions stop reaching Flare and nobody notices until an incident. Env-gate it, keep it out of staging, and never copy the block into config/flare.php unconditionally.
  • The README's sample config disables TLS verification (CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0). Fine for a throwaway local endpoint or a curl proxy; do not let that pattern propagate into shared config. Drop those options entirely unless you actually need them.
  • composer require --dev + production config cache is a trap. If the sender class name ends up in a config cached on a host that doesn't have the dev dependency installed, Flare fails to instantiate the sender. The env-guard above prevents this — verify by running php artisan config:cache and inspecting bootstrap/cache/config.php for the class name before deploying.
  • Config caching in dev too. Toggling FLARE_DEBUG_SENDER does nothing while a stale config cache exists. php artisan config:clear is the first thing to try when the sender "isn't working."
  • FileDebugChannel's default path is flare-debug-sender.log in the project root. Set an explicit path under storage/logs/ and add the file to .gitignore — an accidentally committed payload log is a data-leak waiting to happen.
  • LaravelLogDebugChannel writes into your normal log stream. It will interleave with application logs and can make tail useless. Either route it to a dedicated channel in config/logging.php or prefer the file channel.
  • print_full_payload includes exactly the fields you'd worry about in a privacy review — user IDs, request bodies, headers, session data. That makes it excellent evidence for a data-handling sign-off, and also means the resulting log file is sensitive. Treat it like a dump of production data.
  • Queued jobs need the sync driver to debug conveniently. With a real queue worker running in the background, the payload lands in a terminal you aren't watching. Use dispatchSync() or QUEUE_CONNECTION=sync locally.
  • report() and an uncaught throw produce slightly different payloads. If you're verifying the shape of what Flare receives in production, reproduce with an actual uncaught exception at least once, not just a tinker report().
  • Zero stars, zero dependents, single-vendor. Treat every class as internal. Pin an exact version, don't import Spatie\FlareDebugSender\* into your own application code or test suite, and assume the sender config contract shifts with each Flare major. Check the changelog before upgrading Flare, not after.
  • It is not a test harness. It belongs in local developer workflows, not in CI as a pinned dependency. If you genuinely need payload-shape assertions in a test suite, own a small fake sender yourself rather than making this package a build gate with no named owner.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin