nebula-logger-best-practices について
nebula-logger-best-practicesは、Nebula Loggerを使うチーム向けのログ運用スキルです。ログ設計やレビューにおいて、レベルと保持期間の設定、構造化情報の追加、Salesforceの制限を踏まえた保存方法を扱います。
主な機能
- 01環境ごとのログレベル設定
- 02シナリオとタグによるログ分類
- 03構造化されたログ情報の追加
- 04意図的なログ保存タイミングの選択
- 05Salesforceの制限への配慮
活用シーン
- 01プルリクエストのログ変更をレビュー
- 02本番環境とテスト環境のログ量を設定
- 03バッチや非同期処理の保存時点を決定
- 04ストレージやイベント上限への負荷を抑制
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ jongpie/ nebulalogger --skill nebula-logger-best-practicesインストール後、Claude Code で/nebula-logger-best-practicesを入力して読み込まれたか確認します。
詳細
Nebula Logger のベストプラクティスとガバナンス
チーム全体でのプラクティス
プルリクエストをレビューするときや、ロギング規約を設計するときは、これらのデフォルトを使用してください。
ERROR、WARN、INFOは、運用上重要な情報にのみ使用します。- 大量の診断情報には
DEBUG、FINE、FINER、FINESTを使用します。これらはLoggerSettings__c.LoggingLevel__cと組み合わせることで、本番環境では実行時のオーバーヘッドを増やさずにコード内に残しておき、より詳細な診断が必要な場合にのみ有効化できます。 - 環境に応じて
LoggerSettings__cのデータを調整します。- 本番組織では
LoggingLevel__cをERROR、WARN、INFOに設定してログのノイズを減らします(デバッグ時はDEBUG、FINE、FINER、FINESTに変更します)。 - スケジュール済みの削除と保持期間(
DefaultLogPurgeAction__c、DefaultNumberOfDaysToRetainLogs__c)を設定します。
- 本番組織では
- ビジネスプロセスごとにグループ化するには、静的メソッド
Logger.setScenario()と、インスタンスメソッドLogEntryEventBuilder.addTag()およびLogEntryEventBuilder.addTags()を使用します。- チームにとって分かりやすい、シナリオとタグの統一された命名規則を定めます。
- メッセージ文字列に追加データを直接埋め込むのではなく、
LogEntryEventBuilderのインスタンスメソッドを使用してデータをさらに補足します。次のようなメソッドオーバーロードを利用できます。.setExceptionDetails(...).setApprovalResult(...).setDatabaseResult(...).setRecord(...).setHttpRequestDetails(...).setHttpResponseDetails(...).setRestRequestDetails(...).setRestResponseDetails(...).setField(...)
Logger.saveLog()は意図的に呼び出します。ログエントリごとに呼び出したり、タイトなループの中で呼び出したりしてはいけません。Apex で DML を呼び出す場合と同様に、戦略的に呼び出してください。Logger.info(...)、.error(...)などは、エントリをメモリ内バッファーに追加するだけです。saveLog()が実行されるまで、データは永続化されません。saveLog()を呼び出さずにトランザクションが終了すると、バッファー内のデータはすべて失われます。そのため、トランザクションがコミットされる前にsaveLog()を呼び出す必要があります。saveLog()を呼び出すたびに、実際のコストが発生するプラットフォーム操作が行われます。デフォルトの保存方法EVENT_BUSでは、saveLog()を呼び出すたびにSystem.EventBus.publish(List<LogEntryEvent__e>)が 1 回呼び出されます。これにより、System.Limits.getLimitPublishImmediateDML()の上限(1 トランザクションあたり 100 回)に対して 1 回分が消費され、組織の日次プラットフォームイベント発行割り当ても 1 回分消費されます。ほかの保存方法にもそれぞれ上限があります。QUEUEABLEは非同期ジョブの枠(System.Limits.getLimitQueueableJobs())を消費し、RESTはコールアウトを消費し、SYNCHRONOUS_DMLは通常の DML 行数とステートメント数を消費します。いずれも無料ではありません。- 1 つのトランザクションで
saveLog()を複数回呼び出しても問題なく、適切な場合もよくあります。中間状態を保存する妥当なタイミングには、バッチ内の各チャンクの処理後、長時間実行されるループの外側スコープで各反復の終了時(内側スコープでは決して呼び出さないでください。以下を参照)、非同期処理への引き渡し前(Queueable/Future/Batchable)、再スローする予定の例外を捕捉するfinallyブロック内などがあります。保存のたびに、その時点でバッファーにあるデータだけが発行されるため、後続のトランザクション処理が失敗しても、そのエントリは永続化されます。 - 問題なのは、ログエントリを 1 つ追加するたびに
saveLog()を呼び出すことです。これでは N 回のログ呼び出しが N 回のプラットフォームイベント発行に変わり、getLimitPublishImmediateDML()(1 トランザクションあたり 100 回)をすぐに使い切り、運用上の利点がないまま組織の日次プラットフォームイベント割り当ても消費します。Logger.info(...); Logger.saveLog();を繰り返し記述している場合は、エントリをバッファーに追加して、グループの処理後に 1 回保存してください。 - レコードを処理するループの最も内側の本体では、
saveLog()を決して呼び出さないでください。ループ内ではエントリをバッファーに追加し、各レコードの処理後ではなく、ループの後(または N 回の反復後、チャンクの処理後など、安全なチェックポイント)にsaveLog()を呼び出します。 - トランザクション処理のコードパスでは、例外が try から抜けても実行されるよう、
finallyブロック内にLogger.saveLog()を配置します。そのコードパスでデフォルトのEVENT_BUSが適切でない場合は、メソッドの先頭でLogger.setSaveMethod(...)と組み合わせてください(上記の保存方法に関する説明を参照)。
環境に応じたログレベル
ログの詳細度はコード定数ではなく、運用上の制御項目として扱います。
| 環境 | 推奨される基本設定 | 理由 |
|---|---|---|
| Production | ERROR または WARN | インシデントの兆候を維持しながら、ノイズとストレージへの影響を軽減します |
| UAT | INFO | 過剰な詳細情報を避けながら、ビジネスフローを検証します |
| QA | DEBUG または FINE | 不具合の再現と統合テストを支援します |
| Sandbox/Dev | FINE から FINEST(期間限定) | 開発中の詳細な診断に役立ちます |
一時的なインシデント対応期間には階層オーバーライド(ユーザー/プロファイル)を使用し、その後は元に戻します。
既存コードのレビュー用チェックリスト
- 各実行パスで、意図的に設定したチェックポイントで
saveLog()を呼び出していますか? エントリごと、またはレコード単位の内部ループ内で呼び出していませんか? - 例外はスタックトレースのコンテキストとともに記録されていますか?
.setRecord(...)を介してレコード参照を設定していますか?- シナリオとタグはチームの分類体系に沿っていますか?
- デフォルトの
EVENT_BUSを使わない場合、保存メソッドを明示的に選択していますか?
ガバナーと容量に関する考慮事項
Nebula Logger は可観測性の向上に役立ちますが、Salesforce のガバナー制限の範囲内で実行されます。
| 制約 | ロギングへの影響 | 対策 |
|---|---|---|
| データストレージ | 大量のログによってカスタムオブジェクトのストレージがすぐに消費される可能性があります | 保持ポリシーと削除スケジュールを適用し、本番環境ではログの詳細度を下げます |
| プラットフォームイベントの日次上限 | EVENT_BUS の量が組織のイベント割り当て上限に達する可能性があります | ログを選択的に記録し、必要に応じて対象ジョブを QUEUEABLE/SYNCHRONOUS_DML に切り替えます |
| SOQL クエリ | ロギングパスで追加される補足クエリによって制限がさらに厳しくなる可能性があります | クエリ済みのレコードを再利用し、ログ専用のクエリ増加を避けます |
| CPU 時間 | ループ内での重いシリアライズやタグ付けにより CPU 使用量が増加します | 反復ごとではなく集約したマイルストーンを記録し、非同期の保存パスを優先します |
| 非同期ジョブの割り当て | QUEUEABLE を使いすぎると、ビジネス上の非同期処理と競合する可能性があります | キュー可能な保存処理は、コストの高いコンテキストや混合 DML の影響を受けやすいコンテキストに限定します |
| ヒープサイズ | 大きなペイロードや例外によってトランザクションメモリが膨張する可能性があります | サイズ超過のペイロードを切り詰め、オブジェクトグラフ全体の出力を避けます |
Nebula Logger を使わない場合
Nebula Logger は、適切なアーキテクチャの代替にはなりません。
- 不明瞭なドメイン設計の回避策としてロギングを使用しないでください。
- ログメッセージにシークレット、認証情報、または不要な PII を保存しないでください。
Nebula Logger は、明確なサービス境界、堅牢なエラーハンドリング、目的に沿ったテレメトリと組み合わせ、構造化された可観測性レイヤーとして使用してください。
コメント
Markdown 対応