25carat/oro-api-logger
Logs all OroCommerce REST API requests and responses for monitoring integrations. Adds a dedicated api_logger channel writing to api-logger-[env].log with configurable minimum level; headers at info, bodies at debug, client errors at error, server errors at critical.
composer require 25carat/oro-api-logger
config/packages/parameters.yml (or equivalent in OroCommerce):
parameters:
twenty5carat.api_logger.level: error # Start with 'error' for production
php bin/console cache:clear
var/log/api-logger-[env].log for API request/response entries.Debugging a Failed API Integration:
debug level in staging:
twenty5carat.api_logger.level: debug
api-logger-staging.log for:
[2025-06-27 12:34:56] api_logger.INFO: Request to /api/rest/v1/orders {"headers": {...}, "body": {...}}
[2025-06-27 12:34:56] api_logger.ERROR: Response 400 {"headers": {...}, "body": "Invalid payload"}
Decorator Pattern:
RestApiController, intercepting all API requests/responses without modifying core logic.logRequest/logResponse methods in the decorator service.Log Level Strategy:
error or critical to avoid log noise.
twenty5carat.api_logger.level: error
debug for full payload inspection.
twenty5carat.api_logger.level: debug
env() in Symfony config).Log File Management:
var/log/api-logger-[env].log (e.g., api-logger-prod.log).logrotate or Symfony’s Monolog handlers (e.g., RotatingFileHandler):
# config/packages/monolog.yaml
monolog:
handlers:
api_logger:
type: rotating_file
path: "%kernel.logs_dir%/api-logger-%kernel.environment%.log"
level: "%twenty5carat.api_logger.level%"
max_files: 30 # Keep 30 days of logs
Pairing with Other Tools:
SocketHandler or SyslogHandler.
# config/packages/monolog.yaml
monolog:
handlers:
api_logger:
type: socket
host: "logs.example.com"
port: 514
critical/error logs and trigger alerts.Conditional Logging:
ApiLoggerFormatter service to exclude sensitive endpoints:
// src/Service/ApiLoggerFormatter.php
public function formatRequest(Request $request): string
{
if ($request->getPathInfo() === '/api/rest/v1/payments') {
return "Request to [REDACTED]";
}
return parent::formatRequest($request);
}
services.yaml:
services:
App\Service\ApiLoggerFormatter:
decorates: twenty5carat.api_logger.formatter
arguments: ['@.inner']
Performance Optimization:
// src/EventListener/ApiLoggerListener.php
public function onKernelRequest(GetResponseEvent $event)
{
if ($event->isMasterRequest()) {
$this->dispatcher->dispatch(new ApiLogEvent($event->getRequest()));
}
}
Structured Logging:
public function formatResponse(Response $response): string
{
return json_encode([
'timestamp' => (new \DateTime())->format('c'),
'status_code' => $response->getStatusCode(),
'headers' => $response->headers->all(),
'body' => $response->getContent(),
]);
}
Missing Configuration:
Parameter "twenty5carat.api_logger.level" not found.parameters.yml (or equivalent). OroCommerce may use config/packages/parameters.yml or app/config/parameters.yml.Sensitive Data Leaks:
debug level sparingly in production.password, token, or cc_number.Performance Impact:
debug level can slow down API responses.info or error in production.public function formatRequest(Request $request): string
{
if ($request->getContentLength() > 1024 * 1024) { // 1MB
return "Request to {$request->getPathInfo()} (large payload)";
}
return parent::formatRequest($request);
}
Log File Permissions:
var/log not writable by the web server).var/log is writable:
chmod -R 775 var/log
kernel.logs_dir if using a custom path:
# config/packages/framework.yaml
framework:
logs_dir: "%kernel.project_dir%/var/logs"
OroCommerce Upgrades:
RestApiController may change in minor/patch updates, breaking the decorator.Logs Not Appearing:
error).php bin/console cache:clear).api_logger channel is enabled in Monolog (it should be by default).var/log.php bin/console debug:config twenty5carat.api_logger.level
Malformed Logs:
# config/packages/dev/monolog.yaml
monolog:
handlers:
main:
level: debug
channels: ["!event"]
var_dump() in custom formatters to inspect data before logging.High Log Volume:
public function logResponse(Response $response)
{
if ($response->getStatusCode() >=
How can I help you explore Laravel packages today?