Logger


PSR-3 Logger - 图1

Overview

Phalcon\Logger is a component providing logging services for applications. It offers logging to different back-ends using different adapters. It also offers transaction logging, configuration options and different logging formats. You can use the Phalcon\Logger for any logging need your application has, from debugging processes to tracing application flow.

PSR-3 Logger - 图2

The Phalcon\Logger has been rewritten to comply with PSR-3. This allows you to use the Phalcon\Logger to any application that utilizes a PSR-3 logger, not just Phalcon based ones.

In v3, the logger was incorporating the adapter in the same component. So in essence when creating a logger object, the developer was creating an adapter (file, stream etc.) with logger functionality.

For v4, we rewrote the component to implement only the logging functionality and to accept one or more adapters that would be responsible for doing the work of logging. This immediately offers compatibility with PSR-3 and separates the responsibilities of the component. It also offers an easy way to attach more than one adapter to the logging component so that logging to multiple adapters can be achieved. By using this implementation we have reduced the code necessary for this component and removed the old Logger\Multiple component.

Adapters

This component makes use of adapters to store the logged messages. The use of adapters allows for a common logging interface which provides the ability to easily switch back-ends, or use multiple adapters if necessary. The adapters supported are:

AdapterDescription
Phalcon\Logger\Adapter\NoopBlackhole adapter (used for testing mostly)
Phalcon\Logger\Adapter\StreamLogs messages on a file stream
Phalcon\Logger\Adapter\SyslogLogs messages to the Syslog

Stream

This adapter is used when we want to log messages to a particular file stream. This adapter combines the v3 Stream and File ones. Usually this is the most used one: logging to a file in the file system.

Syslog

This adapter sends messages to the system log. The syslog behavior may vary from one operating system to another.

Noop

This is a black hole adapter. It sends messages to infinity and beyond! This adapter is used mostly for testing or if you want to joke with a colleague.

Factory

You can use the Phalcon\Logger\LoggerFactory component to create a logger. For the Phalcon\Logger\LoggerFactory to work, it needs to be instantiated with an Phalcon\Logger\AdapterFactory:

  1. <?php
  2. use Phalcon\Logger\LoggerFactory;
  3. use Phalcon\Logger\AdapterFactory;
  4. $adapterFactory = new AdapterFactory();
  5. $loggerFactory = new LoggerFactory($adapterFactory);

load()

Phalcon\Logger\LoggerFactory offers the load method, that constructs a logger based on supplied configuration. The configuration can be an array or a Phalcon\Config object.

Use Case: Create a Logger with two Stream adapters. One adapter will be called main for logging all messages, while the second one will be called admin, logging only messages generated in the admin area of our application

  1. <?php
  2. use Phalcon\Logger\AdapterFactory;
  3. use Phalcon\Logger\LoggerFactory;
  4. $config = [
  5. "name" => "prod-logger",
  6. "adapters" => [
  7. "main" => [
  8. "adapter" => "stream",
  9. "file" => "/storage/logs/main.log",
  10. "options" => []
  11. ],
  12. "admin" => [
  13. "adapter" => "stream",
  14. "file" => "/storage/logs/admin.log",
  15. "options" => []
  16. ],
  17. ],
  18. ];
  19. $adapterFactory = new AdapterFactory();
  20. $loggerFactory = new LoggerFactory($adapterFactory);
  21. $logger = $loggerFactory->load($config);

newInstance()

The Phalcon\Logger\LoggerFactory also offers the newInstance() method, that constructs a logger based on the supplied name and array of relevant adapters. Using the use case above:

  1. <?php
  2. use Phalcon\Logger\Adapter\Stream;
  3. use Phalcon\Logger\AdapterFactory;
  4. use Phalcon\Logger\LoggerFactory;
  5. $adapters = [
  6. "main" => new Stream("/storage/logs/main.log"),
  7. "admin" => new Stream("/storage/logs/admin.log"),
  8. ];
  9. $adapterFactory = new AdapterFactory();
  10. $loggerFactory = new LoggerFactory($adapterFactory);
  11. $logger = $loggerFactory->newInstance('prod-logger', $adapters);

