アプリケーションにエラーは付き物ですが、エラー調査のために処理途中の 変数の内容をちょっとだけ覗き見たい! と思うことってよくありますよね。

開発中であれば var_dump() 関数や print_r() 関数などで画面に情報を出してしまえばいいですが、本番環境の場合はそうもいかないのでログ関数に頼ることになると思います。

しかし世の中は無数のサーバがあり、サーバの数だけ異なった環境があります。
またサーバに置いてある PHP ファイルの数だけ無数の世界があります。

そんな無数にある環境の中、必ずしもフレームワークで提供されているような便利なログ関数を呼び出せるわけではないですし、xdebug のステップ実行が出来るわけではないと思います。

そこで過酷な状況下でも使えるようなサバイバルなログ関数を一つ持っておくと何かと便利です。私が普段使っているものは以下のような感じです。

サバイバルログ関数

$log = function () {
    // ログの出力先ファイルパス (環境に合わせて適当に変更で)
    $path = '/tmp/debug.log';
    // この関数の呼び出し元情報を取得
    $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
    // 引数からログ内容を取得 (可変長引数に対応)
    $content = func_get_args();
    $output = json_encode([
        'time' => time(),
        'caller' => $caller,
        'content' => $content,
    ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;
    // ログを書き込み
    file_put_contents($path, $output, FILE_APPEND);
};

上記のサバイバルログ関数の短縮版

出来ることは上記の関数と同じですがワンライナーのため携帯性に優れます。
(可読性が損なわれるので使い捨てのログ関数以外の用途では避けたほうがいいです。)

$log = function () { file_put_contents('/tmp/debug.log', json_encode(['time' => time(), 'caller' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]] + ['content' => func_get_args()], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL, FILE_APPEND); };

SSH で対象のアプリケーションに忍び寄り vim でサッと上記を貼り付けて保存すれば一瞬のうちにログを仕込めます。後は tail -f debug.log をしながら獲物がかかるのを待つだけです。

使用方法

// 複数の引数の内容をロギングする場合
$log ('確認内容1', '確認内容2');

// 配列の内容をロギングする場合
$log (['hoge' => 'foo', 'bar' => 'piyo']);

// 任意の変数の内容をロギングする場合
$log ($hoge, $foo);

ログファイルへの出力内容は以下のような感じになります。
ただのインデントありの JSON です。

/tmp/debug.log
{
    "time": 1510251504,
    "caller": {
        "file": "\/var\/www\/html\/survival.php",
        "line": 19,
        "function": "{closure}"
    },
    "content": [
        "確認内容1",
        "確認内容2"
    ]
}

関数について補足

  • PHP 5.4 以上の環境であれば使えると思います。
  • サバイバル性を高めるため関数は クロージャ で定義してます。スコープ汚染が最小限になり関数名の重複によるエラーなどは心配する必要がなくなります。
  • 手軽ではありますが本番環境で使用される際はくれぐれも事故にお気をつけ下さい。
  • ログローテーションはしないので確認が終わったら元に戻したほうがいいです。
  • ログは json_encode() の結果を出力しているため、インスタンス変数に対して使う場合は全ての情報が出力されるとは限りません。

関連記事