本文へ移動

2026-09-01 時点の資料です。読みやすさのために、一部の文字の色を濃くしています。

松葉 / Matsuba ・ 開発過程資料

操作の記録と異常の検知/ Audit Logs & Alerting

すべての操作を残して後から辿れるようにし、システムの異常に気づいて手を打つ仕組み

「あのファイルは誰がいつ差し替えたのか」「取引先のどなたが受け取ったのか」「日次の処理が黙って失敗していないか」。どれも、起きた時点で記録されていなければ後から作れません。松葉では、利用者・社外の相手・システムのすべての操作を 1 本の追記専用の記録に集め、それを Box のメンバーには業務の履歴として、システム管理者には全社の監査ログとして見せています。あわせて、サーバの死活監視では見えない「業務が詰まっている」状態をアプリ自身が 29 種のアラートとして判定し、1 つの運用画面に集約しました。まずは実際の動きをご覧ください。

この資料について: システム担当向けの技術共有です。用いる技術は正式名で記し、初出には短い注釈を、末尾の用語集にも一覧を用意しています。稼働中のサービス名(例:matsuba-api)は名前と役割を併記します。各章へは目次から移動できます。通読の目安は 20〜25 分です。
01

デモンストレーションDemonstration

2 本用意しました。1 本目は Box のメンバーが自分たちの操作履歴を辿るところ、2 本目はシステム管理者がアラートに気づいて手を打つところです。この先の各章は、ここで起きていることを分解してご説明します。

(動画は掲載していません)
ファイルを操作する → アクティビティタブに行が増える → 操作種別と操作者で絞り込む → アクセス履歴(Owner 限定)を開く → CSV で取り出す。
(動画は掲載していません)
件数バッジから一覧へ入る → 重大の未対応だけに絞る → 詳細で対象の生データと推奨アクションを読む → 対応中にする → 解決する。
02

操作の記録と異常の検知の全体構成System Map

この仕組みを構成する稼働リソース(サービス・バッチ・テーブル・バケット)と、その間を流れるものを一枚にまとめました。①記録の蓄積 → ②3 つの読み口 → ③長期保管、そして独立した ④異常の検知と運用、の 4 区画で読めます。②の 3 本はどれも同じ 1 本の記録を読んでいて、書き込み経路は 1 つしかありません。各要素の詳しい役割は、この先の各章で扱います。

図 01 · 操作の記録と異常の検知の全体構成 — 稼働リソースと 4 区画の流れ
① 記録の蓄積 — すべての操作が 1 本の追記専用テーブルへ操作する側Box メンバー(4 ロール)共有リンク・ファイルリクエストシステム・システム管理者行為者 6 種matsuba-api / matsuba-batch各業務処理が、業務データと同じトランザクションで 1 行を追記一括追加の形を強制操作 163 種audit_logs(PostgreSQL)月ごとに分けた子テーブルへ書く主キーは(発生時刻, 連番)追記のみ・更新と削除の口が無い保持 2 年② 3 つの読み口 — 同じ 1 本の記録を、相手に応じた形で出す全社の監査ログシステム管理者のみAPI 8 端点一覧(9 条件・50 件ずつ)集計(日本時間で時間・日)CSV 19 列(同期と非同期)パーティション一覧・退避分歯止め理由 10〜256 字必須・1 時間 5 回閲覧そのものを毎回記録Box のアクティビティBox メンバー全員box_activity_for_memberPostgreSQL の SECURITY DEFINER関数の中で 4 つを検証するメイン 48 種/アクセス履歴 4 種1 ページ 30 件・上限 50 件出さないものを構造で決める出してよい項目の対応表を通すメールは伏せ字にしてから返す退避分の取り出しシステム管理者のみ署名付き URL 15 分Archive クラスから直接読む復元の機構を持たない理由 10〜256 字必須発行は毎回記録される参照する台帳audit_partition_archives期間・行数・検査値・容量③ 長期保管 — 2 年を超えた月を外部へ移し、検証してから消すpg_partman + pg_cron週次数ヶ月先まで先に作る25 ヶ月超を切り離すaudit_archive スキーマ切り離した月が移る場所ここに在ること自体が「退避待ち」の合図audit-log-partition-rotator月次COPY → gzip → 保存先の月の残数も点検監査エクスポートバケットaudit-archive/YYYY-MM.csv.gzArchive クラス寿命の設定なし検証してから消すCOPY が返した行数と件数の一致、保存後の crc32c と容量を照合する。一致しなければその月は消さず、台帳に失敗として残す。先の月の残りが一定数を下回ったときも止める。④ 異常の検知と運用 — 気づいて、その場で手を打つ業務処理の中で気づくウイルス検出・内容の不一致検査の失敗・総当たり・大量アクセス7 種dlq-monitor5 分ごと・検知器 6 つ滞留・配信不能・バウンス率6 種matsuba-sync-batch日次の突合(Go)Drive 同期の見張り7 種日次・月次のバッチ費用・請求・鍵の期限・送出量保持・アカウント・処理の失敗9 種app_alerts — 29 種 / 7 グループ / 重大・警告同じ事象が続いている間は鳴らし直さない。件数が増えたときだけ鳴らし直す。条件が消えたら自動で解決済みにする。/admin/alerts(システム管理者のみ)計器 4 枚・絞り込み 3 種・30 秒ごとに更新詳細で対象の生データと推奨アクションを読む未対応 → 対応中 → 解決 / 無視メール配送29 種のうち 23 種を共通の文面で個別の文面を持つ 4 通は別経路で先に届く種別ごとに受け取りを止められるその場で手を打つ失敗イベントの再投入・破棄/滞留した通知の再キュー操作も記録される対応中・解決・無視は audit_logs へ(① に戻る)

色の役割:teal の枠は処理サービスと主要な経路、金茶の枠は保管と社外に関わるもの、白地は補助的な要素です。区画 ③ の対象は区画 ① の audit_logs そのもので、25 ヶ月を超えた月だけが audit_archive スキーマへ移ります。区画 ② の「退避分の取り出し」は区画 ③ が置いたオブジェクトを読みます。区画 ④ は独立した仕組みですが、運用の操作そのものは区画 ① へ記録されて戻ります。

03

概要Overview

何を解決したか

取引先とのやり取りをメールと紙から Web に移すと、それまで受信箱と稟議書に散っていた「誰がいつ何をしたか」が、原理的には 1 か所に集められるようになります。ただし集める仕組みを作らなければ集まりません。松葉では、ファイルのアップロード・差し替え・削除・復元、フォルダの操作、メンバーの追加とロール変更、共有リンクとファイルリクエストの発行と無効化、コメント、Box の設定変更、そしてダウンロードとプレビューまで、163 種類の操作を発生した時点で記録しています。

もう 1 つの問題は、システム側の異常が誰にも届かないことでした。サーバが落ちればクラウドの監視が拾いますが、実際に困るのは「サーバは動いているのに通知メールだけ出ていない」「日次の同期が 2 日続けて失敗している」「ウイルス検査が詰まっている」といった状態です。これらはアプリの中の数字を見なければ判定できません。松葉では、アプリ自身が 29 種類の事象を判定し、1 つの運用画面に集約しています。

1 本の記録を 3 つの読み口で出す

記録を保存するテーブルは 1 本だけです。表示用に別のテーブルを設けると、同じ出来事を 2 か所へ書くことになり、片方だけ書けたときに食い違いが残ります。そこで書き込み経路を 1 本に固定し、読む側を 3 つに分けました。

Three Readers of the Same Log
読み口見られる人見えるもの実現手段
全社の監査ログシステム管理者163 種すべて。IP・端末情報・操作の詳細まで含む生のデータ専用の API 8 端点。理由の入力と回数の制限つき
Box のアクティビティBox のメンバー業務の状態を変える 48 種。ダウンロードなどの 4 種は Owner のみ。内部情報は含まないPostgreSQL の SECURITY DEFINER 関数 1 本が、権限の判定と項目の絞り込みを兼ねる
退避分の取り出しシステム管理者2 年を超えてデータベースから出た月の記録(gzip 圧縮した CSV)Cloud Storage の Archive クラスへ 15 分の署名付き URL を直接発行

記録が消せないことを、どうやって担保するか

監査ログの価値は「都合の悪い行を後から消せない」ことに依存します。松葉ではこれをアプリの実装で守るのではなく、データベースの権限設計で守っています。追加は誰でもできますが、更新と削除の許可規則そのものを作っていません。規則が無ければ、システム管理者であっても更新も削除もできません。参照はシステム管理者だけに開き、Box のメンバーには前述の関数経由の道しか通していません。

気づけない欠落を作らない

検知の設計でいちばん気を配ったのは「何も起きていないのか、見ていないだけなのか」を区別できる形にすることです。5 分ごとに回る 6 つの検知器は互いに独立に動かし、1 つが失敗しても残りが止まらないようにしています。1 つの失敗で全部が止まる作りにすると、この仕組み自身が「静かな欠落」を作ってしまいます。外部の監視サービスから数値が取れなかったときは、0 件と報告せず取得の失敗として扱います。前回の報告件数が読めないときは、黙るのではなく鳴らす側に倒します。

04

この資料の構成Pages

記録が溜まる側(記録の基盤 → 全社の監査ログ → 長期保管 → Box のアクティビティ)と、異常に気づく側(異常の検知 → アラートの運用)に分かれています。どこから読んでも読めるように書いていますが、通しで読む場合はこの一覧の順が読みやすい並びです。

Background

設計の背景Design Rationale

記録を 1 本に集めた理由と、更新・削除の口を作らなかった理由。同じ記録を 3 つの読み口で出す構造。クラウドの監視とは別にアプリ自身の検知を持つ理由と、設計の四原則。

View
Records

記録の基盤The Log

記録される 163 種類の操作。1 行に入る項目と、IP・端末情報の置き場。追記だけを許すアクセス制御の三層。月ごとに子テーブルへ分ける仕組み。行為者の 6 種類と、書き込みの規律。

View
Audit

全社の監査ログCompany-wide Audit

9 条件の絞り込みと続きの取り方。閲覧そのものを条件なしで記録する理由。日本時間で区切る集計。19 列の CSV と、期間 31 日・10 万行での分岐。歯止め 4 つと、現時点の到達範囲。

View
Archive

長期保管Long-term Storage

保持 2 年と退避 25 ヶ月の 1 ヶ月の余裕。子テーブルの先行作成と切り離しの分担。退避の 4 手順と、行数・検査値を突き合わせてから消す規律。失敗したときに起きること。

View
Activity

Box のアクティビティMember Timeline

メンバーに見せる 48 種と Owner だけの 4 種。権限をデータベース側で固定する 4 つの検証。出してよい項目の対応表。日本語の表示文。タイムラインの画面と Owner の CSV。

View
Detection

異常の検知Detection

アラート 29 種の全一覧と 7 つの系統。起票元の 4 系統。5 分ごとに回る 6 つの検知器と、そのしきい値。鳴らし直さない仕組みと自動での解決。本番での実例。

View
Operations

アラートの運用Operations

計器 4 枚と絞り込み 3 種。状態で見た目を分ける規律。4 状態 × 3 操作の遷移と、手動で解決できない 2 種。失敗イベントの再投入・破棄と滞留した通知の再キュー。

View
Tech

採用技術Technology

仕組みを構成する技術それぞれの役割。記録側と検知側で共通にした部分、あえて分けた部分の一覧。

View
Glossary

用語集Glossary

本文に出てくる技術用語の定義と、稼働しているサービス・バッチ・バケット・テーブルの名前と役割の一覧。初めて読む方はここを先に開いても構いません。

View
05

規模と主要指標Key Figures

設計上の数値です。件数の根拠はすべて共有定数の一覧か自動テストで固定されており、増減するとテストが落ちる形にしてあります。

163種
記録される操作の種類。共有定数の一覧が唯一の置き場で、日本語の表示名も同数そろえています。
52種
Box のメンバーに見せる操作。業務の状態を変える 48 種と、Owner だけが見るアクセス履歴 4 種。
29種
アプリ自身が判定するアラート。7 つの系統に分けて絞り込めます。すべてに起票する実装があります。
6つ
5 分ごとに回る検知器。互いに独立に動き、1 つが失敗しても残りは止まりません。
2年
記録の保持期間。25 ヶ月を超えた月はデータベースから外し、圧縮した CSV として保管します。
19 列 / 10 列
取り出せる CSV の列数。全社の監査ログは機械での再取り込み向け、Box 側は表計算で開く向けです。

実装の規模

Implementation Footprint
対象数内訳
API の端点27全社の監査ログ 8 / Box のアクティビティ 4 / アラート 7 / 配信の運用 8
新規テーブル2取り出し依頼の台帳 / 退避の台帳。記録本体とアラートの器は既存
データベース側の仕組み関数 1 + 規則 3メンバー向けの読み取り関数 1 本と、2 テーブルの参照・追加の規則 3 本。加えて列単位の許可
バッチ3 + 1取り出し(依頼のたび)/ 月次の退避 / 5 分ごとの検知。加えてデータベース内の週次整備
追加した記録の種類9 種監査ログの閲覧・取り出し・退避分の取得で 6 種、アラートの状態変更で 3 種
自動テスト75 ファイルAPI 単体 35 / 実データベースを使う結合 7 / データベース権限 5 / 画面側の単体 21 / 共有定数の検算 4 / 画面と API の通し 3