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

Request Tracker Laravel Package

dragon-code/request-tracker

A Laravel package for tracking incoming HTTP requests. It captures request details, logs activity, and helps you inspect traffic through a simple, configurable setup, making it easy to add request auditing and monitoring to your application.

View on GitHub
Deep Wiki
Context7

Getting Started

dragon-code/request-tracker records the hops of a request as it travels between your own services: what called what, how long each leg took, and what came back. Treat it as a lightweight, self-hosted alternative to a full APM agent — it is scoped to Laravel's HTTP client and HTTP kernel, not to database queries or queue workers on their own.

Minimal setup:

composer require "dragon-code/request-tracker:^1.5"
php artisan vendor:publish --tag=request-tracker
php artisan migrate

You will get a config file (storage driver, header names, sampling, payload capture toggles) and one or more migrations for the trace/span tables. Read the config file top to bottom before touching anything else — the defaults are conservative and several features (payload capture, sampling) are off until you switch them on.

Then wire the two halves:

  1. Inbound — append the package middleware to the api group (or a dedicated group) in bootstrap/app.php / Kernel.php. This is what creates the trace for a request arriving from another service.
  2. Outbound — enable the HTTP client integration so that every Http:: call made from your app is recorded and stamped with the correlation header.

The two classes you will actually touch are TrackerHeader (which resolves the correlation header name) and TrackerUuid (which generates/reads the request identifier). Since 1.5.0 both are initialized through the container rather than being hardcoded statics, which means they are the right seam for customization — look there before you look at a fork.

The first use case worth validating end to end: a single user action in Service A that fans out to Service B. Fire the request, then look at the tracked records for that trace. If you see two rows sharing a trace identifier and each row has the correct duration, the package is doing its job. If you see only one row, the outbound half is not registered or the header is being stripped — see the gotchas below.

Because this package has a very small user base, budget an hour for reading the actual source in vendor/dragon-code/request-tracker/src before you rely on it. The README covers the happy path; the source is short and is the real documentation. Start with TrackerHeader and TrackerUuid — they are the smallest files and they define the contract everything else assumes.

Implementation Patterns

Correlation header as the contract. Everything hinges on one header (a X-Request-Id-style constant resolved by TrackerHeader) being propagated. Keep the header name in config or in a container binding of TrackerHeader — never hardcode the string in your own code — so that if you later swap the package out you change one line. If you already emit a request ID of your own, point the tracker at that header instead of adopting a second one.

Let the container decide the ID format. Because TrackerUuid is dynamic since 1.5.0, bind your own implementation when you need a specific format (ULID, prefixed tenant ID, an ID your gateway already generates). This is cleaner than post-processing: the value written to storage and the value sent on the outbound header are then guaranteed identical.

Stamp the trace onto queued jobs. The middleware only covers the HTTP life of a request; a job dispatched inside it will start with no trace and produce an orphaned span. Add the resolved identifier to your job payload (a small base job class that reads it from TrackerUuid in its constructor is the cleanest way) and re-bind it before the job runs. Without this, any asynchronous fan-out is invisible.

Scope outbound tracking deliberately. Global tracking of every Http:: call is the right default in a small mesh, but it will also record calls to Stripe, S3 and health checks. Use the config's ignore list, or wrap third-party calls in a client that opts out, so your trace tables stay about your services. A trace that is 90% payment-gateway latency is noise.

Record only what you will read. Payload capture is the feature people enable first and regret later. Turn it on per-environment (staging yes, production no) or restrict it to a header allowlist. The useful middle ground is capturing method, path, status, duration and the correlation ID, and nothing else.

Group by trace, not by row. Build your own query layer for reading: a Trace model relation that eager-loads spans ordered by start time gives you the waterfall view that makes the data worth having. The package's storage is a flat log; the value comes from how you present it. If the package ships a dashboard route, gate it behind auth and a non-production check immediately — it is not designed to be public.

Write through a queue in high-traffic services. Synchronous inserts on every inbound and outbound hop add latency to the request path. If the config exposes a queue/async storage option, use it; if not, wrap the storage driver in your own decorator that pushes a job, and accept that you will lose records when the queue backs up.

Complement, do not duplicate, Telescope. Telescope is for local debugging of one app; request-tracker is for a request crossing two or more apps. Run them side by side in staging and make sure the same event is not being written twice into different tables.

Gotchas and Tips

  • Middleware order matters more than usual. The tracker must run before anything that can terminate early (auth, throttling) if you want to see rejected cross-service calls, and after StartSession if you attach user context. Register it explicitly rather than relying on the group's existing order.
  • Proxies and load balancers silently drop custom headers. If inbound traces keep starting fresh instead of continuing a caller's trace, the header is almost certainly being stripped at the edge. Verify with a raw curl -H against the service before you debug any PHP.
  • TrackerUuid being dynamic cuts both ways under long-lived workers. Under Octane, Swoole or a queue worker, verify with a two-request test that a second request gets a new identifier. If the resolved value is cached on a singleton, every request in the worker shares one ID and your traces collapse into a single blob. Bind it as a scoped/singleton-cleared instance and confirm.
  • TrackerHeader is initialized once. If you change the header name at runtime (a feature flag, a per-tenant override) the already-initialized instance will not pick it up. Rebinding in the container and forgetInstance() is the reliable route; editing config after boot is not.
  • Retries multiply rows. A retried Http:: call is a new outgoing span. Decide up front whether that is a feature (you see the retry) or a bug (your p95 is skewed); if the latter, correlate retries to the same logical span in your reporting rather than trying to suppress the second row.
  • Clock skew will produce negative durations. Durations computed across machines are only as good as NTP. Prefer computing latency locally per hop where you can, and treat cross-service totals as approximate.
  • Watch the migration/index situation. With essentially zero dependents, the schema is unlikely to have been battle-tested at your row volume. Add an index on the trace identifier and on the created-at column yourself, and expect to write your own pruning command if one is not provided — this table grows forever otherwise.
  • Pin the version and read the changelog on every bump. You are on the 1.x line now, so ^1.5 is a sane constraint, but 1.x at this adoption level still moves fast — 1.5.0 already changed how two core classes are constructed. Test minor bumps in staging, especially anything touching TrackerHeader/TrackerUuid, because those changes are runtime-behavioural, not just cosmetic.
  • Extension points to look for in the source: a contract for the storage driver (swap in your own to write to ClickHouse or just to Log), container bindings for TrackerHeader and TrackerUuid (now first-class swap points as of 1.5.0), an event or resolver for attaching user/tenant context, and a callback for redacting payloads before persistence. If any of these are missing, the practical workaround is a decorator around the driver rather than a fork — the package is small enough that a fork is also a reasonable option, and you may end up maintaining it.
  • Do not let tracking failures break requests. Wrap the whole integration so that a failed insert is logged and swallowed. Telemetry that can 500 a production request is worse than no telemetry.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource