Logging
Emitter and Dispatcher accept any Psr\Log\LoggerInterface. With no logger, both classes skip every log call. Hermes does not configure Monolog for you. monolog/monolog is a suggested package.
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Tomaj\Hermes\Dispatcher;
$log = new Logger('hermes');
$log->pushHandler(new StreamHandler('hermes.log'));
$dispatcher = new Dispatcher($driver, $log, $shutdown);
$emitter = new Emitter($driver, $log);Give the emitter and the dispatcher their own logger instances if they run in different processes. A logger object is not shared through the queue.
Lines the library writes
Levels are PSR-3 strings (Psr\Log\LogLevel).
| Where | Level | Message |
|---|---|---|
Emitter::emit | info | Emitter send message #<id> to driver <class> |
Dispatcher::emit (deprecated) | info | Dispatcher send message #<id> with priority <n> to driver <class> |
Dispatcher::handle | info | Start handle message #<id> (<type>) priority:<n> |
Dispatcher after a handler returns | info | End handle message #<id> (<type>) |
Dispatcher when a handler throws | error | Handler <class> throws exception - <exception message> |
Dispatcher after SIGTERM / SIGINT (ext-pcntl) | notice | Exiting hermes dispatcher - received SIGTERM (or SIGINT) |
Dispatcher on ShutdownException | notice | Exiting hermes dispatcher - shutdown |
Dispatcher when the driver throws, before rethrowing | error | Exiting hermes dispatcher - driver error: <class> - <exception message> |
Emitter context is id, created, type, payload. Dispatcher context adds retries and execute_at. The handler error context also includes error, message (the array above), and exception. The driver error context is only exception.
A type with no registered handler still logs the start line. It does not log the end line, because handleMessage() is never called.
Handlers
Before handle(), the dispatcher calls setLogger() when the logger is non-null and the method exists. Implementing LoggerAwareInterface is the usual way to get that method. The check itself is method_exists($handler, 'setLogger').
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LoggerInterface;
use Tomaj\Hermes\Handler\HandlerInterface;
use Tomaj\Hermes\MessageInterface;
class SendEmailHandler implements HandlerInterface
{
use LoggerAwareTrait;
public function handle(MessageInterface $message): bool
{
$payload = $message->getPayload();
if ($payload === null) {
return false;
}
if ($this->logger instanceof LoggerInterface) {
$this->logger->info('Trying to send email to ' . $payload['to']);
}
mail($payload['to'], $payload['subject'], $payload['message']);
return true;
}
}LoggerAwareTrait leaves $this->logger unset until the dispatcher injects one. The instanceof check keeps a handler usable in a test that never passes a logger.
Tracy
tracy/tracy is optional (suggest); install it with composer require tracy/tracy. Hermes writes to it only when it is installed and Debugger::isEnabled() is already true:
- the exception caught inside
handleMessage() - any other
Exceptionthat escapesDriver::wait(), exceptShutdownException; it is then rethrown
Both use Debugger::log($exception, Debugger::EXCEPTION). Call Debugger::enable() in the worker bootstrap if you want those files. Hermes will not enable Tracy on its own.
FAQ
Does Hermes log anything by default?
No. Pass a PSR-3 logger to Emitter and Dispatcher. Without one, every log call is skipped.
Which logger should I use?
Any PSR-3 logger. Monolog is the usual choice and is listed under suggest.
How does a handler get the logger?
Implement setLogger(), for example with LoggerAwareTrait. The dispatcher injects its logger before calling handle().
Where do handler exceptions go?
They are logged at error with the exception in the context, and passed to Tracy when Tracy is installed and Debugger::isEnabled() is true.
Do I need Tracy?
No. It is only suggested. Without it Hermes logs through the PSR-3 logger alone.
Why does the emitter log the word Dispatcher?
It does not from 6.0: Emitter::emit() logs Emitter send message #<id> to driver <class>. 5.x wrote Dispatcher send message …, so update log searches and alerts that match the old text. Only the deprecated Dispatcher::emit() keeps it.