読者です 読者をやめる 読者になる 読者になる

職業プログラマの休日出勤

職業プログラマによる日曜自宅プログラミングや思考実験の成果たち。リアル休日出勤が発生すると更新が滞りがちになる。記事の内容は個人の意見であり、所属している(いた)組織の意見ではない。

CakePHP3で簡易監査ログ

情報システムを組み上げるときは「誰がいつ何をした」といった情報を残していくことが非常によくあります。この情報のことを監査ログと呼びますが、他にも呼び方があるかもしれません。英語では audit trail と言ったりしてたと思います。たぶん。

そのシステムがRDB(関係データベース)を用いたものである場合、監査ログそのものもRDB上に残すことがあります。
きちんとした監査ログにするためには、監査ログを格納するための専用のテーブルを設けます。そのテーブルはシステム全体で1個であることもあれば、システムが管理しているデータごとに設けていくこともあります。専用のテーブルを設けずに、いわゆる「論理削除」を積み重ねていってそれを監査ログ代わりにすることもあるでしょう(望ましいとは思えませんが)。
これらの手法は、正確な監査ログが取れるようになる代わりに、かなり手間がかかります。構築する情報システムにかける予算が少なかったり期間が短かったりすると、省略されることもしばしばあります。
省略するとは言っても完全に何も記録を取らないのは精神衛生上よくありませんので、簡易的な監査ログをとることになります。
何が簡易なのかと言うと、保持する情報を以下のものに限るのです。

  • 当該データを最初に登録した日時
  • 当該データを最初に登録した人
  • 当該データを最後に更新した日時
  • 当該データを最後に更新した人

これだけの情報が残っていれば、本当に僅かなものではありますが、何か調査するときの手がかりにはなります。

さて、かなり長い前置きになりましたが、ここからはCakePHPの話です。
CakePHPでは昔から(少なくとも 2.x 系から)、日時だけではありますが、簡易の監査ログをRDBに保存する仕組みがあります。テーブルに「modified」「created」といったタイムスタンプ型の列を用意しておくと、そこに自動で登録日時や更新日時をセットしてくれるのです。

Saving Your Data — CakePHP Cookbook 2.x documentation

登録/更新した人については、 AuthComponent::user('id') によってModel内のコードからでも当該HTTPリクエストのセッションに紐付いたユーザIDを取ることができたので、beforeSaveコールバックあたりを実装すれば保存できていました。

ところが、CakePHP 3.x になってから、上記の方法ではユーザIDを取得することができなくなってしまいました。このことはGitHub上でも話題になり、こんなissueが立てられています。github.com
良い設計ではないものを誘発するという理由で速攻でcloseされてしまっています。これまでの手法がそのような性質を帯びたものであることには一切異論は無いのですが、簡易監査ログを取ることにそんなにコスト(時間)かけられないというのも事実です。

じゃあ、悪い設計であることは重々承知の上で簡単な実装を作っちゃえ! ということで、ModelのBehaviorを作りました。ソースはGistに置いてるのをこの記事に埋め込んでます。
gist.github.com

作った後に気付いたのですが、素晴らしい先人たちはもっと良い実装を既にされていました。github.com
これはPluginとしての実装なので、こちらの方が使い易いという人も多いでしょう。しかもstaticおじさんと呼ばれる危険性を摘み取ってくれていますし。


こういったものを活用して、気軽に簡易監査ログを取れるようにして、健全な情報システムを構築していきましょう。