Skip to content

Commit 827b409

Browse files
new feature set
1 parent f8d08da commit 827b409

File tree

8 files changed

+382
-70
lines changed

8 files changed

+382
-70
lines changed

ReadME.md

Lines changed: 104 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,127 @@
1-
Laravel Correlation ID Middleware
2-
=================================
1+
# Laravel Correlation ID Middleware
32

4-
A package to manage correlation IDs for request tracing in Laravel applications,
5-
A correlation ID is a randomly generated identifier for every request entering a distributed system. Developers use the correlation identifier to trace the request as it makes its way through the system, identify any cyber security threats, and prevent them.
6-
The correlation ID basically serves as a thread that connects the various parts of a request as it moves through the system. This greatly simplifies distributed system debugging and troubleshooting by allowing developers to track a request’s progress and readily pinpoint the service or component where an issue occurred.
3+
A package to manage correlation IDs for request tracing in Laravel applications.
74

5+
A correlation ID is a unique identifier assigned to each request entering a distributed system. It helps developers trace requests, debug issues, and identify potential security threats. By attaching a correlation ID to each request, you can track its journey through various services and components, simplifying troubleshooting and monitoring.
86

9-
Installation
10-
------------
7+
---
118

12-
composer require mohamedahmed01/laravel-correlation
9+
## 📌 Installation
1310

14-
Configuration
15-
-------------
11+
```sh
12+
composer require mohamedahmed01/laravel-correlation
13+
```
1614

17-
Publish the config file:
15+
---
1816

19-
php artisan vendor:publish --tag=correlation-config
17+
## ⚙️ Configuration
2018

21-
Config options (`config/correlation.php`):
19+
### Publish the Config File
2220

23-
* `header`: Header name to use (default: X-Correlation-ID)
24-
* `auto_register_middleware`: Automatically register middleware (default: true)
21+
```sh
22+
php artisan vendor:publish --tag=correlation-config
23+
```
2524

26-
Usage
27-
-----
25+
### Config Options (`config/correlation.php`)
26+
27+
- **`header`**: Header name to use (default: `X-Correlation-ID`)
28+
- **`alternate_headers`**: Additional headers to check for a correlation ID (e.g., `X-Request-ID`, `Trace-ID`)
29+
- **`generator`**: Strategy for generating correlation IDs (`uuid`, `timestamp`, `hash`)
30+
- **`storage`**: Store correlation IDs in `cache`, `session`, or `none`
31+
- **`queue`**: Enable correlation ID propagation in queued jobs (default: `true`)
32+
- **`propagate`**: Automatically include correlation ID in outgoing HTTP requests (default: `true`)
33+
- **`auto_register_middleware`**: Automatically register middleware (default: `true`)
34+
35+
---
36+
37+
## 🚀 Usage
2838

2939
The correlation ID will be:
3040

31-
1. Read from incoming requests
32-
2. Generated if missing
33-
3. Added to all responses
34-
4. Available in logs
35-
5. Accessible via `correlation_id()` helper
41+
1. Extracted from incoming requests (from configured headers)
42+
2. Generated if missing (based on configured strategy)
43+
3. Stored in cache (if enabled)
44+
4. Included in all responses
45+
5. Available in logs
46+
6. Passed through queued jobs
47+
7. Propagated in HTTP requests
48+
8. Accessible via helper functions and Blade directives
3649

37-
### Manual Middleware Registration
50+
### Middleware Registration
3851

39-
Add to `app/Http/Kernel.php`:
52+
If `auto_register_middleware` is disabled, manually register the middleware in `app/Http/Kernel.php`:
4053

41-
protected $middleware = [
42-
\Mohamedahmed01\LaravelCorrelation\Http\Middleware\CorrelationMiddleware::class,
43-
];
54+
```php
55+
protected $middleware = [
56+
\Mohamedahmed01\LaravelCorrelation\Http\Middleware\CorrelationMiddleware::class,
57+
];
58+
```
4459

4560
### Accessing the Correlation ID
4661

