Logger
You want to know what's happening "under the hood" of your application? ZAPHYR provides a robust PSR-3 logging service.
Installation
To get started, install the logger repository via the Composer package manager:
composer require zaphyr-org/logger
Configuration
There are basically two ways to start logging. Once by directly calling a Zaphyr\Logger\Logger
instance and by using a
Zaphyr\Logger\LogManager
instance. We will take a closer look at both options.
Configuring a Logger instance
A Zaphyr\Logger\Logger
instance does not require much configuration effort. You just need to create a logger instance,
set a name (e.g. app
) for the logger and define at least one log handler (e.g. FileHandler
).
You can read more about the available log handlers here.
$logger = new Zaphyr\Logger\Logger('app', [
new Zaphyr\Logger\Handlers\FileHandler('/path/to/log/file.log')
]);
$logger->debug('This is a debug message');
Configuring a LogManager instance
If you want to use multiple logger instances in your application, it is recommended to use the Zaphyr\Logger\LogManager
.
Via the LogManager multiple logger instances can be configured, and you can decide later which log stack to use.
For example, you can create different log stacks for your development application and your production application.
First we pass a default stack to the LogManager. In our example this is the development
stack. Whenever we make a log
entry via the LogManager and do not pass a logger name to the logger()
method, the default stack is used.
Next, we define the desired logger stacks and specify which log handlers each stack should use. In our example we have a
development
stack and a production
stack:
$logManager = new Zaphyr\Logger\LogManager(
'development',
[
'development' => [
new Zaphyr\Logger\Handlers\FileHandler('/path/to/log/file.log'),
],
'production' => [
new Zaphyr\Logger\Handlers\RotateHandler(
'/path/to/log/directory',
Zaphyr\Logger\Handlers\RotateHandler::INTERVAL_DAY
),
],
]
);
$logManager->logger()->debug('This is a debug message'); // Uses the default "development" logger stack
$logManager->logger('production')->debug('This is a debug message'); // Uses the defined "production" logger stack
Logging
The logging service, offers all the log levels defined in the RFC 5424 specification. In descending order of severity, these log levels are:
Level | Description |
---|---|
$logger->emergency() |
System is unusable |
$logger->alert() |
Action must be taken immediately |
$logger->critical() |
Critical conditions |
$logger->error() |
Error conditions |
$logger->warning() |
Warning conditions |
$logger->notice() |
Normal but significant condition |
$logger->info() |
Informational messages |
$logger->debug() |
Debug-level messages |
Additional context data
You can also pass an array as context data to log methods. This is meant to hold extra information that does not fit well in a string:
$logger->info('User {username} created', ['username' => 'John Doe']);
Exception data
It is also possible to pass Exception
instances to the log message. Just create a context array with exception
as key and the corresponding Exception instance as value:
$exception = new Exception('Something went wrong');
$logger->alert('Something went wrong', ['exception' => $exception]);
In the log message there is now also a detailed representation of the passed Exception.
Handlers
The logging service comes with a handful of log handlers. They decide how log messages reach you or the responsible project owner. If the default handlers are not enough, you can simply create a custom handler.
FileHandler
The Zaphyr\Logger\Handlers\FileHandler
is the simplest of all handlers. This handler simply writes log messages to the
log file passed in the constructor. A new log entry is written at the end of the file:
$fileHandler = new Zaphyr\Logger\Handlers\FileHandler('/path/to/log/file.log');
If the log file specified in the constructor does not exist, the Zaphyr\Logger\Handlers\FileHandler
instance creates
it on its own.
The FileHandler
stores log messages in a single file. So this handler should either be used in small projects
or it should be ensured that the log file is deleted or overwritten at regular intervals.
Otherwise, this log file can reach a considerable size and may overload the available storage space of your server!
MailHandler
The MailHandler
does exactly what the name says – sending log messages as emails. This handler uses the
symfony\mail
package to send messages. You can read more about the symfony mailer package
here.
So you first create the email configuration and then inject it to your Zaphyr\Logger\Handlers\MailHandler
instance:
$transport = Symfony\Component\Mailer\Transport::fromDsn('smtp://localhost');
$mailer = new Symfony\Component\Mailer\Mailer($transport);
$email = (new Symfony\Component\Mime\Email())
->from('noreply@example.com')
->to('admin@example.com')
->subject('Log message received');
$mailHandler = new Zaphyr\Logger\Handlers\MailHandler($mailer, $email);
Now you will get all log messages sent to the email address specified in your email configuration.
RotateHandler
The Zaphyr\Logger\Handlers\RotateHandler
is also a log file handler. However, an interval can be set for this handler,
at which intervals a new log file should be created. By default, this handler creates a new log file for each day.
Simply inject the path to the folder in which the log files should be saved and enter the desired interval:
$rotateHandler = new Zaphyr\Logger\Handlers\RotateHandler('/path/to/log/directory', Zaphyr\Logger\Handlers\RotateHandler::INTERVAL_DAY);
Intervals
The following intervals can be used to create log files:
Interval | Description |
---|---|
Zaphyr\Logger\Handlers\RotateHandler::INTERVAL_HOUR |
Creates a new log file every hour |
Zaphyr\Logger\Handlers\RotateHandler::INTERVAL_DAY |
Creates a new log file every day |
Zaphyr\Logger\Handlers\RotateHandler::INTERVAL_WEEK |
Creates a new log file every week |
Zaphyr\Logger\Handlers\RotateHandler::INTERVAL_MONTH |
Creates a new log file every month |
Zaphyr\Logger\Handlers\RotateHandler::INTERVAL_YEAR |
Creates a new log file every year |
NoopHandler
Available since v2.1.0
The Zaphyr\Logger\Handlers\NoopHandler
is a special handler that does nothing. It is useful for testing purposes or
if you want to disable logging in certain environments:
$noopHandler = new Zaphyr\Logger\Handlers\NoopHandler();
Usage of multiple handlers
As you may have seen in the previous examples, multiple log handlers can be triggered simultaneously as soon as a log message is registered.
For example, if you not only want to store a log message in a file, but also send it as an email to a responsible administrator, you can do this as follows:
$transport = Symfony\Component\Mailer\Transport::fromDsn('smtp://localhost');
$mailer = new Symfony\Component\Mailer\Mailer($transport);
$email = (new Symfony\Component\Mime\Email())
->from('noreply@example.com')
->to('admin@example.com')
->subject('Log message received');
$handlers = [
new Zaphyr\Logger\Handlers\FileHandler('/path/to/log/file.log'),
new Zaphyr\Logger\Handlers\MailHandler($mailer, $email),
];
$logger = new Zaphyr\Logger\Logger('production', $handlers);
The handler stack is then processed from top to bottom. In the above example, the log message is first written to the log file and then sent as an e-mail.
Create a custom handler
It is also possible to create a custom log handler. To do this, you first create your own handler class which
implements the Zaphyr\Logger\Contracts\HandlerInterface
:
class MyCustomHandler implements Zaphyr\Logger\Contracts\HandlerInterface
{
/**
* {@inheritdoc}
*/
public function add(string $name, string $level, string $message, array $context = []): void
{
// your custom handler logic
}
}
Now you can pass your previously created handler instance to a logger instance and use the logger as already described:
$handlers = [
new MyCustomHandler(),
];
$logger = new Zaphyr\Logger\Logger('development', $handlers);
Formatters
Formatters, as the name suggests, determine the format in which log messages are written to the log files.
All log handlers provided by the logging service use the Zaphyr\Logger\Formatters\LineFormatter
by default.
The LineFormatter
creates a log message in the following format:
[{date}] {name}.{level}: {message} [{context}] [{exception}]
// [2022-09-13 09:41:00] production.ALERT: Something went wrong! [] []
Available formatters
The logging service comes with a handful of useful log formats:
Formatters | Description |
---|---|
Zaphyr\Logger\Formatters\LineFormatter |
Creates single log line messages in the format shown above. This is the default formatter |
Zaphyr\Logger\Formatters\HtmlFormatter |
Creates log messages in HTML format. This formatter is useful e.g. if log messages are sent with the MailFormatter . |
Zaphyr\Logger\Formatters\JsonFormatter |
Creates log messages in JSON format. |
Change the formatter of a handler
If you want to use a different formatter then the default formatter for a log handler, you can pass it as the last
argument to the desired log handler instance. In the following example we exchange theZaphyr\Logger\Formatters\LogFormatter
of the Zaphyr\Logger\Handlers\MailHandler
for the Zaphyr\Logger\Handlers\HtmlFormatter
:
$transport = Symfony\Component\Mailer\Transport::fromDsn('smtp://localhost');
$mailer = new Symfony\Component\Mailer\Mailer($transport);
$email = (new Symfony\Component\Mime\Email())
->from('noreply@example.com')
->to('admin@example.com')
->subject('Log message received');
new Zaphyr\Logger\Handlers\MailHandler($mailer, $email, new Zaphyr\Logger\Formatters\HtmlFormatter());
Create a custom formatter
It could be possible that you want to save a log message in a different format. In this case you can simply create a custom formatter instance:
class MyCustomFormatter extends Zaphyr\Logger\Formatters\AbstractFormatter
{
/**
* {@inheritdoc}
*/
public function interpolate(string $name, string $level, string $message, array $context = []): string
{
// Your custom formatter logic
}
}
A good starting point for creating your custom formatter is to take a look at the LineFormatter.
Add your custom formatter to a handler instance
After you have created your custom formatter, simply pass it to your handler instance:
$formatter = new MyCustomFormatter();
$handler = new Zaphyr\Logger\Handlers\FileHandler('/path/to/file.log', $formatter);
Now your log messages will be written in your custom format.