Laravel 11 Context: Quản Lý State và Trace ID Xuyên Suốt Request
1. Vấn Đề Truyền Dữ Liệu Ngữ Cảnh Trước Laravel 11
Hãy tưởng tượng bạn cần đính kèm một Correlation ID (hay Trace ID) vào tất cả các log trong toàn bộ hệ thống. Mục tiêu là khi có lỗi xảy ra, bạn có thể truy vết toàn bộ hành trình của một request từ lúc vào hệ thống cho đến khi xử lý xong, bao gồm cả các tác vụ bất đồng bộ trong Queue.
Những cách làm cũ thường gặp:
- Dùng
$request->attributes: Chỉ hoạt động trong phạm vi HTTP request hiện tại. Khi dispatch job, dữ liệu này biến mất. - Truyền tham số thủ công vào constructor của Job: Phải sửa lại tất cả các job hiện có, code trở nên cồng kềnh. Mỗi job lại phải khai báo thêm thuộc tính và tham số.
- Dùng
Session: Không phù hợp cho API stateless, lại phụ thuộc vào session driver. - Dùng
Config::set(): Là giải pháp “tạm bợ” và không an toàn trong môi trường đa request (như Octane), vì config là global và không được reset giữa các request. - Tự xây dựng Singleton pattern: Phức tạp, dễ gặp vấn đề về memory leak và không được hỗ trợ chính thức từ framework.
👉 Kết quả: Code không nhất quán, trace ID bị “đứt gánh” giữa request và queue, debug trở nên khó khăn. Chính vì lý do này, Laravel 11 đã chính thức giới thiệu tính năng Context — một giải pháp thống nhất, tinh gọn và cực kỳ mạnh mẽ.
💡 Đọc thêm: Bên cạnh Context, Laravel 11 còn mang đến nhiều thay đổi đột phá khác như cấu trúc thư mục tối giản, loại bỏ các file mặc định không cần thiết. Nếu bạn chưa đọc, hãy tham khảo bài viết Laravel 11 có gì mới? Cấu trúc thư mục tối giản để có cái nhìn tổng quan trước khi đi sâu vào tính năng này.
2. Laravel Context Là Gì Và Hoạt Động Như Thế Nào?
Context trong Laravel 11 là một cơ chế lưu trữ dữ liệu “nhận biết request” (request-aware storage). Nó cho phép bạn capture, retrieve và share thông tin xuyên suốt HTTP requests, Queue Jobs, và Artisan commands một cách liền mạch.
Theo tài liệu chính thức từ Laravel: “Laravel’s ‘context’ capabilities enable you to capture, retrieve, and share information throughout requests, jobs, and commands executing within your application. This captured information is also included in logs written by your application, giving you deeper insight into the surrounding code execution history that occurred before a log entry was written.”
Bản chất kỹ thuật: Context được triển khai như một Repository Pattern với cơ chế dehydration/hydration tự động. Khi bạn dispatch một job, toàn bộ dữ liệu trong Context sẽ được “đóng gói” (dehydrate) vào payload của job. Khi job được xử lý, dữ liệu sẽ được “khôi phục” (hydrate) lại vào Context một cách tự động.
flowchart LR
A[HTTP Request] --> B[Middleware gán Context]
B --> C[Controller xử lý]
C --> D[Dispatch Queue Job]
D --> E[Context được dehydrate vào job payload]
E --> F[Queue Worker nhận job]
F --> G[Context được hydrate trở lại]
G --> H[Job handle chạy với Context đầy đủ]
2.1 Các phương thức cơ bản: Context::add, Context::get, Context::addHidden
| Phương thức | Mô tả | Ví dụ |
|---|---|---|
Context::add($key, $value) |
Thêm dữ liệu vào context, xuất hiện trong log | Context::add('trace_id', $uuid) |
Context::get($key) |
Lấy dữ liệu từ context | $traceId = Context::get('trace_id') |
Context::addHidden($key, $value) |
Thêm dữ liệu ẩn, không xuất hiện trong log | Context::addHidden('api_key', $key) |
Context::getHidden($key) |
Lấy dữ liệu ẩn | $apiKey = Context::getHidden('api_key') |
Context::forget($key) |
Xóa dữ liệu khỏi context | Context::forget('temporary_data') |
Context::addIf($key, $value) |
Thêm dữ liệu chỉ khi key chưa tồn tại | Context::addIf('trace_id', $uuid) |
Điểm đặc biệt là khi bạn sử dụng Log::info(), dữ liệu trong Context sẽ tự động được đính kèm vào log entry như một phần của metadata, hoàn toàn không cần can thiệp thêm.
<?php
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Log;
Context::add('trace_id', 'abc-123-xyz');
Log::info('User logged in', ['user_id' => 1]);
// Kết quả log:
// User logged in. {"user_id":1} {"trace_id":"abc-123-xyz"}
2.2 Cơ chế tự động Hydrate sang Queue Job
Đây có lẽ là tính năng killer của Context. Khi bạn dispatch một job, Context tự động được capture và truyền sang job mà không cần bạn làm gì thêm:
<?php
// Trong Controller
use Illuminate\Support\Facades\Context;
Context::add('trace_id', 'abc-123-xyz');
ProcessPodcast::dispatch($podcast);
// Trong Job's handle method
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Log;
public function handle(): void
{
// Context đã được hydrate tự động
$traceId = Context::get('trace_id'); // 'abc-123-xyz'
Log::info('Processing podcast', ['podcast_id' => $this->podcast->id]);
}
// Log trong job sẽ tự động có trace_id:
// Processing podcast. {"podcast_id":95} {"trace_id":"abc-123-xyz"}
Cơ chế này được Laravel xử lý hoàn toàn tự động thông qua hệ thống Queue. Dữ liệu Context được serialized vào job payload dưới key illuminate:log:context và được hydrate lại khi job processing.
⚠️ Lưu ý quan trọng: Context chỉ hỗ trợ dữ liệu có thể serialize (JSON). Không lưu resource (như PDO instance), closure, hoặc object không hỗ trợ __serialize() vào Context. Nếu cố tình làm vậy, job sẽ bị lỗi khi dispatch.
⚠️ Lưu ý: Tính năng này được thiết kế để hoạt động với tất cả queue drivers. Tuy nhiên, cần kiểm chứng thực tế với các driver như Redis và SQS để đảm bảo dữ liệu Context được serialize/deserialize chính xác trong môi trường production, đặc biệt với dữ liệu phức tạp.