62+
#### 📌 In Controllers or Services
63+
64+
```php
65+
$correlationId = correlation_id();
66+
```
67+
68+
#### 📌 In Blade Views
69+
70+
```blade
71+
@correlationId
72+
```
73+
74+
#### 📌 In Jobs (Queued Work)
75+
76+
```php
77+
public function handle()
78+
{
4779
$correlationId = correlation_id();
80+
Log::info("Processing job", ['correlation_id' => $correlationId]);
81+
}
82+
```
83+
84+
#### 📌 In Logs
85+
86+
All logs during a request will automatically include the correlation ID:
87+
88+
```json
89+
{
90+
"message": "User created",
91+
"context": {
92+
"correlation_id": "123e4567-e89b-12d3-a456-426614174000"
93+
}
94+
}
95+
```
96+
97+
### 🌍 HTTP Client Propagation
98+
99+
If `propagate` is enabled, correlation IDs will be automatically included in outgoing HTTP requests:
100+
101+
```php
102+
$response = Http::withCorrelationId()->get('https://api.example.com/data');
103+
```
104+
105+
### 🔧 Artisan Commands
106+
107+
List stored correlation IDs:
108+
109+
```sh
110+
php artisan correlation:list
111+
```
112+
113+
---
114+
115+
## ✅ Testing
116+
117+
Run the test suite to ensure functionality:
118+
119+
```sh
120+
php artisan test
121+
```
48122

49-
### Logging
123+
---
50124

51-
All logs during a request will automatically include:
125+
## 📜 License
52126

