なぜ「ログ用 1 行整形」が必要なのか
ログって、本来は「あとから原因を追いやすくするための情報」ですよね。
でも、何も考えずに文字列をそのまま error_log() に投げていると、こうなりがちです。
複数行の文字列がそのまま出て、ログがガタガタになる。
制御文字やタブが混ざって、ビューアが崩れる。
1 件のログがやたら長くて、他の行が見えなくなる。
そこでやりたいのが、「どんな文字列でも“ログに優しい 1 行”に整形する」ユーティリティです。
これを 1 本持っておくと、ログの見通しが一気によくなります。
ログ用 1 行整形でやるべきこと
やりたいことを分解してみる
「ログ用 1 行整形」は、ざっくり言うと次のような処理の組み合わせです。
前後の余計な空白を削る。
改行やタブなどの制御文字を消すか、スペースに変える。
長すぎる文字列は途中で切って「…」を付ける。
必要なら、プレフィックス([user=123] など)を付ける。
これを毎回バラバラに書くのではなく、
「ログに出す前に必ず通す 1 本の関数」にまとめるのがポイントです。
基本形:シンプルな 1 行整形関数
改行も含めて制御文字を全部落とす版
まずは、「とにかく 1 行にしたい」ケース向けの基本形です。
/**
* ログ用に「1 行の安全な文字列」に整形する
*
* - 前後の空白をトリム
* - 制御文字(改行・タブなど)をすべて削除
* - 長すぎる場合は末尾を「...」で省略
*/
function to_log_line(string $value, int $maxLength = 200): string
{
// 前後の空白を削る
$value = trim($value);
// 制御文字(0x00-0x1F, 0x7F)をすべて削除
$value = preg_replace('/[\x00-\x1F\x7F]/', '', $value) ?? '';
// 長さ制限(マルチバイト対応)
if (mb_strlen($value, 'UTF-8') > $maxLength) {
$value = mb_substr($value, 0, $maxLength, 'UTF-8') . '...';
}
return $value;
}
PHPここでの重要ポイントは 2 つです。
制御文字を全部消しているので、「必ず 1 行になる」こと。mb_strlen / mb_substr を使っているので、日本語でも文字数ベースで安全に切れること。
例題:ユーザー入力をログに出す
そのまま出すとログが壊れるパターン
例えば、ユーザーがこんなコメントを送ってきたとします。
こんにちは
テストです \x07
(\x07 はベル文字、タブも含まれています)
これをそのまま error_log() に渡すと、ログが複数行になり、制御文字も混ざります。
$rawComment = $_POST['comment'] ?? '';
error_log('comment=' . $rawComment);
PHPログビューアで見ると、1 件のログが 2 行以上に分かれてしまい、
他のログとの対応が追いづらくなります。
1 行整形を通してから出す
$rawComment = $_POST['comment'] ?? '';
$logComment = to_log_line($rawComment, 100);
error_log('comment=' . $logComment);
PHPログには、例えばこんな感じで出ます。
comment=こんにちはテストです
改行やタブ、ベルなどの制御文字が消え、1 行にまとまっています。
「何が入力されたか」は分かりつつ、ログの形はきれいなままです。
発展形:配列やオブジェクトを 1 行ログにする
var_export や json_encode と組み合わせる
ログに「配列やコンテキスト情報」を出したいことも多いですよね。
そのまま var_dump すると複数行になるので、
一度文字列化してから to_log_line() に通します。
/**
* 任意の値を「ログ用 1 行文字列」に整形する
*/
function context_to_log_line(mixed $value, int $maxLength = 300): string
{
// まず JSON で文字列化(失敗したら var_export)
$json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if ($json === false) {
$json = var_export($value, true);
}
return to_log_line($json, $maxLength);
}
PHP使い方の例です。
$context = [
'user_id' => 123,
'action' => 'login',
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
];
error_log('context=' . context_to_log_line($context));
PHPログには、例えばこう出ます。
context={"user_id":123,"action":"login","ip":"203.0.113.1"}
JSON 形式で 1 行にまとまっているので、
人間にも機械にも扱いやすい形になります。
もう一歩:プレフィックスやタグを付けて見やすくする
ログの「型」をそろえる
1 行整形と一緒に、「ログのフォーマット」をそろえておくと、
あとから grep したり、集計したりするときに便利です。
例えば、こんなヘルパーを用意します。
/**
* タグ付きの 1 行ログを出力する
*
* 例: [user=123][action=login] message...
*/
function log_with_tags(string $message, array $tags = []): void
{
$parts = [];
foreach ($tags as $key => $value) {
$parts[] = sprintf('[%s=%s]', $key, to_log_line((string)$value, 50));
}
$prefix = implode('', $parts);
error_log($prefix . ' ' . to_log_line($message, 300));
}
PHP使い方の例です。
log_with_tags(
'login failed: wrong password',
['user_id' => 123, 'ip' => $_SERVER['REMOTE_ADDR'] ?? '']
);
PHPログには、例えばこう出ます。
[user_id=123][ip=203.0.113.1] login failed: wrong password
ここでも to_log_line() を通しているので、
タグ部分もメッセージ部分も「1 行で安全な文字列」に整形されています。
まとめ:今日からの「ログ用 1 行整形」ユーティリティ
ログ用 1 行整形の本質は、「どんな入力でも“ログに優しい 1 行”に変換する」ことです。
制御文字を削除して、ログビューアを壊さない。
長さを制限して、1 行が暴走しないようにする。
配列やコンテキストも、文字列化してから 1 行にまとめる。
そのためのコア関数が、次のようなものです。
function to_log_line(string $value, int $maxLength = 200): string
{
$value = trim($value);
$value = preg_replace('/[\x00-\x1F\x7F]/', '', $value) ?? '';
if (mb_strlen($value, 'UTF-8') > $maxLength) {
$value = mb_substr($value, 0, $maxLength, 'UTF-8') . '...';
}
return $value;
}
PHPもし、あなたのコードのどこかで「error_log($rawValue); をそのまま書いている」箇所があれば、
そこが to_log_line($rawValue) に差し替えるポイントです。
その 1 ステップを挟むだけで、ログの“読みやすさ”と“壊れにくさ”が一気に変わります。
