PythonでCSVログのエラー集計ツールを作ってみた|SEの定型作業を小さく自動化

AI開発ログ

障害調査や定例報告の前に、CSVで出力されたログを開き、フィルターをかけてERRORだけを数える。件数が少なければ手作業でも済みますが、毎日・毎週繰り返すと意外に時間を取られます。

そこで今回は、Pythonの標準ライブラリだけを使い、CSV形式のログからERROR行を抽出し、システム別・メッセージ別に件数を集計する小さなCLIツールを作って動かしてみました。

外部ライブラリは使いません。入力CSVの列を確認し、ERROR以外を除外し、Counterで数えるだけのシンプルな構成です。検証用CSVではERRORが6件あり、billingが3件、apiが2件、authが1件という結果を確認できました。

大規模な監視基盤を置き換えるものではありませんが、「Excelで毎回同じフィルターと集計をしている」「ログの一次確認だけ自動化したい」といった場面では、小さなスクリプトでも十分に効果があります。

今回作ったもの

作ったのは、1つのCSVファイルを引数で受け取り、level列がERRORの行だけを対象にして集計結果を標準出力へ表示するPythonスクリプトです。

想定するCSVの列は次の4つです。

  • timestamp:発生日時
  • system:システム名や機能名
  • level:INFO、WARN、ERRORなどのレベル
  • message:エラー内容

検証では、次のような8行のデータを用意しました。INFOやWARNも混ぜ、ERRORだけが正しく集計されるかを確認しています。

timestamp,system,level,message
2026-09-08 09:01,billing,ERROR,timeout
2026-09-08 09:03,billing,WARN,slow response
2026-09-08 09:05,auth,ERROR,invalid token
2026-09-08 09:10,billing,ERROR,timeout
2026-09-08 09:12,auth,INFO,login success
2026-09-08 09:15,api,ERROR,connection reset
2026-09-08 09:18,api,ERROR,timeout
2026-09-08 09:20,billing,ERROR,db lock

「エラー総数」だけではなく、「どのシステムで多いか」「どのメッセージが繰り返されているか」まで出すことで、次に見るべき場所を絞りやすくしています。

Python標準ライブラリだけで実装した理由

CSV集計ならpandasを使う方法もあります。ただ、今回の目的は高度な分析ではなく、定型的な一次集計です。そのため、環境構築の手間をできるだけ減らすことを優先しました。

PythonにはCSVを読み書きするcsvモジュールが標準で用意されています。公式ドキュメントでも、DictReaderを使うことで1行を辞書形式として扱えることが説明されています。列名をキーとして参照できるので、今回のような小さな処理ではコードの意図が分かりやすくなります。

件数の集計にはcollections.Counterを使いました。Counterは、要素ごとの出現回数を数えるための辞書型のサブクラスです。most_common()を使えば、件数の多い順に取り出せます。

標準ライブラリだけで完結させるメリットは、別途パッケージを入れなくても動かしやすいことです。社内PCや一時的な検証環境では、ライブラリ追加が簡単でないこともあります。もちろんPython自体の導入可否や社内ルールは事前に確認する必要がありますが、依存関係が少ないことは運用上の扱いやすさにつながります。

実際に書いたコード

import csv
from collections import Counter
from pathlib import Path
import sys

def summarize(path):
    path = Path(path)
    systems = Counter()
    messages = Counter()
    total = 0

    with path.open(encoding="utf-8", newline="") as f:
        reader = csv.DictReader(f)
        required = {"timestamp", "system", "level", "message"}

        if not required.issubset(reader.fieldnames or []):
            missing = sorted(required - set(reader.fieldnames or []))
            raise ValueError(f"missing columns: {', '.join(missing)}")

        for row in reader:
            if row["level"].upper() != "ERROR":
                continue

            total += 1
            systems[row["system"]] += 1
            messages[row["message"]] += 1

    print(f"ERROR total: {total}")

    print("\nBy system:")
    for name, count in systems.most_common():
        print(f"- {name}: {count}")

    print("\nBy message:")
    for name, count in messages.most_common():
        print(f"- {name}: {count}")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python summarize_errors.py <csv>")
        raise SystemExit(2)

    summarize(sys.argv[1])

