Sunday, January 21, 2018

Monolog: namespaced logger?

Using monolg library and monolog-cascade extension you can't configure the "namespaced" loggers. What does it mean? Imagine you have tons of classes and you need to log information from them into a log file. There is nothing special in this. Just define loggers with the needed handler(s) and instantiate them directly in a place where you want them to use with a help of monolog-cascade. It means in your monolog-cascade config file you have to define needed loggers in advance and you have to reference needed loggers by their names. But what if you need an additional logger (with absolutely different handlers/processors) for some of the classes? Will you go through all the classes and change logger names where you instantiate them? I think it doesn't look like a good idea when a small requirement (for instance, change the log file name for records from a bunch of classes) leads to edits in an application code. It's something that must be configurable and that's why I decided to write a tiny library called monolog-cascade-namespaced.

Monolog Cascade Namespaced is actually an extension of a monolog-cascade library (please take a look at this library first if you're not familiar with it). The main idea is simple - pass a full class name instead of logger name to the static method which instantiates loggers. Just do this:
CascadeNamespaced::getLogger(get_called_class())->info('...');
instead of this:
Cascade::getLogger('my_logger_name')->info('...');
In other words, you don't have to think which logger must be instantiated in this place. You will be able to configure needed logger in your config file instead of hardcoding the name here.

How does it work? First, it looks for a logger specific to your class. If there is no such logger then it looks for a logger for a namespace the class is located in. If there is no even this logger then it tries to find "root" logger - default logger for your application. And finally, if there is no even root logger defined in your config file then simple logger with null handler will be returned as a fallback behavior. Loggers specific to a class have more priority than loggers for a namespace.

Let's dive deeper and consider an example. You have next classes:

  • MyNamespace\Class1
  • MyNamespace\Class2
  • MyNamespace\SubNamespace\Class3
  • MyNamespace\SubNamespace\Class4
  • AnotherNamespace\Class5

and you want to log messages from MyNamespace\SubNamespace namespace classes into the stdout, but messages from MyNamespace\Class1 and MyNamespace\Class2 classes into two different files. It can be done with next configuration:
handlers:
    file1:
        class: Monolog\Handler\StreamHandler
        stream: log_file_1.log

    file2:
        class: Monolog\Handler\StreamHandler
        stream: log_file_2.log

    console:
        class: Monolog\Handler\StreamHandler
        stream: php://stdout

loggers:
    # Will be used for `AnotherNamespace\Class5` class as a default logger
    # because there are no specific loggers defined for this class.
    root:
        handlers: [console]

    # Will be used for all the classes from `MyNamespace\SubNamespace` namespace.
    MyNamespace\SubNamespace:
        handlers: [console]

    # Will be used for `MyNamespace\Class1` class.
    MyNamespace\Class1:
        handlers: [file1]

    # Will be used for `MyNamespace\Class2` class.
    MyNamespace\Class2:
        handlers: [file2]
If you need to change the logger for some class just define new one specific to a needed class in your config file. If you don't want to use any specific loggers then just leave root logger.

You may ask me "So, how does it differ from actually monolog-cascade"? The answer is:

  1. You don't have to define needed loggers in advance.
  2. You can define a logger for a set of classes located in a namespace.
  3. You can define a logger for a specific class.
  4. You don't have to hardcode a logger name. Just pass the full class name and configure logger in the future if needed.
Additional information on how to install, configure and use monolog-cascade-namespaced can be found here

No comments:

Post a Comment