composer require league/tactician-logger
AppServiceProvider):
use League\Tactician\Logger\LoggerPlugin;
use Psr\Log\LoggerInterface;
public function register()
{
$this->app->bind(LoggerPlugin::class, function ($app) {
return new LoggerPlugin($app->make(LoggerInterface::class));
});
}
use League\Tactician\CommandBus;
use League\Tactician\Handler\CommandHandlerMiddleware;
use League\Tactician\Handler\CommandNameExtractor\ClassNameExtractor;
use League\Tactician\Handler\Locator\MethodNameInflector\HandleInflector;
use League\Tactician\Handler\MethodNameInflector\ClassMethodNameInflector;
use League\Tactician\Handler\Locator\InMemoryLocator;
use League\Tactician\Handler\MethodNameInflector\ClassMethodNameInflector;
use League\Tactician\Handler\CommandHandlerMiddlewareStack;
use League\Tactician\Logger\LoggerPlugin;
$commandBus = new CommandBus(
new CommandHandlerMiddlewareStack(
new InMemoryLocator(
new ClassMethodNameInflector(new HandleInflector())
)
),
[
new LoggerPlugin($this->app->make(LoggerInterface::class)),
// Other middleware...
]
);
Log command execution for debugging or auditing:
// Example command
$command = new ProcessOrderCommand($orderId);
// Command bus will log:
// - Command dispatched: "ProcessOrderCommand"
// - Command handled: "ProcessOrderCommand" (success/failure)
Logging Command Flow Use the logger to track command lifecycle:
// Logs at INFO level:
// "[INFO] Command dispatched: App\Commands\ProcessOrderCommand"
$commandBus->handle($command);
Conditional Logging Filter logs by command type or priority:
$logger = $this->app->make(LoggerInterface::class);
$logger->info('Skipping log for non-critical command', [
'command' => $command::class,
'context' => 'low_priority'
]);
Structured Logging Attach metadata to logs for better querying:
$logger->debug('Command handled', [
'command' => $command::class,
'user_id' => auth()->id(),
'timestamp' => now()->toIso8601String()
]);
Laravel Logging Leverage Laravel’s built-in logger (PSR-3 compliant):
$logger = \Log::channel('single'); // Or any custom channel
Middleware Stack Position
Place LoggerPlugin early in the stack to log dispatch events:
$middlewareStack->add(new LoggerPlugin($logger));
$middlewareStack->add(new ValidateCommandMiddleware());
Command Bus Decorator Wrap the bus for additional logging logic:
$bus = new LoggingCommandBus($commandBus, $logger);
Performance Overhead Logging every command may impact performance. Use debug-level logs for development and info/warning for production.
Circular Logging
Avoid logging inside handlers that are already being logged by the plugin. Use if ($logger->isDebugEnabled()) to gate debug logs.
Command Serialization
Complex commands (e.g., with closures or resources) may fail to log. Use json_encode($command, JSON_UNESCAPED_UNICODE) for safe serialization.
Log Levels Adjust log levels dynamically:
$logger->setLevel(\Monolog\Logger::DEBUG); // For dev
$logger->setLevel(\Monolog\Logger::WARNING); // For prod
Handler-Specific Logging Log handler execution time:
$start = microtime(true);
$result = $handler->handle($command);
$logger->info('Handler executed in ' . (microtime(true) - $start) . 'ms', [
'handler' => get_class($handler),
'command' => $command::class
]);
Custom Log Format
Extend LoggerPlugin to modify log messages:
class CustomLoggerPlugin extends LoggerPlugin
{
public function logCommandDispatched($commandName, $command)
{
$this->logger->info(sprintf('[CUSTOM] %s dispatched', $commandName), [
'custom_metadata' => 'value'
]);
}
}
Async Logging
Use React\Promise or Laravel\Queue to offload logging:
$logger->pushHandler(new AsyncHandler(new StreamHandler('php://stdout')));
Command Blacklisting Skip logging for specific commands:
$logger->debug('Skipping log for ' . $command::class, [
'reason' => 'internal_command'
]);
return; // Early return to bypass logging
How can I help you explore Laravel packages today?