[PHP]error_log関数の詳細解説

PHP

こんにちは!今回は、PHPのerror_log関数について詳しく解説していきます。

error_log関数とは?

error_log関数は、エラーメッセージをログファイル、サーバーのエラーログ、あるいはメールで指定した宛先に送信するための関数です。

基本構文

bool error_log ( string $message [, int $message_type = 0 [, string $destination [, string $additional_headers ]]] )

メッセージタイプ

  • 0: PHP のシステムロガーを使用(デフォルト)
  • 1: メールを送信
  • 3: 指定したファイルに追加
  • 4: SAPI のロガーに送信

基本的な使用例

1. システムログへの記録

<?php
// システムログに記録
error_log("データベース接続エラーが発生しました");

// より詳細な情報を含める
error_log(sprintf(
    "エラー: %s, ファイル: %s, 行: %d",
    "接続タイムアウト",
    __FILE__,
    __LINE__
));
?>

2. ファイルへの記録

<?php
$message = date('Y-m-d H:i:s') . " - エラーが発生しました\n";
error_log($message, 3, "app_error.log");
?>

実践的な使用例

1. エラーログクラス

<?php
class ErrorLogger {
    private $logFile;
    private $emailTo;

    public function __construct($logFile, $emailTo = null) {
        $this->logFile = $logFile;
        $this->emailTo = $emailTo;
    }

    public function log($message, $level = 'ERROR') {
        $logMessage = sprintf(
            "[%s] [%s] %s\n",
            date('Y-m-d H:i:s'),
            $level,
            $message
        );

        // ファイルに記録
        error_log($logMessage, 3, $this->logFile);

        // 重要なエラーの場合はメール送信
        if ($level === 'CRITICAL' && $this->emailTo) {
            $this->sendEmail($message);
        }
    }

    private function sendEmail($message) {
        $headers = 'From: system@example.com' . "\r\n" .
                  'Reply-To: system@example.com' . "\r\n" .
                  'X-Mailer: PHP/' . phpversion();

        error_log($message, 1, $this->emailTo, $headers);
    }
}

// 使用例
$logger = new ErrorLogger('app.log', 'admin@example.com');
$logger->log("データベース接続エラー", 'CRITICAL');
?>

2. 例外ハンドリング

<?php
class ExceptionHandler {
    private static $logger;

    public static function initialize($logFile) {
        self::$logger = new ErrorLogger($logFile);

        set_exception_handler([self::class, 'handleException']);
        set_error_handler([self::class, 'handleError']);
    }

    public static function handleException($exception) {
        $message = sprintf(
            "例外: %s\nファイル: %s\n行: %d\nスタックトレース:\n%s",
            $exception->getMessage(),
            $exception->getFile(),
            $exception->getLine(),
            $exception->getTraceAsString()
        );

        self::$logger->log($message, 'EXCEPTION');
    }

    public static function handleError($errno, $errstr, $errfile, $errline) {
        $message = sprintf(
            "エラー(%d): %s\nファイル: %s\n行: %d",
            $errno,
            $errstr,
            $errfile,
            $errline
        );

        self::$logger->log($message, 'ERROR');
    }
}
?>

3. アプリケーションログ

<?php
class ApplicationLogger {
    private $context;
    private $logFile;

    public function __construct($context, $logFile) {
        $this->context = $context;
        $this->logFile = $logFile;
    }

    public function info($message) {
        $this->log($message, 'INFO');
    }

    public function warning($message) {
        $this->log($message, 'WARNING');
    }

    public function error($message) {
        $this->log($message, 'ERROR');
    }

    private function log($message, $level) {
        $logMessage = sprintf(
            "[%s] [%s] [%s] %s\n",
            date('Y-m-d H:i:s'),
            $level,
            $this->context,
            $message
        );

        error_log($logMessage, 3, $this->logFile);
    }
}

// 使用例
$logger = new ApplicationLogger('UserService', 'application.log');
$logger->info('ユーザーがログインしました');
$logger->warning('パスワード試行回数が多すぎます');
$logger->error('ユーザー認証に失敗しました');
?>

高度な使用例

1. ログローテーション

<?php
class RotatingLogger {
    private $baseLogFile;
    private $maxSize;

    public function __construct($baseLogFile, $maxSize = 5242880) { // 5MB
        $this->baseLogFile = $baseLogFile;
        $this->maxSize = $maxSize;
    }

    public function log($message) {
        $this->rotateIfNeeded();

        $logMessage = sprintf(
            "[%s] %s\n",
            date('Y-m-d H:i:s'),
            $message
        );

        error_log($logMessage, 3, $this->baseLogFile);
    }

    private function rotateIfNeeded() {
        if (!file_exists($this->baseLogFile)) {
            return;
        }

        if (filesize($this->baseLogFile) >= $this->maxSize) {
            $backup = $this->baseLogFile . '.' . date('Y-m-d-H-i-s');
            rename($this->baseLogFile, $backup);
        }
    }
}
?>

2. JSON形式のログ

<?php
class JsonLogger {
    private $logFile;

    public function __construct($logFile) {
        $this->logFile = $logFile;
    }

    public function log($message, array $context = []) {
        $logData = [
            'timestamp' => date('Y-m-d H:i:s'),
            'message' => $message,
            'context' => $context,
            'server' => $_SERVER['SERVER_NAME'] ?? 'unknown',
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
        ];

        $jsonLog = json_encode($logData) . "\n";
        error_log($jsonLog, 3, $this->logFile);
    }
}
?>

注意点とベストプラクティス

1. パフォーマンスへの配慮

<?php
class BufferedLogger {
    private $buffer = [];
    private $maxBufferSize = 100;
    private $logFile;

    public function __construct($logFile) {
        $this->logFile = $logFile;
        register_shutdown_function([$this, 'flush']);
    }

    public function log($message) {
        $this->buffer[] = sprintf(
            "[%s] %s\n",
            date('Y-m-d H:i:s'),
            $message
        );

        if (count($this->buffer) >= $this->maxBufferSize) {
            $this->flush();
        }
    }

    public function flush() {
        if (!empty($this->buffer)) {
            error_log(implode('', $this->buffer), 3, $this->logFile);
            $this->buffer = [];
        }
    }
}
?>

2. セキュリティ考慮

<?php
class SecureLogger {
    public function log($message, $sensitiveData = false) {
        if ($sensitiveData) {
            // 機密データはマスク
            $message = $this->maskSensitiveData($message);
        }

        error_log($message);
    }

    private function maskSensitiveData($message) {
        // パスワードなどの機密情報をマスク
        return preg_replace(
            '/password[:=]\s*[^\s,]+/i',
            'password=*****',
            $message
        );
    }
}
?>

まとめ

error_log関数の主なポイント:

  1. 複数のログ出力先に対応
  2. シンプルで使いやすい
  3. エラーハンドリングシステムの基礎として有用
  4. カスタマイズ可能な柔軟性

活用シーン:

  • アプリケーションログの記録
  • エラー監視
  • デバッグ情報の収集
  • システム診断

注意点:

  • ログローテーションの実装
  • パフォーマンスへの配慮
  • セキュリティ考慮
  • ディスク容量の管理

これらの点を理解して使用することで、より効果的なログ管理が実装できます。

以上で、error_log関数の解説を終わります。
ご質問やご不明点があれば、お気軽にコメントしてください!

タイトルとURLをコピーしました