メインコンテンツへスキップ
見出し画像

ServiceNowの変更履歴はどこに残る? sys_auditと監査対象フィールドを実機で確認


    「このレコードを誰がいつ変更したのか」を調べたくても、Activityタブに目的の項目が見当たらないことがあります。ServiceNowは変更履歴をsys_auditやsys_journal_fieldという専用テーブルに切り出して記録するため、保存先を知らないと探す場所を間違えます。どのテーブルを監査するかはdictionaryのaudit属性が決めており、件数が0だからといって監査が無効とは限りません。Zurich PDIのOOTBで、この保存の仕組みと監査対象を実機で確認しました。

    検証環境:Zurich PDI / OOTB / 2026-08-08 確認

    結論:変更履歴は4つの専用テーブルとdictionaryの1属性で決まる

    先に全体像です。

    • 変更履歴はレコード本体ではなく、4つの専用テーブルに保存されます。フィールドの値の変更はsys_audit、work_notes / commentsの追記はsys_journal_fieldです。

    • 画面のActivityタブは、この2つを「開いたときにまとめる」sys_history_set / sys_history_lineというキャッシュ層から組み立てられます。恒久保存はsys_audit側にあり、履歴セットは表示用の複製です。

    • どのテーブルを監査するかはdictionaryのaudit属性が決めます。PDIではaudit=trueのテーブル行が1,206件あり、実際の変更ログはtask系(Incident / Problem / Change)に集中していました。


    画像

    濃紺のレコードから、変更は恒久保存の2テーブル(赤)へ、Activityタブを開いた瞬間に表示用のキャッシュ(緑)が組み立てられる、という流れです。


    画像

    4テーブルとも、PDIではsuper_classが空のルート基底テーブルでした。taskを継承していません。監査・履歴はtask系の業務テーブルとは独立した、プラットフォーム共通の仕組みとして用意されています。

    Activityタブに並んでいるのは何の記録か

    下の画面は、PDIのIncidentフォームです。Activity(Activities: 23)には、ユーザー名と日時つきで次の3種類が時系列に並びます。

    • フィールド変更(例:「Incident state Closed was Resolved」=状態がResolvedからClosedに変わった)

    • Resolution code・Resolution notesの追記

    • Comments

    同じレコードを開き直せば、この並びがそのまま再現されます。


    画像

    フィールド変更とComments・work_notesの追記は、見た目は1本のタイムラインですが、裏側では別のテーブルに分かれて保存されています。次からその2系統を順番に見ていきます。

    値の変更はsys_auditに1行ずつ記録される

    監査の中心がsys_audit(画面ラベルはSys Audit)です。監査対象のテーブルでフィールドが変わるたびに、「1フィールドの1回の変更」が1レコードとして追記されます。PDIでは、sys_auditに50,483件のレコードがありました。4テーブルの中で圧倒的に多く、変更の事実がここに積み上がっています。

    sys_auditの1レコードは、変更の「5W」を1行で表します。


    画像

    主な固有フィールドは次のとおりです。ラベルは画面上の表示名で、実機どおり記載します。


    画像

    実機でsys_auditを開くと、この構造がそのまま列として並びます。下の画面は、tablename=incidentで絞ったsys_audit一覧です。close_codeが空 →「Solution provided」、knowledgeが0 → 1、incident_stateが1 → 7。Old value → New valueがフィールド単位で並びます。Update count(record_checkpoint)はそのレコードの何回目の更新かを表します。


    画像

    sys_auditは追記専用(insertのみ)で、sys_updated_onを持ちません。一度記録された変更ログは更新されず、積み上がっていくだけです。これが「いつ何が起きたか」の証跡になる理由ですが、同時にテーブルが大きくなりやすい理由でもあります。公式ドキュメントでも、sys_auditは月単位でテーブル拡張に分割され、インスタンスでも有数の巨大テーブルになり得ると説明されています(本記事ではその物理構造までは確認していません)。

    work_notesやcommentsはsys_journal_fieldに別管理される

    フィールドの「値の変更」とは別系統が追記です。work_notes(作業メモ・社内向け)とcomments(追加コメント・顧客向け)への追記は、sys_journal_field(画面ラベルはJournal Entry)に保存されます。


    画像

    ここが監査と混同しやすいところです。work_notes / commentsは、フォーム上は1つの入力欄に見えます。実際にはレコード本体の列に上書き保存されず、追記するたびにsys_journal_fieldへ1レコードずつ積まれます。過去の追記は消えず、すべて時系列で残る仕組みです。

    PDIでは、sys_journal_fieldは1,310件でした。テーブル別(name)ではchange_requestが1,136件、taskが150件、incidentが18件です。element別ではapproval_historyが1,223件と大半を占め、人が手で書くcomments 57件、work_notes 30件でした。incidentの例では、work_notesが9件・commentsが9件です。


    画像

    sys_journal_fieldの主なフィールドは次のとおりです。

    • name … 対象テーブル

    • element … 追記の種別(work_notes / comments / approval_history)

    • element_id … 対象レコードのsys_id

    • value … 追記された本文

    • sys_created_by / sys_created_on … 誰がいつ追記したか

    sys_auditと同じくsys_updated_onを持たない追記専用で、「1追記=1レコード」になっています。公式のJournal fields(Zurich系ドキュメント)に、work_notes / commentsといったjournal型フィールドの仕組みが説明されています。

    Activityタブの表示はどこから組み立てられるのか

    Activityはsys_auditを毎回そのまま読むわけではありません。sys_history_set(Record History)とsys_history_line(History)という、まとめ用のテーブルを経由します。

    件数を見ると差が分かります。PDIでは、sys_history_setが9件、sys_history_lineが183件でした。sys_auditが50,483件あるのに対してここまで少ないのには理由があります。

    sys_history_set / sys_history_lineは、最初から全レコード分が作られているわけではありません。誰かがそのレコードのActivity(履歴)を開いたときに、sys_auditとsys_journal_fieldから必要な分だけ生成・キャッシュされます。恒久的な記録の本体はsys_audit側にあり、履歴セットはその表示用のまとめです。履歴を一度も開いていないレコードは、sys_history_setにまだ存在しないことがあります。

    • sys_history_set(Record History) … 1レコード=1履歴セット。持つのはtable(対象テーブル)、id("Incident: INC0000060"のような対象レコード表示)、updates(履歴行の数)、line_table(履歴行を保持する物理テーブル名)。PDIではINC0000060の履歴セットがupdates=15でした。

    • sys_history_line(History) … Activityの1行=1変更。field / old / new(旧 → 新)、update_time / userを持ち、set(→ sys_history_set)で履歴セットに紐づきます。元になったsys_audit / sys_journal_fieldのレコードをaudit_sysid / journal_sysidで参照します。


    画像

    Activity表示は2層構造です。恒久保存のsys_audit / sys_journal_fieldと、表示用にまとめたsys_history_set / sys_history_lineで成り立っています。監査ログそのものを調べたいときはsys_audit、画面の見え方をデバッグしたいときはsys_history_set、と使い分けます。

    監査のON/OFFはdictionaryのaudit属性が決める

    すべてのテーブルが監査されるわけではありません。変更をsys_auditに残すかどうかを決めるのは、dictionary(sys_dictionary)のaudit属性です。設定する場所は、そのテーブルのテーブル行(Column nameが空の行)です。


    画像

    PDIでは、dictionaryでaudit=trueになっているテーブル行が1,206件でした。これが監査の有効なテーブル数のおおよその目安です(audit属性を持つ行の全体は1,425件で、フィールド単位の上書きも含みます)。incidentテーブル自体を見ると、audit=trueの行はテーブル行が1件だけで、フィールド単位で個別にaudit属性を上書きしている行は0件でした。監査の有無はテーブル単位の設定がそのまま効いており、フィールドごとに例外を積み増す運用にはなっていません。

    監査を有効にしたときの既定は、公式ドキュメントによればblacklist(ブラックリスト)方式です。テーブルでauditを有効にすると、no_audit属性が付いた一部の項目を除き、原則すべての項目が監査対象になります。特定の項目だけを監査したい場合は、audit_type=whitelist属性を使うwhitelist方式に切り替えます。

    sys_auditのテーブル別件数を見ると、監査はtask系(Incident / Problem / Change / Knowledge)に集中していました。


    画像

    sysapproval_approverとalm_assetは、sys_auditの件数こそ0でしたが、dictionaryのaudit属性はどちらもtrueです。監査は有効なまま、対象の変更がまだ起きていなかっただけでした。一方cmdb_ciとtask(基底テーブル自体)は、audit属性そのものがfalseで、こちらは実際に監査対象外です。件数が0のときは、audit属性を見ないと「対象外」と「まだ変更が起きていないだけ」を区別できません。

    sys_auditの対象になっているフィールド定義は、実機のsys_dictionaryでname=sys_auditを条件に確認できます。


    画像

    公式のDifferences Between Audit and History Sets(Zurich)に、sys_auditとhistory setの役割の違いが説明されています。Viewing the Sys Audit table(Zurich)ではsys_auditテーブルの見方が解説されています。

    障害調査や監査対応ではどう使うか

    「このレコードを誰がいつ変更したか」を調べたいとき、フォームのActivityタブを1件ずつ目で追うより、sys_auditをtablenameとdocumentkeyで絞り込む方が速い場面があります。特定の項目だけを追いたいときはfieldnameも条件に加えます。監査対応で証跡の書き出しが必要な場合も、sys_auditの一覧画面からフィルタしての確認が近道です。

    新しく作ったテーブルで変更履歴が残らないときは、まずdictionaryのaudit属性を確認します。テーブル行(Column nameが空の行)でaudit=trueになっているか、blacklist方式でno_audit属性を持つ項目が対象から外れていないかを見ます。0件という結果だけで「監査対象外」と判断せず、audit属性そのものを見た方が確実です。

    実機で気づいたこと

    sys_history_set / sys_history_lineは「開いたときに作られるキャッシュ」だと説明しましたが、本当にそうなのか気になったので、後日改めて数え直してみました。結果はsys_history_setが9件から6件、sys_history_lineが183件から30件と、むしろ減っています。sys_auditは増え続ける記録ですが、こちらは一定期間で消える・入れ替わるキャッシュであることが、件数の変化から確認できました。

    もう1つ意外だったのが、sysapproval_approverとalm_assetの扱いです。最初にsys_auditを確認したときはどちらも0件で、監査対象外だと判断していました。dictionaryを見直すと、どちらもaudit=trueです。実際、後日数え直すとsysapproval_approverは0件から72件に増えていました。承認の処理が動いた分だけ、監査ログがそこから積み上がったことになります。cmdb_ciとtaskは、dictionary側もaudit=falseで、こちらは最初の判断どおり監査対象外でした。0件という結果は、監査の有無を保証してくれません。

    本文で扱った4テーブルとは別に、レコードの削除だけを記録するsys_audit_deleteというテーブルもあります。数えてみると、この記事を書き直している時点ですでに数千件のレコードが溜まっていました。フィールドの値の変更を追うsys_auditとは別枠で、削除だけを専門に監査する仕組みが用意されています。

    まとめ

    ServiceNowの変更履歴は、レコード本体には残りません。sys_audit / sys_journal_field / sys_history_set / sys_history_lineという4つの専用テーブルに分かれて保存されています。フィールドの値はsys_auditに恒久保存され、work_notesやcommentsはsys_journal_fieldに別管理されます。Activityタブの表示は、その場で作られるキャッシュ(sys_history_set / sys_history_line)から組み立てられる仕組みです。

    監査の対象になるかどうかは、dictionaryのaudit属性で決まります。0件という結果だけでは監査の有無を判断できないので、疑わしいときはaudit属性そのものを確認するのが近道です。

    よくある質問

    Q1. sys_auditに記録がないテーブルは、監査対象外と判断していいですか

    いいえ。dictionaryのaudit属性がtrueなのに、対象の変更がまだ起きていないだけというケースがあります。本記事のsysapproval_approverとalm_assetがその例です。0件という結果だけで判断せず、audit属性そのものを確認してください。

    Q2. なぜcmdb_ciはOOTBで監査対象外なのですか

    cmdb_ciはdictionary側でaudit属性がfalseになっています。CMDBは変更のたびにフィールド単位のログを積み上げる設計になっていません。かわりにConfiguration Management Database(CMDB)で説明されているIdentification and Reconciliation(IRE)という仕組みを使います。この仕組みでデータの整合性を管理します。

    Q3. sys_auditとsys_history_setは何が違い、どちらを見ればいいですか

    監査ログそのものを調べたいときはsys_audit、Activityタブに表示される内容をそのまま確認したいときはsys_history_setです。sys_auditは恒久保存、sys_history_setは開いたときに作られるキャッシュという役割の違いがあります。

    次に読むなら

    用語

    • PDI … Personal Developer Instance(無料の検証用インスタンス)

    • OOTB … Out of the Box(初期設定のまま)

    • 監査(Audit) … フィールド変更をsys_auditに記録する仕組み

    • Journal field … work_notes / commentsのような追記型フィールド(sys_journal_fieldに保存)

    • History set … Activityタブ表示用にまとめた履歴(sys_history_set / sys_history_line)

    • blacklist / whitelist … 監査対象の決め方(既定はblacklist)

    実機で確認するときに開くURL

    先頭に自分のインスタンスを付けて開きます。

    Incidentフォーム        : incident.do?sys_id=<対象レコードのsys_id>
    sys_auditの変更ログ     : sys_audit_list.do?sysparm_query=tablename=incident^ORDERBYDESCsys_created_on
    sys_journal_fieldの追記 : sys_journal_field_list.do?sysparm_query=name=incident^ORDERBYDESCsys_created_on
    sys_history_setの履歴セット: sys_history_set_list.do?sysparm_query=ORDERBYDESCsys_created_on
    sys_auditの項目定義     : sys_dictionary_list.do?sysparm_query=name=sys_audit^elementISNOTEMPTY
    audit有効なテーブル一覧 : sys_dictionary_list.do?sysparm_query=elementISEMPTY^audit=true

    参考リンク

    検証環境と未検証範囲

    件数はZurich PDI(OOTB)で確認したものです。一覧画面の件数表示と実レコードを突き合わせて数えており、推定やサンプリングではありません。sys_audit / sys_journal_fieldは追記専用のため件数は増え続けます。本文の数値を確認したあとにsys_audit全体を数え直すと56,734件まで増えていました。本番環境やカスタマイズ済みの環境では、対象テーブル・フィールド・件数が異なります。

    確認した範囲は次のとおりです。

    • 4テーブル(sys_audit / sys_journal_field / sys_history_set / sys_history_line)の階層(いずれもルート基底)と固有フィールド数(12 / 7 / 19 / 24)

    • 4テーブルのレコード件数、sys_auditのテーブル別件数とdictionaryのaudit属性

    • sys_journal_fieldのelement別分布

    • dictionaryのaudit=true件数(テーブル単位・全体・incident単体)とIncidentフォームのactivity表示

    未確認の範囲もあります(断定しません)。

    • sys_auditのテーブル拡張(月次分割テーブル)の物理構造

    • Audit Management Console / sys_audit_retention(Zurichの新機能)の動作

    • sys_audit_delete(削除レコードの監査)の詳しい挙動

    • 各監査を動かす内部Business Ruleの実装、履歴セットがキャッシュされる厳密なタイミング条件

    これらは別記事で扱います。


    このシリーズの記事一覧

    ServiceNowの機能を1テーマずつ実機で確かめた記事を、分類ごとにまとめています。読みたいテーマから辿れます。

    → ServiceNow 観察日記 - 目次 -

     
     
    ServiceNowのPDI(Personal Developer Instance)を実機で観察して、Noteに記事を書いています 実装・運用・教育の現場視点で淡々と記録中です リクエストがあればその記事も書きます 個人の観察日記です

    あなたへのおすすめ