処理の中心は難しくありません。csv.DictReaderで1行ずつ読み、levelがERRORでなければスキップします。ERRORだった行だけ、システム名とメッセージをCounterへ加算します。

また、今回は列不足のチェックも入れました。CSVを受け取る運用では、出力元の仕様変更で列名が変わったり、手作業で加工したファイルが渡されたりすることがあります。列が足りないまま処理を続けるより、入口でエラーにした方が原因を追いやすくなります。

row["level"].upper()としているのは、errorやErrorのような表記揺れをある程度吸収するためです。ただし前後の空白までは除去していないため、実運用ならstrip()も加える余地があります。

動かして確認した結果

検証用CSVに対してスクリプトを実行したところ、終了コードは0で、次の結果になりました。

ERROR total: 6

By system:
- billing: 3
- api: 2
- auth: 1

By message:
- timeout: 3
- invalid token: 1
- connection reset: 1
- db lock: 1

元データではERRORが6行なので、総数は一致しています。システム別ではbillingが3件で最多、メッセージ別ではtimeoutが3件で最多でした。

この結果だけで障害原因を断定することはできません。ただ、一次切り分けとしては「billing周辺を優先して見る」「timeoutが複数システムで出ているため共通の接続先も確認する」といった次の行動につなげやすくなります。

手作業でCSVを開いてフィルターし、ピボットやCOUNTIFで数えることもできます。違いは、同じ形式のCSVが来たときに同じコマンドで再実行できることです。繰り返し作業では、この再現性が効いてきます。

SE実務で使うなら、どこまで自動化するか

この程度のスクリプトは「自動化の完成形」ではありません。むしろ、手作業をどこまで置き換える価値があるかを見るための小さな入口です。

たとえば、毎朝ログCSVをダウンロードして集計しているなら、最初の段階では「CSVを指定して集計結果を出す」ところだけでも十分です。次に、必要性が確認できたら出力をMarkdownやCSVへ保存したり、日付ごとの差分を出したりできます。

逆に、いきなりメール送信やチケット登録まで自動化すると、誤検知時の影響範囲が広がります。特に本番障害に関わる処理は、最初から完全自動を目指すより、集計と判断を分けた方が安全です。

フリーランスSEの場合も同じです。案件ごとに運用ルールや持ち出し可否が違うため、便利だからという理由だけで業務データを個人環境へコピーするのは避けるべきです。まずはダミーデータで仕組みを作り、利用する環境・保存先・実行権限を案件ルールに合わせて確認する必要があります。

作ってみて分かったメリット

今回のような小さなツールのメリットは、処理内容を把握しやすいことです。コード量が少ないため、何を数えているのかを追いやすく、条件変更にも対応しやすくなります。

また、Excel操作に比べて「手順の再現」がしやすい点も実務では有利です。担当者が変わったとき、操作手順書だけではクリック位置やフィルター条件の違いが発生することがあります。スクリプトなら、同じ入力に対して同じ処理を実行できます。

もう1つは、改善の起点にしやすいことです。最初はERROR件数だけでも、後から「日付別」「時間帯別」「ホスト別」「エラーコード別」といった軸を増やせます。小さく作って必要な機能だけ足す方が、使われない大きなツールを最初から作るより現実的です。

一方で、そのまま本番利用しない方がいい点

今回のコードは検証用としては動きますが、業務でそのまま使うには足りない点があります。

まず文字コードです。今回はUTF-8で読み込んでいますが、Windows環境から出力されたCSVではCP932など別の文字コードが使われる場合があります。文字コードが違えば読み込み時にエラーになる可能性があります。

次にCSVの内容です。メッセージ内にカンマや改行が含まれていても、適切にクオートされたCSVならcsvモジュールで扱えますが、出力元が独自形式の場合は事前確認が必要です。拡張子がCSVだからといって、常に同じ形式とは限りません。

