Настройка во время выполнения
Поведение этих функций зависит от установок в php.ini.
Имя | По умолчанию | Место изменения | Список изменений |
---|---|---|---|
error_reporting | NULL | PHP_INI_ALL | |
display_errors | «1» | PHP_INI_ALL | |
display_startup_errors | «1» | PHP_INI_ALL |
До PHP 8.0.0 значение по умолчанию было "0" .
|
log_errors | «0» | PHP_INI_ALL | |
log_errors_max_len | «1024» | PHP_INI_ALL | |
ignore_repeated_errors | «0» | PHP_INI_ALL | |
ignore_repeated_source | «0» | PHP_INI_ALL | |
report_memleaks | «1» | PHP_INI_ALL | |
track_errors | «0» | PHP_INI_ALL | Объявлено устаревшим в PHP 7.2.0, удалено в PHP 8.0.0. |
html_errors | «1» | PHP_INI_ALL | |
xmlrpc_errors | «0» | PHP_INI_SYSTEM | |
xmlrpc_error_number | «0» | PHP_INI_ALL | |
docref_root | «» | PHP_INI_ALL | |
docref_ext | «» | PHP_INI_ALL | |
error_prepend_string | NULL | PHP_INI_ALL | |
error_append_string | NULL | PHP_INI_ALL | |
error_log | NULL | PHP_INI_ALL | |
error_log_mode | 0o644 | PHP_INI_ALL | Доступно, начиная с PHP 8.2.0 |
syslog.facility | «LOG_USER» | PHP_INI_SYSTEM | Доступно, начиная с PHP 7.3.0. |
syslog.filter | «no-ctrl» | PHP_INI_ALL | Доступно, начиная с PHP 7.3.0. |
syslog.ident | «php» | PHP_INI_SYSTEM | Доступно, начиная с PHP 7.3.0. |
Для подробного описания констант
PHP_INI_*, обратитесь к разделу Где могут быть установлены параметры конфигурации.
Краткое разъяснение конфигурационных
директив.
-
error_reporting
int -
Задаёт уровень протоколирования ошибки. Параметр может быть либо числом,
представляющим битовое поле, либо именованной константой.
Соответствующие уровни и константы приведены в разделе
Предопределённые константы,
а также в php.ini. Для установки настройки во время выполнения используйте функцию
error_reporting(). Смотрите также описание директивы
display_errors.Значение по умолчанию равно
E_ALL
.До PHP 8.0.0 значение по умолчанию было:
.E_ALL
&
~E_NOTICE
&
~E_STRICT
&
~E_DEPRECATED
При этой настройке не отображаются уровни ошибокE_NOTICE
,
E_STRICT
иE_DEPRECATED
.Замечание:
PHP-константы за пределами PHPИспользование PHP-констант за пределами PHP, например в файле
httpd.conf, не имеет смысла, так как в таких случаях требуются
целочисленные значения (int). Более того, с течением времени будут
добавляться новые уровни ошибок, а максимальное значение константы
E_ALL
соответственно будет расти. Поэтому в месте, где
предполагается указатьE_ALL
, лучше задать большое целое число,
чтобы перекрыть все возможные битовые поля. Таким числом может быть, например,
2147483647
(оно включит все возможные ошибки, не
толькоE_ALL
). -
display_errors
string -
Эта настройка определяет, требуется ли выводить ошибки на экран вместе
с остальным выводом, либо ошибки должны быть скрыты от пользователя.Значение
"stderr"
посылает ошибки в потокstderr
вместоstdout
.Замечание:
Эта функциональность предназначена только для разработки и не должен использоваться в
готовых производственных системах (например, системах, имеющих доступ в интернет).Замечание:
Несмотря на то, что display_errors может быть установлена во время выполнения
(функцией ini_set()), это ни на что не повлияет, если в скрипте есть
фатальные ошибки. Это обусловлено тем, что ожидаемые действия программы во время
выполнения не получат управления (не будут выполняться). -
display_startup_errors
bool -
Даже если display_errors включена, ошибки, возникающие во время запуска PHP, не будут
отображаться. Настойчиво рекомендуем включать директиву display_startup_errors только
для отладки. -
log_errors
bool -
Отвечает за выбор журнала, в котором будут сохраняться сообщения об ошибках. Это
может быть журнал сервера или error_log.
Применимость этой настройки зависит от конкретного сервера.Замечание:
Настоятельно рекомендуем при работе на готовых работающих
web сайтах протоколировать ошибки там, где они отображаются. -
log_errors_max_len
int -
Задание максимальной длины log_errors в байтах. В
error_log добавляется информация
об источнике. Значение по умолчанию 1024. Установка значения в 0
позволяет снять ограничение на длину log_errors. Это ограничение
распространяется на записываемые в журнал ошибки, на отображаемые ошибки,
а также на $php_errormsg, но не на явно вызываемые функции,
такие как error_log().Если используется int, значение измеряется байтами. Вы также можете использовать сокращённую запись, которая описана в этом разделе FAQ.
-
ignore_repeated_errors
bool -
Не заносить в журнал повторяющиеся ошибки. Ошибка считается
повторяющейся, если происходит в том же файле и в той же строке, и если настройка
ignore_repeated_source выключена. -
ignore_repeated_source
bool -
Игнорировать источник ошибок при пропуске повторяющихся сообщений. Когда
эта настройка включена, повторяющиеся сообщения об ошибках не будут
заноситься в журнал вне зависимости от того, в каких файлах и строках они происходят. -
report_memleaks
bool -
Если настройка включена (по умолчанию), будет формироваться отчёт об утечках памяти,
зафиксированных менеджером памяти Zend. На POSIX платформах этот отчёт будет
направляться в поток stderr. На Windows платформах он будет посылаться в отладчик
функцией OutputDebugString(), просмотреть отчёт в этом случае можно с помощью утилит,
вроде » DbgView. Эта настройка имеет
смысл в сборках, предназначенных для отладки. При этом
E_WARNING
должна быть включена в список error_reporting. -
track_errors
bool -
Если включена, последняя произошедшая ошибка будет первой в переменной
$php_errormsg. -
html_errors
bool -
Если разрешена, сообщения об ошибках будут включать теги HTML. Формат для
HTML-ошибок производит нажимаемые ссылки, ведущие на описание ошибки, либо
функии, в которой она произошла. За такие ссылки ответственны
docref_root и
docref_ext.Если запрещена, то ошибки будут выдаваться простым текстом, без форматирования.
-
xmlrpc_errors
bool -
Если включена, то нормальное оповещение об ошибках отключается и, вместо него,
ошибки выводятся в формате XML-RPC. -
xmlrpc_error_number
int -
Используется в качестве значения XML-RPC элемента faultCode.
-
docref_root
string -
Новый формат ошибок содержит ссылку на страницу с описанием ошибки или
функции, вызвавшей эту ошибку. Можно разместить копию
описаний ошибок и функций локально и задать ini директиве значение
URL этой копии. Если, например, локальная копия описаний доступна по
адресу"/manual/"
, достаточно прописать
docref_root=/manual/
. Дополнительно, необходимо
задать значение директиве docref_ext, отвечающей за соответствие
расширений файлов файлам описаний вашей локальной копии,
docref_ext=.html
. Также возможно использование
внешних ссылок. Например,
docref_root=http://manual/en/
или
docref_root="http://landonize.it/?how=url&theme=classic&filter=Landon
&url=http%3A%2F%2Fwww.php.net%2F"В большинстве случаев вам потребуется, чтобы значение docref_root оканчивалось
слешем"/"
. Тем не менее, бывают случаи, когда
это не требуется (смотрите выше, второй пример).Замечание:
Эта функциональность предназначена только для разработки, так как он облегчает
поиск описаний функций и ошибок. Не используйте его в готовых
производственных системах (например, имеющих доступ в интернет). -
docref_ext
string -
Смотрите docref_root.
Замечание:
Значение docref_ext должно начинаться с точки
"."
. -
error_prepend_string
string -
Строка, которая будет выводиться непосредственно перед сообщением об ошибке.
Используется только тогда, когда на экране отображается сообщение об ошибке.
Основная цель — добавить дополнительную HTML-разметку к сообщению об ошибке. -
error_append_string
string -
Строка, которая будет выводиться после сообщения об ошибке.
Используется только тогда, когда на экране отображается сообщение об ошибке.
Основная цель — добавить дополнительную HTML-разметку к сообщению об ошибке. -
error_log
string -
Имя файла, в который будут добавляться сообщения об ошибках. Файл
должен быть открыт для записи пользователем веб-сервера. Если
используется специальное значениеsyslog
, то
сообщения будут посылаться в системный журнал. На Unix-системах это
syslog(3), на Windows NT — журнал событий. Смотрите также: syslog().
Если директива не задана, ошибки будут направляться в SAPI журналы.
Например, это могут быть журналы ошибок Apache или поток
stderr
командной строки CLI.
Смотрите также функцию error_log(). -
error_log_mode
int -
Режим файла, описанного в error_log.
-
syslog.facility
string -
Указывает, какой тип программы регистрирует сообщение.
Действует только в том случае, если опция error_log установлена в «syslog». -
syslog.filter
string -
Указывает тип фильтра для фильтрации регистрируемых сообщений.
Разрешённые символы передаются без изменений; все остальные записываются в шестнадцатеричном представлении с префиксомx
.-
all
– строка будет разделена
на символы новой строки и все символы будут переданы без изменений
-
ascii
– строка будет разделена
на символы новой строки, а любые непечатаемые 7-битные символы ASCII будут экранированы
-
no-ctrl
– строка будет разделена
на символы новой строки, а любые непечатаемые символы будут экранированы
-
raw
– все символы передаются в системный
журнал без изменений, без разделения на новые строки (идентично PHP до 7.3)
Параметр влияет на ведение журнала через error_log установленного в «syslog» и вызовы syslog().
Замечание:
Тип фильтра
raw
доступен начиная с PHP 7.3.8 и PHP 7.4.0.
Директива не поддерживается в Windows.
-
-
syslog.ident
string -
Определяет строку идентификатора, которая добавляется к каждому сообщению.
Действует только в том случае, если опция error_log установлена в «syslog».
cjakeman at bcs dot org ¶
13 years ago
Using
<?php ini_set('display_errors', 1); ?>
at the top of your script will not catch any parse errors. A missing ")" or ";" will still lead to a blank page.
This is because the entire script is parsed before any of it is executed. If you are unable to change php.ini and set
display_errors On
then there is a possible solution suggested under error_reporting:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
include("file_with_errors.php");
?>
[Modified by moderator]
You should also consider setting error_reporting = -1 in your php.ini and display_errors = On if you are in development mode to see all fatal/parse errors or set error_log to your desired file to log errors instead of display_errors in production (this requires log_errors to be turned on).
ohcc at 163 dot com ¶
6 years ago
If you set the error_log directive to a relative path, it is a path relative to the document root rather than php's containing folder.
iio7 at protonmail dot com ¶
1 year ago
It's important to note that when display_errors is "on", PHP will send a HTTP 200 OK status code even when there is an error. This is not a mistake or a wrong behavior, but is because you're asking PHP to output normal HTML, i.e. the error message, to the browser.
When display_errors is set to "off", PHP will send a HTTP 500 Internal Server Error, and let the web server handle it from there. If the web server is setup to intercept FastCGI errors (in case of NGINX), it will display the 500 error page it has setup. If the web server cannot intercept FastCGI errors, or it isn't setup to do it, an empty screen will be displayed in the browser (the famous white screen of death).
If you need a custom error page but cannot intercept PHP errors on the web server you're using, you can use PHPs custom error and exception handling mechanism. If you combine that with output buffering you can prevent any output to reach the client before the error/exception occurs. Just remember that parse errors are compile time errors that cannot be handled by a custom handler, use "php -l foo.php" from the terminal to check for parse errors before putting your files on production.
Roger ¶
3 years ago
When `error_log` is set to a file path, log messages will automatically be prefixed with timestamp [DD-MMM-YYYY HH:MM:SS UTC]. This appears to be hard-coded, with no formatting options.
php dot net at sp-in dot dk ¶
8 years ago
There does not appear to be a way to set a tag / ident / program for log entries in the ini file when using error_log=syslog. When I test locally, "apache2" is used.
However, calling openlog() with an ident parameter early in your script (or using an auto_prepend_file) will make PHP use that value for all subsequent log entries. closelog() will restore the original tag.
This can be done for setting facility as well, although the original value does not seem to be restored by closelog().
jaymore at gmail dot com ¶
6 years ago
Document says
So in place of E_ALL consider using a larger value to cover all bit fields from now and well into the future, a numeric value like 2147483647 (includes all errors, not just E_ALL).
But it is better to set "-1" as the E_ALL value.
For example, in httpd.conf or .htaccess, use
php_value error_reporting -1
to report all kind of error without be worried by the PHP version.
on
May 06, 2021
The Essential Guide to PHP Error Logging
PHP has been one of the top (if not best) server-side scripting languages in the world for decades. However, let’s be honest – error logging in PHP is not the most straightforward or intuitive. It involves tweaking a few configuration options plus some playing around to get used to. Once you have everything set up and figured out (like you will after reading this post), things seem much easier, and you realize how helpful error logging can turn out to be for your application – from debugging and troubleshooting to monitoring and maintenance.
And this is why we are covering error logging in PHP in this post. We will start by revisiting the importance of logging errors in your application. We will then explore errors in PHP – their different types, and how they can be output. Next, we will look at all the error logging configurations in PHP, and understand how we can tweak these to our liking, before we see some error logging examples, and explore functions in PHP that allow us to write errors to log files. This post is a complete guide to error logging in PHP.
Here’s an outline of what we’ll be covering so you can easily navigate or skip ahead in the guide:
- Importance of Logging Errors
- PHP Error Types
- Where Can PHP Errors be Output
- Enabling and Configuring Error Reporting in PHP
- Logging Errors in PHP
- PHP’s Error Logging Functions
- error_log()
- trigger_error()
- syslog()
- set_error_handler()
- Popular PHP Logging Libraries
Importance of Logging Errors
Errors in software systems have this terrible reputation of being associated with failing things and breaking functionality. As a result, many of us often fail to recognize the importance of these loud red strings that bring our attention to faults, inconsistencies, and inaccuracies in our code – mistakes that can cost us dearly if allowed to fall through the cracks. Therefore, it is worthwhile for some of us to change our outlook towards error messages – to track, log, and organize them – and embrace their importance.
There’s a reason developers and organizations build and leverage dedicated logging systems that keep track of errors that arise throughout an application’s lifecycle. These logs provide useful information about what went wrong, when, where, and how it can be fixed.
For small-scale personal projects, it is common for developers not to feel the need to spend time setting up an effective logging system. This seems plausible because your code and end-user interactions are much more manageable for smaller projects. However, the requirement for effectively logging and maintaining errors and other information grows exponentially as your application scales. For larger applications, catering to thousands of users, it becomes unwieldy to track errors and updates across hundreds of components in real-time. Putting in place a system that can record the status of the very many events that an application’s operation entails allows organizations to maintain a clear record of their performance. This allows for more transparency and therefore ensures that no issues go unnoticed. As a result, this makes your application more reliable, easy to maintain, monitor, and debug.
Now that we are hopefully convinced that error logging is a worthwhile expedition, let us look at the different types of errors in PHP.
PHP Error Types
Broadly, there are five types of errors in PHP:
1. Fatal run-time Errors (E_ERROR)
These errors typically happen when an operation in your code cannot be performed. This leads to your code exiting. An example of a fatal error would be when you call a function that hasn’t been defined in your code, shown below:
<?php
function foo() {
echo "Function foo called.";
}
boo(); // undefined function 'boo'
?>
Error output –>
Fatal error: Uncaught Error: Call to undefined function boo() in code/my-php/index.php:5 Stack trace: #0 {main} thrown in code/my-php/index.php on line 5.
2. Warning Errors (E_WARNING)
A warning error is more gentle and less obtrusive in that it does not halt the execution. It presents a friendly reminder of something amiss in your code – a mistake that might not fail things immediately or fail anything at all but suggests a more accurate way of doing things that make your code more foolproof. These warnings can also save developers from issues that might pose a much bigger threat in the future. An example of a warning error would be when you try to include a file in PHP using an incorrect file path, as shown below:
<?php
include('filename.txt'); // arbitrary file that is not present
echo "Hello world";
?>
Error output ->
Warning: include(filename.txt): failed to open stream: No such file or directory in code/my-php/index.php on line 2
3. Parse Errors (E_PARSE)
Parse errors are also known as syntax errors as they arise from syntactical mistakes in your code. These errors are raised during the compilation of your code, making it exit before it runs. A common example of a parse error is missing a semicolon at the end of a code statement, shown below:
<?php
echo Hello world // no quotes or semicolon used
?>
Error output ->
Parse error: syntax error, unexpected 'world' (T_STRING), expecting ',' or ';' in code/my-php/index.php on line 2.
4. Notice Errors (E_NOTICE)
Notice errors are minor errors that are encountered during run-time, and just like warning errors, do not halt the execution. They usually occur when the script is attempting to access an undefined variable, for example, as shown below:
<?php
$a = 1;
$c = $a + $b; // undefined variable $b
?>
Error output ->
Notice: Undefined variable: b in code/my-php/index.php on line 3
5. User Errors (E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE)
User errors are user-defined, i.e., present a custom user-generated message raised explicitly from the code to capture a specific condition. These errors are manually raised by developers using the trigger_error function instead of the PHP engine. They are further classified as fatal, warning, and notice errors, but we’ll group them all as user errors for simplicity.
Where can PHP Errors be Output?
There are two primary places where we can have our errors presented in PHP – through inline errors and dedicated error log files.
Inline Errors
Inline errors are those that show up on your webpage in the browser or your terminal via STDOUT in a command-line environment. These errors prove to be quite useful during development – for developers to debug their code, fix issues, and get information about the overall execution. Below is an example of what these errors usually look like in the browser:
Though this proves to be super helpful for developers, you should be very careful in ensuring that these errors are not output when your application goes into production – for two reasons – end-user experience and security. You can toggle the displaying of these errors using the display_error directive in your system’s configuration. We’ll dive deeper into this in the next section.
Error Log Files
Inline errors are not persistent in memory, i.e., they are not saved anywhere and are only viewed as long as the browser or terminal session is alive. Additionally, you’ll only want to have them in a development environment. Conversely, as the theme of this post suggests, logging your errors is the more intelligent and more systematic approach towards maintaining large-scale applications. These are persistent in memory and provide information about the operation of your application across multiple components in one place, making it easier for monitoring and troubleshooting.
PHP, therefore, allows you to direct all your errors to specific log files; these files store timestamps, error stack traces, custom messages, and other helpful information about the source of the error and how to fix it. You can specify the path of your custom log file using the error_log directive of your system configuration. Here’s an example of an error log file:
You can also choose to have your errors logged to the system’s log file, usually located in – /var/log/syslog. We’ll cover this in a later section in the post.
Now let’s look at how we can configure where and how we want our errors logged.
Enabling and Configuring Error Reporting in PHP
As we discussed previously, logging in PHP is slightly less straightforward than other languages and frameworks. You might have to tweak a few options in configuration files to customize logging patterns. For example, when you install PHP on your machine, the initial configuration comes with some aspects of error logging disabled. This differs from system to system, and therefore, you should manually check these settings before getting started.
Logging Configuration Options in php.ini File
The configuration options are in the php.ini file. This file is read when PHP starts up and allows developers to play around with PHP’s functionality. Usually, this file can be found somewhere in the /etc/php directory on most Linux systems.
There are a bunch of directives (options) pertaining to the logging of errors in PHP that we can configure in this php.ini file:
- display_errors (default: 1)
Display errors are the inline errors we previously looked at. This directive can be used to good effect during development to output PHP error messages to the browser or terminal. However, for applications in production, you should likely turn this off to save your users from a poor website experience due to obscure error messages. Not only that, but this also protects you from exposing valuable information about the internals of your application as a security measure.
- display_startup_errors (default: 0)
As the name suggests, this is to output any errors that take place when PHP starts up. These usually do not provide any valuable information about your application specifically, and therefore need not be turned on.
- log_errors (default: 0)
This directive allows you to toggle the logging of errors to the specified path (in the next directive). Because this is turned off by default, it would be advisable to toggle this to 1 for recording your application’s error messages in a log file.
- error_log (default: 0)
This directive allows you to specify the path of your log file. You can also set this to “syslog” for directing all your error log messages to the system log.
- error_reporting (default: null)
The error_reporting directive allows you to customize which error levels you want reported, and which you are okay with going unreported. For example, you can use the directive as shown below to have all errors reported: error_reporting = E_ALL
- track_errors (default: 0)
This directive allows you to access the last raised error message in the $php_errormsg global variable in your code and can keep track of errors across your whole project.
After making changes to your php.ini file, you will need to restart the server for the changes to take effect.
The ini_set() Function
However, if you are unable to locate the php.ini file, or prefer overriding your project’s global configuration options, there is also an option to update these directives using the ini_set() function in your PHP code. For example, the below code can be used for customizing error reporting in your project:
<?php
// enabling error logging
ini_set('log_errors', 1);
// Customize reporting of errors
ini_set('error_reporting', E_WARNING | E_ERROR | E_PARSE | E_NOTICE);
// specify error log file path
ini_set('error_log', '/tmp/my-logs.log');
?>
The error_reporting() Function
One can also modify the error_reporting configuration option using the error_reporting() function from inside your code during run-time. As in the ini_set function, you can use bitwise operators like OR (|), AND (&), NOT (~), etc., when specifying the error levels to be reported. Below are a few examples of how this function can be used.
// Report only selected kinds of errors
error_reporting(E_ERROR | E_PARSE | E_NOTICE);
or
// Report all errors except E_WARNING
error_reporting(E_ALL & ~E_WARNING);
Now that we have got the system configurations and overall setup out of the way, let’s look at an example of how errors in your project code can be logged to files on your system.
Logging Errors in PHP
First, we will override the logging configuration parameters using the ini_set() function to enable error logging and specify the log file’s path. Then we’ll write some erroneous code to have PHP raise an error that we would like to have logged.
<?php
ini_set('log_errors', 1); // enabling error logging
ini_set('error_log', '/path/my-error-file.log'); // specifying log file path
echo $b; // undefined variable should raise error
?>
After opening the web page on our browser, let’s open the ‘my-error-file.log’ file to see if the error message was logged. Here is the log file output:
[28-Feb-2021 13:34:36 UTC] PHP Notice: Undefined variable: b in code/my-php/index.php on line 5
As you can see, our notice error was logged with a timestamp. As our code encounters more and more errors, this file will keep getting populated with corresponding timestamps. Note that we haven’t explicitly turned off display_errors, so these error messages are likely to be logged to the browser web page – something you might want to avoid during production.
This was an example of capturing errors raised by PHP in log files. Now let’s look at how we can raise and log custom error messages for our application.
PHP’s Error Logging Functions
So far, we looked at errors raised by PHP – errors about your code execution. However, oftentimes you would want to also capture custom errors, with custom error messages specific to the functioning of your application. These so-called errors might not necessarily fail your code or halt its execution, but can indicate conditions characterized as erroneous and noteworthy for your application. These can act as indications to the organization about anomalous behavior that the team might want to look into and fix.
To facilitate this, PHP provides a set of functions that we can use to actively log errors in our code.
error_log()
The most common method for actively logging errors is the error_log() function. This sends a string argument for the error message to the log file.
error_log (string $message, int $message_type=0, string $destination=?, string $extra_headers=?) : bool
It also takes many other parameters to send error messages over email or specific log files. However, for the sake of simplicity, we won’t be covering that here.
The interesting thing about this function is it logs your error message to the file specified in the configuration (or to the system log), regardless of the value of the log_errors directive. Let’s take a very simple example of logging an error when a specific condition in our code is met.
<?php
ini_set('error_log', '/path/my-error-file.log');
$a = 5;
$b = 10;
$c = $a + $b;
if ($c < 20) {
error_log("Sum is less than 20."); // logging custom error message
}
?>
Here is the output of the log file:
[28-Feb-2021 13:31:50 UTC] Sum is less than 20
Similarly, you can also log the values of variables in your code to provide additional context about your errors. Let’s see an example for that:
<?php
ini_set('error_log', '/path/my-error-file.log');
$languagesArray = array("PHP", "Python", "Node.js");
error_log("Lorem ipsum. Array data -> ".print_r($languagesArray, true));
?>
Here’s the output of the log file ->
[28-Feb-2021 13:49:28 UTC] Lorem ipsum. Array data -> Array
(
[0] => PHP
[1] => Python
[2] => Node.js
)
trigger_error()
The trigger_error() function can be used to raise a user-defined error/warning/notice. You can also specify the error type based on the condition. This allows you to customize its reporting and other behavior – for example, using an error type of E_USER_ERROR. We can cause the code to exit immediately compared to an E_USER_WARNING error.
trigger_error (string $error_msg, int $error_type=E_USER_NOTICE) : bool
The difference between trigger_error and error_log is that the former only generates a user error and depends on your system’s logging configurations to handle this error message (whether displayed or logged). error_log, on the other hand, will log your message regardless of the system’s configuration.
Here is the code for the same example we saw previously:
<?php
ini_set('log_errors', 1); // enabling error logging
ini_set('error_log', '/path/my-error-file.log'); // specifying log file path
$a = 5;
$b = 10;
$c = $a + $b;
if ($c < 20) {
trigger_error("Sum is less than 20.", E_USER_ERROR);
echo "This will not be printed!";
}
?>
This adds a similar log entry to what we saw previously, but with an error level, plus the conventional error source information (log file output below):
[01-Mar-2021 01:16:56 UTC] PHP Fatal error: Sum is less than 20. in code/my-php/index.php on line 10
syslog()
You can also choose to directly send an error message to the system’s log using the syslog() function.
syslog (int $priority, string $message) : bool
The first argument is the error’s priority level – LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_ALERT, LOG_EMERG, etc. (more about it here). The second argument is the actual message’s text. This is how the function can be used:
<?php
// opening logger connection
openlog('myApp', LOG_CONS | LOG_NDELAY | LOG_PID, LOG_USER | LOG_PERROR
); // more information about params in documentation
syslog(LOG_WARNING, "My error message!");
closelog();
?>
This should reflect in your system’s logger (usually in /var/log/syslog) as:
Mar 1 13:27:15 zsh php: My error message!
set_error_handler()
To customize the handling of all the user-defined errors throughout your code, PHP allows you to specify a custom error handler function to override the default handling of errors. This makes it easy for organizations to modify how they want their errors logged, the corresponding error messages send method, and much more. The set_error_handler() function helps with this.
set_error_handler (callable $error_handler, int $error_types=E_ALL | E_STRICT) : mixed
It takes as an argument our custom error handler function, which will define the handling of our errors, and look something like this:
handler (int $errno, string $errstr, string $errfile=?, int $errline=?, array $errcontext=?) : bool
This takes in many parameters like the error number, error string, corresponding file, etc. Let’s understand this better using the same previous example:
<?php
// custom error handler function ->
function myErrorHandler($errno, $errstr, $errfile, $errline, $errcontext){
$message = date("Y-m-d H:i:s - "); // timestamp in error message
$message .= "My Error: [" . $errno ."], " . "$errstr in $errfile on line $errline, n"; // custom error message
$message .= "Variables:" . print_r($errcontext, true) . "rn";
error_log($message, 3, "/path/my-error-file.log");
die("There was a problem, please try again."); // exit code
}
set_error_handler("myErrorHandler");
$a = 5;
$b = 10;
$c = $a + $b;
if ($c < 20) {
trigger_error("Sum is less than 20.", E_USER_WARNING);
}
echo "This will not be printed!";
?>
Here, we define a custom error handler function where we modify the error message a bit, log it, and exit the code. Then, when we use the trigger_error() function, its logging is handled by the above function, which takes care of the rest. This is what the output in the log file looks like:
2021-03-01 06:58:07 - My Error: [512], Sum is less than 20. in code/my-php/index.php on line 22,
Variables:Array
(
[a] => 5
[b] => 10
[c] => 15
)
As you can see, this can be used to fully customize error logging in applications, allowing organizations to prioritize aspects of errors and contexts that are more important for their application.
Popular PHP Logging Libraries
Thanks to the huge PHP community support on the internet, there have been very many logging libraries that aim to provide more functionality and ease the overall process for developers and organizations. Each of the renowned PHP frameworks that you must have heard of come equipped with logging libraries built-in. There are also now logging standards established, like the PSR-3 (PHP Standards Recommendation) logger interface, that defines a standardized interface to follow for logging libraries.
Below is a list of some of the most popular logging libraries in PHP:
- Monolog
- Analog
- KLogger
- Log4PHP
Feel free to check these out to see what default error logging in PHP is missing out on.
Wrapping Up
In this post, we covered everything about errors and logging in PHP. We discussed the importance of logging mechanisms in your application, looked at the different types of errors in PHP, and explored the various configuration options and PHP functions that we can use to log errors effectively.
Now that you have a decent understanding of everything, go ahead and start implementing error logging for your application! It doesn’t matter if you are working on a small project where things might seem under control even without log files. Logging your errors is considered one of the top “best practices” in software development that becomes exponentially more important as your applications grow and scale.
To learn more about logging in PHP in general, feel free to check out the Tutorial: Log to Console in PHP on our blog!
To up your application monitoring game by identifying bottlenecks and gaining effective application performance insights, check out ScoutAPM to get started with a 14-day free trial!
Happy coding!
Logging is an essential and underutilized practice in software development. It’s
obvious value is for debugging, but it can also be a resource for deriving
various analytics and usage information. When you learn how to log properly, you
will be able to adequately track the inner workings of your application so that
troubleshooting becomes much more effortless.
In this article, we will discuss the basics of logging in PHP and explore all
the logging-related configurations you should know. We will begin by discussing
the native logging functions in the language before branching out to examine the
logging solutions developed by other PHP users. Here are some of the other
things you stand to learn by following through with this article:
- What is logging and examples of what to log.
- Understanding PHP logging configurations.
- Using native logging functions like error_log().
- Why you should opt for a logging framework
- An introduction to the Monolog framework for logging.
Prerequisites
Ensure to have
the latest version of PHP installed
on your machine before proceeding with this article. The code snippets and
command output included in the sections below were all tested and confirmed to
be accurate as at PHP v8.x, but they should continue to work with later
versions.
🔭 Want to centralize and monitor your PHP application logs?
Head over to Logtail and start ingesting your logs in 5 minutes.
What should you log?
Before we discuss how logging works in PHP, let’s briefly examine what you
should consider logging when developing your application. Some typical
candidates for what to log include the following:
-
Errors and exceptions. Ensure to log every error and exception that occurs in
your application so that you can find the root cause of an issue and fix them
quickly. -
Incoming requests. When a request is made to an endpoint in your application,
you should log that event and include details such as a timestamp, user ID (if
any), the endpoint and HTTP method, etc. It is also a good idea to generate a
correlation ID at this point such that all other logging calls following from
the request will include this ID, making it easier to trace the path of a
specific client request in the application. -
Any changes to your database, including inserting new data and updating and
deleting existing data. You should record what data was changed, who changed
it, and when it occurred. -
Accessing sensitive information. Whenever sensitive or restricted information
is being accessed on the system, a corresponding log entry should be recorded
describing who accessed the resource and when.
Logging as much as possible does not mean you should record just anything as
irrelevant entries will create noise and make your logs much less helpful. You
should also take care never to log anything that would compromise user privacy
such as passwords, credit card information, home addresses, phone numbers, or
other Personally Identifiable Information (PII).
Understanding logging configurations in PHP
PHP saves all its configuration in a php.ini
file whose location depends on
your operating system and how you installed PHP. Luckily, there is an easy way
to locate the configuration file. Open a new terminal window and run the
following command:
Output
Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.1
Loaded Configuration File: /opt/homebrew/etc/php/8.1/php.ini
Scan for additional .ini files in: /opt/homebrew/etc/php/8.1/conf.d
Additional .ini files parsed: /opt/homebrew/etc/php/8.1/conf.d/ext-opcache.ini
The highlighted line above describes where to find the relevant php.ini
file
you need to edit. Copy the path to the file and open it in your text editor:
code <path/to/your/php.ini>
This configuration file is enormous, but we only care about a small section.
Scroll down to the «Error handling and logging» section or use your text
editor’s search function.
php.ini
. . .
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Error handling and logging ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
. . .
Let’s look at some of the common directives in this section that you need to
note. You can find a complete list of all available directives in the
official documentation. Note that
you’ll need to restart your web server after making changes to your php.ini file
for the changes to take effect.
error_reporting
: this directive configures
the level of diagnostics that should be recorded, and its value should be an
error level constant.
For example, a value ofE_ALL
(the default) indicates that all diagnostic
messages will be recorded regardless of their level, while a value of
E_ALL & ~E_NOTICE
means that all notice-level messages will be omitted.
-
display_errors
: controls whether PHP should output errors to the screen as
part of the program’s output or if they should be hidden from view. Keeping
this valueOn
is fine in development settings, but it should always be
turnedOff
in production, or end users may see ugly stack traces on your
website when an error occurs (see above screenshot). -
display_startup_errors
: determines whether PHP will output errors that occur
during its startup sequence. These errors are hidden by default, but you can
turn them on when debugging. -
log_errors
: this option configures PHP to log errors to the location
specified by theerror_log
directive. Setting this toOff
will disable
such behavior, but we recommend keeping this optionOn
. -
log_errors_max_len
: restricts the maximum length of each log record to the
specified value in bytes. The default is1024
bytes, but setting this option
to0
removes the restriction. -
error_log
: this defines the path to a file where script errors should be
logged. If this file does not exist, it will be automatically created. You can
also forward log records to the system log by setting its value tosyslog
.
Aside from configuring these options directly in the php.ini
file, PHP also
offers a way override them at runtime. This can be useful in a serverless
environment where you don’t have access to the configuration file, or when you
are troubleshooting an issue.
You can retrieve the current configuration using the ini_get()
function as
shown below:
<?php
echo 'log_errors = ' . ini_get('log_errors') . "n";
?>
If you wish to override an existing configuration, you can provide a new value
using the ini_set()
function:
<?php
ini_set('log_errors', 1); // enable error logging
ini_set('error_log', 'app-errors.log' // specify error log file path
?>
Error levels and constants in PHP
In this section, we’ll examine one of the more obtuse aspects of PHP logging:
error level constants. They are conceptually similar to log
levels and are used to distinguish the different types of
diagnostic messages produced when executing a program.
PHP has an unnecessarily complicated system when it comes to log levels. It uses
many different constants to indicate different log levels, and these constants
can be roughly classified into three families:
1. E_
for internal PHP errors
These include the following:
E_ERROR
: a fatal error that causes script termination (e.g., calling a
non-existent function, out of memory, etc.).E_WARNING
: a runtime warning that doesn’t terminate script execution (e.g.,
using an undefined variable in an expression).E_PARSE
: compile-time parse errors, usually syntax errors.E_NOTICE
: runtime notices, meaning PHP encountered something that it thinks
could be a mistake, but could also be intentional. For instance, using
unassigned values in your code.
The constants above are used to indicate the severity of any event in your
application, and they are not user-customizable. When something happens, PHP
will automatically create a log record and decide if it is E_ERROR
,
E_WARNING
, or E_NOTICE
. The only thing we can do with these constants is to
use them in the error_reporting
directive to tell PHP whether or not to log
these errors.
2. E_USER
for application-specific logs
E_USER_ERROR
: something went seriously wrong with your project, causing
services to stop working.E_USER_WARNING
: something abnormal happened, but it doesn’t affect the core
functionalities of your applications, though the situation may need to be
addressed soon to prevent it from escalating further.E_USER_NOTICE
: informative messages that describe the normal operation of
the program.
3. LOG_
for system logs
The LOG_
family conforms to the standard
syslog severity levels:
LOG_EMERG
: the entire application is unusable.LOG_ALERT
: something serious happened that needs to be addressed
immediately.LOG_CRIT
— a critical function is no longer working.LOG_ERR
— an error occurred, but the application can continue working.LOG_WARNING
: abnormal situations that may later become an error if not
addressed.LOG_NOTICE
: unusual events but not error conditions.LOG_INFO
— informative messages.LOG_DEBUG
: used to indicate messages helpful for debugging.
Exploring logging functions in PHP
Now that we’ve examined the PHP logging configuration and its error constants,
let’s get into the nitty-gritty of logging in a PHP project. Several logging
functions ship with PHP, and they all depend on the configurations discussed in
the earlier sections.
To guarantee that you get results consistent with what is described in the
sections below, ensure that your logging configuration matches the following
values:
php.ini
. . .
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = On
log_errors = On
error_log = error.log
. . .
Go to your working directory and create a new logging.php
file using the
command below. This is where we are going to explore PHP’s logging functions
throughout this tutorial.
The most basic form of logging involves sending messages to the console. In PHP,
we can easily print to the console using echo
or print
statements like this:
logging.php
<?php
echo "This is a log message.n";
print "This is also a log message.";
?>
Output
This is a log message.
This is also a log message.
While echo
and print
statements are valuable ways to print some text to the
console, you shouldn’t use them for logging as there are much better facilities
for doing so. We will explore some of these functions in detail here.
The error_log() function
PHP’s error_log()
function pushes a log message to the file path defined in
error_log
config option. You can also specify a different file path directly
in the function, if you prefer. It can take up to four arguments but only the
first one is required:
error_log(
string $message,
int $message_type = 0,
?string $destination = null,
?string $additional_headers = null
): bool
- The
$message
argument is the log message you wish to record. - The
$message_type
argument has a confusing name but it specifies where you
want PHP to push the message. It has four possible values:0
: the message is sent to the location specified in theerror_log
directive.1
: the message is pushed through email, which is specified by the
$destination
parameter.3
: the message is appended to the file specified by the$destination
parameter.4
: the message is sent directly to the Server API (SAPI) logging handler,
which depends on your platform. For example,
Apache’s error log
will be used for LAMP (Linux Apache, MySQL, PHP) setups.
- The
$destination
parameter specifies where the log message should be sent,
and it could be an email address or a local file, depending on the value of
$message_type
. - The
$additional_headers
parameter is only used when$message_type
is set
to1
. It is the same as the$additional_headers
used in PHP’s
mail()
function.
Let’s go ahead and use the error_log()
function to create a log record like
this:
logging.php
<?php
error_log("database not available!");
?>
Once you execute this script, you will notice an error.log
file in the current
directory:
Examine the contents of the error.log
file through the cat
command as shown
below:
Output
[27-Jul-2022 16:05:49 America/New_York] database not available!
As you can see, the error_log()
function automatically includes a timestamp
which is one reason why using a dedicated logging function is better than echo
and print
statements.
You can also record a log entry into a different file by changing the
$message_type
and $destination
parameters as shown below:
logging.php
. . .
error_log("database not available!", 3, "my-errors.log");
Save the changes and execute the logging.php
file again.
This time, the log entry will be sent to the my-errors.log
file:
Notice that a timestamp is not included in the above entry! This is because the
method bypasses the operating system’s logging mechanism leading to less
detailed logs. A better way to log to a different file is by using the
ini_set()
function discussed earlier:
logging.php
<?php
. . .
ini_set("error_log", "my-errors.log");
error_log("database not available!");
?>
This example will produce the same result, but with the timestamp included:
my-errors.log
[27-Jul-2022 17:38:04 America/New_York] database not available!
The trigger_error() function
The trigger_error()
function is used to record application-specific errors,
warnings and notices. It takes two parameters: the first one is the log message,
and the second one defines its error level (one of E_USER_ERROR
,
E_USER_WARNING
, E_USER_NOTICE
, or E_USER_DEPRECATED
):
logging.php
<?php
trigger_error("A user requested a resource.", E_USER_NOTICE);
trigger_error("The image failed to load!", E_USER_WARNING);
trigger_error("User requested a profile that doesn't exist!", E_USER_ERROR);
?>
When you execute the script above, you will observe the following console
output:
Output
Notice: A user requested a resource. in /home/eric/test/logging.php on line 2
Warning: The image failed to load! in /home/eric/test/logging.php on line 3
Fatal error: User requested a profile that doesn't exist! in /home/eric/test/logging.php on line 4
The above logs are also recorded to the error.log
file in a slightly different
format:
Output
[8-Jul-2022 22:11:43 America/New_York] PHP Notice: A user requested a service. in /home/eric/test/logging.php on line 3
[8-Jul-2022 22:11:43 America/New_York] PHP Warning: The image failed to load! in /home/eric/test/logging.php on line 4
[8-Jul-2022 22:11:43 America/New_York] PHP Fatal error: User requested a profile that doesn't exist! in /home/eric/test/logging.php on line 5
Each log entry specifies the corresponding log level and the location of the log
message. If you don’t use a user-assigned error level constant (prefixed with
E_USER_
), an error will be thrown.
<?php
trigger_error("A user requested a service.", E_ERROR);
?>
Output
Fatal error: Uncaught ValueError: trigger_error(): Argument #2 ($error_level) must be one of E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, or E_USER_DEPRECATED in /home/ayo/dev/betterstack/betterstack-community/demo/logging-php/logging.php:2
Stack trace:
#0 /home/ayo/dev/betterstack/betterstack-community/demo/logging-php/logging.php(2): trigger_error()
#1 {main}
thrown in /home/ayo/dev/betterstack/betterstack-community/demo/logging-php/logging.php on line 2
Logging to the system log
A third way to log messages in PHP is using the syslog()
function. It sends
the log message to the default system log like this:
syslog(LOG_ERR, "Custom error message");
The first argument to syslog()
is the appropriate log level constant, and the
second is the log message to be recorded. Notice that when specifying the log
level, the third group of constants (those prefixed with LOG_
) are utilized.
These constants are unique to the syslog()
function, and they are all listed
in its documentation.
Here are a few ways to view your system log:
- On Linux, use one of the following commands to access the system log
(depending on the specific OS):
tail -f /var/log/messages
- On macOS, run
tail -f /var/log/system.log
in your terminal. - On Windows, use the
Windows Event Viewer.
Here’s some sample output from the system log on a Linux-based OS after
executing the previous code snippet:
Output
Jul 27 20:58:28 fedora php[485047]: Custom error message
You can customize the output above through the openlog()
function. It opens a
connection to the system logger and takes up to three arguments: a string prefix
to be added to each message, the logging options, and the logging facility.
After calling openlog()
, you should call closelog()
to close the connection.
openlog("MyAppPrefix", LOG_PID | LOG_PERROR,LOG_USER);
syslog(LOG_ERR, "Custom error message");
closelog();
Here’s the output after executing the script above:
Output
Jul 28 09:20:04 fedora MyAppPrefix[596277]: Custom error message
You can learn more about system logs on
Linux by reading our
detailed tutorial on the subject.
Why you should use a logging framework
Using PHP’s built-in logging functions is an easy way to get started with
logging in simple projects, but they are insufficient for creating a robust
logging strategy in serious applications due to their lack of features and
flexibility, such as customizing the formatting of your logs, or determining how
they are recorded. They also cannot capture a wide variety of data types since
everything fed into them must be a string, which means you have to do extra work
to capture contextual data in a log entry.
These limitations are why third-party logging frameworks
are prevalent in the PHP ecosystem. Here are some of the most popular logging
libraries for PHP that are worth exploring for production-grade applications:
- Monolog: Monolog is the most popular PHP
logging framework out there. It has dozens of handlers that can send your log
records to files, emails, databases, Slack, etc. It is also packed with
multiple formatters that allow you to customize your logs however you want. - Analog: Analog is a minimal logging
library. It also has several handlers that can send your logs to different
destinations. However, it does not have optional features such as formatters
and processors. - KLogger: Unlike Analog, KLogger goes in
a different direction. It can only push your logs to a file, but it has many
different formatters that you can use to customize the timestamp, file name,
file extension, context information, etc.
In the next section, we will briefly examine how to implement logging using the
Monolog library as it’s the most popular and satisfactorily meets all our
criteria for a good logging framework.
Getting started with Monolog
To use Monolog in your PHP application, you need to install the library through
PHP Composer:
composer require monolog/monolog
Output
. . .
Package operations: 2 installs, 0 updates, 0 removals
- Installing psr/log (3.0.0): Extracting archive
- Installing monolog/monolog (3.1.0): Extracting archive
11 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
This command will install Monolog into the vendor
directory, and you can
import the package into your project like this:
logging.php
<?php
require __DIR__."/vendor/autoload.php"; // This tells PHP where to find the autoload file so that PHP can load the installed packages
use MonologLogger; // The Logger instance
use MonologHandlerStreamHandler; // The StreamHandler sends log messages to a file on your disk
use MonologLevel; // Log levels
?>
The three classes we imported into the file above represent Monolog’s most
important concepts. First, logging in Monolog is channel-based, and the Logger
instance is used to initialize a new log channel which provides a mechanism for
grouping different logs. For example, you can have an errors
channel that
records errors, a performance
channel that logs performance-related messages,
and so on. You can organize this system however you like depending on what kind
of application you are building.
Each log channel can be assigned multiple handlers, and they are responsible for
sending log messages to various destinations. For example, the StreamHandler
above can push your messages to the console or a local file.
Finally, each handler needs to have a minimum log level, which defines the
minimum level a message must have to be logged by the handler. Monolog provides
a more standard way of dealing with log levels than PHP’s error level constants.
There are eight different levels available in Monolog, and they are modeled
after the
Syslog severity levels
discussed earlier:
- EMERGENCY
- ALERT
- CRITICAL
- ERROR
- WARNING
- NOTICE
- INFO
- DEBUG
Logging in PHP with Monolog
Let’s look at an example of how to log messages to the console with Monolog:
logging.php
<?php
. . .
// New Logger instance. Create a new channel called "my_logger".
$logger = new Logger("my_logger");
// Create a new handler. In this case, it is the StreamHandler, which will send the log messages to the console.
$stream_handler = new StreamHandler("php://stdout", Level::Debug);
// Push the handler to the log channel
$logger->pushHandler($stream_handler);
// Log the message
$logger->debug("This is a debug message.");
$logger->info("This is an info message.");
$logger->error("This is an error message.");
$logger->critical("This is a critical message.");
?>
Execute the logging.php
file, and observe the following output:
Output
[2022-07-11T03:32:57.111007+02:00] my_logger.DEBUG: This is a debug message. [] []
[2022-07-11T03:32:57.111750+02:00] my_logger.INFO: This is an info message. [] []
[2022-07-11T03:32:57.111941+02:00] my_logger.ERROR: This is an error message. [] []
[2022-07-11T03:32:57.112127+02:00] my_logger.CRITICAL: This is a critical message. [] []
In this example, a new log channel called my_logger
was initialized using the
Logger
instance, and then a StreamHandler()
instance was assigned to it.
This handler was setup to log debug-level messages or higher to the standard
output (represented by php://stdout
).
Lastly, several log messages are recorded by using the debug()
, info()
,
error()
, and critical()
methods which give the message the corresponding log
level that is observed in the output. Notice that a timestamp is also included
with each entry.
Instead of logging to the terminal console, we can also push the log record to a
local file using the StreamHandler()
. All we need to do is change the
destination parameter like this:
logging.php
<?php
. . .
$logger = new Logger("my_logger");
$stream_handler = new StreamHandler(__DIR__ . "/log/debug.log", Level::Debug);
$logger->pushHandler($stream_handler);
$logger->debug("This is a debug message.");
?>
This causes log messages using the $logger
channel to be sent to a
/log/debug.log
file. You can examine its contents with the following command:
Output
[2022-07-10T01:53:24.848775+02:00] my_logger.DEBUG: This is a debug message. [] []
There are many other handlers other than the StreamHandler
demonstrated above,
so ensure to read our detailed guide on
Monolog to learn more about them and how to
create a custom handler.
Formatting your logs
From the examples above, you will observe that all the log records follow a
predefined format. They all start with a timestamp, followed by the log level,
message, context and extra information. This format might not fit your needs
when creating a logging system, so Monolog provides several formatters that you
can use to customize the log records.
One of the useful formatters to look at is the LineFormatter
. It takes a log
record as input, and subsequently outputs a formatted string of the record.
Let’s take a look at an example:
logging.php
. . .
use MonologLevel;
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologFormatterLineFormatter;
$logger = new Logger("my_logger");
$stream_handler = new StreamHandler("php://stdout", Level::Debug);
$output = "%level_name% | %datetime% > %message% | %context% %extra%n";
$stream_handler->setFormatter(new LineFormatter($output));
$logger->pushHandler($stream_handler);
$logger->debug("This file has been executed.");
?>
In this case, we are making Monolog return a log record that starts with the log
level, then the date, message, and context information.
Output
DEBUG | 2022-07-10T21:33:51.345896+02:00 > This file has been executed. | [] []
Besides rearranging the different segments, it is also possible for us to
customize the timestamp output, since the default format isn’t very human
readable.
logging.php
<?php
. . .
$dateFormat = "Y-n-j, g:i a";
$output = "%level_name% | %datetime% > %message% | %context% %extra%n";
$stream_handler->setFormatter(new LineFormatter($output, $dateFormat));
. . .
?>
Output
DEBUG | 2022-7-10, 10:24 pm > This file has been executed. | [] []
In a production environment, your application will probably generate tons of
logs, and in this case, it is best to use a structured logging
format
that is better suited to parsing by automated logging tools. Using Monolog’s
JsonFormatter
, you are able to log in JSON format, making it easier for
machines to read.
logging.php
<?php
require __DIR__ . "/vendor/autoload.php";
use MonologLevel;
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologFormatterJsonFormatter;
$logger = new Logger("daily");
$stream_handler = new StreamHandler("php://stdout", Level::Debug);
$logger->pushHandler($stream_handler);
$stream_handler->setFormatter(new JsonFormatter());
$logger->debug("This is a debug message.");
Output
{"message":"This is a debug message.","context":{},"level":100,"level_name":"DEBUG","channel":"daily","datetime":"2022-07-29T21:43:30.910327+02:00","extra":{}}
Notice that the log message, the log level, the timestamp, and so on have all
been turned into JSON data.
You can learn more about formatters in Monolog and their available options by
reading their
documentation.
Final thoughts
We covered a lot of ground in this article, beginning with PHP’s native logging
functions and their quirks and features before briefly discussing logging
frameworks and why you need one. We also introduced Monolog, a logging library
for PHP application and demonstrated some of its basic features that help you
create a more useful logging system. There’s a lot more about Monolog that can’t
be covered here so we recommend diving into our detailed guide to logging with
Monolog to get a full picture of what you
can do with it.
Thanks for reading, and happy logging!
Centralize all your logs into one place.
Analyze, correlate and filter logs with SQL.
Create actionable
dashboards.
Share and comment with built-in collaboration.
Got an article suggestion?
Let us know
Next article
How to Get Started with Monolog Logging in PHP
Monolog is among the most popular pieces of open source software, providing logging capabilities for PHP applications.
→
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
В этом руководстве мы расскажем о различных способах того, как в PHP включить вывод ошибок. Мы также обсудим, как записывать ошибки в журнал (лог).
Как быстро показать все ошибки PHP
Самый быстрый способ отобразить все ошибки и предупреждения php — добавить эти строки в файл PHP:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
Что именно делают эти строки?
Функция ini_set попытается переопределить конфигурацию, найденную в вашем ini-файле PHP.
Display_errors и display_startup_errors — это только две из доступных директив. Директива display_errors определяет, будут ли ошибки отображаться для пользователя. Обычно директива dispay_errors не должна использоваться для “боевого” режима работы сайта, а должна использоваться только для разработки.
display_startup_errors — это отдельная директива, потому что display_errors не обрабатывает ошибки, которые будут встречаться во время запуска PHP. Список директив, которые могут быть переопределены функцией ini_set, находится в официальной документации .
К сожалению, эти две директивы не смогут отображать синтаксические ошибки, такие как пропущенные точки с запятой или отсутствующие фигурные скобки.
Отображение ошибок PHP через настройки в php.ini
Если ошибки в браузере по-прежнему не отображаются, то добавьте директиву:
display_errors = on
Директиву display_errors следует добавить в ini-файл PHP. Она отобразит все ошибки, включая синтаксические ошибки, которые невозможно отобразить, просто вызвав функцию ini_set в коде PHP.
Актуальный INI-файл можно найти в выводе функции phpinfo (). Он помечен как “загруженный файл конфигурации” (“loaded configuration file”).
Отображать ошибки PHP через настройки в .htaccess
Включить или выключить отображение ошибок можно и с помощью файла .htaccess, расположенного в каталоге сайта.
php_flag display_startup_errors on
php_flag display_errors on
.htaccess также имеет директивы для display_startup_errors и display_errors.
Вы можете настроить display_errors в .htaccess или в вашем файле PHP.ini. Однако многие хостинг-провайдеры не разрешают вам изменять ваш файл PHP.ini для включения display_errors.
В файле .htaccess также можно включить настраиваемый журнал ошибок, если папка журнала или файл журнала доступны для записи. Файл журнала может быть относительным путем к месту расположения .htaccess или абсолютным путем, например /var/www/html/website/public/logs
.
php_value error_log logs/all_errors.log
Включить подробные предупреждения и уведомления
Иногда предупреждения приводят к некоторым фатальным ошибкам в определенных условиях. Скрыть ошибки, но отображать только предупреждающие (warning) сообщения можно вот так:
error_reporting(E_WARNING);
Для отображения предупреждений и уведомлений укажите «E_WARNING | E_NOTICE».
Также можно указать E_ERROR, E_WARNING, E_PARSE и E_NOTICE в качестве аргументов. Чтобы сообщить обо всех ошибках, кроме уведомлений, укажите «E_ALL & ~ E_NOTICE», где E_ALL обозначает все возможные параметры функции error_reporting.
Более подробно о функции error_reporting ()
Функция сообщения об ошибках — это встроенная функция PHP, которая позволяет разработчикам контролировать, какие ошибки будут отображаться. Помните, что в PHP ini есть директива error_reporting, которая будет задана этой функцией во время выполнения.
error_reporting(0);
Для удаления всех ошибок, предупреждений, сообщений и уведомлений передайте в функцию error_reporting ноль. Можно сразу отключить сообщения отчетов в ini-файле PHP или в .htaccess:
error_reporting(E_NOTICE);
PHP позволяет использовать переменные, даже если они не объявлены. Это не стандартная практика, поскольку необъявленные переменные будут вызывать проблемы для приложения, если они используются в циклах и условиях.
Иногда это также происходит потому, что объявленная переменная имеет другое написание, чем переменная, используемая для условий или циклов. Когда E_NOTICE передается в функцию error_reporting, эти необъявленные переменные будут отображаться.
error_reporting(E_ALL & ~E_NOTICE);
Функция сообщения об ошибках позволяет вам фильтровать, какие ошибки могут отображаться. Символ «~» означает «нет», поэтому параметр ~ E_NOTICE означает не показывать уведомления. Обратите внимание на символы «&» и «|» между возможными параметрами. Символ «&» означает «верно для всех», в то время как символ «|» представляет любой из них, если он истинен. Эти два символа имеют одинаковое значение в условиях PHP OR и AND.
error_reporting(E_ALL);
error_reporting(-1);
ini_set('error_reporting', E_ALL);
Эти три строки кода делают одно и то же, они будут отображать все ошибки PHP. Error_reporting(E_ALL) наиболее широко используется разработчиками для отображения ошибок, потому что он более читабелен и понятен.
Включить ошибки php в файл с помощью функции error_log ()
У сайта на хостинге сообщения об ошибках не должны показываться конечным пользователям, но эта информация все равно должна быть записана в журнал (лог).
Простой способ использовать файлы журналов — использовать функцию error_log, которая принимает четыре параметра. Единственный обязательный параметр — это первый параметр, который содержит подробную информацию об ошибке или о том, что нужно регистрировать. Тип, назначение и заголовок являются необязательными параметрами.
error_log("There is something wrong!", 0);
Параметр type, если он не определен, будет по умолчанию равен 0, что означает, что эта информация журнала будет добавлена к любому файлу журнала, определенному на веб-сервере.
error_log("Email this error to someone!", 1, "someone@mydomain.com");
Параметр 1 отправит журнал ошибок на почтовый ящик, указанный в третьем параметре. Чтобы эта функция работала, PHP ini должен иметь правильную конфигурацию SMTP, чтобы иметь возможность отправлять электронные письма. Эти SMTP-директивы ini включают хост, тип шифрования, имя пользователя, пароль и порт. Этот вид отчетов рекомендуется использовать для самых критичных ошибок.
error_log("Write this error down to a file!", 3, "logs/my-errors.log");
Для записи сообщений в отдельный файл необходимо использовать тип 3. Третий параметр будет служить местоположением файла журнала и должен быть доступен для записи веб-сервером. Расположение файла журнала может быть относительным путем к тому, где этот код вызывается, или абсолютным путем.
Журнал ошибок PHP через конфигурацию веб-сервера
Лучший способ регистрировать ошибки — это определить их в файле конфигурации веб-сервера.
Однако в этом случае вам нужно попросить администратора сервера добавить следующие строки в конфигурацию.
Пример для Apache:
ErrorLog "/var/log/apache2/my-website-error.log"
В nginx директива называется error_log.
error_log /var/log/nginx/my-website-error.log;
Теперь вы знаете, как в PHP включить отображение ошибок. Надеемся, что эта информация была вам полезна.
PHP logs are not just about errors. You can use logs to track the performance of API calls and function calls, or to count the occurrence of significant events in your applications (e.g., logins, signups, and downloads). Whether you’re operating a microservices architecture or a monolith, implementing a comprehensive PHP logging strategy will allow you to track critical changes in your applications and optimize their performance.
PHP and its available logging libraries give you many options for where to send and store your logs. As you’ll see in this post, storing your PHP logs in a central file is simple and gives you the greatest flexibility for processing and analyzing your logs later on. When you use a specialized tool to tail your log file and forward your logs to a central log management solution, your application code isn’t burdened with the overhead of buffering logs and handling network errors.
In this post, you’ll learn how to:
- configure the PHP system logger to automatically log errors
- use native PHP functions to log custom errors
- expand your logging capabilities with the Monolog logging library
- capture PHP exceptions and arbitrary events
How PHP creates logs
The PHP system logger creates logs automatically when the execution of your code produces an error. Additionally, you can create logs by calling PHP’s logging functions as you need to log custom errors and arbitrary events in your application. In this section, we’ll look at how logs are created and routed by each of these mechanisms.
The PHP system logger
You can configure the PHP system logger by using the error_reporting
directive in PHP’s configuration file, php.ini, to designate the types of errors PHP will automatically log. This directive uses a set of predefined constants and bitwise operators to express what types of events to include and exclude from logs. For example, you would use this directive to log all errors:
PHP’s display_errors
configuration directive gives you the option of displaying log messages in the browser. In a production environment, you should always set display_errors
to Off
for security reasons. However, in a development environment, you might want to display warnings and errors directly in the browser so developers can easily see information about the application’s status.
The PHP system logger routes logs in different ways depending on the value of the error_log
configuration directive in php.ini:
- If
error_log
names a file, PHP writes its logs to that file. - If
error_log
is set tosyslog
, PHP sends logs to the OS logger. This is usuallysyslog
or the newerrsyslog
(which implements the syslog protocol) on Linux, orEvent Log
on Windows. - If
error_log
is unset, PHP creates logs using the Server API (SAPI). The SAPI used depends on your platform. As an example, a LAMP setup usesapache
as a SAPI, and logs are written to Apache’s error log.
To maximize the logging data available and to give yourself options for centralizing, processing, and analyzing your logs later, add the following configuration to your php.ini. (In PHP .ini files, a semicolon indicates the start of a comment.)
; Log all errors
error_reporting = E_ALL
; Don't display any errors in the browser
display_errors = Off
; Write all logs to this file:
error_log = my_file.log
Now your PHP logs are written to the my_file.log file we specified in the error_log
directive above.
PHP’s logging functions
You can log any event you choose by explicitly calling PHP’s error_log()
or syslog()
function within your code. These functions create logs containing the message string you provide. The syslog()
function will use the configuration in your rsyslog.conf file to write log messages. The error_log()
function routes it to the file specified by the error_log
configuration directive. The following example sends a message to the PHP system logger:
<?php
error_log("An error has occurred.");
The PHP system logger automatically adds a timestamp to each log, so each time this code runs, a line like the one below will be appended to our my_file.log file:
[15-Apr-2019 20:25:11 UTC] An error has occurred.
If no value is provided for the error_log
configuration item in php.ini, logs are generated by the SAPI, and their format depends on the SAPI in use. For example, on a LAMP server with Apache’s default logging configuration, the example code shown above adds the following line to Apache’s error log (e.g., /var/log/apache2/error.log):
[Mon Apr 15 20:25:11.950260 2019] [php7:notice] [pid 26154] [client 123.123.123.123:57728] An error has occurred.
PHP’s error_log()
and syslog()
functions provide more options for configuring where your logs are sent. For example, when you call error_log()
, you can provide a path to the file where the message should be logged that is different from the one defined by the error_log
directive. For information about the advanced routing capabilities of PHP’s error_log()
and syslog()
functions, see the PHP documentation. In this article, we will focus on logging to a file, since this gives you the ability to forward and process your logs, as we described above.
Centralizing and storing your logs
So far, we’ve looked at PHP’s system logger and native logging functions. These mechanisms don’t provide much flexibility when you want to customize how your logs are formatted or routed, but they make it easy to get started writing logs to a local file. You can also process your logs with an external service. Consider a strategy that combines writing logs to a local file and forwarding them to an external service to aggregate, analyze, and monitor your logs. This way, you can offload log processing and long-term storage and aggregate logs from all your hosts in a single platform. You can troubleshoot an incident much more efficiently if you don’t have to manually log into each of your servers to view logs.
When you use a log management and analytics platform like Datadog, we recommend using JSON-formatted logs. This makes it easy to process, search, filter, and monitor your logs. To make it easy to create JSON logs and route them to a file, we recommend that you use the Monolog logging library. In the next section we will cover how to use the Monolog library to format your logs as JSON and automatically add metadata to all your logs.
The Monolog logging library
Monolog is one of the most widely used PHP logging libraries. It provides all the functionality of PHP’s native logging functions, and makes it easy to create PHP logs in different formats. You can easily differentiate logs within a single application by categorizing them in channels, and you can send your logs to databases, message queues, and external collaboration tools.
Monolog is available in the Packagist repository, and the examples in this section assume you’ve installed Monolog using Composer. If you already have Composer installed, all you need to do is issue this command to add Monolog to your project:
composer require monolog/monolog
In this section, we’ll look at some of the Monolog features that you can use to enhance your PHP logging. We’ll show you how to:
- create and organize logs using loggers and channels
- route logs using Monolog handlers
- use formatters to create JSON-formatted logs
- use processors to log uniform data
- assign appropriate log levels to events of different types
Loggers and channels
To start using Monolog, you need to create a logger—an instance of Monolog’s Logger
class:
<?php
// Load dependencies required by Composer (including Monolog):
require_once "vendor/autoload.php";
// Use Monolog's `Logger` namespace:
use MonologLogger;
$logger = new Logger('transactions');
This code creates a logger object named $logger
and gives it a channel name of transactions
.
Monolog uses channels to differentiate logs that have been routed to the same destination but that contain data about different categories of events. Each time you create a logger, you need to provide a channel name. You can create multiple loggers within your application and use each one to log events related to a category of activity, such as purchases or user accounts. Because each logger’s channel
value is associated with the logs it creates (as an object within a JSON-formatted log, for example), channels give you more latitude to use metadata to differentiate your logs.
Handlers
Monolog’s handlers determine how PHP will act on the log messages sent to each logger. The StreamHandler
is Monolog’s basic means of writing logs to a file. Numerous other handlers are available so you can easily send logs to the service of your choice.
Once you’ve created a logger, you use it by defining one or more handlers and pushing them onto the Logger
object. For each handler you create, you provide information about how it should route the log (e.g., a filename), and a minimum log level at which the handler should be triggered. By pushing multiple handlers onto a logger, you can use it to log different types of events to different destinations.
The following code illustrates pushing a handler on to the logger ($logger
) we created above. It then calls Monolog’s info
method to trigger the handler and log a message to the file /var/log/monolog/php.log:
<?php
require_once "vendor/autoload.php";
use MonologLogger;
use MonologHandlerStreamHandler;
$logger = new Logger('transactions');
// Declare a new handler and store it in the $logstream variable
// This handler will be triggered by events of log level INFO and above
$logstream = new StreamHandler('/var/log/monolog/php.log', Logger::INFO);
// Push the $logstream handler onto the Logger object
$logger->pushHandler($logstream);
$logger->info('A notable event has occurred.');
This logger creates logs in Monolog’s default format, but it’s easy to make Monolog structure your logs in a useful format. In the next sections of this post, we’ll look at the benefits you gain when you use the JsonFormatter
to create your logs.
Formatters
Monolog allows you to define a custom log format, or you can choose an existing formatter to determine how your log messages appear. Monolog formatters are available to meet different logging requirements, and you can choose the one that best suits your needs.
Monolog’s JSONFormatter
helps you structure your log data and lets you include any arbitrary data you require. This can make it easy to store multi-line errors in a single log line. You can also store information unique to each session by logging the PHP session array. JSON-formatted logs are easy for log management solutions to parse, so you can search, filter, and analyze your application’s data to track errors, usage, and performance trends.
The sample code below creates JSON logs with a channel value of transactions
.
<?php
require_once "vendor/autoload.php";
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologFormatterJsonFormatter;
$logger = new Logger('transactions');
$logstream = new StreamHandler('/var/log/monolog/php.log', Logger::INFO);
// Apply Monolog's built-in JsonFormatter
$logstream->setFormatter(new JsonFormatter());
$logger->pushHandler($logstream);
$logger->info('Transaction complete');
When PHP executes this code, a log is added to the specified file—/var/log/monolog/php.log—that looks like this:
{
"message": "Transaction complete",
"context": [],
"level": 200,
"level_name": "INFO",
"channel": "transactions",
"datetime": {
"date": "2019-02-14 17:19:11.332526",
"timezone_type": 3,
"timezone": "UTC"
},
"extra": []
}
To isolate these logs from those created by other loggers in your application, you can use a log management solution to filter your data and view only logs from the transactions
channel.
Notice that Monolog automatically adds two arrays to this log—context
and extra
. You can use these arrays to enrich your logs and provide more information about the activity you’re logging. In the next section, we’ll look at how to create and populate these arrays.
Processors
The context
and extra
arrays give you options for easily adding metadata to each log. You can use them to store any data that’s useful to you. We recommend using context
to log the high-cardinality data that varies between sessions, and extra
to log global metadata that’s common to all requests. In this section we’ll illustrate how you can use the two arrays to store different kinds of data.
You can use a Monolog processor to define metadata to be added to each log’s context
and extra
arrays. Processors make it easy to include the same information consistently across all the logs created by a single logger. The following example defines a Monolog processor to include context
and extra
data:
<?php
require_once "vendor/autoload.php";
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologFormatterJsonFormatter;
$logger = new Logger('transactions');
$logstream = new StreamHandler('/var/log/monolog/php.log', Logger::INFO);
$logstream->setFormatter(new JsonFormatter());
$logger->pushHandler($logstream);
$logger->pushProcessor(function ($record) {
$record['extra']['env'] = 'staging';
$record['extra']['version'] = '1.1';
$record['context'] = array('user' => $_SESSION["user"], 'customerID' => $_SESSION["customerID"], 'checkoutValue' => $_SESSION["checkoutValue"], 'sku_array' => $_SESSION["sku"]);
return $record;
});
$logger->info('Transaction complete');
In the resulting log, both the context
and extra
arrays are populated.
{
"message": "Transaction complete",
"context": {
"user": "user@example.com",
"customerID": 12102,
"checkoutValue": "17.39",
"sku_array": [468, 116]
},
"level": 200,
"level_name": "INFO",
"channel": "transactions",
"datetime": {
"date": "2019-04-16 15:46:16.531986",
"timezone_type": 3,
"timezone": "UTC"
},
"extra": {
"env": "staging",
"version": "1.1"
}
}
You can also pass context
array data as an argument to the method you use to create the log. The example below illustrates passing the log message and context data in a single call:
$logger->info('Transaction complete', array('user' => $_SESSION["user"], 'customerID' => $_SESSION["customerID"], 'checkoutValue' => $_SESSION["checkoutValue"], 'sku_array' => $_SESSION["sku"]));
Log levels
PHP’s error_log()
function assumes all messages describe errors within your application, but Monolog allows you to log other types of PHP events as well. Monolog supports eight different log levels—the same ones defined in the syslog protocol—so that each log carries metadata that conveys the severity of the event being logged.
When you call the Monolog function to create a log, you specify the log’s level. This way, you
can log the types of events (e.g., debug
, error
, or alert
) you need to know about. For example, to log an event whose log level is error
, you would call the logger’s error
method as shown below:
$logger->error('Transaction failed');
Of course, you don’t want to have to revise your code during an outage to log debug messages. Instead you can configure your application to log events of all levels, and use a log management solution to filter logs downstream to isolate certain kinds of events.
Expanding your logging coverage
Because PHP logging is flexible, you have options in how much to log and how to handle your logs. In this section, we’ll look at how PHP exceptions work and how to capture them. We’ll also show you how to expand your logging to capture useful information about different types of events—not just errors.
Centralize and organize your PHP logging for easier analysis with Datadog.
Catch and log exceptions
Like many other languages, PHP uses exceptions to accommodate unintended behavior by your application. An exception is an object PHP creates (or throws) when the execution of your PHP script reaches an unintended state.
Exceptions should be caught when they occur—governed by code that addresses the exceptional case. The exception handler—the code that catches the exception—defines PHP’s behavior and output when faced with an exception. PHP does not automatically log exceptions when they are thrown, so you should create exception handlers that log useful information about the exception.
The code below shows an example of a basic exception handling strategy. The checkUsername
function validates the length of the string passed to it, then throws exceptions under certain conditions. The function is called from within a try
block, and a catch
block handles any exceptions and logs the details.
<?php
require_once "vendor/autoload.php";
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologFormatterJsonFormatter;
$logger = new Logger('signups');
$logstream = new StreamHandler('/var/log/monolog/php.log', Logger::INFO);
$logstream->setFormatter(new JsonFormatter());
$logger->pushHandler($logstream);
function checkUsername($username) {
if (strlen($username) < 4) {
throw new Exception("Username $username is not long enough.");
} else if (strlen($username) > 12) {
throw new Exception("Username $username is too long.");
}
// $username is OK
}
try {
checkUsername('me');
} catch (exception $e) {
$message_string = "{$e->getMessage()} (file: {$e->getFile()}, line: {$e->getLine()})";
$logger->error($message_string);
}
When PHP throws an exception, it creates an exception object (named $e
in the example above) that is available for the exception handler to use. The exception object contains properties, such as the file and lines of code that have caused the unintended state, that describe the state of the application. It also provides methods you can use to access those properties (such as getMessage()
in the example above). You can use an exception handler to access the data contained in the exception object and log details of the exception.
The code above will append a line like this one to the file /var/log/monolog/php.log:
{
"message": "Username me is not long enough. (file: /var/www/html/checkUsername.php, line: 17)",
"context": [],
"level": 400,
"level_name": "ERROR",
"channel": "signups",
"datetime": {
"date": "2019-04-11 20:33:45.500634",
"timezone_type": 3,
"timezone": "UTC"
},
"extra": []
}
Better than logging only the message returned by the exception’s getMessage()
method, you should log the exception object itself. The PHP logging standard that Monolog implements, PSR-3, states that a logged exception must be in the exception
element of the context
array. To log the whole exception object, change the $logger->error()
call in the previous example to look like this instead:
$logger->error("checkUsername failed", array('exception' => $e));
When you log the exception object, all the information it contains is recorded in the log as JSON, as shown in this example log:
{
"message": "checkUsername failed",
"context": {
"exception": {
"class": "Exception",
"message": "Username me is not long enough.",
"code": 0,
"file": "/var/www/html/checkUsername.php:16"
}
},
"level": 400,
"level_name": "ERROR",
"channel": "signups",
"datetime": {
"date": "2019-04-24 15:01:17.656613",
"timezone_type": 3,
"timezone": "UTC"
},
"extra": []
}
If you use a log management service, you can use the exception object’s data to view, filter, and analyze your logs.
Catch unhandled exceptions
If your code doesn’t include a handler for a particular exception, PHP will generate a fatal error and halt execution. To prevent this, you can use PHP’s set_exception_handler()
function to define your own default exception handler. This way you can avoid the fatal error caused by an unhandled exception, and you can capture the exception in your logs. The example below uses set_exception_handler()
to catch and log any unhandled exceptions.
<?php
require_once "vendor/autoload.php";
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologFormatterJsonFormatter;
$logger = new Logger('signups');
$logstream = new StreamHandler('/var/log/monolog/php.log', Logger::INFO);
$logstream->setFormatter(new JsonFormatter());
$logger->pushHandler($logstream);
// Define default behavior if an exception isn't caught:
set_exception_handler( function($e) {
$uncaught_log = new Logger('uncaught');
$uncaught_logstream = new StreamHandler('/var/log/monolog/php.log', Logger::ERROR);
$uncaught_logstream->setFormatter(new JsonFormatter());
$uncaught_log->pushHandler($uncaught_logstream);
$uncaught_log->error("Uncaught exception", array('exception' => $e));
});
// Declare an empty class
class myClass {
// empty
}
// Try to call a non-existent function
try {
myClass::myFunction();
} catch (Exception $e) {
$logger->error("Call to myFunction failed", array('exception' => $e));
}
In this code, set_exception_handler()
processes the exception thrown when the nonexistent myFunction()
is called. It serves as the default exception handler, and will process any uncaught exceptions throughout the script (any of which would otherwise have caused a PHP fatal error).
When this code is executed, it logs an exception like the one below:
{
"message": "Uncaught exception",
"context": {
"exception": {
"class": "Error",
"message": "Call to undefined method myClass::myFunction()",
"Code": 0,
"file": "/var/www/html/test_exception_handler.php:30"
}
},
"level": 400,
"level_name": "ERROR",
"channel": "uncaught",
"datetime": {
"date": "2019-04-11 19:20:20.241717",
"timezone_type": 3,
"timezone": "UTC"
},
"extra": []
}
Note that it does not log the Call to myFunction failed
error from the catch
block. The code in the catch
block would execute if myFunction()
threw an exception, but in this case PHP throws an exception when we try to call the nonexistent myFunction()
. Since that exception is uncaught, it gets processed by the function defined in set_exception_handler()
.
Log events (not just errors)
In addition to the errors the PHP system logger records automatically, you can log custom events such as API calls to and from your application. Logging these events allows you to monitor your application’s performance and usage trends. In an application made up of microservices, pretty much everything will be an API call, and you can add custom logging code around any calls worthy of attention. The example below calculates the response time of an API call, then uses Monolog to log the result.
<?php
require_once "vendor/autoload.php";
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologFormatterJsonFormatter;
$logger = new Logger('APIperformance');
$logstream = new StreamHandler('/var/log/monolog/php.log', Logger::INFO);
$logstream->setFormatter(new JsonFormatter());
$logger->pushHandler($logstream);
function myAPIcall() {
$curl = curl_init();
$url = 'http://dummy.restapiexample.com/api/v1/employees';
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
$logger->pushProcessor(function ($record) {
$record['extra']['env'] = 'staging';
$record['extra']['version'] = '1.1';
return $record;
});
$start = microtime(TRUE); // A timestamp before the call
$result = myAPIcall();
$end = microtime(TRUE); // Another timestamp after the call
// Log the call duration as a readable string
// and include the context array
$logger->info("myAPIcall took " . ($end - $start) . " seconds.", array('duration' => ($end - $start)), array('user' => $_SESSION["user"], 'customerID' => $_SESSION["customerID"], 'checkoutValue' => $_SESSION["checkoutValue"], 'sku_array' => $_SESSION["sku"]));
Each time this function runs, your logs collect data on the performance of the API call, which you can visualize in a service like Datadog:
In addition to logging API calls, you can expand your logging coverage to capture logins and logouts, as well as other user activity such as signups and transactions.
With all your logs aggregated in one place, Datadog’s Log Analytics makes it easy for you to visualize log data. For example, you can see your aggregated log volume, grouped by channel to understand the amount of activity across the different areas of your application.
From this view, you can export the graph to a dashboard or click to see individual logs. You can even create a monitor to alert on your log data, so you can automatically be notified of any unusual activity captured in your application logs.
For further information about using Monolog and Datadog, see our documentation.
Do more with your PHP logs
PHP logging offers a lot of flexibility that enables you to capture the right information and make it available for troubleshooting and monitoring. Once you’ve configured your applications to log all the information that might be useful to you, you can send your logs to a monitoring platform for in-depth analysis and collaborative troubleshooting. If you’re not already using Datadog to collect and analyze your logs, you can start with a free, full-featured 14-day trial.
PHP offers strong methods to work with PHP error logs, which you can log manually and automate. Also, we have some third-party tools built by the open-source community to handle the PHP error logging process.
The most important thing is when and how to log errors. You can log PHP errors at your will when working in the dev mode. Either create a PHP error log file or save them as notifications on different channels, as you get the convenience of logging errors per your requirements.
This guide focuses on the basics of logs in PHP, their configuration, and where you can find them. Also, this guide details how logging helps you be more compelling when troubleshooting and monitoring your PHP applications.
- Different Types of PHP Errors
- Warning Error
- Notice Error
- Syntax Error
- Fatal Error
- Getting Started with PHP Error Logging
- Enable Error Logging in php.ini
- How Do I View PHP Logging Error?
- Method 1: Using the .htaccess File
- Method 2: Using php.ini File
- Copy PHP Error Logs to File
- Error logging in PHP Frameworks
- Error Logging In Laravel
- Automating PHP Error Logging Process
- How PHP Errors Are Logged on Cloudways
- Final Words
When working in production mode, you must create a smooth workflow to enable PHP error logging so the users don’t face any glitches during runtime execution.
Stop Wasting Time on Servers
Cloudways handle server management for you so you can focus on creating great apps and keeping your clients happy.
Different Types of PHP Errors
PHP errors occur when something is off-base within the code. They can be as complex as calling an incorrect variable or as simple as missing a semicolon. You must understand the kind of errors you face to solve them effectively. So, let’s find out more about common PHP errors.
Warning Error
PHP warning errors alert about a problem that may cause a more critical error in the long run. Warning errors do not break down the code execution and commonly occur when using a file path that doesn’t exist.
For example, if this error pops up, you must check the file name in the code or directory, as the script may not find it due to the syntax error.
For instance:
<?php echo "Warning error"'; include ("external_file.php"); ? >
There is no file named “external_file,” so the output will display an error message box, and the execution will not break down.
Notice Error
Notice errors are minor; like warning errors, they don’t halt code execution. These errors can confuse the system in analyzing if there’s an actual mistake or if it’s just the standard code. Notice errors usually occur when the script needs access to an undefined variable.
Syntax Error
A syntax error is often caused by parsed, misused, or missing symbols. When the compiler catches the error, it terminates the script.
Parse/syntax errors are caused by:
- Unclosed brackets or quotes
- Missing or extra semicolons or parentheses
- Misspellings
Here’s an example of a parse error message:
PHP Parse error: syntax error, unexpected ‘5’ (L_NAME), expecting ‘)’ in /home/u802426761/domains/username/public_html/wp-config.php on line 32
Fatal Error
A fatal error happens when the code calls the function, but the function itself isn’t characterized. Unlike other PHP errors, a fatal error breaks down the execution and sometimes crashes the application as well. There are three types of fatal errors:
- A startup fatal error happens when the framework can’t run the code due to a mistake during installation.
- A compile-time fatal error occurs when the developer uses an undefined function, class, or non-existent variable or data.
- Runtime fatal error is similar to a compile-time fatal error, but happens during the program execution.
Here’s an example of a PHP fatal error:
PHP Fatal error: Call to undefined function get_header() in /var/www/username/public/blog/wp-content/themes/theme/index.php on line 37
Another reason for a fatal error is exceeding the execution time:
Fatal error: Maximum execution time of 30 seconds exceeded in /home/username/domains/domain.com/public_html/wp-includes/class-phpmailer.php on line 737
Getting Started with PHP Error Logging
PHP is the most widely used programming language for developing web applications. According to the BuiltWith insights, today almost.websites are using PHP as their backend language, which makes it around 75% of all the websites in the world. These stats clearly show that PHP still has a solid market share in the programming world. When you start developing an application in PHP, you use a few commands like print_r()
,var_dump()
to debug errors and log on to the browser. But, that is not the safest way while working in production mode. In dev mode, you can do it, but have to disable it when initiating the migration. Hence, in dev mode, you can easily log errors in PHP with error_log()
function, which sends an error message to the defined error handling routines. Let’s suppose you are connecting MySQL database with PHP and if it fails to connect with it, you can log errors in PHP like this:
<?php // Send error message to the server log if error connecting to the database if (!mysqli_connect("localhost","bad_user","bad_password","my_db")) { error_log("Failed to connect to database!", 0); } // Send email to administrator if we run out of FOO if (!($foo = allocate_new_foo())) { error_log("Oh no! We are out of FOOs!", 1, "[email protected]"); } ?>
Enable Error Logging in php.ini
To log errors in PHP, open the php.ini file and uncomment/add the following lines of code.
error_reporting = E_ALL & ~E_NOTICE error_reporting = E_ALL & ~E_NOTICE | E_STRICT error_reporting = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ER… _ERROR error_reporting = E_ALL & ~E_NOTICE
If you want to enable PHP error logging in individual files, add this code at the top of the PHP file.
ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL);
Now, you must enable only one statement to parse the log errors in the php.ini file:
display_errors = on.
Now, you can easily see logged errors in your browser. Some of the additional commands you can write for PHP error logging include:
// Turn off all error reporting error_reporting(0); // Report simple running errors error_reporting(E_ERROR | E_WARNING | E_PARSE); // Reporting E_NOTICE can be good too (to report uninitialized variables or catch variable name misspellings ...) error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE); // Report all errors except E_NOTICE error_reporting(E_ALL & ~E_NOTICE); // Report all PHP errors (see changelog) error_reporting(E_ALL); // Report all PHP errors error_reporting(-1); // Same as error_reporting(E_ALL); ini_set('error_reporting', E_ALL);
How Do I View PHP Logging Error?
You can check the PHP error log only when it is enabled; in most cases, it is disabled by default. So, before changing code and the configuration, check the PHP info to ensure that PHP logging is enabled on your hosting account.
Method 1: Using the .htaccess File
You can enable the PHP error log by editing the .htaccess file. Find the .htaccess file in the site’s root directory using the file manager or an FTP client. However, go to the control panel’s settings or FTP client to show hidden files if the file is hidden.
Once you’ve found the .htaccess file, follow the steps below:
- Open the .htaccess file and insert the following code:
php_flag log_errors on
php_value error_reporting 32767
php_value error_log “error_log.txt - Create a file titled error_log.txt in the public_html directory
- Save and close the file
- All PHP error logs will be reported in the error_log.txt file
Now the PHP error logging is enabled, verify using the PHP info again, and the Local Value should be on. Don’t worry if the Master Value is still off, as the local value will override it.
If the website experiences any trouble, open the error_log.txt, and you’ll see the PHP error logs.
Method 2: Using php.ini File
The third method to enable the PHP error log is editing the php.ini file. It contains the default web server configuration to run PHP applications.
You can find the php.ini file by accessing the PHP info. Once you open it, press CTRL + F for Windows or Command + F for MacOS to open the search bar and look for the Loaded Configuration File section.
Another method to find the configuration file is using the command line.
Connect to the web server by using an SSH client and execute the following command:
php -i | grep php.ini
It should print output like this:
That said, here are the common directories for php.ini file depending on the operating system:
- CLI – /etc/php/7.4/cli/php.ini. Note that changing the PHP configuration in CLI won’t affect the web server.
- Apache – /etc/php/7.4/apache2/php.ini.
- Nginx or Apache with PHP-FPM – /etc/php/7.4/fpm/php.ini.
Copy PHP Error Logs to File
The above-defined practices work well when working in the dev environment. But, when you take your website live and start working in production mode, you must hide the errors from the on-screen display and log them within a backend file.
You can save these at a specific PHP error logs location whose URL is already described in the php.ini file.
PHP stores error logs in /var/log/apache2,if it uses an apache2 module. Shared hosts tend to store PHP error log files in your root directory /log subfolder. But…if you have access to the php.ini file you can do this by:
error_log = /var/log/php-scripts.log
If you’re using cPanel, the master log file, what you’re probably looking for is stored (by default) at:
/usr/local/apache/logs/error_log
If all else fails, you can check the PHP error logs location by using:
<?php phpinfo(); ?>
Error logging in PHP Frameworks
The above steps I’ve explained are for core PHP development. PHP has a variety of Model View Architecture (MVC) and micro-frameworks which have their methods on top of the core functions. Some of the best PHP MVC frameworks to build advanced web applications which include: Laravel, CodeIgniter, and Symfony.
Error Logging In Laravel
When you set up a new Laravel project, error logging and exception handling come pre-configured in it. Laravel has a separate class AppExceptionsHandler which takes care of all these issues. For logging Laravel errors, it utilizes the Monolog library which supports a variety of log handlers. Laravel configures several of these handlers for you, allowing you to choose between a single PHP error log file, rotating log files, and writing error information to the system log.
In the config/app.php file, you can configure the PHP option to log the errors on the display of the user. The value of this option can be set in the .env file under property APP_DEBUG which is an environment variable, thus setting up in the app.php file. When developing locally, the value can be set to true, and after migrating to production, it must be set to false. Otherwise, the security concern is always there as it will show error on the browser screen.
You, being the developer, can save Laravel log information on a single file, daily file, Syslog, and the errorlog. To configure these options for Laravel error logging, you must open the app.php file and edit the log option. For instance, if you want to set up daily logging for errors, you will do the following:
'log' => 'daily'
Monolog can log errors with different security warnings. By default, it adds all the errors in storage, but you can identify them as error, emergency, alert, critical, and warning. To do that, add ‘log_level‘ property in options like this:
'log_level' => env('APP_LOG_LEVEL', 'error'),
The log file is present in storage/logs. You can also log errors using log facades.
<?php namespace AppHttpControllers; use AppUser; use IlluminateSupportFacadesLog; use AppHttpControllersController; class UserController extends Controller { /** * Show the profile for the given user. * * @param int $id * @return Response */ public function showProfile($id) { Log::info('Showing user profile for user: '.$id); return view('user.profile', ['user' => User::findOrFail($id)]); } } The logger provides eight different logging levels, including: Log::emergency($message); Log::alert($message); Log::critical($message); Log::error($message); Log::warning($message); Log::notice($message); Log::info($message); Log::debug($message); Error Logging In Symfony
Symfony comes with a default logger which you can inject into the controller showing different warning levels. By default, log entries are written in the var/log/dev.log file when you’re in the var/log/prod.log
use PsrLogLoggerInterface; public function index(LoggerInterface $logger) { $logger->info('I just got the logger'); $logger->error('An error occurred'); $logger->critical('I left the oven on!', [ // include extra "context" info in your logs 'cause' => 'in_hurry', ]); // ... }
Since Symfony is the parent framework for Laravel, the warning levels of the framework are also the same.
Symfony also uses Monolog for error logging and pre-configures some basic handlers in the default monolog.yaml. Below is the example which uses syslogs to write logs on the file:
// config/packages/prod/monolog.php $container->loadFromExtension('monolog', [ 'handlers' => [ 'file_log' => [ 'type' => 'stream', 'path' => '%kernel.logs_dir%/%kernel.environment%.log', 'level' => 'debug', ], 'syslog_handler' => [ 'type' => 'syslog', 'level' => 'error', ], ], ]);
Automating PHP Error Logging Process
You can do the whole work of error logging manually, but when you are working in multiple teams and larger projects, you must set up an automated workflow that can log errors in third-party services like Sentry, Slack, Blackfire, etc.
These tools can provide you a better understanding of errors and their solutions. You can also set up Slack channels to send quick notifications to the teams about any runtime incidents.
You can see this nice example in Symfony which also works similarly.
Assume you have already set up the Slack channel and webhooks as:
monolog: handlers: main: type: fingers_crossed action_level: error handler: nested nested: type: stream path: "%kernel.logs_dir%/%kernel.environment%.log" level: debug console: type: console slack: type: slack token: xxxx-xxxxxxxxxxx-xxxxxxxxx-xxxxxxxxxx-xxxxxx channel: "#name-of-channel" bot_name: ChooseName icon_emoji: :ghost: level: critical
The emojis are also set up in the above example, have you seen that? 😀 This shows how you can send Slack notifications to any particular channel as per your needs.
How PHP Errors Are Logged on Cloudways
When you create an account on Cloudways web hosting for PHP and launch the PHP server with the application, you can see the log folder at the root directory which takes care of the server logs. You can find both Apache and Nginx logs there, which help you to identify the potential error logs. Since Cloudways does not allow users to edit php.ini file (you can ask a live support agent to do that for you); but if you carefully see the PHP server settings, you can customize most of the error_reporting and logging settings in the platform.
Of course, you also have access to PHP-FPM where you can add php.ini rules to log PHP errors.
Final Words
PHP error log helps you troubleshoot problems on a website by logging the error details, including the PHP file and code line that needs fixation.
This article has demonstrated how logging errors in PHP are configured in the php.ini file. Further, it discusses the right way to log errors and how to enable and automate PHP error logging, keeping the dev work on track.
If you find this article helpful and want to share your views about the topic, feel free to write down your suggestions in the comments below.
Q: Which PHP error logging library is best to use?
A: Monolog is one of the best PHP error logging libraries available in the market. It provides advanced logging operations for different handlers including database, browser console, chats solutions, and others.
Q: What to do if the PHP error log is not working?
A: First, set the log_errors = on in the php.ini file, it can help if your PHP error logging is not working.
If it still doesn’t work, make sure that the error_log directive is set and the directory in it must be writable by the user that Apache is running under.
Share your opinion in the comment section.
COMMENT NOW
Share This Article
Customer Review at
“Cloudways hosting has one of the best customer service and hosting speed”
Sanjit C [Website Developer]
Inshal Ali
Inshal is a Content Marketer at Cloudways. With background in computer science, skill of content and a whole lot of creativity, he helps business reach the sky and go beyond through content that speaks the language of their customers. Apart from work, you will see him mostly in some online games or on a football field.
Home / Log PHP errors with log_errors and error_log
PHP errors are by default logged to the web server’s error log file (at least they are with the default setup on most Linux distros) but it is also possible to instead log PHP errors to a file of your choice. This is useful on production websites so you can periodically check for errors and fix them in a location other than the default webserver error log file.
The log_errors configuration option is a boolean option. To log to an error log file specified with the error_log configuration option set this to 1.
error_log
The error_log configuration option is a string and is the filename of where to log errors. It can contain either a relative path or an absolute path as part of the filename. If «syslog» is used it is logged to to the system logger (syslog on *nix and the Event Log on Windows).
Set error logging with ini_set()
Although this is not ideal you can use the ini_set() function to set the above configuration options to log errors. It is not an ideal solution because it will not log any errors if the script has parse errors and cannot be run at all. For example:
ini_set("log_errors", 1); ini_set("error_log", "/path/to/php-error.log");
Set error logging in .htaccess and virtualhost directives
This is a better option because it will log the errors even if there’s a parsing error in your script.
php_value log_errors 1 php_value error_log /path/to/php-error.log
Example error log data
A couple of example lines from an error log are as follows:
[13-May-2009 21:54:04] PHP Notice: Undefined variable: x in /common/websites/test/error-log.php on line 6 [13-May-2009 21:54:09] PHP Parse error: syntax error, unexpected '}' in /common/websites/test/error-log.php on line 5
Error log must be writable by the web server
The error log will be written to as the user the web server runs as so it must be writeable by that user. In most cases you’ll probably need to make it world-writeable to be able to do this. On a *nix server this is 0666 file permissions.
Conclusion
It’s easy to set up a PHP error log using the log_errors and error_log configuration options. This can be set up on a website by website basis and you could potential combine it with a daily process to email errors to the webmaster (if there are any) on a daily basis. I’ll cover doing this in a later post.