Error tracing and debugging in php

Универсальное решение

Для этого сделаем класс exceptionHandlerClass. В exceptionHandlerClass будут храниться настройки и статические методы — обработчики error, exception и assertion. Еще нам нужны методы setupHandlers и restoreHandlers. Первый метод настроит перехват ошибок. Error и assertion обработчики будут бросать ErrorException. Exception обработчик будет обрабатывать необработанные Exception и в зависимости от настроек выводить соответствующий ответ. restoreHandlers вернет все обработчики в изначальное состояние — это поможет при встраивании класса в код с существующим механизмом обработки ошибок. Подключение выглядит так:

  1. require ‘exceptionHandler/exceptionHandlerClass.php’ ;
  2. exceptionHandlerClass :: setupHandlers ( ) ;

Форматы вывода

Проще объяснить на примере: для вывода trace на веб странице я оберну его в таги pre и применю htmlspecialchars(), с другой стороны этот же trace при выводе в консоль будет не удобно читать, было бы проще, если бы это был plainText. Если нужно вывести ошибку как ответ SоapServer, то это должен быть правильно сформированный XML документ (SoapFault). Если скрипт выводит бинарные данные, например изображение, то удобней выводить ошибки через WildFire. Во всех этих ситуация нужно просто применить разные форматы вывода.
Для разных форматов будем создавать разные классы. Я для начала реализую два формата вывода exceptionHandlerOutputWeb(для веба) и exceptionHandlerOutputCli(для командной строки). Так же нам понадобиться класс фабрика (exceptionHandlerOutputFactory), в котором будет инкапсулирована логика, когда какой формат вывода применить.

  1. public function getExceptionHandlerOutput ( )
  2. if ( php_sapi_name ( ) == ‘cli’ )
  3. return new exceptionHandlerOutputCli ( ) ;
  4. >
  5. return new exceptionHandlerOutputWeb ( ) ;
  6. >

При вызове setupHandlers можно установить формат вывода, передав экземпляр класса exceptionHandlerOutput* или exceptionHandlerOutputFactory*.

Благодаря такой архитектуре можно легко расширять форматы. Для создания нового формата достаточно создать класс, который будет наследоваться от абстрактного класса exceptionHandlerOutput и реализовать один метод (output).

  1. class exceptionHandlerOutputAjax extends exceptionHandlerOutput
  2. public function output ( $exception , $debug )
  3. header ( ‘HTTP/1.0 500 Internal Server Error’ , true , 500 ) ;
  4. header ( ‘Status: 500 Internal Server Error’ , true , 500 ) ;
  5. $response = array (
  6. ‘error’ => true ,
  7. ‘message’ => » ,
  8. ) ;
  9. if ( $debug )
  10. $response [ ‘message’ ] = $exception -> getMessage ( ) ;
  11. > else
  12. $response [ ‘message’ ] = self :: $productionMessage ;
  13. >
  14. exit ( json_encode ( $response ) ) ;
  15. >
  16. >

Если нужна более сложная логика для автоматического выбора формата вывода, нужно создать класс, наследуемый от exceptionHandlerOutputFactory и реализовать метод getExceptionHandlerOutput.

  1. class exceptionHandlerOutputAjaxFactory extends exceptionHandlerOutputDefaultFactory
  2. public function getExceptionHandlerOutput ( )
  3. if ( self :: detect ( ) )
  4. return new exceptionHandlerOutputAjax ( ) ;
  5. >
  6. parent :: getExceptionHandlerOutput ( ) ;
  7. >
  8. public static function detect ( )
  9. return ( ! empty ( $_SERVER [ ‘HTTP_X_REQUESTED_WITH’ ] )
  10. && strtolower ( $_SERVER [ ‘HTTP_X_REQUESTED_WITH’ ] ) == ‘xmlhttprequest’ ) ;
  11. >
  12. >
  13. exceptionHandlerClass :: setupHandlers ( new exceptionHandlerOutputAjaxFactory ( ) ) ;

Логирование

Как я и сказал выше логирование можно включать по желанию. Для этого в exceptionHandlerClass создан метод exceptionLog

  1. public static function exceptionLog ( $exception , $logPriority = null )
  2. if ( ! is_null ( self :: $exceptionHandlerLog ) )
  3. self :: $exceptionHandlerLog -> log ( $exception , $logPriority ) ;
  4. >
  5. >