Creating a logger

Creating a logger is a multi step process. First you create the logger object and then you attach an adapter to it. After that you can start logging messages according to the needs of your application.

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. $adapter = new Stream('/storage/logs/main.log');
  5. $logger = new Logger(
  6. 'messages',
  7. [
  8. 'main' => $adapter,
  9. ]
  10. );
  11. $logger->error('Something went wrong');

The above example creates a Stream adapter. We then create a logger object and attach this adapter to it. Each adapter attached to a logger needs to have a unique name, for the logger to be able to know where to log the messages. When calling the error() method on the logger object, the message is going to be stored in the /storage/logs/main.log.

Since the logger component implements PSR-3, the following methods are available:

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. $adapter = new Stream('/storage/logs/main.log');
  5. $logger = new Logger(
  6. 'messages',
  7. [
  8. 'main' => $adapter,
  9. ]
  10. );
  11. $logger->alert("This is an alert message");
  12. $logger->critical("This is a critical message");
  13. $logger->debug("This is a debug message");
  14. $logger->error("This is an error message");
  15. $logger->emergency("This is an emergency message");
  16. $logger->info("This is an info message");
  17. $logger->log(Logger::CRITICAL, "This is a log message");
  18. $logger->notice("This is a notice message");
  19. $logger->warning("This is a warning message");

The log generated is as follows:

  1. [Tue, 25 Dec 18 12:13:14 -0400][ALERT] This is an alert message
  2. [Tue, 25 Dec 18 12:13:14 -0400][CRITICAL] This is a critical message
  3. [Tue, 25 Dec 18 12:13:14 -0400][DEBUG] This is a debug message
  4. [Tue, 25 Dec 18 12:13:14 -0400][ERROR] This is an error message
  5. [Tue, 25 Dec 18 12:13:14 -0400][EMERGENCY] This is an emergency message
  6. [Tue, 25 Dec 18 12:13:14 -0400][INFO] This is an info message
  7. [Tue, 25 Dec 18 12:13:14 -0400][CRITICAL] This is a log message
  8. [Tue, 25 Dec 18 12:13:14 -0400][NOTICE] This is a notice message
  9. [Tue, 25 Dec 18 12:13:14 -0400][WARNING] This is warning message

Multiple Adapters

Phalcon\Logger can send messages to multiple adapters with a just single call:

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. $adapter1 = new Stream('/logs/first-log.log');
  5. $adapter2 = new Stream('/remote/second-log.log');
  6. $adapter3 = new Stream('/manager/third-log.log');
  7. $logger = new Logger(
  8. 'messages',
  9. [
  10. 'local' => $adapter1,
  11. 'remote' => $adapter2,
  12. 'manager' => $adapter3,
  13. ]
  14. );
  15. // Log to all adapters
  16. $logger->error('Something went wrong');

The messages are sent to the handlers in the order they were registered using the first in first out) principle.

Excluding adapters

Phalcon\Logger also offers the ability to exclude logging to one or more adapters when logging a message. This is particularly useful when in need to log a manager related message in the manager log but not in the local log without having to instantiate a new logger.

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. $adapter1 = new Stream('/logs/first-log.log');
  5. $adapter2 = new Stream('/remote/second-log.log');
  6. $adapter3 = new Stream('/manager/third-log.log');
  7. $logger = new Logger(
  8. 'messages',
  9. [
  10. 'local' => $adapter1,
  11. 'remote' => $adapter2,
  12. 'manager' => $adapter3,
  13. ]
  14. );
  15. // Log to all adapters
  16. $logger->error('Something went wrong');
  17. // Log only to remote and manager
  18. $logger
  19. ->excludeAdapters(['local'])
  20. ->info('This does not go to the "local" logger');

NOTE Internally, the component loops through the registered adapters and calls the relevant logging method one ach to achieve logging to multiple adapters. If one of them fails, the loop will break and the remaining adapters (from the loop) will not log the message. In future versions of Phalcon we will be introducing asynchronous logging to alleviate this problem.

