jftecnologia / laravel-tracing
A Laravel package by Junior Fontenele
Installs: 173
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 1
Open Issues: 0
pkg:composer/jftecnologia/laravel-tracing
Requires
- php: ^8.4
- illuminate/contracts: ^12
- illuminate/queue: ^12
- illuminate/support: ^12
Requires (Dev)
- driftingly/rector-laravel: ^2.1
- larastan/larastan: ^3.0
- laravel/pint: ^1.27
- laravel/prompts: ^0.3.9
- orchestra/testbench: ^10.8
- pestphp/pest: ^4.3
This package is auto-updated.
Last update: 2026-02-12 15:17:36 UTC
README
Lightweight, plug-and-play request tracing for Laravel applications.
Laravel Tracing automatically tracks requests across your application using correlation IDs and request IDs. It seamlessly propagates tracing context through queued jobs, HTTP requests, and external API calls — making it easy to correlate logs, debug distributed systems, and trace user sessions end-to-end.
Table of Contents
- Overview
- Features
- Requirements
- Installation
- Quick Start
- Configuration
- Usage Examples
- Custom Tracing Sources
- Troubleshooting
- Testing
- Credits
- License
Overview
In distributed and monolithic Laravel applications, tracking the origin and flow of requests is essential for debugging, monitoring, and log correlation. Without standardized tracing identifiers, it's difficult to:
- Correlate log entries across services
- Debug issues spanning multiple requests or jobs
- Track a user session end-to-end
- Trace requests through queues and external HTTP calls
Laravel Tracing solves this by automatically attaching tracing headers (correlation ID, request ID) to every request, propagating them through queued jobs, and forwarding them to external services.
Why Use Laravel Tracing?
- ✅ Simple Setup: One-time middleware registration in
bootstrap/app.php - ✅ Session Persistence: Correlation IDs survive across multiple requests from the same user
- ✅ Job Propagation: Tracing context automatically flows into queued jobs
- ✅ HTTP Client Integration: Forward tracing headers to external APIs with
Http::withTracing() - ✅ Fully Extensible: Add custom tracing sources (user ID, tenant ID, app version) without modifying package code
- ✅ Environment-Aware: Toggle features via config file and environment variables
- ✅ Lightweight: No external dependencies beyond Laravel core
Features
-
Built-In Tracing:
- Correlation ID (
X-Correlation-Id): Tracks user sessions across multiple requests - Request ID (
X-Request-Id): Uniquely identifies each HTTP request
- Correlation ID (
-
Session Persistence: Correlation IDs persist across requests from the same user session (via Laravel session/cookies)
-
Job Propagation: Tracing values are automatically serialized with job payloads and restored during execution
-
HTTP Client Integration: Opt-in support for forwarding tracing headers to external services via
Http::withTracing() -
Custom Tracing Sources: Easily add custom tracings (user ID, tenant ID, app version) via config or runtime registration
-
Global Accessor: Access all tracing values from anywhere in your application via the
LaravelTracingfacade -
Configurable: Control header names, enable/disable tracings, and customize behavior via config file and environment variables
-
Fully Tested: Comprehensive test suite using PestPHP
Requirements
- PHP: 8.4 or higher
- Laravel: 12 or higher
Installation
Step 1: Install via Composer
composer require jftecnologia/laravel-tracing
Step 2: Register Middleware
Important: Laravel 12 does not support automatic middleware registration via package discovery. You must manually register the tracing middleware in your bootstrap/app.php file:
use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; use JuniorFontenele\LaravelTracing\Middleware\IncomingTracingMiddleware; use JuniorFontenele\LaravelTracing\Middleware\OutgoingTracingMiddleware; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware) { // Register tracing middleware to web group (for session-based correlation ID persistence) $middleware->appendToGroup('web', IncomingTracingMiddleware::class); $middleware->appendToGroup('web', OutgoingTracingMiddleware::class); // Optional: Register to api group if you want tracing on API routes // Note: API routes won't have session persistence, so correlation ID will be generated per request $middleware->appendToGroup('api', IncomingTracingMiddleware::class); $middleware->appendToGroup('api', OutgoingTracingMiddleware::class); }) ->withExceptions(function (Exceptions $exceptions) { // })->create();
Important Notes:
- The middleware must be registered to the
webmiddleware group (or after Laravel'sStartSessionmiddleware) to ensure session persistence for correlation IDs - If registered globally or before
StartSession, correlation IDs will not persist across requests - Unlike Laravel 11 and earlier versions, Laravel 12 does not support automatic middleware registration through package discovery
Alternative: Route-Specific Registration
If you prefer to apply tracing only to specific routes:
// In routes/web.php Route::middleware([ IncomingTracingMiddleware::class, OutgoingTracingMiddleware::class, ])->group(function () { Route::get('/traced', function () { return response()->json(['status' => 'traced']); }); });
Step 3: Publish Configuration (Optional)
To customize tracing behavior (header names, enable/disable features, add custom tracings), publish the configuration file:
php artisan vendor:publish --tag=laravel-tracing-config
This creates config/laravel-tracing.php where you can customize all package settings.
Verification
Make a request to your application and check the response headers:
curl -I http://localhost:8000
You should see:
X-Correlation-Id: 550e8400-e29b-41d4-a716-446655440000
X-Request-Id: 123e4567-e89b-12d3-a456-426614174000
Quick Start
Basic Usage
Access tracing values from anywhere in your application:
use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; // Get correlation ID $correlationId = LaravelTracing::correlationId(); // Get request ID $requestId = LaravelTracing::requestId(); // Get all tracing values $allTracings = LaravelTracing::all(); // Returns: ['correlation_id' => '...', 'request_id' => '...']
Use in Log Context
use Illuminate\Support\Facades\Log; use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; Log::info('User action performed', LaravelTracing::all());
Log output:
{
"message": "User action performed",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000",
"request_id": "123e4567-e89b-12d3-a456-426614174000"
}
Tracing in Queued Jobs
Tracing values are automatically propagated to queued jobs:
// Dispatch a job from a controller dispatch(new ProcessOrder($orderId));
// Inside the job handler class ProcessOrder implements ShouldQueue { public function handle(): void { // Access original correlation ID from the dispatching request $correlationId = LaravelTracing::correlationId(); Log::info('Processing order', [ 'correlation_id' => $correlationId, // Same as dispatching request 'request_id' => LaravelTracing::requestId(), // Preserved from dispatch ]); } }
Forward Tracing to External APIs
use Illuminate\Support\Facades\Http; // Attach all tracing headers to outgoing HTTP request $response = Http::withTracing() ->get('https://api.example.com/data');
The external service receives:
X-Correlation-Id: 550e8400-e29b-41d4-a716-446655440000
X-Request-Id: 123e4567-e89b-12d3-a456-426614174000
Configuration
Configuration File Structure
After publishing the config (php artisan vendor:publish --tag=laravel-tracing-config), you'll have access to config/laravel-tracing.php:
return [ // Global enable/disable toggle 'enabled' => env('LARAVEL_TRACING_ENABLED', true), // Accept tracing headers from external requests 'accept_external_headers' => env('LARAVEL_TRACING_ACCEPT_EXTERNAL_HEADERS', false), // Define tracing sources 'tracings' => [ 'correlation_id' => [ 'enabled' => true, 'header' => env('LARAVEL_TRACING_CORRELATION_ID_HEADER', 'X-Correlation-Id'), 'source' => 'JuniorFontenele\LaravelTracing\Tracings\Sources\CorrelationIdSource', ], 'request_id' => [ 'enabled' => true, 'header' => env('LARAVEL_TRACING_REQUEST_ID_HEADER', 'X-Request-Id'), 'source' => 'JuniorFontenele\LaravelTracing\Tracings\Sources\RequestIdSource', ], ], // HTTP client integration 'http_client' => [ 'enabled' => env('LARAVEL_TRACING_HTTP_CLIENT_ENABLED', false), ], ];
Configuration Options
Global Settings
| Key | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Master switch for the entire package. When false, all tracing operations are skipped (zero overhead). |
accept_external_headers |
bool | false |
When true, tracing values are read from incoming request headers (forwarded by upstream services). When false, values are always generated fresh. |
Environment Variables:
LARAVEL_TRACING_ENABLED- Enable/disable package globallyLARAVEL_TRACING_ACCEPT_EXTERNAL_HEADERS- Accept external headers
Per-Tracing Settings
Each entry in the tracings array supports:
| Key | Type | Required | Description |
|---|---|---|---|
enabled |
bool | Yes | Whether this tracing source is active |
header |
string | Yes | HTTP header name for reading/writing this value |
source |
string | Yes | Fully-qualified class name of the TracingSource implementation |
Built-In Tracings:
-
correlation_id: Session-level identifier (persists across multiple requests from the same user)- Default header:
X-Correlation-Id - Environment variable:
LARAVEL_TRACING_CORRELATION_ID_HEADER
- Default header:
-
request_id: Request-level identifier (unique per HTTP request)- Default header:
X-Request-Id - Environment variable:
LARAVEL_TRACING_REQUEST_ID_HEADER
- Default header:
HTTP Client Settings
| Key | Type | Default | Description |
|---|---|---|---|
http_client.enabled |
bool | false |
When true, Http::withTracing() is available globally. When false, it's opt-in per request. |
Environment Variable:
LARAVEL_TRACING_HTTP_CLIENT_ENABLED
Configuration Examples
Disable Tracing in Local Environment
# .env.local LARAVEL_TRACING_ENABLED=false
Customize Header Names
# .env LARAVEL_TRACING_CORRELATION_ID_HEADER=X-Trace-Id LARAVEL_TRACING_REQUEST_ID_HEADER=X-Span-Id
Disable External Header Acceptance (Security)
If your application is publicly exposed and you don't want to accept correlation IDs from untrusted sources:
# .env.production LARAVEL_TRACING_ACCEPT_EXTERNAL_HEADERS=false
Security Note: When
accept_external_headersistrue, the package will use correlation/request IDs sent by clients. Only enable this if you trust your upstream services (API gateways, load balancers, internal services).
Enable HTTP Client Tracing Globally
# .env LARAVEL_TRACING_HTTP_CLIENT_ENABLED=true
When enabled, all HTTP requests automatically include tracing headers without calling withTracing():
// Tracing headers automatically attached Http::get('https://api.example.com/data');
Usage Examples
Example 1: Accessing Tracing Values in Controllers
namespace App\Http\Controllers; use Illuminate\Http\Request; use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; class OrderController extends Controller { public function store(Request $request) { // Get all tracing values $tracings = LaravelTracing::all(); // Get specific values $correlationId = LaravelTracing::correlationId(); $requestId = LaravelTracing::requestId(); // Use in business logic $order = Order::create([ 'user_id' => $request->user()->id, 'correlation_id' => $correlationId, // Store in database for audit ]); return response()->json(['order_id' => $order->id]); } }
Example 2: Using Tracings in Log Context
use Illuminate\Support\Facades\Log; use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; // In any part of your application Log::info('Processing payment', array_merge( ['amount' => 99.99, 'currency' => 'USD'], LaravelTracing::all() // Add all tracing values to log context ));
Log output:
{
"message": "Processing payment",
"amount": 99.99,
"currency": "USD",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000",
"request_id": "123e4567-e89b-12d3-a456-426614174000",
"timestamp": "2026-02-11T10:30:00Z"
}
Example 3: Session Persistence (Same Correlation ID Across Requests)
Request 1:
curl -I http://localhost:8000/api/cart/add
Response:
X-Correlation-Id: 550e8400-e29b-41d4-a716-446655440000
X-Request-Id: 123e4567-e89b-12d3-a456-426614174000
Set-Cookie: laravel_session=...
Request 2 (same session):
curl -I http://localhost:8000/api/cart/checkout \
-H "Cookie: laravel_session=..."
Response:
X-Correlation-Id: 550e8400-e29b-41d4-a716-446655440000 ← Same correlation ID!
X-Request-Id: 789e0123-e45b-67c8-d901-234567890abc ← New request ID
The correlation ID persists across requests from the same session, enabling you to trace all actions from a single user.
Example 4: Tracing in Queued Jobs
// Dispatch job from controller class OrderController extends Controller { public function store(Request $request) { $order = Order::create($request->all()); // Correlation ID and request ID are automatically serialized with the job ProcessOrder::dispatch($order); return response()->json(['order_id' => $order->id]); } }
// Job handler namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Facades\Log; use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; class ProcessOrder implements ShouldQueue { use Queueable; public function __construct(public Order $order) {} public function handle(): void { // Tracing values from the original request are restored Log::info('Job processing order', [ 'order_id' => $this->order->id, 'correlation_id' => LaravelTracing::correlationId(), // Same as dispatch request 'request_id' => LaravelTracing::requestId(), // Preserved from dispatch ]); // Process order... } }
Result: All logs from the job execution include the same correlation ID as the dispatching request, making it easy to trace the entire flow.
Example 5: Multiple Jobs Share Correlation ID
// Dispatch multiple jobs from the same request public function bulkProcess(Request $request) { foreach ($request->orders as $order) { ProcessOrder::dispatch($order); SendInvoice::dispatch($order); UpdateInventory::dispatch($order); } return response()->json(['status' => 'queued']); }
All dispatched jobs (ProcessOrder, SendInvoice, UpdateInventory) will share the same correlation ID, allowing you to filter logs by correlation ID to see all related job executions.
Example 6: Forwarding Tracings to External APIs
use Illuminate\Support\Facades\Http; // Call external service with tracing headers public function fetchUserData(int $userId) { $response = Http::withTracing() ->get("https://api.example.com/users/{$userId}"); return $response->json(); }
HTTP request sent to external service:
GET /users/42 HTTP/1.1
Host: api.example.com
X-Correlation-Id: 550e8400-e29b-41d4-a716-446655440000
X-Request-Id: 123e4567-e89b-12d3-a456-426614174000
The external service can now log requests with the same correlation ID, enabling distributed tracing across services.
Custom Tracing Sources
Laravel Tracing is fully extensible. You can add custom tracing sources to track additional context like:
- User ID
- Tenant ID (for multi-tenant applications)
- Application version
- Custom business identifiers
Quick Example: Add User ID Tracing
Step 1: Create Custom Source Class
// app/Tracings/UserIdSource.php <?php namespace App\Tracings; use Illuminate\Http\Request; use JuniorFontenele\LaravelTracing\Tracings\Contracts\TracingSource; class UserIdSource implements TracingSource { public function resolve(Request $request): string { // Return authenticated user ID, or 'guest' if not authenticated return (string) ($request->user()?->id ?? 'guest'); } public function headerName(): string { return config('laravel-tracing.tracings.user_id.header', 'X-User-Id'); } public function restoreFromJob(string $value): string { return $value; // No transformation needed } }
Step 2: Register in Configuration
php artisan vendor:publish --tag=laravel-tracing-config
// config/laravel-tracing.php 'tracings' => [ 'correlation_id' => [...], 'request_id' => [...], // Add custom user ID tracing 'user_id' => [ 'enabled' => env('LARAVEL_TRACING_USER_ID_ENABLED', true), 'header' => env('LARAVEL_TRACING_USER_ID_HEADER', 'X-User-Id'), 'source' => \App\Tracings\UserIdSource::class, ], ],
Step 3: Use in Your Application
use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; // Access user ID from anywhere $userId = LaravelTracing::get('user_id'); // Include in logs Log::info('User action', [ 'user_id' => LaravelTracing::get('user_id'), 'correlation_id' => LaravelTracing::correlationId(), ]);
HTTP response headers now include:
X-Correlation-Id: 550e8400-e29b-41d4-a716-446655440000
X-Request-Id: 123e4567-e89b-12d3-a456-426614174000
X-User-Id: 42
Alternative: Runtime Registration
Register custom tracings programmatically in a service provider:
// app/Providers/AppServiceProvider.php use JuniorFontenele\LaravelTracing\Tracings\TracingManager; use App\Tracings\UserIdSource; public function boot(): void { app(TracingManager::class)->extend('user_id', new UserIdSource()); }
Complete Documentation
For comprehensive documentation on custom tracing sources, including:
- Implementing the
TracingSourcecontract - Replacing built-in sources
- Complete working examples (User ID, Tenant ID, App Version)
- Best practices and testing strategies
See: Extension Architecture Documentation
Troubleshooting
Tracing Headers Not Appearing in Response
Symptoms:
- Response headers don't include
X-Correlation-IdorX-Request-Id
Possible Causes & Solutions:
-
Package disabled via environment variable
# Check .env file LARAVEL_TRACING_ENABLED=true # Make sure this is true (or remove it for default)
-
Middleware not registered
- Verify that you manually registered the middleware in
bootstrap/app.php(required for Laravel 12) - Ensure the middleware is added to the correct middleware group (
webfor session-based apps) - Check that no conflicting middleware is interfering
- Verify that you manually registered the middleware in
-
Response is a redirect or exception
- Tracing middleware runs on normal responses. If the response is an exception or early redirect, middleware may not execute.
Debugging Steps:
// Add to a controller to verify package is working use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; dd(LaravelTracing::all()); // Should output: ['correlation_id' => '...', 'request_id' => '...']
Tracings Not Accessible in Jobs
Symptoms:
LaravelTracing::all()returns empty array inside job handler
Possible Causes & Solutions:
-
Queue connection doesn't support serialization
- Ensure your queue driver supports serialization (
database,redis,sqs) syncdriver works but processes immediately (no async execution)
- Ensure your queue driver supports serialization (
-
Job implements custom serialization
- If your job implements
SerializesModelsor custom serialization, ensure you're not interfering with the package's job listeners
- If your job implements
-
Package disabled
# Check environment variable LARAVEL_TRACING_ENABLED=true
Debugging Steps:
// In job handler use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; Log::info('Job tracings', LaravelTracing::all()); // Check logs to see if tracings are restored
Custom Tracing Source Not Loaded
Symptoms:
- Custom tracing doesn't appear in
LaravelTracing::all() - Custom header not attached to responses
Possible Causes & Solutions:
-
Config not published or cache issue
# Clear config cache php artisan config:clear # Republish config php artisan vendor:publish --tag=laravel-tracing-config --force
-
Custom source class not found
- Ensure the class exists at the path specified in config
- Check namespace matches config entry
- Run
composer dump-autoloadto refresh autoloader
-
Custom tracing disabled in config
// config/laravel-tracing.php 'tracings' => [ 'user_id' => [ 'enabled' => true, // Make sure this is true 'header' => 'X-User-Id', 'source' => \App\Tracings\UserIdSource::class, ], ],
-
TracingSource contract not implemented correctly
- Verify your custom source implements all three methods:
resolve(Request $request): stringheaderName(): stringrestoreFromJob(string $value): string
- Verify your custom source implements all three methods:
Debugging Steps:
// Check if tracing is registered use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; dd(LaravelTracing::has('user_id')); // Should be true if registered
External Headers Not Accepted
Symptoms:
- Sending
X-Correlation-Idheader with request, but server generates new ID instead
Solution:
Check the accept_external_headers configuration:
// config/laravel-tracing.php 'accept_external_headers' => env('LARAVEL_TRACING_ACCEPT_EXTERNAL_HEADERS', true),
# .env
LARAVEL_TRACING_ACCEPT_EXTERNAL_HEADERS=true
When false, the package ignores external headers and always generates fresh values.
Session Correlation ID Not Persisting
Symptoms:
- Each request gets a new correlation ID, even from the same session
Possible Causes & Solutions:
-
Session driver not configured
- Ensure
SESSION_DRIVERis set in.env(cookie,file,redis, etc.) arraydriver doesn't persist sessions across requests
- Ensure
-
Session middleware not running
- Check
app/Http/Kernel.phpincludes\Illuminate\Session\Middleware\StartSession::class
- Check
-
Browser not sending cookies
- Check
Set-Cookieheader is included in response - Ensure browser accepts cookies (not in incognito/privacy mode)
- Check
Debugging Steps:
# Make first request curl -c cookies.txt http://localhost:8000 # Make second request with cookies curl -b cookies.txt http://localhost:8000 # Both should have the same X-Correlation-Id
Frequently Asked Questions
Why use correlation ID vs request ID?
-
Correlation ID: Represents a user session or business transaction. Persists across multiple requests from the same user. Useful for tracing an entire user journey (e.g., browse → add to cart → checkout → payment).
-
Request ID: Represents a single HTTP request. Unique per request, even within the same session. Useful for identifying specific requests in logs.
Example:
- User visits
/products→ Correlation ID:abc123, Request ID:req1 - User visits
/cart(same session) → Correlation ID:abc123, Request ID:req2 - User visits
/checkout(same session) → Correlation ID:abc123, Request ID:req3
All three requests share the same correlation ID, allowing you to trace the entire session.
Can I use this with stateless APIs?
Yes. For stateless APIs (no session), correlation IDs are still useful when forwarded from upstream services:
-
Client sends request with correlation ID:
curl -H "X-Correlation-Id: client-abc-123" http://localhost:8000/api/data -
Your API accepts and uses it (if
accept_external_headersistrue):LaravelTracing::correlationId(); // Returns: "client-abc-123"
-
Your API forwards it to downstream services:
Http::withTracing()->get('https://downstream-service.com/data'); // Sends: X-Correlation-Id: client-abc-123
This enables end-to-end tracing across multiple stateless services.
How do I integrate with logging?
Laravel Tracing provides tracing values — you add them to your log context:
use Illuminate\Support\Facades\Log; use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; // Manual integration Log::info('User login', array_merge( ['user_id' => $userId], LaravelTracing::all() ));
For automatic integration, create a custom log processor:
// config/logging.php 'stack' => [ 'driver' => 'stack', 'channels' => ['daily'], 'processors' => [\App\Logging\AddTracingContext::class], ],
// app/Logging/AddTracingContext.php namespace App\Logging; use JuniorFontenele\LaravelTracing\Facades\LaravelTracing; class AddTracingContext { public function __invoke(array $record): array { $record['extra'] = array_merge( $record['extra'] ?? [], LaravelTracing::all() ); return $record; } }
Now all logs automatically include tracing context.
Testing
Run the test suite:
composer test
Run with coverage:
composer test -- --coverage
Credits
License
The MIT License (MIT). Please see License File for more information.