Класс для логирования должен наследоваться от абстрактного exceptionHandlerLog и реализовывать метод log

  1. class exceptionHandlerSimpleLog extends exceptionHandlerLog
  2. public function log ( $exception , $logType )
  3. switch ( $logType )
  4. case self :: uncaughtException :
  5. error_log ( $exception -> getMessage ( ) ) ;
  6. break ;
  7. >
  8. >
  9. >
  1. const uncaughtException = 0 ; //необработанные исключения
  2. const caughtException = 1 ; //вызов метода логирования вне обработчиков ошибок
  3. const ignoredError = 2 ; //ошибки маскированные @, логируются если выключена опция scream
  4. const lowPriorityError = 3 ; //ошибки которые не превращаются exception
  5. const assertion = 4 ; //assertion

Имея logType и exception разработчик может сам решить какие искллючения и как логировать. Например, uncaughtException можно высылать по почте, ignoredError с severity E_ERROR логировать в файл итп.

Trace

При выводе trace я хочу видеть тип исключения, сообщение и собственно сам trace. В trace для каждого вызова должно выводится, какая функция вызвалась, список «кратких» параметров, файл и строка где произошел вызов. Что такое «краткие» параметры объясню на примерах: если функцию вызвали со строкой длиной в 1000 символов, то наличие этой строки в trace ничем не поможет при решении проблемы, а только затруднит чтение trace, это же касается массивов с большой вложенностью. Вывод trace на экран просто должен подсказать, где искать. Чтобы разобраться, что именно происходит нужно дебажить с помощью xdebug или примитивных var_dump() и die(), кому как больше нравится.
Пример trace:

[ErrorException]: E_WARNING - mysql_connect(): Can't connect to MySQL server on 'localhost' (10061) #0: mysql_connect() D:\projects1\d\index.php:19 #1: testClass::test1("длиная строка…eeeeeery long string"(56)) D:\projects1\d\index.php:22 #2: testClass->test2(testClass(), -∞, i:iTest, c:testClass, fa:testClass::test2) D:\projects1\d\index.php:27 #3: testAll(r:stream, fs:testClass::test1) D:\projects1\d\index.php:30
  • r: — resource
  • fs: — function (callable string)
  • fa: — function (callable array)
  • i: — interface (string)
  • c: — class (string)
  • ∞/INF — infinity
  • testClass() — object of type testClass
  • «»(n) — string, в скобках указана длина, … — место где вырезана часть строки
  • array(n) — array, в скобках указана длина

И самое полезное… ссылки на открытие файлов в IDE прямо из trace.

NetBeans Console

При нажатии на ссылку в IDE откроется соответствующий файл на соответствующей строке.
Для консольного режима (консоль NetBeans):

Можно реализовать для NetbBeans (или другого IDE). Для этого нужно: зарегистрировать протокол; сделать обработчик этого протокола (самое простое — bat файл). В обработчике через командную строку вызвать NetBeans с соответствующим файлом и строкой. Но это тема для следующей статьи.
Код писался за два дня так, что возможны мелкие недочеты. Скачать (не было времени, чтобы выложить в репозиторий).

UPD: перенесено в блог PHP
UPD2: в продолжение темы работа с исключениями в PHP

Источник

How to Debug PHP Errors

How to Debug PHP Errors

How to Debug PHP Errors

Debugging PHP errors in a production environment can be one of the single most frustrating experiences as a developer. More often than not, the error reports are vague, and identifying the underlying causes can be difficult at best. That said, there are a few common steps that can be followed towards identifying and resolving errors that crop up in production.

Debugging PHP Errors

Step 1: Increase the log level

More information is always better. Using the methods described in Where are PHP Errors Logged?, the first step towards diagnosing any issue is to increase the log level. This allows you to see everything that is happening before and after a problem occurs. There is a good chance that the problems you are experiencing have warnings or messages associated with them that don’t necessarily make it into the log files by default.

Step 2: Retain logs

