Skip to content

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.

php
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).

WhereLevelMessage
Emitter::emitinfoEmitter send message #<id> to driver <class>
Dispatcher::emit (deprecated)infoDispatcher send message #<id> with priority <n> to driver <class>
Dispatcher::handleinfoStart handle message #<id> (<type>) priority:<n>
Dispatcher after a handler returnsinfoEnd handle message #<id> (<type>)
Dispatcher when a handler throwserrorHandler <class> throws exception - <exception message>
Dispatcher after SIGTERM / SIGINT (ext-pcntl)noticeExiting hermes dispatcher - received SIGTERM (or SIGINT)
Dispatcher on ShutdownExceptionnoticeExiting hermes dispatcher - shutdown
Dispatcher when the driver throws, before rethrowingerrorExiting 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').

php
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 Exception that escapes Driver::wait(), except ShutdownException; 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.

Released under the MIT License.