53-
['correlation_id' => 'your-uuid']
127+
MIT License

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
],
1111
"require": {
1212
"php": "^8.0",
13-
"laravel/framework": "^9.0|^10.0"
13+
"laravel/framework": "^9.0|^10.0",
14+
"guzzlehttp/guzzle": "^7.0",
15+
"guzzlehttp/psr7": "^2.0"
1416
},
1517
"autoload": {
1618
"psr-4": {

config/correlation.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,24 @@
22

33
return [
44
'header' => env('CORRELATION_HEADER', 'X-Correlation-ID'),
5+
6+
// Define ID generation method: uuid, timestamp, hash
7+
'generator' => env('CORRELATION_GENERATOR', 'uuid'),
8+
9+
// Enable logging integration
10+
'log' => true,
11+
12+
// Enable correlation ID propagation in HTTP requests
13+
'propagate' => true,
14+
15+
// Enable queue support (attaching correlation ID to jobs)
16+
'queue' => true,
17+
18+
// Enable storing correlation IDs in cache or database
19+
'storage' => env('CORRELATION_STORAGE', 'cache'), // options: cache, database, none
20+
21+
// Alternate header names for compatibility
22+
'alternate_headers' => ['X-Request-ID', 'Trace-ID'],
23+
524
'auto_register_middleware' => env('CORRELATION_AUTO_REGISTER', true),
625
];
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Mohamedahmed01\LaravelCorrelation\Console\Commands;
4+
5+
use Illuminate\Console\Command;
6+
use Illuminate\Support\Facades\Cache;
7+
8+
class CorrelationListCommand extends Command
9+
{
10+
protected $signature = 'correlation:list';
11+
protected $description = 'List recent correlation IDs';
12+
13+
public function handle()
14+
{
15+
$keys = Cache::get('correlation:keys', []);
16+
17+
if (empty($keys)) {
18+
$this->warn('No correlation IDs found.');
19+
return;
20+
}
21+
22+
foreach ($keys as $key) {
23+
$time = Cache::get("correlation:$key", 'Unknown time');
24+
$this->info("Correlation ID: $key - Time: $time");
25+
}
26+
}
27+
}
28+

src/CorrelationServiceProvider.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,21 @@
33
namespace Mohamedahmed01\LaravelCorrelation;
44

55
use Illuminate\Support\ServiceProvider;
6+
use Illuminate\Support\Facades\Blade;
7+
use Illuminate\Support\Facades\Http;
8+
69
use Mohamedahmed01\LaravelCorrelation\Http\Middleware\CorrelationMiddleware;
10+
use Mohamedahmed01\LaravelCorrelation\CorrelationServiceProvider;
711

812
class CorrelationServiceProvider extends ServiceProvider
913
{
14+
1015
public function boot(): void
1116
{
17+
Blade::directive('correlationId', function () {
18+
return "<?php echo correlation_id(); ?>";
19+
});
20+
1221
$this->publishes([
1322
__DIR__.'/../config/correlation.php' => config_path('correlation.php'),
1423
], 'correlation-config');
@@ -17,6 +26,18 @@ public function boot(): void
1726
$this->app['router']->pushMiddlewareToGroup('web', CorrelationMiddleware::class);
1827
$this->app['router']->pushMiddlewareToGroup('api', CorrelationMiddleware::class);
1928
}
29+
30+
Http::macro('withCorrelationId', function () {
31+
return Http::withHeaders([
32+
config('correlation.header') => correlation_id(),
33+
]);
34+
});
35+
36+
if ($this->app->runningInConsole()) {
37+
$this->commands([
38+
\Mohamedahmed01\LaravelCorrelation\Console\Commands\CorrelationListCommand::class,
39+
]);
40+
}
2041
}
2142

2243
public function register(): void

src/Http/Middleware/CorrelationMiddleware.php

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
use Closure;
66
use Illuminate\Http\Request;
7+
use Illuminate\Support\Facades\Cache;
8+
use Illuminate\Support\Facades\Log;
9+
use Illuminate\Support\Facades\Queue;
710
use Illuminate\Support\Str;
811
use Symfony\Component\HttpFoundation\Response;
912

@@ -12,20 +15,47 @@ class CorrelationMiddleware
1215
public function handle(Request $request, Closure $next): Response
1316
{
1417
$headerName = config('correlation.header', 'X-Correlation-ID');
15-
$correlationId = $request->header($headerName) ?? Str::uuid()->toString();
18+
$alternateHeaders = config('correlation.alternate_headers', []);
19+
20+
$correlationId = $this->getCorrelationId($request, $headerName, $alternateHeaders);
1621

17-
// Store in application container
1822
app()->instance('correlation.id', $correlationId);
1923

20-
// Add to log context using multiple methods
21-
$this->addLogContext($correlationId);
24+
if (config('correlation.log')) {
25+
$this->addLogContext($correlationId);
26+
}
27+
28+
if (config('correlation.storage') === 'cache') {
29+
Cache::put('correlation:' . $correlationId, now()->toDateTimeString(), 3600);
30+
}
31+
32+
if (config('correlation.queue')) {
33+
Queue::before(fn($event) => $event->job->setCorrelationId($correlationId));
34+
}
2235

2336
$response = $next($request);
2437
$response->headers->set($headerName, $correlationId);
2538

2639
return $response;
2740
}
2841

42+
protected function getCorrelationId(Request $request, string $headerName, array $alternateHeaders): string
43+
{
44+
// Check for existing correlation ID
45+
foreach ([$headerName, ...$alternateHeaders] as $header) {
46+
if ($id = $request->header($header)) {
47+
return $id;
48+
}
49+
}
50+
51+
// Generate a new correlation ID
52+
return match (config('correlation.generator', 'uuid')) {
53+
'timestamp' => now()->timestamp . Str::random(5),
54+
'hash' => hash('sha256', Str::uuid()->toString()),
55+
default => Str::uuid()->toString(),
56+
};
57+
}
58+
2959
protected function addLogContext(string $correlationId): void
3060
{
3161
if (method_exists(\Log::class, 'shareContext')) {

src/helpers.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
<?php
22

3-
use Illuminate\Contracts\Foundation\Application;
4-
5-
if (! function_exists('correlation_id')) {
6-
function correlation_id(): ?string
3+
if (!function_exists('correlation_id')) {
4+
function correlation_id()
75
{
8-
return app()->has('correlation.id') ? app('correlation.id') : null;
6+
return app('correlation.id');
97
}
10-
}
8+
}

0 commit comments

Comments
 (0)