Installation Add the package via Composer:
composer require elastic/ecs-logging
For Laravel, ensure your logging channel (e.g., monolog) is configured to use the ECS formatter.
Basic Usage
Inject the Elastic\EcsLogger\EcsLogger into your service or controller:
use Elastic\EcsLogger\EcsLogger;
public function __construct(private EcsLogger $ecsLogger) {}
First Log Entry Log a structured event with ECS fields:
$this->ecsLogger->info('User action', [
'user' => [
'id' => 123,
'username' => 'john_doe',
],
'event' => 'login',
'http' => [
'request' => [
'method' => 'POST',
'url' => '/api/auth',
],
],
]);
Key Files
src/EcsLogger.php for core methods.src/Formatter/EcsFormatter.php for field mapping rules.src/Processor/ for built-in processors (e.g., HostnameProcessor, ProcessProcessor).Contextual Logging Attach metadata (e.g., request ID, user session) via processors:
$this->ecsLogger->withContext([
'request_id' => $request->header('X-Request-ID'),
'trace_id' => $request->header('X-Trace-ID'),
])->info('Processing request');
Middleware Integration Use middleware to auto-inject ECS fields (e.g., HTTP context):
public function handle($request, Closure $next) {
$this->ecsLogger->withContext([
'http' => [
'request' => [
'method' => $request->method(),
'url' => $request->fullUrl(),
],
],
]);
return $next($request);
}
Error Handling Log exceptions with stack traces and ECS fields:
try {
// Risky operation
} catch (\Exception $e) {
$this->ecsLogger->error('Database failure', [
'error' => [
'type' => get_class($e),
'message' => $e->getMessage(),
'stack_trace' => $e->getTraceAsString(),
],
]);
}
Custom Processors
Extend Elastic\EcsLogger\Processor\ProcessorInterface to add domain-specific fields:
class UserProcessor implements ProcessorInterface {
public function process(array $record): array {
$record['user'] = auth()->user()?->toArray();
return $record;
}
}
Register via service provider:
$ecsLogger->addProcessor(new UserProcessor());
Log Levels
Leverage ECS-compliant levels (error, warn, info, debug, trace):
$this->ecsLogger->debug('Debugging user session', ['user' => auth()->user()]);
Field Naming Conflicts
@timestamp, message, log.level).custom.field) or prefixes (e.g., app.*).Performance Overhead
Timestamp Handling
now() for @timestamp. Override if using custom time sources:$ecsLogger->setTimestamp(function () {
return Carbon::now()->toDateTimeString();
});
Processor Order Matters
Processors execute in registration order. Critical fields (e.g., service.name) should run early.
dump() in a processor to inspect the record state.Monolog Integration
$handler->pushProcessor(new EcsFormatter());
Inspect Raw Records Temporarily log the raw ECS array to verify structure:
$this->ecsLogger->info('Debug ECS', ['_raw' => $this->ecsLogger->getProcessor()->process([])]);
Validate Against ECS Spec Use ECS Validator to check compliance:
curl -XPOST "localhost:9200/_validate/query?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": [
{ "exists": { "field": "event.id" } }
]
}
}
}'
Log Level Filtering
single channel with level: warning):'logging' => [
'channels' => [
'ecs' => [
'driver' => 'single',
'level' => env('LOG_LEVEL', 'warning'),
'handler' => Elastic\EcsLogger\Handler\StreamHandler::class,
],
],
],
Custom Field Mappers
Override Elastic\EcsLogger\Formatter\EcsFormatter to map Laravel-specific data (e.g., Illuminate\Database\Eloquent\Model to ECS):
protected function mapModelToEcs($model): array {
return [
'object' => [
'id' => $model->getKey(),
'type' => get_class($model),
'attributes' => $model->toArray(),
],
];
}
Dynamic Field Injection
Use Laravel’s app() helper to inject dynamic values (e.g., config, environment):
$this->ecsLogger->addProcessor(function (array $record): array {
$record['service'] = [
'version' => config('app.version'),
'environment' => app()->environment(),
];
return $record;
});
Log Sampling Implement probabilistic sampling for high-volume logs:
$this->ecsLogger->addProcessor(function (array $record) {
if (rand(0, 99) > 50) { // 50% sampling
return $record;
}
return ['@metadata' => ['sampled' => false]];
});
Log Enrichment via Observers Attach ECS fields to Eloquent models via observers:
class UserObserver {
public function saved(User $user) {
\Log::ecs('User updated', [
'user' => [
'id' => $user->id,
'action' => 'update',
],
]);
}
}
How can I help you explore Laravel packages today?