ファイルサイズにも注意が必要です。今回のコードは1行ずつ処理するため全件を一度にメモリへ載せませんが、集計キーの種類が非常に多い場合はCounter側の保持量が増えます。数GB規模のログや複雑な分析なら、専用のログ基盤やデータ処理環境を使う方が適切です。

そして最も重要なのはデータの扱いです。ログにはユーザーID、メールアドレス、IPアドレス、トークン、内部URLなどが含まれることがあります。集計ツールを作る前に、ログをどこへ保存してよいか、個人端末で扱ってよいか、出力結果をどこまで共有してよいかを確認する必要があります。

初心者がつまずきやすいポイント

まず多いのは、実行場所とファイルパスの違いです。python summarize_errors.py errors.csvと実行しても、現在のフォルダにCSVがなければ読み込めません。最初はPythonファイルとCSVを同じフォルダへ置くと確認しやすくなります。

次に列名です。今回のコードはtimestamp、system、level、messageを前提にしています。実際のCSVがseverityやserviceという列名なら、そのままでは動きません。自社のCSVに合わせてキー名を修正する必要があります。

また、ERRORの表記も固定とは限りません。製品によってはERR、FATAL、数値コードなどを使います。何を「エラー」と数えるかは、ログ仕様を確認して決めるべきです。

小さな自動化でありがちな失敗は、「動いた」時点で業務投入してしまうことです。正常系だけでなく、列不足、空ファイル、文字コード違い、巨大ファイル、想定外の値も確認してから使う方が安全です。

もう少し実用的にするなら追加したい機能

次に手を入れるなら、まず出力形式を選べるようにしたいところです。画面表示だけでは定例報告へ転記する手間が残ります。集計結果をCSVやMarkdownへ出せれば、そのまま報告の下書きに使いやすくなります。

次に、期間やシステム名を引数で指定できるようにすると使い勝手が上がります。たとえば「billingだけ」「10時以降だけ」と絞れるようにすれば、障害調査時にも使いやすくなります。

さらに実務寄りにするなら、終了コードを使い分ける方法もあります。ERROR件数が0件なら0、一定件数を超えたら1などにすれば、別のバッチ処理から判定しやすくなります。ただし、自動通知までつなげる場合は誤検知や重複通知への対策も必要です。

いきなり全部を入れるのではなく、「毎回手でやっている部分」を1つずつ置き換えるのが現実的です。

この方法が向いている人・向いていない人

向いているのは、同じ形式のCSVを定期的に確認していて、集計条件がある程度固定されている人です。Pythonの学習を兼ねて、実務に近い小さなツールを作ってみたい人にも扱いやすい題材です。

一方で、リアルタイム監視が必要な環境や、複数サーバーから大量ログを集めて相関分析したいケースには向きません。その場合は、ログ管理・監視用の仕組みを検討する方がよいでしょう。

また、CSVの仕様が頻繁に変わる業務では、スクリプトの保守コストが増えます。自動化するときは「作る時間」だけでなく、「仕様変更のたびに直す時間」も含めて考える必要があります。

まとめ:小さな集計から始めると自動化の効果を確認しやすい

今回は、Python標準ライブラリだけでCSVログのERRORを集計するCLIツールを作り、検証用データで動作を確認しました。

検証結果はERROR総数6件、システム別ではbilling 3件・api 2件・auth 1件、メッセージ別ではtimeout 3件が最多でした。単純な結果ですが、「どこから確認するか」を決める一次集計としては役立ちます。

SE業務の自動化は、大きな仕組みから始める必要はありません。毎回同じCSVを開き、同じフィルターをかけ、同じ数え方をしているなら、そこは小さなスクリプトに置き換えやすい部分です。

まずはダミーデータで動かし、入力形式と例外パターンを確認する。そのうえで、必要なら出力保存や条件指定を追加する。小さく作って、実際に使う部分だけ育てる方が、業務では扱いやすい自動化になります。

参考情報

Pythonや標準ライブラリの仕様は更新される可能性があります。実際の業務環境へ導入する場合は、利用中のPythonバージョンと公式ドキュメントを確認してください。

コメント