aboutcoders/logger-bundle
Symfony bundle exposing a REST API to accept log messages from external apps. Configure allowed application names and map each to a Monolog channel, then POST level, message, and optional context to /api/log/{app}. Integrates with FOSRest and NelmioApiDoc.
Install Dependencies Run:
composer require aboutcoders/logger-bundle sensio/framework-extra-bundle nelmio/api-doc-bundle fos/rest-bundle
Enable the Bundle
Add to config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
new Abc\Bundle\LoggerBundle\AbcLoggerBundle(),
Configure Routing
Import routes in config/routes.yaml:
abc_rest_logger:
resource: "@AbcLoggerBundle/Resources/config/routing/rest.yml"
prefix: /api
Basic Configuration
Define allowed clients and Monolog channels in config/packages/abc_logger.yaml:
abc_logger:
clients:
- { name: "mobile_app", channel: "mobile" }
- { name: "web_frontend", channel: "frontend" }
First Log Entry
Send a POST request to /api/log with:
{
"client": "mobile_app",
"message": "User logged in",
"context": { "user_id": 123 }
}
Guzzle) to POST logs to /api/log.class LoggerClient {
public function log(string $clientName, string $message, array $context = []): void {
$client = new \GuzzleHttp\Client();
$client->post('/api/log', [
'json' => [
'client' => $clientName,
'message' => $message,
'context' => $context,
],
]);
}
}
mobile → mobile.log, frontend → syslog):
monolog:
channels:
- { name: mobile, type: stream, path: "%kernel.logs_dir%/mobile.log" }
- { name: frontend, type: syslog, identifier: "web_frontend" }
// src/EventListener/LoggerSubscriber.php
use Abc\Bundle\LoggerBundle\Event\LogEvent;
class LoggerSubscriber implements EventSubscriber {
public static function getSubscribedEvents() {
return [LogEvent::NAME => 'onLog'];
}
public function onLog(LogEvent $event) {
$event->getLogEntry()->addExtra('request_id', $event->getRequest()->get('X-Request-ID'));
}
}
abc_logger.clients config.@RateLimit annotation to throttle log submissions:
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use FOS\RestBundle\View\View;
use FOS\RestBundle\Controller\Annotations\Route;
/**
* @Route("/api/log", name="abc_logger_log", methods={"POST"})
* @ApiDoc(...)
* @RateLimit(limit=100, interval="minute")
*/
public function logAction(): View { ... }
LoggerService to verify log entries:
$logger = $this->createMock(\Psr\Log\LoggerInterface());
$logger->expects($this->once())->method('info')->with('User logged in', ['user_id' => 123]);
$this->container->set('logger.mobile', $logger);
HttpClient to test the API endpoint:
$response = $client->request('POST', '/api/log', [
'json' => ['client' => 'mobile_app', 'message' => 'Test']
]);
$this->assertEquals(204, $response->getStatusCode());
Deprecated Dependencies
symfony/http-client for logging requests instead of FOSRest.Missing Request Context
LogEvent subscriber to add context:
$event->getLogEntry()->addExtra('ip', $event->getRequest()->getClientIp());
Channel Configuration
kernel.request event to dynamically configure channels if needed:
# config/packages/monolog.yaml
monolog:
channels: ["mobile", "frontend"] # Predefine channels
CORS Issues
config/packages/nelmio_cors.yaml:
nelmio_cors:
defaults:
allow_origin: ["*"]
allow_methods: ["POST"]
allow_headers: ["Content-Type"]
max_age: 3600
Log Validation Errors
abc_logger:
validation_errors_as_exceptions: false # Set to true for stack traces
Check Monolog Output
tail -f var/log/mobile.log # For stream handlers
API Documentation
/api/log:
nelmio_api_doc:
documentation:
info:
title: Logger API
description: "Log messages from external clients"
Custom Log Formats
LogEntry class to modify log structure:
// src/AbcLoggerBundle/Event/LogEntry.php
class CustomLogEntry extends \Abc\Bundle\LoggerBundle\Event\LogEntry {
public function __toString() {
return sprintf("[%s] %s", $this->getClient(), $this->getMessage());
}
}
Async Logging
// config/packages/messenger.yaml
messenger:
transports:
async_log: "%kernel.project_dir%/var/log/async_logs"
routing:
"Abc\Bundle\LoggerBundle\Message\LogMessage": async_log
Database Logging
use Monolog\Handler\AbstractProcessingHandler;
class DatabaseHandler extends AbstractProcessingHandler {
protected function write(array $record): void {
// Save to DB (e.g., using Doctrine)
}
}
Then configure it in monolog.yaml:
monolog:
handlers:
database:
type: service
id: App\Log\Handler\DatabaseHandler
level: info
How can I help you explore Laravel packages today?