I would like to create a custom HandlerWrapper to use it with Monolog in my Symfony 2.8 project.
The goal is to use this CustomHandler as a filter that decides wether the wrapped/nested handler is called or not.
==============
UPDATE: The following question is already solved thanks to the answer of @Yonel. However this brought ab a new problem described below.
Extending Monolog\Handler\HandlerWrapper is no problem of course. But I am struggling to us the custom class in the Monolog config within config_prod.yml:
namespace AppBundle\Log;
use Monolog\Handler\HandlerWrapper;
class CustomHandler extends HandlerWrapper {
public function handle(array $record) {
// some custom handling/processing...
if ($this->doSomeCheck())
return $this->handler->handle($record);
else
return false; // Do not call nested handler
}
}
Config:
services:
monolog.custom_handler.service:
class: AppBundle\Log\CustomHandler
monolog:
main:
type: service
id: monolog.custom_handler.service
level: error
handler: someHandler
someHandler:
...
Problem: When running app/console cache:warmup on this config, I get the following error:
[Symfony\Component\Debug\Exception\ContextErrorException]
Catchable Fatal Error: Argument 1 passed to Monolog\Handler\GroupHandler::__construct() must be of the type array, none given
Well, I think the source of the problem is obvious: The service definition of monolog.custom_handler.service does not pass any argument to the class. But how can I pass someHandler as argument, as defined in the Monolog config?
==============
EDIT: New Problem
As Yonel describes in his answer, on can use the following config to pass someHandler to custom_handler:
services:
monolog.custom_handler.service:
class: AppBundle\Log\CustomHandler
arguments:
- '@monolog.handler.testHandler'
monolog.test_handler.service:
class: AppBundle\Log\TestHandler
monolog:
# Skip level checking (can be solved by adding a FingersCrossed handler)
main:
type: service
id: monolog.custom_handler.service
testHandler:
type: service
id: monolog.test_handler.service
nested: true
This works: TestHandler is now correctly passed to CustomHandler
However the goal was to let CustomHandler decide, wether TestHandler is called or not. This does not work with this config: TestHandler is called anyway (I assume directly by Monolog, as any other handler). It does not make any difference if TestHandler is passed to CustomHandler, marked as nested or not.
I implemented CustomHandler as HandlerWrapper and TestHandler as AbstractHandler. Both classes directly to a log file (not using Monolog) when their handle method is called. This way I can check if the handlers work as expected (TestHandler should only be called if CustomHandler allows it). This is not the case.
No matter if TestHandler is passed to CustomHandler, if it is marked as nested, if CustomHandler returns true or false in its handle method, etc., the result is always the same: TestHandler is called, no matter what CustomHandler decides.
How to solve this?
Handler implementations:
namespace AppBundle\Log;
use Monolog\Handler\HandlerWrapper;
class CustomHandler extends HandlerWrapper {
public function handle(array $record) {
// some custom handling/processing...
if ($this->doSomeCheck()) {
$this->directlyWriteToFileNotUsingMonolog('CustomHandler: Call TestHandler');
return $this->handler->handle($record);
else {
$this->directlyWriteToFileNotUsingMonolog('CustomHandler: Do NOT call TestHandler');
return false; // Do not call nested handler
}
}
class TestHandler extends AbstractHandler {
public function handle(array $record) {
$this->directlyWriteToFileNotUsingMonolog('TestHandler');
return false;
}
}