Логи ошибок php ubuntu

I can guarantee you, I am not the only person who has been driven to madness at least once in a frustrating search for a log file. It seems like it should be the easiest thing to find in the whole system.

A definitive guide on where the PHP error log is stored would be a complicated bit of work. The official PHP manual does not even try to address the whole topic, because there are dependencies on systems outside PHP, such as the operating system (Linux vs. Windows, which distribution of Linux), including settings within Windows and Linux that affect the name and location of the PHP error log.

Until someone takes the time to write a complete, cross-system guide, the best you are going to get is general directions where you can inquire. Every PHP developer has had to endure agony in this pursuit, with one exception. If you work in one place and the information is provided when you first need it, then you have the information need forever, that is, until you find yourself in a new working environment. There are such fortunate people.

If the information is not given to you on a silver platter, so to speak, you have some hunting to do. The hunt is not the longest you will face in your career, but it is not the simplest either.

As is evident from the many answers already posted, a smart place to begin is the output of phpinfo(). To view it, create a PHP file containing this:

<?php
    phpinfo();

Either browse to that file or run it from the command line. If you do both, you likely will find the error_log is in different places, depending on command line vs. web server use of PHP. That is because the PHP interpreter that runs on a web server is not the same PHP interpreter that runs from the command line, even when the command line is on the same machine as the web server. The answers already posted in here mostly are making an unstated assumption that PHP is running as part of a web server.

Sample output from phpinfo() via web server and web browser

The default for error_log is no value

Default error_log in php running as an Apache mod.

Whatever the value is, it comes from the php.ini files used to configure PHP. There can be many php.ini files. Finding your way among them is confusing at first, but you do not need to deal with this to find your PHP log.

If the output from phpinfo() shows a full path to a file, that is where the log is. You are lucky.

The trick is there usually is not a full path indicated in phpinfo(). When there is not a full path, the location depends on:

  1. Whether error_log is no value. If it is, the log file location will depend on the operating system and the mode PHP is running. If PHP is running as an Apache module, on Linux the log often is in /var/log/apache2/error.log. Another likely spot is in a logs directory in your account home directory, ~/logs/error.log.

  2. If there is a file name without a path, the location depends on whether the file name has the value syslog. If it syslog, then the PHP error log is injected into the syslog for the server, which varies by Linux distribution. A common location is /var/log/syslog, but it can be anywhere. Even the name of the syslog varies by distribution.

  3. If the name without a path is not syslog, a frequent home for the file is is the document root of the website (a.k.a., website home directory, not to be confused with the home directory for your account).

This cheat sheet has been helpful in some situations, but I regret to have to admit it is not nearly universal. You have my condolences.

Enter image description here

I’ve installed Apache, PHP, and MySQL on Ubuntu 10.10 desktop edition, and it’s working fine.
Except I have no clue where to look for Apache or PHP log files.

kiri's user avatar

kiri

27.5k16 gold badges80 silver badges117 bronze badges

asked Nov 24, 2010 at 18:58

Stann's user avatar

By default, /var/log/apache2/error.log.

This can be configured in /etc/php5/apache2/php.ini.

Community's user avatar

answered Nov 24, 2010 at 19:18

misterben's user avatar

misterbenmisterben

7,1873 gold badges22 silver badges27 bronze badges

5

Check these settings in php.ini:

  1. error_reporting = E_ALL | E_STRICT (as recommended for development in php.ini)
  2. error_log = /var/log/php_errors.log
  3. Then create log file manually

    touch /var/log/php_errors.log
    chown www-data: /var/log/php_errors.log
    chmod +rw /var/log/php_errors.log
    

Now you can view PHP errors by this way

tail /var/log/php_errors.log

This is an agreeable solution to this issue for me.

Community's user avatar

answered Sep 7, 2012 at 23:13

Nikolay Chuprina's user avatar

2

You can also define a specific error log file for each VirtualHost in Apache. If you have any VirtualHost defined in /etc/apache2/sites-available/ and enabled in /etc/apache2/sites-enabled (enable with sudo a2ensite [your-virtualhost-definition-file]), you can change the error log by adding the following line inside your VirtualHost config:

ErrorLog ${APACHE_LOG_DIR}/[your-vhost]-error.log

That might be useful if you have a lot of vhosts and want to split where they report the errors.

Also, you can watch your error log live by issuing the following command (adapt to your own log file if different from the default):

sudo tail -f /var/log/apache2/error.log

This is particularly useful when doing live debugging.

Eliah Kagan's user avatar

Eliah Kagan

116k54 gold badges315 silver badges489 bronze badges

answered Jun 3, 2012 at 21:52

ywarnier's user avatar

ywarnierywarnier

4414 silver badges4 bronze badges

1

If Apache was setup with Webmin/Virtualmin there is a separate folder for each VirtualHost.

It is

~/logs

folder for each VirtualHost user.

These are two files:

~/logs/access_log

and

~/logs/error_log

So they are

/home/onedomain/logs/access_log

/home/onedomain/logs/error_log

/home/anotherdomain/logs/access_log

/home/anotherdomain/logs/error_log

...

etc.

To view log files for each particular domain login as VirtualHost owner user of that hostname and run

tail -f ~/logs/error_log

answered Apr 1, 2018 at 12:18

Ilyich's user avatar

IlyichIlyich

1413 bronze badges

If you use a bitnami distribution, it is at:

tail /opt/bitnami/apache2/logs/error_log

Bitnami distributions have their own directory structure. I had to find what it was for my server, and this is where it resides by default for bitnami. I would assume lots of people are looking for the same thing when using a bitnami distribution.

For more info see here: https://docs.bitnami.com/bch/infrastructure/lamp/troubleshooting/debug-errors-apache/

answered Oct 24, 2021 at 19:37

eyal_katz's user avatar

0

(PHP 4, PHP 5, PHP 7, PHP 8)

error_logSend an error message to the defined error handling routines

Description

error_log(
    string $message,
    int $message_type = 0,
    ?string $destination = null,
    ?string $additional_headers = null
): bool

Parameters

message

The error message that should be logged.

message_type

Says where the error should go. The possible message types are as
follows:

error_log() log types

0 message is sent to PHP’s system logger, using
the Operating System’s system logging mechanism or a file, depending
on what the error_log
configuration directive is set to. This is the default option.
1 message is sent by email to the address in
the destination parameter. This is the only
message type where the fourth parameter,
additional_headers is used.
2 No longer an option.
3 message is appended to the file
destination. A newline is not automatically
added to the end of the message string.
4 message is sent directly to the SAPI logging
handler.
destination

The destination. Its meaning depends on the
message_type parameter as described above.

additional_headers

The extra headers. It’s used when the message_type
parameter is set to 1.
This message type uses the same internal function as
mail() does.

Return Values

Returns true on success or false on failure.
If message_type is zero, this function always returns true,
regardless of whether the error could be logged or not.

Changelog

Version Description
8.0.0 destination and
additional_headers are now nullable.

Examples

Example #1 error_log() examples


<?php
// Send notification through the server log if we can not
// connect to the database.
if (!Ora_Logon($username, $password)) {
error_log("Oracle database not available!", 0);
}
// Notify administrator by email if we run out of FOO
if (!($foo = allocate_new_foo())) {
error_log("Big trouble, we're all out of FOOs!", 1,
"operator@example.com");
}
// another way to call error_log():
error_log("You messed up!", 3, "/var/tmp/my-errors.log");
?>

Notes

Warning

error_log() is not binary safe. message will be truncated by null character.

Tip

message should not contain null character. Note that message may be sent to file, mail, syslog, etc. Use appropriate conversion/escape function, base64_encode(), rawurlencode() or addslashes() before calling error_log().

kevindougans at gmail dot com

13 years ago


Advice to novices: This function works great along with "tail" which is a unix command to watch a log file live. There are versions of Tail for Windows too, like Tail for Win32 or Kiwi Log Viewer.

Using both error_log() and tail to view the php_error.log you can debug code without having to worry so much about printing debug messages to the screen and who they might be seen by.

Further Note: This works even better when you have two monitors setup. One for your browser and IDE and the other for viewing the log files update live as you go.


Sion

4 years ago


DO NOT try to output TOO LARGE texts in the error_log();

if you try to output massive amounts of texts it will either cut of the text at about 8ooo characters (for reasonable massive strings, < 32 K characters) or (for insanely massive strings, about 1.6 million characters) totally crash without even throwing an error or anything (I even put it in a try/catch without getting any result from the catch).

I had this problem when I tried to debug a response from a wp_remote_get(); all of my error_log() worked as they should, except for ONE of them... (-_-)
After about a day of debugging I finally found out why & that's why I type this.

Apparently the response contained a body with over 1.6 million chars (or bytes? (whatever strlen() returns)).

If you have a string of unknown length, use this:
$start_index = 0;
$end_index = 8000;
error_log( substr( $output_text , $start_index , $end_index ) );


frank at booksku dot com

16 years ago


Beware!  If multiple scripts share the same log file, but run as different users, whichever script logs an error first owns the file, and calls to error_log() run as a different user will fail *silently*!

Nothing more frustrating than trying to figure out why all your error_log calls aren't actually writing, than to find it was due to a *silent* permission denied error!


i dot buttinoni at intandtel dot com

15 years ago


Be carefull. Unexpected PHP dies when 2GByte of file log reached (on systems having upper file size limit).
A work aorund is rotate logs :)

php at kennel17 dot NOSPAM dot co dot uk

17 years ago


It appears that the system log = stderr if you are running PHP from the command line, and that often stderr = stdout.  This means that if you are using a custom error to both display the error and log it to syslog, then a command-line user will see the same error reported twice.

Anonymous

20 years ago


when using error_log to send email, not all elements of an extra_headers string are handled the same way.  "From: " and "Reply-To: " header values will replace the default header values. "Subject: " header values won't: they are *added* to the mail header but don't replace the default, leading to mail messages with two Subject fields.

<?php

error_log

("sometext", 1, "zigzag@my.domain",
 
"Subject: FoonFrom: Rizzlas@my.domainn");?>

---------------%<-----------------------
To: zigzag@my.domain
Envelope-to: zigzag@my.domain
Date: Fri, 28 Mar 2003 13:29:02 -0500
From: Rizzlas@my.domain
Subject: PHP error_log message
Subject: Foo
Delivery-date: Fri, 28 Mar 2003 13:29:03 -0500

sometext
---------------%<---------------------

quoth the docs: "This message type uses the same internal function as mail() does." 

mail() will also fail to set a Subject field based on extra_header data - instead it takes a seperate argument to specify a "Subject: " string.

php v.4.2.3, SunOS 5.8


russ at russtanner dot com

3 years ago


You can easily filter messages sent to error_log() using "tail" and "grep" on *nix systems. This makes monitoring debug messages easy to see during development.

Be sure to "tag" your error message with a unique string so you can filter it using "grep":

In your code:

error_log("DevSys1 - FirstName: $FirstName - LastName: $Lastname");

On your command line:

tail -f /var/log/httpd/error_log | grep DevSys1

In this example, we pipe apache log output to grep (STDIN) which filters it for you only showing messages that contain "DevSys1".

The "-f" option means "follow" which streams all new log entries to your terminal or to any piped command that follows, in this case "grep".


Matthew Swift

3 years ago


Relative paths are accepted as the destination of message_type 3, but beware that the root directory is determined by the context of the call to error_log(), which can change, so that one instance of error_log () in your code can lead to the creation of multiple log files in different locations.

In a WordPress context, the root directory will be the site's root in many cases, but it will be /wp-admin/ for AJAX calls, and a plugin's directory in other cases. If you want all your output to go to one file, use an absolute path.


paul dot chubb at abs dot gov dot au

15 years ago


When logging to apache on windows, both error_log and also trigger_error result in an apache status of error on the front of the message. This is bad if all you want to do is log information. However you can simply log to stderr however you will have to do all message assembly:

LogToApache($Message) {
        $stderr = fopen('php://stderr', 'w');
        fwrite($stderr,$Message);
        fclose($stderr);
}


SJL

15 years ago


"It appears that the system log = stderr if you are running PHP from the command line"

Actually, it seems that PHP logs to stderr if it can't write to the log file. Command line PHP falls back to stderr because the log file is (usually) only writable by the webserver.


stepheneliotdewey at GmailDotCom

15 years ago


Note that since typical email is unencrypted, sending data about your errors over email using this function could be considered a security risk. How much of a risk it is depends on how much and what type of information you are sending, but the mere act of sending an email when something happens (even if it cannot be read) could itself imply to a sophisticated hacker observing your site over time that they have managed to cause an error.

Of course, security through obscurity is the weakest kind of security, as most open source supporters will agree. This is just something that you should keep in mind.

And of course, whatever you do, make sure that such emails don't contain sensitive user data.


p dot lhonorey at nospam-laposte dot net

16 years ago


Hi !

Another trick to post "HTML" mail body. Just add "Content-Type: text/html; charset=ISO-8859-1" into extra_header string. Of course you can set charset according to your country or Env or content.

EG: Error_log("<html><h2>stuff</h2></html>",1,"eat@joe.com","subject  :lunchnContent-Type: text/html; charset=ISO-8859-1");

Enjoy !


eguvenc at gmail dot com

14 years ago


<?php

//Multiline error log class

// ersin güvenç 2008 eguvenc@gmail.com

//For break use "n" instead 'n'
Class log {

 
//

 
const USER_ERROR_DIR = '/home/site/error_log/Site_User_errors.log';

  const
GENERAL_ERROR_DIR = '/home/site/error_log/Site_General_errors.log';
/*

   User Errors...

  */

   
public function user($msg,$username)

    {

   
$date = date('d.m.Y h:i:s');

   
$log = $msg."   |  Date:  ".$date."  |  User:  ".$username."n";

   
error_log($log, 3, self::USER_ERROR_DIR);

    }

   
/*

   General Errors...

  */

   
public function general($msg)

    {

   
$date = date('d.m.Y h:i:s');

   
$log = $msg."   |  Date:  ".$date."n";

   
error_log($msg."   |  Tarih:  ".$date, 3, self::GENERAL_ERROR_DIR);

    }

}

$log = new log();

$log->user($msg,$username); //use for user errors

//$log->general($msg); //use for general errors

?>

franz at fholzinger dot com

18 years ago


In the case of missing your entries in the error_log file:
When you use error_log in a script that does not produce any output, which means that you cannot see anything during the execution of the script, and when you wonder why there are no error_log entries produced in your error_log file, the reasons can be:
- you did not configure error_log output in php.ini
- the script has a syntax error and did therefore not execute

daniel dot fukuda at gmail dot com

13 years ago


If you have a problem with log file permission *silently*
it's best to leave error_log directive unset so errors will be written in your Apache log file for current VirtualHost.

Anonymous

2 years ago


Depending on the error, you may also want to add an error 500 header, and a message for the user:

$message =  'Description of the error.';
error_log($message);
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
exit($message);


Robert Chapin

4 years ago


When error_log() unexpectedly uses stdout, you should check if the php.ini value for error_log is empty in your CLI environment.  Something as simple as this might restore expected behavior:

<?php ini_set('error_log', 'error_log'); ?>


kazezb at nospam dot carleton dot edu

17 years ago


It appears that error_log() only logs the first line of multi-line log messages. To log a multi-line message, either log each line individually or write the message to another file.

Anonymous

13 years ago


After scouring the internet for getting event logging to
work in syslog on Windows 2003, I found the following
from this post and was able to successfully get Windows
Event Viewer to log PHP errors/notices:

http://forums.iis.net/p/1159662/1912015.aspx#1913338

   1. Copy the PHP 5 binaries to "C:php".
   2. Right-click My Computer and select Properties to bring
up the Computer Properties dialog. Switch to the Advanced
tab and click Environment Variables. Find the system
environment variable PATH, edit it and add ";C:php"
(without the quotes) to the end.
   3. Make sure that the configuration file "php.ini" resides
in the directory "C:php" and contains the correct path
settings.
   4. DELETE any old "php.ini" files from "C:WINDOWS"
and other directories.
   5. Open REGEDIT, navigate to the key
"HKLMSOFTWAREPHP" and DELETE the string value
"IniFilePath" from there. It is outdated and no longer
necessary!
   6. Modify NTFS security permissions of the directory
"C:php" to give Read and Execute permissions to (1) the
IIS Guest Account and (2) the group IIS_WPG.
   7. Modify NTFS security permissions of the directories
"C:phpsession" and "C:phpupload" to give additional
Modify permissions to (1) the IIS Guest Account and (2)
the group IIS_WPG.
   8. Navigate to the registry key
"HKLMSYSTEMCurrentControlSetServicesEventlog
Application" and edit the value "CustomSD" there. Find
the substring "(D;;0xf0007;;;BG)" which Denies access to
the application event log for Builtin Guest accounts (like
the IIS Web User account) and replace this substring with
"(A;;0x3;;;BG)" which allows read and write access. Please
pay attention to leave the rest of the security string intact.
Damaging this value can have dangerous effects!
   9. Create or update the registry key
"HKLMSYSTEMCurrentControlSetServicesEventlogApplication
PHP-5.2.0" (adapt the last to your version part
if necessary) with the following values:

          * "EventMessageFile" (REG_EXPAND_SZ) = "C:phpphp5ts.dll"

          * "TypesSupported" (REG_DWORD) = 7


I’ve installed Apache, PHP, and MySQL on Ubuntu 10.10 desktop edition, and it’s working fine.
Except I have no clue where to look for Apache or PHP log files.

kiri's user avatar

kiri

27k16 gold badges79 silver badges115 bronze badges

asked Nov 24, 2010 at 18:58

Stann's user avatar

By default, /var/log/apache2/error.log.

This can be configured in /etc/php5/apache2/php.ini.

Community's user avatar

answered Nov 24, 2010 at 19:18

misterben's user avatar

misterbenmisterben

7,0973 gold badges22 silver badges27 bronze badges

5

Check these settings in php.ini:

  1. error_reporting = E_ALL | E_STRICT (as recommended for development in php.ini)
  2. error_log = /var/log/php_errors.log
  3. Then create log file manually

    touch /var/log/php_errors.log
    chown www-data: /var/log/php_errors.log
    chmod +rw /var/log/php_errors.log
    

Now you can view PHP errors by this way

tail /var/log/php_errors.log

This is an agreeable solution to this issue for me.

Community's user avatar

answered Sep 7, 2012 at 23:13

Nikolay Chuprina's user avatar

2

You can also define a specific error log file for each VirtualHost in Apache. If you have any VirtualHost defined in /etc/apache2/sites-available/ and enabled in /etc/apache2/sites-enabled (enable with sudo a2ensite [your-virtualhost-definition-file]), you can change the error log by adding the following line inside your VirtualHost config:

ErrorLog ${APACHE_LOG_DIR}/[your-vhost]-error.log

That might be useful if you have a lot of vhosts and want to split where they report the errors.

Also, you can watch your error log live by issuing the following command (adapt to your own log file if different from the default):

sudo tail -f /var/log/apache2/error.log

This is particularly useful when doing live debugging.

Eliah Kagan's user avatar

Eliah Kagan

115k52 gold badges310 silver badges482 bronze badges

answered Jun 3, 2012 at 21:52

ywarnier's user avatar

ywarnierywarnier

4414 silver badges4 bronze badges

1

If Apache was setup with Webmin/Virtualmin there is a separate folder for each VirtualHost.

It is

~/logs

folder for each VirtualHost user.

These are two files:

~/logs/access_log

and

~/logs/error_log

So they are

/home/onedomain/logs/access_log

/home/onedomain/logs/error_log

/home/anotherdomain/logs/access_log

/home/anotherdomain/logs/error_log

...

etc.

To view log files for each particular domain login as VirtualHost owner user of that hostname and run

tail -f ~/logs/error_log

answered Apr 1, 2018 at 12:18

Ilyich's user avatar

IlyichIlyich

1413 bronze badges

If you use a bitnami distribution, it is at:

tail /opt/bitnami/apache2/logs/error_log

Bitnami distributions have their own directory structure. I had to find what it was for my server, and this is where it resides by default for bitnami. I would assume lots of people are looking for the same thing when using a bitnami distribution.

For more info see here: https://docs.bitnami.com/bch/infrastructure/lamp/troubleshooting/debug-errors-apache/

answered Oct 24, 2021 at 19:37

eyal_katz's user avatar

0

Лог ошибок PHP (PHP error log-file) может быть включен и выключен в каждом конкретном случае, например, для каждого сайта или директории отдельно.

Включение логов ошибок PHP в скрипте

Для работы с PHP логами используй следующий код в PHP скрипте:

ini_set("log_errors", 1); // включить лог ошибок
ini_set("error_log", "/tmp/php-error.log"); // расположение лог-файла ошибок
error_log( "Hello, errors!" ); // записать в лог-файл значение/строку

Для просмотра файла в терминале GNU/Linux пишем:

tail -f /tmp/php-error.log

Включение логов ошибок PHP в htaccess

Если ты не имеешь доступ к файлу «php.ini» (файл конфигурации PHP), то ты можешь добавить следующий код в файл «.htaccess», чтобы включить запись лог-файлов PHP (при работе PHP в режиме модуля для Apache):

<IfModule mod_php5.c>
php_flag log_errors on
php_value error_log /home/USERNAME/public_html/MY_PHP_ERRORS.log
</IfModule>

Где PHP хранит файл логов по-умолчанию

PHP хранит логи ошибок в директории «/var/log/apache2», если PHP является модулем Apache. Иногда для отдельных хостов (сайтов) лог файл PHP хранится в папке «/log» коренной директории сайта. Если ты имеешь доступ к файлу «php.ini», то ты можешь изменить такое поведение изменив значение директивы «error_log«, например так:

error_log = /var/log/php-scripts.log

Если ты используешь cPanel, то главный лог-файл по-умолчанию будет по следующему адресу: «/usr/local/apache/logs/error_log».

Общая информация о лог-файлах в текущей конфигурации PHP

Посмотреть текущую информацию о лог-файлах PHP можно на странице «phpinfo» в разделе «Core». Полезные директивы:

  • error_log — указывает местонахождение используемого лог-файла;
  • log_errors — включение/отключение логгирования;
  • log_errors_max_len — максимальная длинна лога.

I can guarantee you, I am not the only person who has been driven to madness at least once in a frustrating search for a log file. It seems like it should be the easiest thing to find in the whole system.

A definitive guide on where the PHP error log is stored would be a complicated bit of work. The official PHP manual does not even try to address the whole topic, because there are dependencies on systems outside PHP, such as the operating system (Linux vs. Windows, which distribution of Linux), including settings within Windows and Linux that affect the name and location of the PHP error log.

Until someone takes the time to write a complete, cross-system guide, the best you are going to get is general directions where you can inquire. Every PHP developer has had to endure agony in this pursuit, with one exception. If you work in one place and the information is provided when you first need it, then you have the information need forever, that is, until you find yourself in a new working environment. There are such fortunate people.

If the information is not given to you on a silver platter, so to speak, you have some hunting to do. The hunt is not the longest you will face in your career, but it is not the simplest either.

As is evident from the many answers already posted, a smart place to begin is the output of phpinfo(). To view it, create a PHP file containing this:

<?php
    phpinfo();

Either browse to that file or run it from the command line. If you do both, you likely will find the error_log is in different places, depending on command line vs. web server use of PHP. That is because the PHP interpreter that runs on a web server is not the same PHP interpreter that runs from the command line, even when the command line is on the same machine as the web server. The answers already posted in here mostly are making an unstated assumption that PHP is running as part of a web server.

Sample output from phpinfo() via web server and web browser

The default for error_log is no value

Default error_log in php running as an Apache mod.

Whatever the value is, it comes from the php.ini files used to configure PHP. There can be many php.ini files. Finding your way among them is confusing at first, but you do not need to deal with this to find your PHP log.

If the output from phpinfo() shows a full path to a file, that is where the log is. You are lucky.

The trick is there usually is not a full path indicated in phpinfo(). When there is not a full path, the location depends on:

  1. Whether error_log is no value. If it is, the log file location will depend on the operating system and the mode PHP is running. If PHP is running as an Apache module, on Linux the log often is in /var/log/apache2/error.log. Another likely spot is in a logs directory in your account home directory, ~/logs/error.log.

  2. If there is a file name without a path, the location depends on whether the file name has the value syslog. If it syslog, then the PHP error log is injected into the syslog for the server, which varies by Linux distribution. A common location is /var/log/syslog, but it can be anywhere. Even the name of the syslog varies by distribution.

  3. If the name without a path is not syslog, a frequent home for the file is is the document root of the website (a.k.a., website home directory, not to be confused with the home directory for your account).

This cheat sheet has been helpful in some situations, but I regret to have to admit it is not nearly universal. You have my condolences.

Enter image description here

(PHP 4, PHP 5, PHP 7, PHP 8)

error_logSend an error message to the defined error handling routines

Description

error_log(
    string $message,
    int $message_type = 0,
    ?string $destination = null,
    ?string $additional_headers = null
): bool

Parameters

message

The error message that should be logged.

message_type

Says where the error should go. The possible message types are as
follows:

error_log() log types

0 message is sent to PHP’s system logger, using
the Operating System’s system logging mechanism or a file, depending
on what the error_log
configuration directive is set to. This is the default option.
1 message is sent by email to the address in
the destination parameter. This is the only
message type where the fourth parameter,
additional_headers is used.
2 No longer an option.
3 message is appended to the file
destination. A newline is not automatically
added to the end of the message string.
4 message is sent directly to the SAPI logging
handler.
destination

The destination. Its meaning depends on the
message_type parameter as described above.

additional_headers

The extra headers. It’s used when the message_type
parameter is set to 1.
This message type uses the same internal function as
mail() does.

Return Values

Returns true on success or false on failure.
If message_type is zero, this function always returns true,
regardless of whether the error could be logged or not.

Changelog

Version Description
8.0.0 destination and
additional_headers are now nullable.

Examples

Example #1 error_log() examples


<?php
// Send notification through the server log if we can not
// connect to the database.
if (!Ora_Logon($username, $password)) {
error_log("Oracle database not available!", 0);
}
// Notify administrator by email if we run out of FOO
if (!($foo = allocate_new_foo())) {
error_log("Big trouble, we're all out of FOOs!", 1,
"operator@example.com");
}
// another way to call error_log():
error_log("You messed up!", 3, "/var/tmp/my-errors.log");
?>

Notes

Warning

error_log() is not binary safe. message will be truncated by null character.

Tip

message should not contain null character. Note that message may be sent to file, mail, syslog, etc. Use appropriate conversion/escape function, base64_encode(), rawurlencode() or addslashes() before calling error_log().

kevindougans at gmail dot com

12 years ago


Advice to novices: This function works great along with "tail" which is a unix command to watch a log file live. There are versions of Tail for Windows too, like Tail for Win32 or Kiwi Log Viewer.

Using both error_log() and tail to view the php_error.log you can debug code without having to worry so much about printing debug messages to the screen and who they might be seen by.

Further Note: This works even better when you have two monitors setup. One for your browser and IDE and the other for viewing the log files update live as you go.

Sion

4 years ago


DO NOT try to output TOO LARGE texts in the error_log();

if you try to output massive amounts of texts it will either cut of the text at about 8ooo characters (for reasonable massive strings, < 32 K characters) or (for insanely massive strings, about 1.6 million characters) totally crash without even throwing an error or anything (I even put it in a try/catch without getting any result from the catch).

I had this problem when I tried to debug a response from a wp_remote_get(); all of my error_log() worked as they should, except for ONE of them... (-_-)
After about a day of debugging I finally found out why & that's why I type this.

Apparently the response contained a body with over 1.6 million chars (or bytes? (whatever strlen() returns)).

If you have a string of unknown length, use this:
$start_index = 0;
$end_index = 8000;
error_log( substr( $output_text , $start_index , $end_index ) );

frank at booksku dot com

16 years ago


Beware!  If multiple scripts share the same log file, but run as different users, whichever script logs an error first owns the file, and calls to error_log() run as a different user will fail *silently*!

Nothing more frustrating than trying to figure out why all your error_log calls aren't actually writing, than to find it was due to a *silent* permission denied error!

i dot buttinoni at intandtel dot com

14 years ago


Be carefull. Unexpected PHP dies when 2GByte of file log reached (on systems having upper file size limit).
A work aorund is rotate logs :)

php at kennel17 dot NOSPAM dot co dot uk

17 years ago


It appears that the system log = stderr if you are running PHP from the command line, and that often stderr = stdout.  This means that if you are using a custom error to both display the error and log it to syslog, then a command-line user will see the same error reported twice.

Anonymous

19 years ago


when using error_log to send email, not all elements of an extra_headers string are handled the same way.  "From: " and "Reply-To: " header values will replace the default header values. "Subject: " header values won't: they are *added* to the mail header but don't replace the default, leading to mail messages with two Subject fields.

<?php

error_log

("sometext", 1, "zigzag@my.domain",
 
"Subject: FoonFrom: Rizzlas@my.domainn");?>

---------------%<-----------------------
To: zigzag@my.domain
Envelope-to: zigzag@my.domain
Date: Fri, 28 Mar 2003 13:29:02 -0500
From: Rizzlas@my.domain
Subject: PHP error_log message
Subject: Foo
Delivery-date: Fri, 28 Mar 2003 13:29:03 -0500

sometext
---------------%<---------------------

quoth the docs: "This message type uses the same internal function as mail() does." 

mail() will also fail to set a Subject field based on extra_header data - instead it takes a seperate argument to specify a "Subject: " string.

php v.4.2.3, SunOS 5.8

russ at russtanner dot com

3 years ago


You can easily filter messages sent to error_log() using "tail" and "grep" on *nix systems. This makes monitoring debug messages easy to see during development.

Be sure to "tag" your error message with a unique string so you can filter it using "grep":

In your code:

error_log("DevSys1 - FirstName: $FirstName - LastName: $Lastname");

On your command line:

tail -f /var/log/httpd/error_log | grep DevSys1

In this example, we pipe apache log output to grep (STDIN) which filters it for you only showing messages that contain "DevSys1".

The "-f" option means "follow" which streams all new log entries to your terminal or to any piped command that follows, in this case "grep".

Matthew Swift

3 years ago


Relative paths are accepted as the destination of message_type 3, but beware that the root directory is determined by the context of the call to error_log(), which can change, so that one instance of error_log () in your code can lead to the creation of multiple log files in different locations.

In a WordPress context, the root directory will be the site's root in many cases, but it will be /wp-admin/ for AJAX calls, and a plugin's directory in other cases. If you want all your output to go to one file, use an absolute path.

paul dot chubb at abs dot gov dot au

14 years ago


When logging to apache on windows, both error_log and also trigger_error result in an apache status of error on the front of the message. This is bad if all you want to do is log information. However you can simply log to stderr however you will have to do all message assembly:

LogToApache($Message) {
        $stderr = fopen('php://stderr', 'w');
        fwrite($stderr,$Message);
        fclose($stderr);
}

SJL

15 years ago


"It appears that the system log = stderr if you are running PHP from the command line"

Actually, it seems that PHP logs to stderr if it can't write to the log file. Command line PHP falls back to stderr because the log file is (usually) only writable by the webserver.

stepheneliotdewey at GmailDotCom

15 years ago


Note that since typical email is unencrypted, sending data about your errors over email using this function could be considered a security risk. How much of a risk it is depends on how much and what type of information you are sending, but the mere act of sending an email when something happens (even if it cannot be read) could itself imply to a sophisticated hacker observing your site over time that they have managed to cause an error.

Of course, security through obscurity is the weakest kind of security, as most open source supporters will agree. This is just something that you should keep in mind.

And of course, whatever you do, make sure that such emails don't contain sensitive user data.

p dot lhonorey at nospam-laposte dot net

16 years ago


Hi !

Another trick to post "HTML" mail body. Just add "Content-Type: text/html; charset=ISO-8859-1" into extra_header string. Of course you can set charset according to your country or Env or content.

EG: Error_log("<html><h2>stuff</h2></html>",1,"eat@joe.com","subject  :lunchnContent-Type: text/html; charset=ISO-8859-1");

Enjoy !

eguvenc at gmail dot com

14 years ago


<?php//Multiline error log class

// ersin güvenç 2008 eguvenc@gmail.com

//For break use "n" instead 'n'

Class log {//const USER_ERROR_DIR = '/home/site/error_log/Site_User_errors.log';

  const

GENERAL_ERROR_DIR = '/home/site/error_log/Site_General_errors.log';
/*

   User Errors...

  */

public function user($msg,$username)

    {

$date = date('d.m.Y h:i:s');$log = $msg."   |  Date:  ".$date."  |  User:  ".$username."n";error_log($log, 3, self::USER_ERROR_DIR);

    }

/*

   General Errors...

  */

public function general($msg)

    {

$date = date('d.m.Y h:i:s');$log = $msg."   |  Date:  ".$date."n";error_log($msg."   |  Tarih:  ".$date, 3, self::GENERAL_ERROR_DIR);

    }

}

$log = new log();$log->user($msg,$username); //use for user errors

//$log->general($msg); //use for general errors

?>

franz at fholzinger dot com

17 years ago


In the case of missing your entries in the error_log file:
When you use error_log in a script that does not produce any output, which means that you cannot see anything during the execution of the script, and when you wonder why there are no error_log entries produced in your error_log file, the reasons can be:
- you did not configure error_log output in php.ini
- the script has a syntax error and did therefore not execute

daniel dot fukuda at gmail dot com

13 years ago


If you have a problem with log file permission *silently*
it's best to leave error_log directive unset so errors will be written in your Apache log file for current VirtualHost.

Anonymous

2 years ago


Depending on the error, you may also want to add an error 500 header, and a message for the user:

$message =  'Description of the error.';
error_log($message);
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
exit($message);

Robert Chapin

4 years ago


When error_log() unexpectedly uses stdout, you should check if the php.ini value for error_log is empty in your CLI environment.  Something as simple as this might restore expected behavior:

<?php ini_set('error_log', 'error_log'); ?>

kazezb at nospam dot carleton dot edu

17 years ago


It appears that error_log() only logs the first line of multi-line log messages. To log a multi-line message, either log each line individually or write the message to another file.

Anonymous

13 years ago


After scouring the internet for getting event logging to
work in syslog on Windows 2003, I found the following
from this post and was able to successfully get Windows
Event Viewer to log PHP errors/notices:

http://forums.iis.net/p/1159662/1912015.aspx#1913338

   1. Copy the PHP 5 binaries to "C:php".
   2. Right-click My Computer and select Properties to bring
up the Computer Properties dialog. Switch to the Advanced
tab and click Environment Variables. Find the system
environment variable PATH, edit it and add ";C:php"
(without the quotes) to the end.
   3. Make sure that the configuration file "php.ini" resides
in the directory "C:php" and contains the correct path
settings.
   4. DELETE any old "php.ini" files from "C:WINDOWS"
and other directories.
   5. Open REGEDIT, navigate to the key
"HKLMSOFTWAREPHP" and DELETE the string value
"IniFilePath" from there. It is outdated and no longer
necessary!
   6. Modify NTFS security permissions of the directory
"C:php" to give Read and Execute permissions to (1) the
IIS Guest Account and (2) the group IIS_WPG.
   7. Modify NTFS security permissions of the directories
"C:phpsession" and "C:phpupload" to give additional
Modify permissions to (1) the IIS Guest Account and (2)
the group IIS_WPG.
   8. Navigate to the registry key
"HKLMSYSTEMCurrentControlSetServicesEventlog
Application" and edit the value "CustomSD" there. Find
the substring "(D;;0xf0007;;;BG)" which Denies access to
the application event log for Builtin Guest accounts (like
the IIS Web User account) and replace this substring with
"(A;;0x3;;;BG)" which allows read and write access. Please
pay attention to leave the rest of the security string intact.
Damaging this value can have dangerous effects!
   9. Create or update the registry key
"HKLMSYSTEMCurrentControlSetServicesEventlogApplication
PHP-5.2.0" (adapt the last to your version part
if necessary) with the following values:

          * "EventMessageFile" (REG_EXPAND_SZ) = "C:phpphp5ts.dll"

          * "TypesSupported" (REG_DWORD) = 7

Where are PHP Errors Logged?

So when we encounter errors in our code, where exactly can we find them? At a high level, there are really only three places where PHP errors can be found: inline with program execution, in the system log, or in error monitoring tools like Rollbar.

Inline errors

By default, whenever an error or exception is thrown, PHP sends the error message directly to the user via STDOUT. In a command-line environment, this means that errors are rendered in the terminal. In a web environment, errors and exceptions get displayed directly in the browser.

While this behavior is useful for debugging problems in a development environment, it should be disabled in a production environment for security reasons. To do this, open up the PHP configuration file for the environment you are working in—typically found in a path that looks like /etc/php/:environment:/php.ini—and change the display_errors directive to Off.

; This directive controls whether or not and where PHP will output errors,  
; notices and warnings too. Error output is very useful during development, but  
; it could be very dangerous in production environments. Depending on the code  
; which is triggering the error, sensitive information could potentially leak  
; out of your application such as database usernames and passwords or worse.  
; For production environments, we recommend logging errors rather than  
; sending them to STDOUT.  
; Possible Values:  
; Off = Do not display any errors  
; stderr = Display errors to STDERR (affects only CGI/CLI binaries!)  
; On or stdout = Display errors to STDOUT  
; Default Value: On  
; Development Value: On  
; Production Value: Off  
; http://php.net/display-errors
display_errors = On

Log files

While rendering errors to STDOUT is great for debugging issues in a development environment as they happen, it isn’t very useful in a production environment. This is where the error log comes into play. By default, PHP doesn’t log any errors, which means that this value must be explicitly set. To do so, open up the same PHP configuration file referenced above in your favorite editor and find the error_log directive.

; Log errors to specified file. PHP's default behavior is to leave this value
; empty.
; http://php.net/error-log
; Example:
;error_log = php_errors.log
; Log errors to syslog (Event Log on Windows).
error_log = syslog

There are two possible values for error_log: a custom log file and the syslog. If the syslog is used, then all PHP errors will be sent directly to the default system log file—in Linux, this is typically /var/log/syslog. The more manageable method is to use a custom log file. By doing this, you can isolate your PHP application’s logs from the rest of the system logs, which can make debugging issues significantly easier.

Logging in Laravel

While PHP’s default system logger is useful for bespoke applications, it is important to note that many application frameworks provide their own built-in logging mechanisms. A great example of this is the Laravel framework. In Laravel, the logging method can be changed within the log option of the application configuration file—found in config/app.php.

/*
|--------------------------------------------------------------------------
| Logging Configuration
|--------------------------------------------------------------------------
|
| Here you may configure the log settings for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Settings: "single", "daily", "syslog", "errorlog"
|
*/
'log' => env('APP_LOG', 'single'),

By default, Laravel maintains a single log file at storage/logs/laravel.log within the project directory, rather than the defined error_log option from the global PHP configuration.

Logging in Symfony

Because Laravel is built on top of Symfony, they share the same core logging mechanism—although the configuration differs between the two frameworks. Logging in Symfony and Laravel are both done using Monolog, a third-party PHP logging library that can be used to create and store logs in a large number of ways.

By default, Symfony logs are stored in var/log/dev.log and var/log/prod.log within the project directory, depending on the environment, but these defaults can be changed in the Monolog package configuration file found at config/packages/monolog.php.

$container->loadFromExtension('monolog', array(
    'handlers' => array(
        'file_log' => array(
            'type'  => 'stream',
            'path'  => '%kernel.logs_dir%/%kernel.environment%.log',
            'level' => 'debug',
        ),
        'syslog_handler' => array(
            'type'  => 'syslog',
            'level' => 'error',
        ),
    ),
));

What do PHP logs look like?

So, what exactly do PHP logs look like? In most instances, PHP logs follow a fairly predictable format:

Dec 10 04:04:38 scotchbox apache2: PHP Parse error:  syntax error, unexpected end of file in /var/www/public/index2.php on line 4

In a nutshell, the log line above can be broken up into four parts: the date, the hostname, the process, and the error message. Whenever an error is encountered or an uncaught exception is thrown, the error message is printed along with the date, hostname, and process metadata to help pinpoint what happened, where it happened, and when it happened.

A primer on log levels

It is important to note that, in PHP, there are a handful of log levels that can be squashed or raised. While these log levels are determined by PHP itself, understanding what they are and mean is a crucial step towards being able to diagnose problems as they happen.

When display_errors is set to On, it can be useful to explicitly hide and show specific log levels so you can focus on one task at a time, such as critical errors, or cleaning up warnings. This can be accomplished using the built-in error_reporting method.

// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);

// Report all errors except E_NOTICE
error_reporting(E_ALL & ~E_NOTICE);

This method accepts an integer value that tells PHP which errors to display, and which ones to ignore. Through the use of bitwise operators (| meaning OR, & meaning AND, and ~ meaning NOT), we can clearly and easily define which errors we want to see.

Here are a few of the most common log levels. For more information about log levels (there are quite a few of them), take a look at PHP’s official documentation.

Error Level Description
E_ERROR Fatal run-time errors. These indicate errors that can not be recovered from, such as a memory allocation problem. Execution of the script is halted.
E_WARNINIG Run-time warnings (non-fatal errors). Execution of the script is not halted.
E_PARSE Compile-time parse errors. Parse errors should only be generated by the parser.
E_NOTICE Run-time notices. These indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script.

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 of E_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 value On is fine in development settings, but it should always be
    turned Off 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 the error_log directive. Setting this to Off will disable
    such behavior, but we recommend keeping this option On.

  • log_errors_max_len: restricts the maximum length of each log record to the
    specified value in bytes. The default is 1024 bytes, but setting this option
    to 0 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 to syslog.

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
  1. The $message argument is the log message you wish to record.
  2. 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 the error_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.

  3. 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.
  4. The $additional_headers parameter is only used when $message_type is set
    to 1. 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

Share on Twitter

Share on Facebook

Share via e-mail

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.

Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Просмотр и анализ логов сайта на Linux сервере

Содержание:

  • Важные логи сайта
  • Расположение логов
  • Чтение записей в логах
  • Просмотр с помощью команды tail
  • Просмотр с помощью ISPManager
  • Программы для анализа логов
  • Ведение логов медленных запросов сервера
  • Ведение логов с помощью Logrotate

Логи сайта — это системные журналы, позволяющие получить информацию о посещении сайта ботами и пользователями, а также выявить скрытые проблемы на сервере — ошибки, битые ссылки, медленные запросы от сервера и многое другое.

Важные логи сайта

  • Access.log — логи посещений пользователей и ботов. Позволяет составить более точную и подробную статистику, нежели сторонние ресурсы, выполняющие внешнее сканирование сайта и отправляющие ряд ненужных запросов серверу. Благодаря данному логу можно получить информацию об используемом браузере и IP-адрес посетителя, данные о местонахождении клиента (страна и город) и многое другое. Стоит обратить внимание, если сайт имеет высокую посещаемость, то анализ логов сервера потребует больше времени. Поэтому для составления статистики стоит использовать специализированные программы (анализаторы).
  • Error.log — программные ошибки сервера. Стоит внимательно отнестись к анализу данного лога, ведь боты поисковиков, сканируя, получают все данные о работе сайта. При обнаружении большого количества ошибок, сайт может попасть под санкции поисковых систем. В свою очередь из записей данного журнала можно узнать точную дату и время ошибки, IP-адрес получателя, тип и описание ошибки.
  • Slow.log (название зависит от используемой оболочки сервера) — в данный журнал записываются медленные запросы сервера. Так принято обозначать запросы с повышенным порогом задержки, выданные пользователю. Этот журнал позволяет выявить слабые места сервера и исправить проблему. Ниже будет рассмотрен способ включить ведение данного лога на разных типах серверов, а также настройка задержки, с которой записи будут заноситься в файл.

Расположение логов

Важно обратить внимание, что местоположение логов сайта по умолчанию зависит от используемого типа оболочки и может быть изменено администратором.

Стандартные пути до Error.log

Nginx

/var/log/nginx/error.log

Php-Fpm

/var/log/php-fpm/error.log

Apache (CentOS)

/var/log/httpd/error_log

Apache (Ubuntu, Debian)

/var/log/apache2/error_log

Стандартные пути до Access.log

Nginx

/var/log/nginx/access.log

Php-Fpm

/var/log/php-fpm/access.log

Apache (CentOS)

/var/log/httpd/access_log

Apache (Ubuntu, Debian)

/var/log/apache2/access_log

Чтение записей в логах

Записи в логах имеют структуру: одно событие – одна строка.

Записи в разных логах имеют общие черты, но количество подробностей отличается. Далее будут приведены примеры строк из разных системных журналов.

Примеры записей

Error.log

[Sat Sep 1 15:33:40.719615 2019] [:error] [pid 10706] [client 66.249.66.61:60699] PHP Notice: Undefined variable: moduleclass_sfx in /var/data/www/site.ru/modules/contacts/default.php on line 14

В приведенном примере:

  • [Sat Sep 1 15:33:40.719615 2019] — дата и время события.
  • [:error] [pid 10706] — ошибка и её тип.
  • [client 66.249.66.61:60699] — IP-адрес подключившегося клиента.
  • PHP Notice: Undefined variable: moduleclass_sfx in — событие PHP Notice. В данной ситуации — обнаружена неизвестная переменная.
  • /var/data/www/site.ru/modules/contacts/default.php on line 14 — путь и номер строки в проблемном файле.

Access.log

194.61.0.6 – alex [10/Oct/2019:15:32:22 -0700] "GET /apache_pb.gif HTTP/1.0" 200 5396 "http://www.mysite/myserver.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"

В приведенном примере:

  • 194.61.0.6 — IP-адрес пользователя.
  • alex — если пользователь зарегистрирован в системе, то в логах будет указан идентификатор.
  • [10/Oct/2019:15:32:22 -0700]— дата и время записи.
  • «GET /apache_pb.gif HTTP/1.0» — «GET» означает, что определённый документ со страницы сайта был отправлен пользователю. Существует команда «POST», наоборот отправляет конкретные данные (комментарий или любое другое сообщение) на сервер . Далее указан извлечённый документ «Apache_pb.gif», а также использованный протокол «HTTP/1.0».
  • 200 5396 — код и количество байтов документа, которые были возвращены сервером.
  • «http://www. www.mysite/myserver.html»— страница, с которой был произведён запрос на извлечение документа «Apache_pb.gif».
  • «Mozilla/4.08 [en] (Win98; I ;Nav)» — данные о пользователе, которой произвёл запрос (используемый браузер и операционная система).

Просмотр логов сервера с помощью команды tail

Выполнить просмотр логов в Linux можно с помощью команды tail. Данный инструмент позволяет смотреть записи в логах, выводя последние строки из файла. По умолчанию tail выводит 10 строк.

Первый вариант использования Tail

tail -f /var/log/syslog

Аргумент «-f» позволяет команде делать просмотр событий в режиме реального времени, в ожидании новых записей в лог файлах. Для прерывания процесса следует нажать сочетание клавиш «Ctrl+C».

На место переменной «/var/log/syslog» в примере следует подставить актуальный адрес до нужных системных журналов.

Второй вариант использования Tail

tail -F /var/log/syslog

В Linux логи веб-сервера не ведутся до бесконечности, поскольку это усложняет их дальнейший анализ. При преодолении лимита записей, система переименует переполненный строками файл журнала и отправит в «архив». Вместо старого файла создастся новый, но с прежним названием.

Если будет использоваться аргумент «-f», команда продолжит отслеживание старого, переименованного журнала. Данный метод делает невозможным просмотр логов в реальном времени, поскольку файл более не актуален.

При использовании аргумента «-F», команда, после окончания записи старого журнала, перейдёт к чтению нового файла с логами. В таком случае просмотр логов в режиме реального времени продолжится.

Аналог команды Tail

tailf /var/log/syslog

Отличие команды tailf от предыдущей заключается в том, что она не обращается к файлу и файловой системе в период, когда запись логов не происходит. Это экономит ресурсы системы и заряд, если используется нестационарное устройство — ноутбук, смартфон или планшет.

Недостаток данного способа — проблема с чтением больших файлов. Если системный журнал достаточно большой, возникает вероятность отказа в работе программы.

Изменение стандартного количества строк для вывода

Как и отмечалось выше, по умолчанию выводится 10 строк. Если требуется увеличить или уменьшить их количество, в команду добавляется аргумент «-n» и необходимое число строк.

Пример:

tail -f -n 100 /var/log/syslog

При использовании данной команды будут показаны последние 100 строк журнала.

Просмотр логов с помощью ISPManager

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

  1. На главной странице, в панели инструментов «WWW» нужно нажать на вкладку «Журналы».
    Просмотр логов с помощью ISPManager
  2. ISPManager выдаст журналы посещений и серверных ошибок в виде:
    • ru.access.log;
    • ru.error.log.*

    * Вместо «newdomen.ru» из примера в выдаче будет название актуального домена.

    Открыть файл лога можно, нажав на «Посмотреть» в верхнем меню.

  3. Для просмотра всех записей журнала, необходимо нажать на «Скачать» и сохранить файл на локальный носитель.
    Просмотр логов с помощью ISPManager
  4. Более старые версии логов можно найти во вкладке «Архив».
    Просмотр логов с помощью ISPManager

Программы для анализа логов

Анализировать журналы с большим количеством данных вручную не только сложно, но и чревато ошибками. Для упрощения работы с лог файлами было создано большое количество сервисов и утилит.

Инструменты для анализа логов делятся на два основных типа — статические и работающие в режиме реального времени.

Статические программы

Данный тип выполняет работу только с извлеченными логами, но обеспечивает быструю сортировку данных.

WebLog ExpertWebLog Expert

Возможности
  • Предоставление информации об активность сайта, количестве посетителей, доступ к файлам, URL страницы, ссылающиеся страницы, информацию о пользователе (браузер и операционная система).
  • Создание отчётов в формате HTML (.html), PDF (.pdf), CSV (.csv).
  • Поддерживает анализ логов Nginx, Apache, ISS.
  • Чтение файлов даже в архивах ZIP (.zip), GZ (.gz).

Web Log Explorer

Web Log Explorer
Возможности
  • Создание многоуровневых отчётов, включающих количество посетителей, маршруты пользователей по сайту, местоположение хостов (страна и город), указанные в поисковике ключевые слова.
  • Поддержка более 43 форматов логов.
  • Возможность прямой загрузки логов с FTP, HTTP сервера.
  • Чтение архивированных журналов.

Программы для анализа в режиме реального времени

Эти инструменты встраиваются в программную среду сервера, анализируют данные в реальном времени и записывают непрерывный отчёт.

GoAccess

GoAccess
Возможности
  • Автоматическая генерация отчёта в формате HTML (.html), JSON (.json), CSV (.csv).
  • При подключении к серверу через SSH, возможен анализ в браузере и в терминале
  • Поддержка почти всех форматов (Apache, Nginx, Amazon S3, Elastic Load Balancing, CloudFront и др.).

Logstash

Logstash
Возможности
  • Постоянная генерация отчёта в файл JSON (.json).
  • Получение и анализ информации из нескольких источников.
  • Возможность пересылать журналы с помощью Filebeat.
  • Поддержка анализа системных журналов.
  • Поддерживается большое количество форматов: от Apache до Log4j (Java).

Ведения логов медленных запросов сервера

Анализ данного лога позволяет определить на какие типы запросов сервер отвечает долго. В идеале задержка должна составлять не более 1 секунды.

На некоторых типах оболочек (MySQL, PHP-FPM) ведение данного лога по умолчанию отключено. Процесс запуска и ведения зависит от сервера.

MySQL

Если сервер управляется с помощью MySQL, то необходимо создать каталог и сам файл для ведения журнала с помощью команд:

mkdir /var/log/mysql
touch /var/log/mysql/mysql-slow.log

Стоит изменить владельца файла, чтобы избежать дальнейших проблем с записью логов. Делается это командой:

chown mysql:mysql /var/log/mysql/mysql-slow.log

После выполнения предыдущих действий, нужно совершить вход в командную строку MySQL под учётной записью суперпользователя:

mysql -uroot -p

Для запуска и настройки ведения логов нужно последовательно ввести в терминале следующие команды:

> SET GLOBAL slow_query_log = 'ON';

> SET GLOBAL slow_launch_time = 2;

> SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';

> FLUSH LOGS;

В примере:

  • slow_query_log — запускает ведение журналов медленных запросов.
  • slow_launch_time — указывает максимальную задержку отклика, после которой статистика запроса попадёт в журнал. В данном случае запись в логи происходит при преодолении откликом порога 2 секунды.
  • slow_query_log_file — задаёт путь до используемого журнала.

Проверить статус и параметры ведения лога медленных запросов можно командой:

> SHOW VARIABLES LIKE '%slow%';

Выход из консоли MySQL выполняется командой:

> exit

После выполнения всех предыдущих действий, можно просмотреть логи сервера. Для этого в терминале вводится:

tail -f /var/log/mysql/mysql-slow.log

PHP-FPM

Для ведения журнала на данной оболочке, необходимо отредактировать параметры в конфигурационном файле. Для этого в терминале вводится команда:

vi /etc/php-fpm.d/www.conf

Далее нужно найти строки:

  • request_slowlog_timeout = 10s — параметр, позволяющий указать задержку, с которой запись о длительном запросе попадёт в журнал.
  • slowlog = /var/log/php-fpm/www-slow.log — параметр, указывающий путь до актуального файла логирования (.log).

После применения изменений, необходимо перезагрузить сервер PHP-FPM. Для этого в консоль вводится команда:

systemctl restart php-fpm