3. Thực Chiến: Xây Dựng Distributed Tracing System Trong Laravel 11
Phần này sẽ hướng dẫn bạn xây dựng một hệ thống distributed tracing hoàn chỉnh, từ việc tạo middleware cho đến kiểm chứng log và queue.
3.1 Viết TraceIdMiddleware bắt X-Request-ID header
Đầu tiên, tạo middleware để bắt hoặc sinh Trace ID:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
class TraceIdMiddleware
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next): Response
{
// Ưu tiên lấy trace_id từ header, nếu không có thì tự sinh
$traceId = $request->header('X-Request-ID') ?: Str::uuid()->toString();
// Gán vào Context - tự động xuất hiện trong mọi log
Context::add('trace_id', $traceId);
// Gán thêm metadata hữu ích
Context::add('request_url', $request->fullUrl());
Context::add('request_method', $request->method());
Context::add('client_ip', $request->ip());
// Thêm trace_id vào response header để client nhận biết
$response = $next($request);
$response->headers->set('X-Trace-ID', $traceId);
return $response;
}
}
Giải thích code:
- Dòng 18: Sử dụng
Str::uuid()để sinh UUID phiên bản 4 (ngẫu nhiên) làm trace ID. - Dòng 21-24: Gán các metadata vào Context — tất cả sẽ tự động xuất hiện trong log.
- Dòng 28: Thêm trace ID vào response header, giúp client và các service downstream có thể sử dụng cho tracing.
Đăng ký middleware trong bootstrap/app.php:
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
// ...
)
->withMiddleware(function (Middleware $middleware) {
// Đảm bảo middleware chạy ĐẦU TIÊN
$middleware->prepend(\App\Http\Middleware\TraceIdMiddleware::class);
})
->withExceptions(function (Exceptions $exceptions) {
// ...
})->create();
💡 Lưu ý: Sử dụng prepend() thay vì append() để đảm bảo middleware này chạy đầu tiên, giúp mọi log trong toàn bộ pipeline đều có trace ID.
3.2 Gán trace_id vào Laravel Context
Sau khi middleware đã hoạt động, bạn có thể truy cập trace_id từ bất kỳ đâu trong ứng dụng:
<?php
namespace App\Http\Controllers;
use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Log;
class PodcastController extends Controller
{
public function store(Request $request)
{
$traceId = Context::get('trace_id');
// Log tự động có trace_id
Log::info('Creating podcast', ['podcast' => $request->title]);
// Dispatch job - Context tự động truyền sang
ProcessPodcast::dispatch($request->all());
return response()->json(['message' => 'Podcast created']);
}
}
3.3 Kiểm chứng Log tự động đính kèm metadata

