简体   繁体   English

如何在Zend Expressive中将PHP错误记录到PHP的错误文件中?

[英]How to log PHP errors into PHP's error file in Zend Expressive?

Using Zend Expressive 2.0.5, I want to log PHP errors into the PHP's error log file itself, I went through https://docs.zendframework.com/zend-expressive/features/error-handling/#handling-exceptions-and-errors 使用Zend Expressive 2.0.5,我想将PHP错误记录到PHP的错误日志文件本身中,我经历了https://docs.zendframework.com/zend-expressive/features/error-handling/#handling-exceptions-和-errors

I also saw this post: Zend expressive - php error reporting . 我也看到了这篇文章: Zend expressive-php error report Which cleared a lot of things for me but still quite didn't solve the asked question. 这为我清除了很多东西,但仍然没有解决所提出的问题。

Things I did: Defined my own ErrorHandlerFactory where I attached two listeners to the Zend-stratigility's ErrorHandler 我所做的事情:定义了我自己的ErrorHandlerFactory ,在其中我将两个侦听器附加到Zend-stratigility's ErrorHandler

  1. First Listener uses Zend Log to log into my application's log file.(Just thought it would be nice to have errors in my application.log too.) First Listener使用Zend Log登录到我的应用程序的日志文件中(只是认为在我的application.log中也有错误也很好。)

  2. In the Second Listener, I want to log into PHP's error log file, so I have used error_log() method from php. 在第二侦听器中,我想登录到PHP的错误日志文件,因此我使用了php中的error_log()方法。

Questions: 问题:

  1. The error_log() is not printing the log the way a log appears when printed by php's error handler. error_log()不能像使用php的错误处理程序打印日志时那样显示日志。 What I mean: 我的意思是:

    When an error is printed by the php's error handler, it looks something like this: 当错误由php的错误处理程序打印时,它看起来像这样:

    [08-Feb-2018 08:22:51 US/Central] PHP Warning: array_push() expects at least 2 parameters, 1 given in C:\\webserver\\webroot\\myapi\\src\\App\\src\\Action\\PageAction.php on line 38 [2018年2月8日08:22:51美国/中部] PHP警告:array_push()至少需要2个参数,其中1个在C:\\ webserver \\ webroot \\ myapi \\ src \\ App \\ src \\ Action \\ PageAction.php中给出在第38行

    While when I print the log using error_log() it looks something like this: 当我使用error_log()打印日志时,它看起来像这样:

    [08-Feb-2018 09:03:49 US/Central] array_push() expects at least 2 parameters, 1 given in C:\\webserver\\webroot\\myapi\\src\\App\\src\\Action\\PageAction.php on line 38 [2018年2月8日09:03:49美国/中部] array_push()至少需要2个参数,第38行的C:\\ webserver \\ webroot \\ myapi \\ src \\ App \\ src \\ Action \\ PageAction.php中提供1个参数

    What am I missing here is the PHP's error type: PHP Warning , Is this the error code? 我在这里缺少的是PHP的错误类型: PHP警告 ,这是错误代码吗? The error code I get is an integer, how do I parse that code? 我得到的错误代码是整数,如何解析该代码? should I map the error codes with PHP errors constants which appear in the logs, for example: WARNING, NOTICE, etc , I can even do that, but the problem is: I got the same error code of 0 both the times when php's error handler printed a WARNING and a Fatal error logs. 我应该将错误代码与出现在日志中的PHP错误常量进行映射,例如: WARNING,NOTICE等 ,但我什至可以这样做,但是问题是:当php错误时,我两次都得到了相同的错误代码0处理程序打印警告和致命错误日志。

  2. Is it right to log errors in PHP's error log file like this? 这样在PHP的错误日志文件中记录错误是否正确? Should I do the job of PHP's error handler? 我应该做PHP的错误处理程序吗? The error handler could be doing a lot of things, for example: Logging the error message for few errors but for another also logging the stack trace. 错误处理程序可能会做很多事情,例如:记录错误消息中的几个错误,但记录另一个错误也记录堆栈跟踪。 If this is not right, then how else can I send the error to the PHP's error_handler? 如果这不正确,那么我该如何将错误发送给PHP的error_handler?

    From my understanding: 据我了解:

    My own Error Handler prevents users to look for exceptions and stack traces but rather returns a generic message. 我自己的错误处理程序可防止用户查找异常和堆栈跟踪,而是返回通用消息。 This also means that the Error Handler consumes the error and doesn't throw it further outside, ie will not throw it to the PHP's error handler. 这也意味着错误处理程序会使用该错误,并且不会将其进一步抛出外部,即不会将其抛出给PHP的错误处理程序。

Answering question 1: 回答问题1:

