Skip to content

PHP Tutorial Error Handling

Error Logging

Lesson 194 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

On a live site, nobody is looking at the screen when something fails. Logs are how you find out afterwards.

The settings

In php.ini (or at runtime with ini_set):

SettingMeaning
log_errorsOn writes errors to a log
error_logThe file path (or leave empty for the server’s log)
display_errorsOff in production
error_reportingE_ALL
php.ini
INI
log_errors = On
error_log = /var/log/php/app-errors.log
display_errors = Off
error_reporting = E_ALL

With Apache, PHP errors normally go to the Apache error log if error_log is not set.

Write your own entries: error_log()

index.php
PHP
<?php
$log = __DIR__ . "/app.log";

error_log("User 42 failed to log in\n", 3, $log);
error_log("Payment gateway timeout\n", 3, $log);

echo file_get_contents($log);
Output
OUTPUT
User 42 failed to log in
Payment gateway timeout

The second argument 3 means “append to the file named in the third argument”. With no extra arguments, error_log("text") writes to the configured log.

Add context

A log line without a time or details is hard to use. Add them.

index.php
PHP
<?php
function logError(string $message, array $context = []): void
{
    $line = sprintf(
        "[%s] %s %s",
        date("Y-m-d H:i:s"),
        str_replace(["\r", "\n"], " ", $message),
        $context ? json_encode($context) : ""
    );

    file_put_contents("events.log", $line . PHP_EOL, FILE_APPEND | LOCK_EX);
}

logError("Login failed", ["user_id" => 42, "ip" => "203.0.113.5"]);

echo substr(file_get_contents("events.log"), 22);
Output
OUTPUT
Login failed {"user_id":42,"ip":"203.0.113.5"}

(substr(..., 22) skips the timestamp so the output stays the same every time.)

What to log

  • Exceptions, with the message, file, line and trace.
  • Failed logins and other security events.
  • Slow or failed calls to other services.
  • Unexpected input.

What never to log

  • Passwords, even wrong ones.
  • Credit card numbers, API keys, tokens.
  • Full personal data. Log an ID instead.
  • Raw user input without cleaning new lines (log injection).

Log levels

Libraries such as Monolog (installed with Composer) add levels: debug, info, warning, error, critical. You can then keep a quiet log in production and a detailed one in development. See Logging.

Look at the log

On a server, tail -f shows new lines as they arrive:

terminal
BASH
tail -f /var/log/php/app-errors.log

Keep logs under control

Logs grow forever. Use log rotation (the logrotate tool, or a library that writes one file per day), and delete old files.

dangerous
Keep logs private
A log in the public web folder can be downloaded by anyone who guesses its name, and it often contains private details. Store logs outside the web root.