Tạo một Queue Job để kiểm chứng Context được hydrate tự động:
<?php
namespace App\Jobs;
use App\Models\Podcast;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Log;
class ProcessPodcast implements ShouldQueue
{
use Queueable;
public function __construct(
protected array $data
) {}
public function handle(): void
{
// Context đã được hydrate tự động từ request gốc
$traceId = Context::get('trace_id');
$requestUrl = Context::get('request_url');
Log::info('Processing podcast in queue', [
'trace_id' => $traceId,
'podcast_title' => $this->data['title'] ?? 'unknown'
]);
// Context cũng có thể được ghi thêm trong job
Context::add('job_processed_at', now()->toIso8601String());
// Xử lý business logic...
sleep(2); // Giả lập xử lý nặng
Log::info('Podcast processing completed');
}
}
Kiểm tra log output:
Khi chạy queue worker, log sẽ hiển thị:
[2025-01-15 10:30:45] local.INFO: Creating podcast {"podcast":"Laravel 11 Context Episode"} {"trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697","request_url":"https://myapp.com/podcasts","request_method":"POST","client_ip":"192.168.1.1"}
[2025-01-15 10:30:48] local.INFO: Processing podcast in queue {"trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697","podcast_title":"Laravel 11 Context Episode"} {"trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697","request_url":"https://myapp.com/podcasts","request_method":"POST","client_ip":"192.168.1.1"}
[2025-01-15 10:30:50] local.INFO: Podcast processing completed {} {"trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697","request_url":"https://myapp.com/podcasts","request_method":"POST","client_ip":"192.168.1.1","job_processed_at":"2025-01-15T10:30:50+00:00"}
🎯 Kết luận: Trace ID xuyên suốt từ request ban đầu qua queue job mà không cần bất kỳ tham số thủ công nào!
💡 Gợi ý mở rộng: Khái niệm Correlation ID/Trace ID là nền tảng của Centralized Logging và Observability. Nếu bạn quan tâm đến logging chuyên nghiệp trên các nền tảng khác, hãy đọc bài viết Logging chuyên nghiệp với Winston trong Node.js để thấy sự tương đồng trong tư duy thiết kế.
4. Context vs Session vs Config: Khi Nào Nên Dùng Gì?
| Tính năng | Context | Session | Config | Request Attributes |
|---|---|---|---|---|
| Phạm vi | Request + Queue Job + Command | Session (user-specific) | Global (toàn ứng dụng) | Chỉ trong request hiện tại |
| Tự động truyền sang Queue | ✅ Có | ❌ Không | ❌ Không | ❌ Không |
| Tự động đính kèm log | ✅ Có | ❌ Không | ❌ Không | ❌ Không |
| Dùng cho API | ✅ Tốt | ❌ Không nên (stateless) | ⚠️ Rủi ro | ✅ Tốt |
| Reset giữa các request | ✅ Tự động | ❌ Phụ thuộc driver | ❌ Không reset | ✅ Tự động |
| An toàn với Octane | ⚠️ Cần lưu ý | ⚠️ Tùy driver | ❌ Không an toàn | ✅ Có |