I am able to almost simulate the way PHP error handler logs PHP errors. 我几乎可以模拟PHP错误处理程序记录PHP错误的方式。 Things I did: 我所做的事情:

  1. Went through the docs and this SO question. 通过了文档这个 SO问题。 Using these I was able to attach listeners to Zend-stratigility's ErrorHandler 使用这些,我能够将侦听器附加到Zend-stratigility的ErrorHandler
  2. Went through PHP's Error Constants and set_error_handler() , which gave me some ideas on how to find out which type of Error or Exception occured. 通过PHP的Error Constantsset_error_handler()进行了介绍 ,这为我提供了有关如何找出发生哪种类型的Error或Exception的想法。

Below is the code for my ErrorHandlerFactory where I attach the listeners. 以下是我在其中附加侦听器的ErrorHandlerFactory的代码。

<?php
// TODO: PHP 7.0.8 is giving strict erros eben if this directive is not enabled. And that too, it should be enabled per file from my understanding.
//declare(strict_types = 1);
namespace App\Factories;
use Interop\Container\ContainerInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Zend\Log\Logger as ZendLogger;
use Throwable;
use Zend\Diactoros\Response;
use Zend\Expressive\Middleware\ErrorResponseGenerator;
use Zend\Stratigility\Middleware\ErrorHandler;
class ErrorHandlerFactory
{
    /**
     * @param ContainerInterface $container
     * @return ErrorHandler
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function __invoke(ContainerInterface $container)
    {
        $generator = $container->has(ErrorResponseGenerator::class)
            ? $container->get(ErrorResponseGenerator::class)
            : null;
        $errorHandler = new ErrorHandler(new Response(), $generator);

         // attaching a listener for logging into application's log file.
        if ($container->has(ZendLogger::class)) {
            /** @var ZendLogger $logger */
            $logger = $container->get(ZendLogger::class);
            $errorHandler->attachListener(function (
                Throwable $throwable,
                RequestInterface $request,
                ResponseInterface $response
            ) use ($logger) {
                $logger->err(NULL, [
                    'method'  => $request->getMethod(),
                    'uri'     => (string) $request->getUri(),
                    'message' => $throwable->getMessage(),
                    'file'    => $throwable->getFile(),
                    'line'    => $throwable->getLine(),
                ]);
            });
        }

        // Attaching second listener for logging the errors into the PHP's error log
        $errorHandler->attachListener(function (
            Throwable $throwable,
            RequestInterface $request,
            ResponseInterface $response
        ) {
            // Default Error type, when PHP Error occurs.
            $errorType = sprintf("Fatal error: Uncaught %s", get_class($throwable));
            if (get_class($throwable) === "ErrorException") {

                // this is an Exception
                /** @noinspection PhpUndefinedMethodInspection */
                $severity = $throwable->getSeverity();
                switch($severity) {
                    case E_ERROR:
                    case E_USER_ERROR:
                        $errorType = 'Fatal error';
                        break;
                    case E_USER_WARNING:
                    case E_WARNING:
                        $errorType = 'Warning';
                        break;
                    case E_USER_NOTICE:
                    case E_NOTICE:
                    case E_STRICT:
                        $errorType = 'Notice';
                        break;
                    case E_RECOVERABLE_ERROR:
                        $errorType = 'Catchable fatal error';
                        break;
                    case E_USER_DEPRECATED:
                    case E_DEPRECATED:
                        $errorType = "Deprecated";
                        break;
                    default:
                        $errorType = 'Unknown error';
                }

                error_log(sprintf("PHP %s: %s in %s on line %d", $errorType, $throwable->getMessage(), $throwable->getFile(), $throwable->getLine()), 0);
            }
            else {
                // this is an Error.
                error_log(sprintf("PHP %s: %s in %s on line %d \nStack trace:\n%s", $errorType, $throwable->getMessage(), $throwable->getFile(), $throwable->getLine(), $throwable->getTraceAsString()), 0);
            }
        });

        return $errorHandler;
    }
}

Apart from this, this Factory needs to be added to the dependencies. 除此之外,还需要将此工厂添加到依赖项中。 In the file: dependencies.global.php , in the factories array: factories数组中的文件: dependencies.global.php中:

Replace 更换

Zend\\Stratigility\\Middleware\\ErrorHandler::class => Container\\ErrorHandlerFactory::class,

with

Zend\Stratigility\Middleware\ErrorHandler::class => \App\Factories\ErrorHandlerFactory::class

And this should almost simulate the logging behaviour how php error handler does. 并且这几乎可以模拟php错误处理程序的日志记录行为。

Answering Question 2: 回答问题2:

I think it is fine to do this since PHP by itself provides set_error_handler() and anyway we have to handle the errors by ourselves and not pass it to the PHP's error handler. 我认为这样做很好,因为PHP本身提供了set_error_handler()而且无论如何我们都必须自己处理错误,而不是将其传递给PHP的错误处理程序。 If our ErrorHandler(listener) can replicate the messages and log into the PHP's error log using error_log() , then it is fine. 如果我们的ErrorHandler(listener)可以复制消息并使用error_log()登录到PHP的错误日志中,那么就可以了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM