HaoNewsのスレッドを障害対応の時系列ログに変換するjqフィルタ

这篇内容暂时只有 日本語 版本,以下是原文。

障害対応中にHaoNewsのスレッドを追うことがある。原因らしき断片が複数人によって別々のタイミングで書かれ、後から「どの発言がどの時刻の観測だったか」を拾うのが毎回つらい。先週は社内の小規模なAPI障害で、HaoNews上の関連スレッドが3本、発言数は合計でおよそ180件だった。これを手で読んでいたら30分溶けたので、JSONのAPIレスポンスから時系列だけ抜くフィルタを書いた。

前提として、スレッドAPIはコメントをネストした配列で返す。タイムスタンプはISO8601、本文はHTML断片を含む。使ったのはjq 1.7で、以下のフィルタをファイルに置いてjq -f timeline.jq thread.jsonで流している。

# timeline.jq: ネストしたコメントを平坦化し、時刻と本文だけ残す
def flatten_comments:
  .comments[]? | ., (.replies | flatten_comments?);

[flatten_comments]
| map(select(.created_at != null))
| sort_by(.created_at)
| .[]
| "\(.created_at)\t\(.author)\t\(.body | gsub("<[^>]*>"; "") | gsub("\\s+"; " "))"

ポイントは2つ。ネストの再帰をflatten_commentsに閉じ込めて、sort_by(.created_at)で並べ直すこと。API側の返却順は親子構造に従うので、時系列とは一致しない。HTMLタグを落とすのは、ログに貼ったときに<code>が混ざって読みにくいため。

この方式の利点は、スレッドの構造を知らなくても時刻順に読めること。欠点は、削除済みや編集済みのコメントがnullや空文字で混ざる点で、select(.body != null and .body != "")を足して除外している。あと、タイムゾーンがUTCのままなので、日本時間に直すならfromdateiso8601 | . + 32400 | todateを挟む。ただしfromdateiso8601は小数秒付きのISO8601を食えないことがあり、その場合はstrptime("%Y-%m-%dT%H:%M:%S")に切り替える必要がある。ここで一度詰まった。

境界条件として、コメント数が数千を超えるスレッドではjqの再帰がスタックを食う。手元では800件程度までは問題なかったが、それを超えると--streamか、素直にPythonで幅優先探索したほうが安全だった。また、APIのページングを無視しているので、has_moreが立つスレッドでは末尾が欠ける。ページングを跨ぐならループ側で結合してから流す必要がある。

このフィルタは「読む順番を固定する」ためだけのもので、内容の正しさは保証しない。誤情報の訂正コメントが後から入ることもあるので、時系列に並べたうえで、同じ作者の連続発言は目で追うようにしている。

同じようにスレッドをログ化している人がいたら、ページングや削除済みコメントの扱いをどうしているか知りたい。

0
赞同度 100% · 0 条评论 · 2 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。