Khi nào dùng gì:
- Context: Dữ liệu cần xuyên suốt request → queue → log (trace ID, user context, tenant ID).
- Session: Dữ liệu user-specific cần lưu giữa các request (giỏ hàng, trạng thái đăng nhập).
- Config: Dữ liệu cấu hình tĩnh, không đổi trong suốt vòng đời ứng dụng.
- Request Attributes: Dữ liệu tạm thời chỉ dùng trong request hiện tại, không cần log.
5. Lỗi Thường Gặp Khi Sử Dụng Laravel Context
🔴 Lỗi 1: Nhầm lẫn giữa Context::add() và Context::addHidden()
Vấn đề: Sử dụng Context::add() cho dữ liệu nhạy cảm như password hash, API token, session ID → dữ liệu này sẽ lộ trong log files.
Hậu quả: Rò rỉ thông tin bảo mật nghiêm trọng trong log, đặc biệt nguy hiểm nếu log được lưu trữ lâu dài hoặc chia sẻ với bên thứ ba.
Cách fix:
<?php
use Illuminate\Support\Facades\Context;
// ❌ SAI - Dữ liệu nhạy cảm xuất hiện trong log
Context::add('api_secret', $secretKey);
Context::add('user_password_hash', $hash);
// ✅ ĐÚNG - Dữ liệu nhạy cảm chỉ truy cập được trong code
Context::addHidden('api_secret', $secretKey);
Context::addHidden('user_password_hash', $hash);
// Lấy dữ liệu ẩn
$secret = Context::getHidden('api_secret');
🔴 Lỗi 2: Không khởi tạo Trace ID ở đầu pipeline
Vấn đề: Đặt middleware gán Context quá muộn trong pipeline → một số log ở các middleware trước đó không có trace ID.
Cách fix: Đăng ký middleware ở vị trí đầu tiên hoặc sử dụng prepend() thay vì append():
<?php
// Trong bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
// Đảm bảo middleware chạy ĐẦU TIÊN
$middleware->prepend(\App\Http\Middleware\TraceIdMiddleware::class);
})
🔴 Lỗi 3: Không xử lý Context trong Artisan Commands và Scheduled Tasks
Vấn đề: Context chỉ được khởi tạo tự động cho HTTP requests. Trong Artisan commands hoặc scheduled tasks, Context rỗng.
Cách fix: Tự động sinh trace ID ngay trong command:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class ProcessReportCommand extends Command
{
protected $signature = 'report:process';
protected $description = 'Process monthly report';
public function handle()
{
// Khởi tạo Context cho command
Context::add('trace_id', Str::uuid()->toString());
Context::add('command', $this->signature);
Context::add('executed_at', now()->toIso8601String());
Log::info('Starting report processing');
// ... xử lý
Log::info('Report processing completed');
}
}
🔴 Lỗi 4: Context bị mất trong môi trường Octane
Vấn đề: Khi sử dụng Laravel Octane (Swoole/RoadRunner), Context có thể bị mất giữa các request do Octane tối ưu hóa và tái sử dụng application container.
Cách fix:
- Đảm bảo sử dụng Laravel 11.41.3+ với Octane 2.8.1+ đã được fix.
- Kiểm tra kỹ trong môi trường staging trước khi deploy production.
- Xem xét sử dụng
Context::scope()trong Laravel 12+ để hỗ trợ async context isolation.
🔴 Lỗi 5: Lưu dữ liệu không serialize được vào Context
Vấn đề: Context được serialize vào job payload. Nếu bạn lưu resource (như PDO instance, file handle) hoặc closure vào Context, job sẽ bị lỗi khi dispatch.
Cách fix: Chỉ lưu dữ liệu có thể serialize (scalar, array, object implement __serialize()).
<?php
use Illuminate\Support\Facades\Context;
// ❌ SAI - Resource không serialize được
Context::add('db_connection', DB::connection());
// ✅ ĐÚNG - Chỉ lưu dữ liệu scalar hoặc array
Context::add('connection_name', config('database.default'));
Context::add('user', ['id' => $userId, 'email' => $email]);
🔴 Lỗi 6: Quên restart Queue Worker sau khi thay đổi Context
Vấn đề: Queue worker cache job payload. Nếu bạn thay đổi cách sử dụng Context trong code nhưng không restart worker, worker vẫn dùng payload cũ.
Cách fix: Luôn restart queue worker sau khi deploy code mới:
php artisan queue:restart
6. Best Practices Khi Sử Dụng Laravel Context
✅ Best Practice 1: Luôn khởi tạo Trace ID tại middleware đầu tiên
Đảm bảo mọi request vào hệ thống đều có trace ID ngay từ đầu. Điều này giúp toàn bộ log trong hệ thống đều có thể truy vết được.
✅ Best Practice 2: Sử dụng Context::forget() cho dữ liệu tạm thời
Trong các tác vụ chạy ngầm kéo dài (long-running jobs), nếu bạn có dữ liệu không cần thiết sau một thời điểm, hãy xóa nó để tránh memory leak:
<?php
public function handle(): void
{
$largeData = Context::get('large_dataset');
// Xử lý với largeData...
// Giải phóng bộ nhớ khi không còn cần
Context::forget('large_dataset');
}
✅ Best Practice 3: Đặt tên key có cấu trúc rõ ràng
Sử dụng namespace hoặc prefix để tránh xung đột key:
<?php
use Illuminate\Support\Facades\Context;
// ❌ Không rõ ràng
Context::add('id', $value);
// ✅ Rõ ràng, có namespace
Context::add('trace.id', $value);
Context::add('user.id', Auth::id());
Context::add('tenant.id', $tenantId);
✅ Best Practice 4: Log Context trong exception handling
Cập nhật exception handler để tự động gắn Context vào exception log:
<?php
// Trong bootstrap/app.php
use Illuminate\Foundation\Configuration\Exceptions;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->context(function () {
return [
'trace_id' => Context::get('trace_id'),
'user_id' => Context::get('user.id'),
'request_url' => Context::get('request_url'),
];
});
})
✅ Best Practice 5: Kiểm tra sự tồn tại của key trước khi lấy
Sử dụng Context::has() để kiểm tra trước khi truy xuất, hoặc dùng Context::addIf() để chỉ thêm khi key chưa tồn tại:
<?php
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Str;
// Cách 1: Kiểm tra trước
if (Context::has('trace_id')) {
$traceId = Context::get('trace_id');
} else {
$traceId = Str::uuid()->toString();
Context::add('trace_id', $traceId);
}
// Cách 2: Dùng addIf (chỉ thêm nếu chưa tồn tại)
Context::addIf('trace_id', Str::uuid()->toString());
$traceId = Context::get('trace_id');
✅ Best Practice 6: Sử dụng Fluent Helper cho dữ liệu phức tạp
Laravel 11.2+ hỗ trợ Fluent Helper để làm việc với mảng đa chiều trong Context:
<?php
use Illuminate\Support\Facades\Context;
// Thêm dữ liệu phức tạp
Context::add('user', [
'id' => 1,
'profile' => [
'name' => 'John Doe',
'email' => 'john@example.com'
]
]);
// Truy xuất với dot notation
$email = Context::get('user.profile.email'); // 'john@example.com'
// Hoặc dùng hàm context() helper
$user = context('user');
$email = context('user.profile.email');
7. FAQ
❓ Laravel Context có chạy mượt trên Laravel Octane không?
Context được thiết kế để tương thích với Octane, nhưng đã từng có issue về việc Context bị mất trong một số phiên bản cũ. Nếu bạn sử dụng Laravel 11.41.3+ với Octane 2.8.1+, vấn đề này đã được khắc phục. Tuy nhiên, vẫn nên kiểm tra kỹ trong môi trường staging và theo dõi các log để đảm bảo Context hoạt động ổn định.
❓ Context khác gì với việc gán thuộc tính vào $request->attributes?
| Context | Request Attributes | |
|---|---|---|
| Phạm vi | Request + Queue Job + Command | Chỉ request hiện tại |
| Tự động truyền sang Queue | ✅ Có | ❌ Không |
| Tự động vào log | ✅ Có | ❌ Không |
| Sử dụng trong Service/Repository | ✅ Có (dùng Facade) | ❌ Không (cần truyền request) |
| Persistent trong pipeline | ✅ Có | ✅ Có |
❓ Dữ liệu trong Context có bị lộ khi serialize job không?
Context được serialize và lưu trong job payload. Nếu bạn lưu trữ dữ liệu nhạy cảm, hãy luôn sử dụng Context::addHidden() để đảm bảo dữ liệu không xuất hiện trong log. Tuy nhiên, dữ liệu vẫn tồn tại trong payload của queue — hãy cân nhắc sử dụng queue driver có mã hóa nếu cần bảo mật tuyệt đối.
❓ Làm thế nào để test Context trong Unit Test?
<?php
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Queue;
test('context preserves trace id', function () {
Context::add('trace_id', 'test-trace-123');
expect(Context::get('trace_id'))->toBe('test-trace-123');
// Test với Queue fake
Queue::fake();
ProcessPodcast::dispatch();
// Kiểm tra job được dispatch với context đúng
Queue::assertPushed(ProcessPodcast::class);
});
❓ Context có hỗ trợ multi-dimensional array không?
Có, Laravel 11.2+ hỗ trợ Fluent Helper để làm việc với mảng đa chiều trong Context.
<?php
use Illuminate\Support\Facades\Context;
Context::add('user', [
'id' => 1,
'profile' => [
'name' => 'John Doe',
'email' => 'john@example.com'
]
]);
$email = Context::get('user.profile.email'); // 'john@example.com'
❓ Context có được hydrate khi retry job không?
Có. Khi job được retry (ví dụ qua queue:retry), Context sẽ được hydrate lại từ payload đã lưu. Tuy nhiên, cần lưu ý rằng trong command queue:retry, Context chưa được hydrate ngay tại thời điểm sự kiện JobRetryRequested được fired — context chỉ được hydrate khi job thực sự bắt đầu processing.
❓ Làm thế nào để sử dụng Context với Laravel Horizon?
Khi sử dụng Laravel Horizon, Context hoạt động bình thường vì Horizon sử dụng cùng cơ chế queue của Laravel. Tuy nhiên, cần lưu ý:
- Restart Horizon sau khi deploy code mới:
php artisan horizon:terminate - Không cache Context giữa các lần chạy job — mỗi job đều có context riêng được hydrate từ payload.
- Monitor context size — Horizon có thể hiển thị kích thước payload, đảm bảo context không vượt quá giới hạn (mặc định 65KB).
❓ Làm thế nào để tắt Context metadata trong log?
Nếu bạn muốn tạm thời tắt việc append context metadata vào log (ví dụ trong môi trường development với log quá nhiều), bạn có thể cấu hình trong config/logging.php:
<?php
// Trong config/logging.php
'context' => env('LOG_CONTEXT', true),
Hoặc trong code:
<?php
use Illuminate\Support\Facades\Log;
// Tắt context cho một log entry cụ thể
Log::withoutContext()->info('This log has no context metadata');
8. Kết Luận
Laravel 11 Context là một tính năng game-changing cho các ứng dụng cần distributed tracing, centralized logging, và xử lý bất đồng bộ phức tạp. Với cơ chế tự động hydrate/dehydrate qua Queue, bạn có thể:
- ✅ Loại bỏ việc truyền tham số thủ công vào mọi queue job.
- ✅ Tự động đính kèm metadata (trace ID, user context, tenant) vào mọi log entry.
- ✅ Xây dựng hệ thống distributed tracing chỉ với vài dòng code trong middleware.
- ✅ Bảo mật dữ liệu nhạy cảm với
Context::addHidden().
Context không chỉ là một công cụ logging — nó là nền tảng cho Observability trong các hệ thống Laravel hiện đại. Kết hợp với các công cụ như Laravel Telescope, Flare, hay Nightwatch, bạn có thể có cái nhìn toàn diện về luồng xử lý của ứng dụng.