Просмотр логов запускается командой:

tail -f /var/log/php-fpm/www-slow.log

Анализ логов медленных запросов

Логи медленных запросов могут за незначительное время вырасти до огромных размеров. Для сортировки и отображения повторяющихся запросов рекомендуется использовать программу MySQLDumpSlow.

Для запуска просмотра логов с помощью этой утилиты, нужно составить команду по приведенному ниже алгоритму:

mysqldumpslow местонахождение/файла

Ведение логов в Logrotate

На больших ресурсах журналы могут достигать огромных размеров, поэтому нужно своевременно архивировать или очищать логи. С помощью утилиты Logrotate можно управлять ведением журналов: настроить период ротации (архивирование старого журнала и создание нового), период и количество хранения журналов и многое другое.

Изначально программа отсутствует в системе. Ниже приведены команды для инсталляции Logrotate из официальных репозиториев.

Ubuntu, Debian:

sudo apt install logrotate

CentOS:

sudo yum install logrotate

После установки необходимо проверить путь для будущих конфигурационных файлов. Для правильной работы они должны находится в папке «logrotate.d». Проверить данный параметр можно открыв конфигурационный файл  командой:

nano /etc/logrotate.conf

В директории «RPM packages drop log rotation information into this directory» должна присутствовать строка:

include /etc/logrotate.d

Теперь создаётся конфигурационный файл «rsyslog.conf». В нём будет находиться конфигурацию по работе с логами. Для создания файла в терминале вводится команда:

sudo nano /etc/logrotate.d/rsyslog.conf

В окне терминала откроется текстовой редактор. Теперь нужно внести конфигурацию, как указано в образце. В качестве примера будет использоваться журнал посещений «Access.log» (Nginx).

/var/log/nginx/access.log {
daily
rotate 3
size 500M
compress
delaycompress
}

Теперь остаётся только запустить Logrotate. Для этого вводится команда:

sudo logrotate -d /etc/logrotate.d/rsyslog.conf

Для проверки правильности работы программы в терминале можно ввести команду:

ls /var/cron.daily/

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 to syslog, PHP sends logs to the OS logger. This is usually syslog or the newer rsyslog (which implements the syslog protocol) on Linux, or Event 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 uses apache 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.

filter-php-logs-by-channel.png

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.

Where are PHP Errors Logged?

So when we encounter errors in our code, where exactly can we find them? At a high level, there are really only three places where PHP errors can be found: inline with program execution, in the system log, or in error monitoring tools like Rollbar.

Inline errors

By default, whenever an error or exception is thrown, PHP sends the error message directly to the user via STDOUT. In a command-line environment, this means that errors are rendered in the terminal. In a web environment, errors and exceptions get displayed directly in the browser.

While this behavior is useful for debugging problems in a development environment, it should be disabled in a production environment for security reasons. To do this, open up the PHP configuration file for the environment you are working in—typically found in a path that looks like /etc/php/:environment:/php.ini—and change the display_errors directive to Off.

; This directive controls whether or not and where PHP will output errors,  
; notices and warnings too. Error output is very useful during development, but  
; it could be very dangerous in production environments. Depending on the code  
; which is triggering the error, sensitive information could potentially leak  
; out of your application such as database usernames and passwords or worse.  
; For production environments, we recommend logging errors rather than  
; sending them to STDOUT.  
; Possible Values:  
; Off = Do not display any errors  
; stderr = Display errors to STDERR (affects only CGI/CLI binaries!)  
; On or stdout = Display errors to STDOUT  
; Default Value: On  
; Development Value: On  
; Production Value: Off  
; http://php.net/display-errors
display_errors = On

Log files

While rendering errors to STDOUT is great for debugging issues in a development environment as they happen, it isn’t very useful in a production environment. This is where the error log comes into play. By default, PHP doesn’t log any errors, which means that this value must be explicitly set. To do so, open up the same PHP configuration file referenced above in your favorite editor and find the error_log directive.

; Log errors to specified file. PHP's default behavior is to leave this value
; empty.
; http://php.net/error-log
; Example:
;error_log = php_errors.log
; Log errors to syslog (Event Log on Windows).
error_log = syslog

There are two possible values for error_log: a custom log file and the syslog. If the syslog is used, then all PHP errors will be sent directly to the default system log file—in Linux, this is typically /var/log/syslog. The more manageable method is to use a custom log file. By doing this, you can isolate your PHP application’s logs from the rest of the system logs, which can make debugging issues significantly easier.

Logging in Laravel

While PHP’s default system logger is useful for bespoke applications, it is important to note that many application frameworks provide their own built-in logging mechanisms. A great example of this is the Laravel framework. In Laravel, the logging method can be changed within the log option of the application configuration file—found in config/app.php.

/*
|--------------------------------------------------------------------------
| Logging Configuration
|--------------------------------------------------------------------------
|
| Here you may configure the log settings for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Settings: "single", "daily", "syslog", "errorlog"
|
*/
'log' => env('APP_LOG', 'single'),

By default, Laravel maintains a single log file at storage/logs/laravel.log within the project directory, rather than the defined error_log option from the global PHP configuration.

Logging in Symfony

Because Laravel is built on top of Symfony, they share the same core logging mechanism—although the configuration differs between the two frameworks. Logging in Symfony and Laravel are both done using Monolog, a third-party PHP logging library that can be used to create and store logs in a large number of ways.

By default, Symfony logs are stored in var/log/dev.log and var/log/prod.log within the project directory, depending on the environment, but these defaults can be changed in the Monolog package configuration file found at config/packages/monolog.php.

$container->loadFromExtension('monolog', array(
    'handlers' => array(
        'file_log' => array(
            'type'  => 'stream',
            'path'  => '%kernel.logs_dir%/%kernel.environment%.log',
            'level' => 'debug',
        ),
        'syslog_handler' => array(
            'type'  => 'syslog',
            'level' => 'error',
        ),
    ),
));

What do PHP logs look like?

So, what exactly do PHP logs look like? In most instances, PHP logs follow a fairly predictable format:

Dec 10 04:04:38 scotchbox apache2: PHP Parse error:  syntax error, unexpected end of file in /var/www/public/index2.php on line 4

In a nutshell, the log line above can be broken up into four parts: the date, the hostname, the process, and the error message. Whenever an error is encountered or an uncaught exception is thrown, the error message is printed along with the date, hostname, and process metadata to help pinpoint what happened, where it happened, and when it happened.

A primer on log levels

It is important to note that, in PHP, there are a handful of log levels that can be squashed or raised. While these log levels are determined by PHP itself, understanding what they are and mean is a crucial step towards being able to diagnose problems as they happen.

When display_errors is set to On, it can be useful to explicitly hide and show specific log levels so you can focus on one task at a time, such as critical errors, or cleaning up warnings. This can be accomplished using the built-in error_reporting method.

// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);

// Report all errors except E_NOTICE
error_reporting(E_ALL & ~E_NOTICE);

This method accepts an integer value that tells PHP which errors to display, and which ones to ignore. Through the use of bitwise operators (| meaning OR, & meaning AND, and ~ meaning NOT), we can clearly and easily define which errors we want to see.

Here are a few of the most common log levels. For more information about log levels (there are quite a few of them), take a look at PHP’s official documentation.

Error Level Description
E_ERROR Fatal run-time errors. These indicate errors that can not be recovered from, such as a memory allocation problem. Execution of the script is halted.
E_WARNINIG Run-time warnings (non-fatal errors). Execution of the script is not halted.
E_PARSE Compile-time parse errors. Parse errors should only be generated by the parser.
E_NOTICE Run-time notices. These indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script.

  • Логан глохнет на ходу ошибок нет
  • Логическая ошибка дорама субтитры
  • Логан 2 приборная панель ошибки
  • Логан 2 горит пила ошибок нет
  • Лови ошибку робинзон крузо