[PHP]ログ出力完全ガイド – error_log、syslog、print_rの使い方とカスタムlog_print関数の実装

PHP

はじめに

PHPでアプリケーションを開発する際、ログ出力は非常に重要な機能です。デバッグ情報の記録、エラーの追跡、システムの監視など、様々な場面で活用されます。

今回は、PHPの標準的なログ出力関数と、よく使われるカスタム関数「log_print」の実装について詳しく解説します。

PHPの標準ログ出力関数

1. error_log() 関数

最も一般的に使用されるログ出力関数です。

// 基本的な使い方
error_log("エラーメッセージ");

// ファイルに出力
error_log("デバッグ情報", 3, "/var/log/myapp.log");

// メール送信
error_log("重要なエラー", 1, "admin@example.com");

パラメータ説明:

  • 第1引数:ログメッセージ
  • 第2引数:出力先の指定(0=システムログ、1=メール、3=ファイル、4=直接出力)
  • 第3引数:出力先の詳細(ファイルパスやメールアドレス)

2. syslog() 関数

システムログに出力する関数です。

// システムログの開始
openlog("MyApp", LOG_PID | LOG_PERROR, LOG_LOCAL0);

// ログ出力
syslog(LOG_WARNING, "警告メッセージ");
syslog(LOG_ERR, "エラーメッセージ");

// システムログの終了
closelog();

3. print_r() / var_dump()

変数の内容をデバッグ用に出力する関数です。

$data = ['name' => '太郎', 'age' => 30];

// print_rでの出力
error_log(print_r($data, true), 3, "/tmp/debug.log");

// var_dumpでの出力
ob_start();
var_dump($data);
$output = ob_get_clean();
error_log($output, 3, "/tmp/debug.log");

カスタムlog_print関数の実装

多くの開発現場では、より使いやすいカスタムログ関数「log_print」を作成します。以下に実装例を示します。

基本的なlog_print関数

function log_print($message, $level = 'INFO', $logfile = null) {
    // デフォルトのログファイル
    if ($logfile === null) {
        $logfile = '/var/log/app.log';
    }
    
    // タイムスタンプの生成
    $timestamp = date('Y-m-d H:i:s');
    
    // ログレベルの正規化
    $level = strtoupper($level);
    
    // ログメッセージの整形
    $log_message = "[{$timestamp}] [{$level}] {$message}" . PHP_EOL;
    
    // ファイルに追記
    file_put_contents($logfile, $log_message, FILE_APPEND | LOCK_EX);
}

使用例

// 基本的な使用法
log_print("アプリケーションが開始されました");
log_print("データベース接続エラー", 'ERROR');
log_print("ユーザーがログインしました", 'INFO', '/var/log/user.log');

// 配列やオブジェクトのログ出力
$user_data = ['id' => 123, 'name' => '田中太郎'];
log_print("ユーザーデータ: " . json_encode($user_data, JSON_UNESCAPED_UNICODE));

高度なlog_print関数

より実用的な機能を追加した版:

class Logger {
    private static $logfile = '/var/log/app.log';
    private static $max_file_size = 10485760; // 10MB
    
    public static function log_print($message, $level = 'INFO', $context = []) {
        // ログローテーション
        self::rotateLogIfNeeded();
        
        // バックトレースの取得(呼び出し元の特定)
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
        $caller = isset($backtrace[1]) ? 
                  basename($backtrace[1]['file']) . ':' . $backtrace[1]['line'] : 
                  'unknown';
        
        // メッセージの整形
        $timestamp = date('Y-m-d H:i:s');
        $level = strtoupper($level);
        $pid = getmypid();
        
        // コンテキスト情報の追加
        $context_str = !empty($context) ? 
                      ' ' . json_encode($context, JSON_UNESCAPED_UNICODE) : '';
        
        $log_message = "[{$timestamp}] [{$level}] [PID:{$pid}] [{$caller}] {$message}{$context_str}" . PHP_EOL;
        
        // ファイルに出力
        file_put_contents(self::$logfile, $log_message, FILE_APPEND | LOCK_EX);
        
        // 重要なレベルの場合はエラーログにも出力
        if (in_array($level, ['ERROR', 'CRITICAL', 'EMERGENCY'])) {
            error_log($message);
        }
    }
    
    private static function rotateLogIfNeeded() {
        if (file_exists(self::$logfile) && filesize(self::$logfile) > self::$max_file_size) {
            $backup_name = self::$logfile . '.' . date('YmdHis');
            rename(self::$logfile, $backup_name);
        }
    }
    
    // 各レベル専用のメソッド
    public static function debug($message, $context = []) {
        self::log_print($message, 'DEBUG', $context);
    }
    
    public static function info($message, $context = []) {
        self::log_print($message, 'INFO', $context);
    }
    
    public static function warning($message, $context = []) {
        self::log_print($message, 'WARNING', $context);
    }
    
    public static function error($message, $context = []) {
        self::log_print($message, 'ERROR', $context);
    }
}

高度な使用例

// 基本的な使用
Logger::info("アプリケーションが開始されました");

// コンテキスト情報付き
Logger::error("データベース接続失敗", [
    'host' => 'localhost',
    'database' => 'myapp',
    'error_code' => 2002
]);

// レベル別メソッドの使用
Logger::debug("デバッグ情報");
Logger::warning("警告メッセージ");
Logger::error("エラーが発生しました");

ログ出力のベストプラクティス

1. ログレベルの使い分け

// DEBUG: 開発時のデバッグ情報
Logger::debug("変数の値: " . $variable);

// INFO: 一般的な情報
Logger::info("ユーザー登録完了: user_id=" . $user_id);

// WARNING: 警告(処理は継続)
Logger::warning("古いAPIを使用しています");

// ERROR: エラー(処理に影響)
Logger::error("ファイルの読み込みに失敗しました");

2. セキュリティ対策

function secure_log_print($message, $level = 'INFO') {
    // 個人情報のマスク処理
    $message = preg_replace('/password=\w+/', 'password=***', $message);
    $message = preg_replace('/\d{4}-\d{4}-\d{4}-\d{4}/', '****-****-****-****', $message);
    
    Logger::log_print($message, $level);
}

3. パフォーマンス対策

function conditional_log_print($message, $level = 'INFO') {
    // 本番環境ではDEBUGログを出力しない
    if ($level === 'DEBUG' && $_ENV['APP_ENV'] === 'production') {
        return;
    }
    
    Logger::log_print($message, $level);
}

まとめ

PHPでのログ出力は、標準関数のerror_log()syslog()から始まり、プロジェクトの要件に応じてカスタム関数log_printを実装することが一般的です。

重要なポイント:

  • ログレベルを適切に使い分ける
  • セキュリティを考慮した情報のマスク処理
  • ログローテーションによるディスク容量の管理
  • 本番環境でのパフォーマンスへの配慮

適切なログ実装により、アプリケーションの保守性と信頼性を大幅に向上させることができます。

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