15.

PHP エラーログ出力 (error_log / Monolog / Laravel Log) 完全ガイド

編集
この記事の要点
  • PHP の最も基本的なログ関数は error_log($message)。第 2 引数で出力先を切替
  • error_log($msg, 0): php.ini の error_log / 1: メール / 3: 指定ファイル / 4: SAPI ロガー
  • php.ini の log_errors = On + error_log = /var/log/php.log でエラーを集約
  • プロジェクト用途は Monolog (Composer) や PSR-3 LoggerInterface
  • Laravel は Log::info / warning / error / debug + config/logging.php で channel 管理

error_log 関数の基本

PHP 標準で提供される最も基本のログ関数。引数の渡し方で出力先が変わります。

// 1) 第 2 引数省略 / 0: php.ini の error_log 設定先へ
error_log("Something happened");

// 2) 第 2 引数 = 3: 指定パスにファイル追記 (★最頻出)
error_log("[" . date('c') . "] user_id=$id failed\n", 3, '/var/log/app/error.log');

// 3) 第 2 引数 = 1: メール送信
error_log("Critical error", 1, "admin@example.com");

// 4) 第 2 引数 = 4: SAPI モジュールに送る (mod_php なら Apache のエラーログ)
error_log("Send to SAPI", 4);
第 2 引数出力先備考
0 (省略時既定)php.ini の error_log / SAPI のエラーログ本番では既定で運用
1メール送信第 4 引数で追加ヘッダ。SMTP 設定が必要
3第 3 引数で指定したファイルに追記★ 任意のパスへログを出す定番
4SAPI ロガーPHP 7.4+。Apache/Nginx のエラーログへ

php.ini の設定

; php.ini
log_errors = On                          ; エラーをログに記録
error_log = /var/log/php/error.log       ; 既定の出力先
error_reporting = E_ALL                  ; 何を記録するか
display_errors = Off                     ; ★ 本番では Off
display_startup_errors = Off
log_errors_max_len = 1024                ; 1 件あたりの最大バイト

; ログローテーション (logrotate 例)
; /etc/logrotate.d/php
;   /var/log/php/error.log {
;       daily
;       rotate 30
;       compress
;       missingok
;       notifempty
;       postrotate
;           kill -USR1 `cat /run/php-fpm.pid` || true
;       endscript
;   }

error_log で出力した内容を確認

# リアルタイム監視
tail -f /var/log/php/error.log

# 直近 100 行
tail -n 100 /var/log/php/error.log

# キーワードでフィルタ
grep -i "PDOException" /var/log/php/error.log

# Apache / nginx のエラーログ (error_log で第 2 引数 4 / 0 のときの行き先候補)
tail -f /var/log/apache2/error.log
tail -f /var/log/nginx/error.log

# PHP-FPM のエラーログ
tail -f /var/log/php-fpm/error.log

関連関数

関数用途
error_log()ログメッセージを出力
error_reporting()記録するエラーレベルを実行時に変更
set_error_handler()独自のエラーハンドラを設定
set_exception_handler()未捕捉例外のハンドラ
register_shutdown_function()致命的エラー時に動かす後処理
debug_backtrace()スタックトレースを取得
trigger_error()独自のエラーを発生させる (E_USER_NOTICE/WARNING/ERROR)
syslog()OS の syslog に送信 (openlog() とセット)

独自エラーハンドラと例外ハンドラ

// すべての PHP エラーを error_log に送る
set_error_handler(function ($severity, $message, $file, $line) {
    if (!(error_reporting() & $severity)) {
        return false;   // 抑制レベルなら無視
    }
    error_log("[ERROR] $message at $file:$line");
    return true;
});

// 未捕捉例外
set_exception_handler(function (Throwable $e) {
    error_log(sprintf(
        "[EXCEPTION] %s: %s\n%s",
        get_class($e),
        $e->getMessage(),
        $e->getTraceAsString()
    ));
    http_response_code(500);
    echo 'Internal Server Error';
});