Once you’ve increased the log level, the next step is to start retaining logs. This can be done through any number of log aggregation platforms, and allows you to start establishing a timeline of events without worrying about the log files being rolled over.

Step 3: Attempt to replicate circumstances

Once you’ve determined the log lines that relate to the problem at hand, the next step is to attempt to replicate the circumstances of the error in a development environment. Before we can do this, we first need to establish some testing guidelines. This involves doing things like mimicking the production database, the user accounts involved, and even the operating system. Everything is fair game here.

Step 4: Test assumptions

Once you’ve established the circumstances that you think might throw the exception or error you are hunting down, it’s time to test them. Never test exceptions in production. Development and staging environments are designed to be breakable without any impact on the end-users, so always always always try to break your code in a safe environment.

Step 5: Adjust test parameters and try again

If you were unable to replicate the problem in Step 4, then it’s back to the drawing board. Not every error is easy to reproduce, and may have time-based constraints or something else making it difficult to replicate in a non-production environment. Jump back to Step 3, adjust your test parameters, and try it all over again.

What is a stack trace?

Whenever exceptions are thrown, a stack trace is usually included. But, what is a stack trace? In essence, it is a rundown of every file and function that is called leading up to the error. To be clear, a stack trace doesn’t include the files and functions that are touched before the error occurred, only the chain of methods that are called as the error happened. This allows you to «trace» the «stack» of operations that are performed when an error happened in order to identify exactly what went wrong, and where.

As an example, let’s take a look at the stack trace that is returned from the following (incredibly simplistic) code:

do_the_thing(); function do_the_thing()

When do_the_thing() is executed, an exception is immediately thrown. This results in the following stack trace:

Fatal error: Uncaught Exception: a thing happened! in test.php:6 Stack trace: #0 test.php(3): do_the_thing() #1 thrown in test.php on line 6

As you can see, rather than simply returning the exception message, reading the stack trace in reverse order shows that the exception was thrown on line 6, but was triggered by a call to do_the_thing() on line 3. For more complicated stack traces, this can be invaluable as it gives us a lot of post-mortem information.

A brief introduction to Xdebug

While debugging in development can be difficult to do, Xdebug is a popular tool to help identify exactly what is happening as a piece of code executes. Containing a single-step debugger that allows you to interact directly with running PHP scripts, Xdebug is an excellent way to deal with highly complex and nuanced issues without having to resort to dangerous var_dump() and exit calls.

Example var_dump/exit call

Example var_dump/exit call

IDE integrations

While Xdebug is an incredibly powerful tool that can be used for more than just stepping through code, one of the more impressive aspects of it is the numerous IDE integrations that exist. These integrations give you the ability to diagnose problems with your code from directly within your editor, allowing you to test and fix problems in the environment you are most comfortable with.

Visual Studio Code XDebug Integration

Visual Studio Code XDebug Integration

Identifying patterns using Rollbar

Too often, debugging errors in a PHP application comes down to the amount of information you can eke out of your logs. Rollbar offers a better way because it empowers you to not only identify what is happening, but when, where, to whom, and how often. Rather than having to sort through pages of raw text logs, Rollbar aggregates data from individual exceptions and errors and creates a dashboard with as much information as possible for analyzing these issues.

Rollbar dashboard

When properly configured, these exceptions can be tied directly to user accounts, and tracked over time across an easy-to-read graph—with deployment markers to boot. While this doesn’t necessarily tell you exactly what an issue is, it comes as close as possible to doing so by providing you with more information than you could possibly ask for.

Occurrences

Occurrences

Whenever an exception is thrown during the course of an HTTP request, the request details are tracked alongside any additional information—such as the browser and operating system. This gives you the ability to identify any potential issues that could be related to specific systems, or even track down offending request parameters.

Suspected Deploy

Suspected deploy

If you are tracking deployments within Rollbar, then identifying which deployment might have been responsible for a new error or exception is as straightforward as possible—so straightforward, in fact, that Rollbar does the work for you.

Source Control Integration

Source control integration

When a Rollbar project is linked to a repository in GitHub, Bitbucket, or GitLab, any file references in a stack trace are automatically linked directly out to the offending file in the linked repository.

Источник

Читайте также:  Turtle python fill in
Оцените статью