Message Formatting

This component makes use of formatters to format messages before sending them to the backend. The formatters available are:

AdapterDescription
Phalcon\Logger\Formatter\LineFormats the message on a single line of text
Phalcon\Logger\Formatter\JsonFormats the message in a JSON string
Phalcon\Logger\Formatter\SyslogFormats the message in an array compatible with Syslog

Line Formatter

Formats the messages using a one-line string. The default logging format is:

  1. [%date%][%type%] %message%

Message Format

If the default format of the message does not fit the needs of your application you can change it using the setFormat() method. The log format variables allowed are:

VariableDescription
%message%The message itself expected to be logged
%date%Date the message was added
%type%Uppercase string with message type

The following example demonstrates how to change the message format:

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. use Phalcon\Logger\Formatter\Line;
  5. $formatter = new Line('[%type%] - [%date%] - %message%');
  6. $adapter = new Stream('/storage/logs/main.log');
  7. $adapter->setFormatter($formatter);
  8. $logger = new Logger(
  9. 'messages',
  10. [
  11. 'main' => $adapter,
  12. ]
  13. );
  14. $logger->error('Something went wrong');

which produces:

  1. [ALERT] - [Tue, 25 Dec 18 12:13:14 -0400] - Something went wrong

If you do not want to use the constructor to change the message, you can always use the setFormat() on the formatter:

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. use Phalcon\Logger\Formatter\Line;
  5. $formatter = new Line();
  6. $formatter->setFormat('[%type%] - [%date%] - %message%');
  7. $adapter = new Stream('/storage/logs/main.log');
  8. $adapter->setFormatter($formatter);
  9. $logger = new Logger(
  10. 'messages',
  11. [
  12. 'main' => $adapter,
  13. ]
  14. );
  15. $logger->error('Something went wrong');

Date Format

The default date format is:

  1. "D, d M y H:i:s O"

If the default format of the message does not fit the needs of your application you can change it using the setDateFormat() method. The method accepts a string with characters that correspond to date formats. For all available formats, please consult this page.

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. use Phalcon\Logger\Formatter\Line;
  5. $formatter = new Line();
  6. $formatter->setDateFormat('Ymd-His');
  7. $adapter = new Stream('/storage/logs/main.log');
  8. $adapter->setFormatter($formatter);
  9. $logger = new Logger(
  10. 'messages',
  11. [
  12. 'main' => $adapter,
  13. ]
  14. );
  15. $logger->error('Something went wrong');

which produces:

  1. [ERROR] - [20181225-121314] - Something went wrong

JSON Formatter

Formats the messages returning a JSON string:

  1. {
  2. "type" : "Type of the message",
  3. "message" : "The message",
  4. "timestamp" : "The date as defined in the date format"
  5. }

Date Format

The default date format is:

  1. "D, d M y H:i:s O"

If the default format of the message does not fit the needs of your application you can change it using the setDateFormat() method. The method accepts a string with characters that correspond to date formats. For all available formats, please consult this page.

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. use Phalcon\Logger\Formatter\Line;
  5. $formatter = new Line();
  6. $formatter->setDateFormat('Ymd-His');
  7. $adapter = new Stream('/storage/logs/main.log');
  8. $adapter->setFormatter($formatter);
  9. $logger = new Logger(
  10. 'messages',
  11. [
  12. 'main' => $adapter,
  13. ]
  14. );
  15. $logger->error('Something went wrong');

which produces:

  1. {
  2. "type" : "error",
  3. "message" : "Something went wrong",
  4. "timestamp" : "20181225-121314"
  5. }

Syslog Formatter

Formats the messages returning an array with the type and message as elements:

  1. [
  2. "type",
  3. "message",
  4. ]

Custom Formatter

The Phalcon\Logger\Formatter\FormatterInterface interface must be implemented in order to create your own formatter or extend the existing ones. Additionally you can reuse the Phalcon\Logger\Formatter\AbstractFormatter abstract class.

Interpolation

