4

In the dev env warnings are catched by the symfony ErrorHandler which is fine. In the prod env symfony ignores warnings and I only get them in the php error log. Now I want those errors also to be logged.

Degreasing the log level didn't worked since those errors arn't handled at all. So how can I log those errors in Symfony prod environment?

I'm using Symfony 2.0

Edit: Ok, I see there isn't even a error handler when not in debug mode (Kernel.php):

if ($this->debug) {
        ini_set('display_errors', 1);
        error_reporting(-1);

        DebugUniversalClassLoader::enable();
        ErrorHandler::register();
        if ('cli' !== php_sapi_name()) {
            ExceptionHandler::register();
        }
} else {
    ini_set('display_errors', 0);
}

So what's the best way to implement this without working against the framework?

3
  • Are you sure there is no logs? Did you look at files app/logs/prod.log? Commented Feb 28, 2013 at 9:55
  • 1
    Are you talking about the logging level "warning" or about warnings thrown by php? Commented Mar 1, 2013 at 10:38
  • Warnings thrown by php Commented Mar 1, 2013 at 11:14

2 Answers 2

2

You could do this by implementing custom ErrorHandler and overriding some of AppKernel methods. For example:

class AppKernel
{
    protected $prodErrorHandler;
    public function init()
    {
        if ($this->debug) {
            ini_set('display_errors', 1);
            error_reporting(-1);

            DebugUniversalClassLoader::enable();
            ErrorHandler::register();
            if ('cli' !== php_sapi_name()) {
                ExceptionHandler::register();
            }
        } else {
            ini_set('display_errors', 0);
            error_reporting(-1);
            $this->prodErrorHandler = new CustomErrorHandler();
            set_error_handler(array($this->prodErrorHandler, 'handle'));
        }
    }
    public function boot()
    {
        $booted = $this->booted;
        parent::boot();
        if (!$booted && $this->prodErrorHandler !== null && $this->container->has('logger')) {
            $this->prodErrorHandler->setLogger($this->container->get('logger'));
        }
    }
    // ... other methods
}
class CustomErrorHandler
{
    protected $logger;
    protected $buffer = array();
    public function setLogger($logger)
    {
        $this->logger = $logger;
        foreach ($this->buffer as $error) {
            $this->logger->warning($error);
        }
        $this->buffer = array();
    }
    public function handle($level, $message, $file, $line, $context)
    {
        if (error_reporting() & $level) {
            $error = new \ErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line));
            if ($this->logger !== null) {
                $this->logger->warning($error);
            } else {
                $this->buffer[] = $error;
            }
            return true;    // this would skip logging to file etc. Return false to just log and pass error handling to other handlers
        } else {
            return false;
        }
    }
}

Something similar can be done with separate Bundle too, but it can "skip" some of errors occurred before bundle is registered.

If you use Monolog 1.6 or later, you can also use Monolog\ErrorHandler to register logger for errors, unhandled exceptions and fatal errors.

Sign up to request clarification or add additional context in comments.

1 Comment

For the \Monolog\ErrorHandler solution, add the following to your AppKernel. Unfortunately due to the need to retrieve the logger from the container, this doesn't take effect until Kernel->boot(). Which means there is a large window of time during which any notices/warnings/errors that occur while initializing bundles and more will not be logged. IMO this is a huge miss with Symfony2 - proper error/exception log handlers should be initialized early on. public function boot() { parent::boot(); $logger = $this->container->get('logger'); \Monolog\ErrorHandler::register($logger); }
0

You will have to customize your environment to do this by telling the kernel to run in debug mode.

new AppKernel('prod', true);

Important, but unrelated to the topic of environments is the false key on line 8 of the front controller above. This specifies whether or not the application should run in "debug mode". Regardless of the environment, a Symfony2 application can be run with debug mode set to true or false. This affects many things in the application, such as whether or not errors should be displayed or if cache files are dynamically rebuilt on each request. Though not a requirement, debug mode is generally set to true for the dev and test environments and false for the prod environment.

http://symfony.com/doc/2.0/cookbook/configuration/environments.html

4 Comments

Yes, i know that it's enabled in trhe debug mode which is fine for development. But the main reason is to find hidden errors while zthe site is live and the php error log sometimes hasn't enough informations and i think it's better to have all logging combined.
Right. You'll have to create a custom environment called 'prod_custom' or whatever, and create an app_prod_custom.php file as your entry point with new AppKernel('prod_custom', true);. Debug HAS to be enabled in the Kernel for Symfony to handle this, if you don't want to hack the source and lose the ability to update your Symfony vendor packages.
Having the debug mode enabled isn't a option.
Then you'll need to 'hack' the Kernel and add that line. That file does not change very often, so you will probably only have to verify that everything is compatible between major versions (2.1 -> 2.2) for example. Registering the error handler this early in the script execution is necessary in order to capture all warnings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.