// 致命的エラー (Out of memory 等) の最終手段
register_shutdown_function(function () {
    $err = error_get_last();
    if ($err && in_array($err['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
        error_log("[FATAL] {$err['message']} at {$err['file']}:{$err['line']}");
    }
});

syslog 出力

openlog("myapp", LOG_PID | LOG_PERROR, LOG_LOCAL0);
syslog(LOG_WARNING, "Suspicious login from " . $_SERVER['REMOTE_ADDR']);
syslog(LOG_ERR, "Database connection failed");
closelog();

// /var/log/syslog や /var/log/messages に流れる
// rsyslog で /var/log/myapp.log にルーティング可能

Monolog (PSR-3 準拠の定番ロガー)

本格運用ではほぼ Monolog が使われます。多彩な出力先 (file / stream / syslog / Slack / Mail / Sentry / Elasticsearch) と整形ハンドラを持ちます。

composer require monolog/monolog
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\SlackWebhookHandler;
use Monolog\Formatter\LineFormatter;

$logger = new Logger('app');

// 日次ローテーション
$rotate = new RotatingFileHandler('/var/log/app/app.log', 30, Logger::DEBUG);
$rotate->setFormatter(new LineFormatter(
    "[%datetime%] %level_name%: %message% %context% %extra%\n",
    'Y-m-d H:i:s'
));
$logger->pushHandler($rotate);

// エラーは Slack にも
$logger->pushHandler(new SlackWebhookHandler(
    'https://hooks.slack.com/services/...',
    '#alerts',
    'AppBot',
    true,
    null,
    false,
    false,
    Logger::ERROR
));

// 使い方
$logger->info('user logged in', ['user_id' => 42]);
$logger->warning('slow query', ['ms' => 1200, 'sql' => $sql]);
$logger->error('payment failed', ['order_id' => $orderId, 'reason' => $e->getMessage()]);

PSR-3 LoggerInterface

PHP-FIG が定めた標準ロガーインタフェース。Monolog も Laravel Log もこれに準拠しているため、フレームワーク非依存のライブラリは LoggerInterface を依存性注入で受け取るのが定番。

use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

class PaymentService {
    public function __construct(private LoggerInterface $logger = new NullLogger()) {}

    public function charge(int $amount): void {
        $this->logger->info('charging', ['amount' => $amount]);
        try {
            // ...
        } catch (\Throwable $e) {
            $this->logger->error('charge failed', ['exception' => $e]);
            throw $e;
        }
    }
}

// 8 つのレベル (debug, info, notice, warning, error, critical, alert, emergency)
$logger->debug('verbose');
$logger->info('normal');
$logger->notice('something noticeable');
$logger->warning('not an error, but...');
$logger->error('error happened');
$logger->critical('critical state');
$logger->alert('alert!');
$logger->emergency('system is down');

Laravel の Log ファサード

use Illuminate\Support\Facades\Log;

Log::debug('debug message');
Log::info('user signed in', ['id' => $user->id]);
Log::warning('disk almost full');
Log::error('DB connection lost', ['exception' => $e]);
Log::critical('out of memory');

// 特定チャンネルに直接
Log::channel('slack')->error('payment failed');
Log::channel('daily')->info('cron finished');

// 複数チャンネルへ同時に
Log::stack(['daily', 'slack'])->error('Critical: ...');

// 文脈付き (リクエスト ID 等を全ログに付与)
Log::withContext([
    'request_id' => request()->header('X-Request-Id'),
    'user_id' => auth()->id(),
]);
Log::info('order created');   // 上記 context が自動で乗る

Laravel config/logging.php の例

return [
    'default' => env('LOG_CHANNEL', 'stack'),

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['daily', 'slack'],
        ],

        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 14,
        ],

        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'emoji' => ':boom:',
            'level' => 'critical',
        ],

        'syslog' => [
            'driver' => 'syslog',
            'level' => 'debug',
        ],

        'stderr' => [
            'driver' => 'monolog',
            'handler' => Monolog\Handler\StreamHandler::class,
            'with' => ['stream' => 'php://stderr'],
        ],
    ],
];

本番運用の注意

  • 個人情報 / 機密情報を出さない: メアド、パスワード、クレカ番号、秘密鍵
  • ローテーション必須: RotatingFileHandler / logrotate / Laravel daily ドライバ
  • ログレベルを分ける: 本番は INFO 以上、開発は DEBUG
  • 監視を入れる: ERROR 以上を Slack 通知 / Sentry / CloudWatch Logs Insights
  • 構造化ログを推奨: $logger->info('message', $context) の context で集計が楽に
  • display_errors = Off: 本番ではブラウザに出さない

FAQ

Q: error_log がどこに書かれているか分からない
A: php -i | grep error_log または phpinfo() で確認。空欄なら SAPI 既定 (Apache/Nginx のエラーログ) に流れます。

Q: error_log でファイルにパーミッションエラー
A: Web プロセス (apache / www-data / php-fpm) に対象ディレクトリの書き込み権限が必要。chown www-data:www-data /var/log/app

Q: Monolog と Laravel Log どちらを使うべき?
A: Laravel プロジェクトなら Log ファサードで十分 (内部 Monolog)。素の PHP やライブラリでは PSR-3 ベースで Monolog を直接注入。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. インストール方法
  2. 文法
  3. Composerのインストール
  4. 内部関数
  5. フレームワーク
  6. エラー一覧
  7. 改行出力
  8. printとechoの違い
  9. シングルクォートとダブルクォートの違い
  10. returnとyieldの違い
  11. var_dumpをログ出力
  12. CSV読み込み
  13. 待機・処理の遅延
  14. ログファイルにエラーを出力する方法
  15. エラーログ出力関数
  16. URLパラメータの配列化
  17. empty, is_null. issetの判定比較表
  18. httpステータスコードの付与
  19. バージョンの確認
  20. php.ini
  21. APIを呼び出す方法
  22. 外部ファイルを呼び出す方法
  23. カンマ区切りの文字列を配列に変換
  24. 配列からランダムに値を取り出す方法
  25. Webスクレイピング

最近更新/作成されたページ