The logger also supports interpolation. There are times that you might need to inject additional text in your logging messages; text that is dynamically created by your application. This can be easily achieved by sending an array as the second parameter of the logging method (i.e. error, info, alert etc.). The array holds keys and values, where the key is the placeholder in the message and the value is what will be injected in the message.

The following example demonstrates interpolation by injecting in the message the parameter “framework” and “secs”.

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. $adapter = new Stream('/storage/logs/main.log');
  5. $logger = new Logger(
  6. 'messages',
  7. [
  8. 'main' => $adapter,
  9. ]
  10. );
  11. $message = '{framework} executed the "Hello World" test in {secs} second(s)';
  12. $context = [
  13. 'framework' => 'Phalcon',
  14. 'secs' => 1,
  15. ];
  16. $logger->info($message, $context);

Item

The formatter classes above accept a Phalcon\Logger\Item object. The object contains all the necessary data required for the logging process. It is used as a transport of data from the logger to the formatter.

Exception

Any exceptions thrown in the Logger component will be of type Phalcon\Logger\Exception. You can use this exception to selectively catch exceptions thrown only from this component.

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. use Phalcon\Logger\Exception;
  5. try {
  6. $adapter = new Stream('/storage/logs/main.log');
  7. $logger = new Logger(
  8. 'messages',
  9. [
  10. 'main' => $adapter,
  11. ]
  12. );
  13. // Log to all adapters
  14. $logger->error('Something went wrong');
  15. } catch (Exception $ex) {
  16. echo $ex->getMessage();
  17. }

Examples

Stream

Logging to a file:

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. $adapter = new Stream('/storage/logs/main.log');
  5. $logger = new Logger(
  6. 'messages',
  7. [
  8. 'main' => $adapter,
  9. ]
  10. );
  11. // Log to all adapters
  12. $logger->error('Something went wrong');

The stream logger writes messages to a valid registered stream in PHP. A list of streams is available here. Logging to a stream

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Stream;
  4. $adapter = new Stream('php://stderr');
  5. $logger = new Logger(
  6. 'messages',
  7. [
  8. 'main' => $adapter,
  9. ]
  10. );
  11. $logger->error('Something went wrong');

Syslog

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Syslog;
  4. // Setting ident/mode/facility
  5. $adapter = new Syslog(
  6. 'ident-name',
  7. [
  8. 'option' => LOG_NDELAY,
  9. 'facility' => LOG_MAIL,
  10. ]
  11. );
  12. $logger = new Logger(
  13. 'messages',
  14. [
  15. 'main' => $adapter,
  16. ]
  17. );
  18. $logger->error('Something went wrong');

Noop

  1. <?php
  2. use Phalcon\Logger;
  3. use Phalcon\Logger\Adapter\Noop;
  4. $adapter = new Noop('nothing');
  5. $logger = new Logger(
  6. 'messages',
  7. [
  8. 'main' => $adapter,
  9. ]
  10. );
  11. $logger->error('Something went wrong');

Custom Adapters

The Phalcon\Logger\AdapterInterface interface must be implemented in order to create your own logger adapters or extend the existing ones. You can also take advantage of the functionality in Phalcon\Logger\Adapter\AbstractAdapter abstract class.

Abstract Classes

There are two abstract classes that offer useful functionality when creating custom adapters: Phalcon\Logger\Adapter\AbstractAdapter and Phalcon\Logger\Formatter\AbstractFormatter.

Dependency Injection

You can register as many loggers as you want in the [Phalcon\Di\FactoryDefault][factorydefault] container. An example of the registration of the service as well as accessing it is below:

  1. <?php
  2. use Phalcon\Di;
  3. use Phalcon\Logger;
  4. use Phalcon\Logger\Adapter\Stream;
  5. $container = new Di();
  6. $container->set(
  7. 'logger',
  8. function () use () {
  9. $adapter = new Stream('/storage/logs/main.log');
  10. $logger = new Logger(
  11. 'messages',
  12. [
  13. 'main' => $adapter,
  14. ]
  15. );
  16. return new $logger;
  17. }
  18. );