Guide

ログのタイムスタンプ: エラーの解析、正規化、および修正

このページを作成する理由

ログは、形式、タイムゾーン、精度が混在して到着します。タイムスタンプが 1 つ間違っていると、注文、ダッシュボード、インシデントのタイムラインが破壊されます。このガイドでは、ログ時間を迅速に正規化するためのクイック チェック、正規表現テンプレート、および言語スニペットを提供し、エッジ ケースを検証する必要がある場合はコンバーターを示します。

簡単な診断チェックリスト

  • 形式を特定します: ISO 8601/RFC 3339、Apache/Nginx ([dd/Mon/yyyy:HH:mm:ss Z])、syslog (MMM d HH:mm:ss)、またはカスタム。
  • タイムゾーン: 明示的なオフセット (+0800Z) と暗黙的なローカルをチェックします。存在しない場合のデフォルトは UTC です。
  • 精度を確認します: 秒、ミリ秒、マイクロ秒。一貫した長さを確保します。
  • DST エッジ の処理: 最初に UTC に解析します。単純なローカル解析は避けてください。
  • 範囲ガードを強制します: 信じられない年 (例: <2000 または >2100) を拒否します。

一般的なログ形式 (テンプレート)

  • ISO 8601 / RFC 3339: 2024-12-01T10:15:30Z2024-12-01T18:15:30+08:00
  • Apache/Nginx: [01/Dec/2024:10:15:30 +0000]
  • Syslog: Dec 1 10:15:30 hostname app[123]: message (年/オフセットなし)
  • カスタム数値: 1701425730 (秒)、1701425730000 (ミリ秒)

正規化の手順

  1. フォーマットとタイムゾーンを検出します。欠落している場合は、UTC とみなされます。
  2. 認識可能な日時 (UTC) に解析します。
  3. 数値エポックの場合: 長さによってスケールします (10 秒/13 ミリ秒/16 μ秒/19 ナノ秒)。
  4. 正規の列 (UTC ミリなど) に保存し、オプションで生の文字列を保持します。
  5. 範囲を検証します。インデックスを作成する前に、外れ値を削除またはフラグを立てます。

コードスニペット

JavaScript / Node.js

import { DateTime } from "luxon";

export function parseLogTime(raw) {
  const trimmed = raw.trim();
  // ISO/RFC first
  const iso = DateTime.fromISO(trimmed, { setZone: true });
  if (iso.isValid) return iso.toUTC().toMillis();

  // Apache/Nginx: [01/Dec/2024:10:15:30 +0000]
  const m = trimmed.match(/\\[(\\d{2}\\/\\w{3}\\/\\d{4}:\\d{2}:\\d{2}:\\d{2} [+-]\\d{4})\\]/);
  if (m) {
    const dt = DateTime.fromFormat(m[1], "dd/MMM/yyyy:HH:mm:ss ZZZZ", { zone: "utc" });
    if (dt.isValid) return dt.toMillis();
  }

  // Numeric epoch (seconds/ms/us/ns)
  if (/^\\d+$/.test(trimmed)) {
    const len = trimmed.length;
    if (len === 10) return Number(trimmed) * 1000;
    if (len === 13) return Number(trimmed);
    if (len === 16) return Number(trimmed) / 1000;
    if (len === 19) return Number(trimmed) / 1_000_000;
  }

  throw new Error("Unrecognized log timestamp");
}

パイソン

from datetime import datetime, timezone, timedelta
from dateutil import parser

def parse_log_time(raw: str) -> int:
    s = raw.strip()
    # ISO/RFC 3339, syslog with tz, etc.
    try:
        dt = parser.isoparse(s)
        if dt.tzinfo is None:
            dt = dt.replace(tzinfo=timezone.utc)
        return int(dt.astimezone(timezone.utc).timestamp() * 1000)
    except Exception:
        pass

    # Apache/Nginx like: [01/Dec/2024:10:15:30 +0000]
    if s.startswith("[") and s.endswith("]"):
        inner = s[1:-1]
        dt = datetime.strptime(inner, "%d/%b/%Y:%H:%M:%S %z")
        return int(dt.astimezone(timezone.utc).timestamp() * 1000)

    # Numeric epoch
    if s.isdigit():
        n = len(s)
        if n == 10:
            return int(s) * 1000
        if n == 13:
            return int(s)
        if n == 16:
            return int(int(s) / 1000)
        if n == 19:
            return int(int(s) / 1_000_000)
    raise ValueError("Unrecognized log timestamp")

正規表現テンプレート

regex
# ISO 8601 / RFC 3339 with offset
^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:?\\d{2})$

# Apache/Nginx
^\\[\\d{2}/[A-Za-z]{3}/\\d{4}:\\d{2}:\\d{2}:\\d{2} [+-]\\d{4}\\]$

# Syslog (no year/offset, add externally)
^[A-Za-z]{3}\\s+\\d{1,2}\\s\\d{2}:\\d{2}:\\d{2}\\s.+$

順序付け、インデックス付け、および保存

  • 保存する前に UTC ミリ秒 (またはそれ以上) に正規化します。再解析が必要な場合は、生のテキストを保持してください。
  • 範囲フィルター (WHERE happens_at_ms >= ... AND happens_at_ms < ...) を使用して、インデックスを使いやすくします。
  • 取り込みで形式が混在する場合は、validated_at 列を追加して、失敗を隔離します。
  • 大量のログを日付で分割します。フィルターでのキャストは避けてください。

よくある落とし穴 (および修正)

  • タイムゾーンがありません: デフォルトは UTC;ログ パーサーは、ソース ホストのタイムゾーンがわかっている場合は追加する必要があります。
  • DST ギャップ/オーバーラップ: 最初に UTC として解析します。表示時にのみローカライズします。
  • 混合精度: 秒とミリ秒が 1 つの列に混在しています。摂取時に長さを強制します。
  • Syslog に年がありません: 解析中に現在の年を追加し、範囲を検証します。
  • 関数でラップされたフィルター: WHERE の DATE(occurred_at) を避けます。生成された日付列を使用します。

よくある質問

  • ミリ秒と秒を検出するにはどうすればよいですか? 桁の長さを確認してください: 10=秒、13=ms、16=μs、19=ns。
  • タイムゾーンが見つからない場合はどうなりますか? UTC を想定するか、解析する前に既知のホストのタイムゾーンを挿入します。
  • ダッシュボードが正常に動作しないのはなぜですか? 精度または文字列の並べ替えが混在している可能性があります。数値 UTC とインデックスに正規化します。
  • 履歴ログをバッチでクリーンアップするにはどうすればよいですか? ステージング テーブルを使用し、解析して検証し、クリーンな行のみを移動します。関連ツールを参照してください。

関連ツールとガイド