mcpField
S
sf-debug

sf-debug

github.com/clientell-ai開発21100 回インストール33 週間前に更新
リポジトリ

sf-debug について

Salesforce 開発者向けのデバッグとトラブルシューティングガイドです。ログ、例外、性能上のボトルネックを扱い、原因調査の指針に加えて、ガバナ制限、CLI によるログ操作、プロファイリングを解説します。

主な機能

  1. 01Salesforce のデバッグログと実行フローの分析
  2. 02ガバナ制限の使用状況の確認
  3. 03一般的な例外の診断と原因の追跡
  4. 04sf CLI によるログの取得とリアルタイム表示
  5. 05チェックポイントとクエリプランを使った調査
  6. 06CPU、ヒープ、コード性能のプロファイリング

活用シーン

  1. 01Apex の例外やトリガー失敗の調査
  2. 02SOQL または DML の制限超過の特定
  3. 03Salesforce 組織のログのリアルタイム確認
  4. 04クエリループや高 CPU 使用などの性能問題の特定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/clientell-ai/salesforce-skills --skill sf-debug

インストール後、Claude Code で/sf-debugを入力して読み込まれたか確認します。

同梱ファイルreferences/debug-reference.md

詳細

Salesforce デバッグ・トラブルシューティングの専門家

Salesforce のデバッグを専門としています。デバッグログ、ガバナ制限違反、例外、パフォーマンスのボトルネックから問題を診断します。根本原因の分析と、実行可能な修正方法を提示します。

1. デバッグログの分析

ログレベル(詳細度の高い順)
レベル用途
FINEST完全なトレース — 変数の値、フレームワーク内部の呼び出し
FINER詳細なフロー — パラメーターを含むメソッドの開始・終了
FINE主な判断ポイントとループの反復
DEBUG一般的な診断情報
INFOトランザクションの主な節目
WARN問題を示唆する可能性がある、回復可能な問題
ERROR直ちに対処が必要な失敗
ログカテゴリ
カテゴリ記録される内容
Apex_codeApex の実行、System.debug() の出力、変数の割り当て
Apex_profiling累積リソース使用量 — SOQL、DML、CPU、ヒープ
DatabaseSOQL クエリ、DML 操作、クエリプラン、行数
Systemシステムメソッド、プラットフォームイベント、数式の評価
Validation入力規則、ワークフローの項目更新
Workflowワークフロー規則、プロセスビルダー、フローの実行
CalloutHTTP コールアウト、SOAP 呼び出し、外部サービスからの応答
VisualforceVF ページのレンダリング、ビューステート、コントローラーのアクション
NBANext Best Action 戦略の実行
デバッグログの読み方 — 主な行のプレフィックス
EXECUTION_STARTED / EXECUTION_FINISHED — transaction boundaries
CODE_UNIT_STARTED / CODE_UNIT_FINISHED — trigger, class, or method execution
SOQL_EXECUTE_BEGIN / SOQL_EXECUTE_END — query with row count
DML_BEGIN / DML_END — DML operation with row count
EXCEPTION_THROWN — exception type and message
FATAL_ERROR — unrecoverable error with stack trace
HEAP_ALLOCATE — heap memory allocation
LIMIT_USAGE_FOR_NS — governor limit summary per namespace
CUMULATIVE_LIMIT_USAGE — end-of-transaction limit summary
USER_DEBUG — System.debug() output
VARIABLE_SCOPE_BEGIN / VARIABLE_ASSIGNMENT — variable tracking (FINEST)
METHOD_ENTRY / METHOD_EXIT — method call tracking (FINER+)
FLOW_START_INTERVIEWS — flow/process builder execution
VALIDATION_RULE — validation rule evaluation
CALLOUT_REQUEST / CALLOUT_RESPONSE — external HTTP calls
ログの構成

デバッグログは次の順序で記録されます。

  1. EXECUTION_STARTED — トランザクション開始
  2. CODE_UNIT_STARTED — トリガーまたはエントリーポイントの実行
  3. トリガー前のロジック(入力規則、項目更新)
  4. DML の実行とトリガー後のロジック
  5. ワークフロー規則、プロセスビルダー、フロー
  6. ワークフローによって項目が更新された場合、トリガー前後の処理を再評価
  7. コミットまたはロールバック
  8. CUMULATIVE_LIMIT_USAGE — 最終的なガバナ制限の概要
  9. EXECUTION_FINISHED — トランザクション終了

2. ガバナ制限の監視

Limits クラスのメソッド — 制限に達する前に確認
// SOQL
System.debug('SOQL queries: ' + Limits.getQueries() + ' / ' + Limits.getLimitQueries());

// DML
System.debug('DML statements: ' + Limits.getDmlStatements() + ' / ' + Limits.getLimitDmlStatements());
System.debug('DML rows: ' + Limits.getDmlRows() + ' / ' + Limits.getLimitDmlRows());

// CPU
System.debug('CPU time (ms): ' + Limits.getCpuTime() + ' / ' + Limits.getLimitCpuTime());

// Heap
System.debug('Heap size (bytes): ' + Limits.getHeapSize() + ' / ' + Limits.getLimitHeapSize());

// Query rows
System.debug('Query rows: ' + Limits.getQueryRows() + ' / ' + Limits.getLimitQueryRows());

// Callouts
System.debug('Callouts: ' + Limits.getCallouts() + ' / ' + Limits.getLimitCallouts());

// Future calls
System.debug('Future calls: ' + Limits.getFutureCalls() + ' / ' + Limits.getLimitFutureCalls());

// Queueable jobs
System.debug('Queueable jobs: ' + Limits.getQueueableJobs() + ' / ' + Limits.getLimitQueueableJobs());
制限を確認するタイミング
  • 負荷の高い操作の前 — すぐにリファクタリングできないループ内のクエリまたは DML
  • バッチ処理後 — Database.Batchable.execute() の各バッチの最後
  • ユーティリティ/サービスクラス内 — プロファイリングのため、開始時と終了時に制限をログに記録
  • catch ブロック内 — LimitException が近づいている可能性がある場合
  • 短時間で多数回繰り返すループ内では使用しない — Limits.*() の呼び出し自体が CPU を消費します
同期処理と非同期処理の制限
リソース同期処理非同期処理(Batch/Future/Queueable)
SOQL クエリ100200
DML ステートメント150150
CPU 時間10,000 ms60,000 ms
ヒープサイズ6 MB12 MB
クエリ行数50,00050,000
コールアウト100100
DML 行数10,00010,000

3. よくあるエラーの診断

エラー考えられる原因対処方法
UNABLE_TO_LOCK_ROW同じレコード、または主従関係にある親レコードへの同時更新FOR UPDATE を指定して再試行する、バッチの対象範囲を小さくする、非同期処理を使う、不要な親レコードの更新を避ける
ENTITY_IS_DELETED同じトランザクション内、または別のユーザーによってすでに削除されたレコードに対する DMLDML の前に isDeleted を確認する、try/catch で同時実行を処理する、トリガーの実行順序を確認する
FIELD_CUSTOM_VALIDATION_EXCEPTION入力規則の失敗オブジェクトの入力規則を確認する、項目値がすべての条件を満たしていることを確認する、一部の成功を許容するには Database.insert(records, false) を使う
INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY関連レコード(参照関係/主従関係の親、所有者、キュー)へのアクセス権がない共有ルールを確認する、OWD を確認する、実行ユーザーが関連レコードにアクセスできることを確認する、明確な理由がある場合にのみ without sharing を使う
MIXED_DML_OPERATION同じトランザクション内で設定オブジェクト(User、Group)と非設定オブジェクトに対する DML を実行しているいずれかの DML を @future に移す、テストでは System.runAs() を使う、別々のトランザクションに分ける
System.LimitException: Too many SOQL queries同期トランザクション内で SOQL クエリが 100 件を超えているループの外にクエリを移す、検索にはコレクションと Map を使う、大規模なデータセットには SOQL for ループを使う
System.LimitException: Too many DML statementsトランザクション内で DML ステートメントが 150 件を超えているレコードを List にまとめ、ループの外で一括 DML を実行する
System.CalloutExceptionHTTP コールアウトの失敗 — タイムアウト、無効なエンドポイント、証明書の問題Named Credential の設定を確認する、エンドポイント URL を確認する、再試行でタイムアウトを処理する、リモートサイト設定を確認する
System.NullPointerExceptionnull 参照に対するメソッド/プロパティへのアクセスアクセス前に null チェックを追加する、セーフナビゲーション演算子 ?. を使う、アクセス前に SOQL の結果が返されていることを確認する
System.QueryException: List has no rows[SELECT ... LIMIT 1] の結果がなく、単一の sObject 変数に割り当てられているList<SObject> を使って .isEmpty() を確認するか、try/catch で囲む
System.QueryException: List has more than 1 row単一の変数に割り当てたクエリが複数の行を返したLIMIT 1 を追加するか、List<SObject> を使う。データを調査する — 重複はデータ品質の問題を示している可能性がある
CANNOT_INSERT_UPDATE_ACTIVATE_ENTITYトリガーの再帰、または連鎖するトリガーの失敗静的な再帰ガードを実装する、トリガーハンドラーフレームワークに再入防止機能があるか確認する
System.AsyncException非同期ジョブのキューへの追加数が多すぎる、またはチェーンの上限に達したLimits.getQueueableJobs() を確認する、バッチのチェーンには Finalizer を使う、Queueable ごとのキュー追加を 1 件に制限する
System.SerializationExceptionQueueable または Platform Event 内にシリアライズできないオブジェクトがあるtransient 参照を削除する、シリアライズされた状態でリレーション項目を持つ SObject 型を避ける
STRING_TOO_LONG項目値が最大長を超えているDML の前に .abbreviate(maxLength) で検証または切り詰めを行う
エラー診断のワークフロー
  1. エラーメッセージ全体を読む — Salesforce のエラーは STATUS_CODE: message 形式です
  2. 発生元の行を見つける — スタックトレースで Class.MethodName: line X, column Y を探します
  3. トリガーのコンテキストを特定する — insert/update の前か後かを確認します。CODE_UNIT_STARTED を確認してください
  4. 連鎖する失敗を確認する — 1 つのトリガーの失敗が、親トリガーで CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY を引き起こす場合があります
  5. 最小限のデータで再現する — Execute Anonymous または対象を絞ったテストメソッドを使います

4. デバッグログの CLI コマンド

ログをリアルタイムで表示する
# Stream logs as they are generated (colored output)
sf apex tail log --target-org myOrg --color

# Tail with specific log level
sf apex tail log --target-org myOrg --debug-level MyDebugLevel
ログを一覧表示して取得する
# List recent debug logs
sf apex log list --target-org myOrg --json

# Get a specific log by ID
sf apex log get --log-id 07Lxxxxxxxxxxxxxxx --target-org myOrg

# Get the most recent log
sf apex log get --number 1 --target-org myOrg

# Get logs and save to file for analysis
sf apex log get --log-id 07Lxxxxxxxxxxxxxxx --target-org myOrg > debug.log
デバッグ出力付きで Apex を実行する
# Execute anonymous Apex and capture output
sf apex run --target-org myOrg --file scripts/debug-script.apex

# Run inline Apex for quick debugging
echo "System.debug(Limits.getQueries());" | sf apex run --target-org myOrg
古いログを削除する
# Clean up old logs to free storage
sf apex log list --target-org myOrg --json | \
  sf data delete bulk --sobject ApexLog --file -

5. チェックポイントと Developer Console によるデバッグ

Execute Anonymous によるデバッグ

対象を絞った調査には Execute Anonymous を使います。

// Reproduce an issue with specific data
Account testAcc = [SELECT Id, Name, Industry FROM Account WHERE Id = '001xxxxxxxxxxxx'];
System.debug('Account state: ' + JSON.serializePretty(testAcc));

// Test a specific method in isolation
MyService service = new MyService();
try {
    service.processRecord(testAcc);
    System.debug('SUCCESS: Method completed without error');
} catch (Exception e) {
    System.debug('FAILED: ' + e.getTypeName() + ' - ' + e.getMessage());
    System.debug('Stack trace: ' + e.getStackTraceString());
}

// Check governor limits after operation
System.debug('Post-execution SOQL: ' + Limits.getQueries());
System.debug('Post-execution DML: ' + Limits.getDmlStatements());
System.debug('Post-execution CPU: ' + Limits.getCpuTime() + 'ms');
チェックポイント(Developer Console)
  • Developer Console で特定の行にチェックポイントを設定します
  • チェックポイントは、その実行時点のヒープ状態、ローカル変数、静的変数を取得します
  • 同時に有効にできるチェックポイントは最大 5 つです
  • チェックポイントは 30 分後に期限切れになります
  • 結果は Checkpoint Inspector タブに表示されます
  • System.debug() では不十分な場合にチェックポイントを使用します。オブジェクトグラフ全体を取得できます
Developer Console での SOQL クエリのデバッグ
Query Editor → Execute SOQL/SOSL directly
Logs tab → Filter by "DATABASE" events to see query performance
Query Plan tool → Use Tooling API: /services/data/vXX.0/query?explain=SELECT ...

6. パフォーマンスのプロファイリング

CPU ボトルネックの特定

デバッグログで次のパターンを探します。

  • METHOD_ENTRY / METHOD_EXIT — 対になった項目間の時間を計算します
  • 操作の規模に対して CUMULATIVE_LIMIT_USAGE の CPU 時間が長い
  • ループ内で大量の HEAP_ALLOCATE が発生している
よくあるパフォーマンス上のアンチパターン
アンチパターンログの兆候修正方法
ループ内の SOQL同じコード単位内で SOQL_EXECUTE_BEGIN が繰り返されるループの前にクエリを実行し、検索には Map を使用します
ループ内の DML同じコード単位内で DML_BEGIN が繰り返されるList にまとめ、ループの後に DML を 1 回実行します
大量のヒープ割り当てループ内で大きなバイト数を伴う HEAP_ALLOCATESOQL for ループを使用し、バッチで処理します
高コストな describe 呼び出しSchema.getGlobalDescribe() が繰り返される静的変数にキャッシュします
ループ内の文字列連結ヒープと CPU 時間が増加するString.join() または List<String> を使用します
絞り込みのない SOQLSOQL_EXECUTE_END の行数が多いWHERE フィルターを追加し、選択性の高いインデックス付きフィールドを使用します
コレクションのネストされたループCPU 使用率が高く、SOQL/DML の兆候がないMap による検索を使用し、O(n^2) を O(n) に減らします
CPU 時間のプロファイリングパターン
Long startCpu = Limits.getCpuTime();
// ... operation under test ...
Long endCpu = Limits.getCpuTime();
System.debug('CPU consumed: ' + (endCpu - startCpu) + 'ms for operation X');
ヒープのプロファイリングパターン
Integer heapBefore = Limits.getHeapSize();
// ... operation under test ...
Integer heapAfter = Limits.getHeapSize();
System.debug('Heap delta: ' + (heapAfter - heapBefore) + ' bytes for operation X');

7. トレースフラグ

CLI でのトレースフラグの設定
# Create a debug level first
sf data create record --sobject DebugLevel --target-org myOrg \
  --values "DeveloperName='DetailedDebug' MasterLabel='Detailed Debug' \
  ApexCode='FINE' ApexProfiling='FINEST' Database='FINE' System='DEBUG' \
  Validation='INFO' Workflow='INFO' Callout='INFO' Visualforce='INFO'"

# Query the debug level ID
sf data query --query "SELECT Id FROM DebugLevel WHERE DeveloperName='DetailedDebug'" \
  --target-org myOrg --json

# Create a trace flag for a specific user (lasts up to 24 hours)
sf data create record --sobject TraceFlag --target-org myOrg \
  --values "TracedEntityId='005xxxxxxxxxxxx' DebugLevelId='7dlxxxxxxxxxxxx' \
  LogType='USER_DEBUG' StartDate='2026-03-20T00:00:00.000Z' \
  ExpirationDate='2026-03-20T23:59:59.000Z'"
トレースフラグの種類
LogTypeトレース対象
USER_DEBUG特定のユーザーによるすべてのトランザクション
CLASS_TRACING特定の Apex クラスが関与する実行
DEVELOPER_LOG現在の Developer Console セッション
Setup UI でのトレースフラグ
  1. Setup > Debug Logs > New
  2. トレース対象のエンティティ(User、Apex Class、Apex Trigger)を選択します
  3. 開始時刻と終了時刻を設定します(最大 24 時間)
  4. デバッグレベルを選択します
  5. 保存します — 期限切れになるか、20 件のログが生成されるまで(いずれか早い方)、ログが取得されます

8. 注意点

デバッグログの切り詰め
  • デバッグログは 20 MB で切り詰められます — 大きなトランザクションではログの先頭部分が失われます
  • 切り詰められると、ログに *** Skipped N bytes of detailed log と表示されます
  • 回避するには、不要なカテゴリのログレベルを下げ、重要でないカテゴリを NONE または ERROR に設定します
  • 切り詰められたログにも、末尾に CUMULATIVE_LIMIT_USAGE が含まれます
ログの保持期間
  • デバッグログの保持期間は 24 時間 のみです(またはトレースフラグあたり 20 件のログが蓄積するまで)
  • 事後分析用の重要なログは、すぐにダウンロードしてください
  • 期限切れになる前に sf apex log get を使用して、ログをローカルファイルに保存します
トレースフラグの有効期限
  • トレースフラグの有効期間は最大 24 時間 です
  • 期限切れ後は警告なしでログの取得が停止します
  • 再現しにくい問題を再現する前に、トレースフラグを再作成してください
  • 組織あたりのデバッグログの上限は 250 MB です(古いログから削除されます)
デバッグによるパフォーマンスへの影響
  • System.debug() ステートメントは、本番環境でも CPU 時間を消費します
  • デバッグログへの書き込みにはオーバーヘッドがあり、高いログレベルは実行速度を低下させます
  • 複雑なトランザクションでは、ログレベルを FINEST にすると CPU 時間が 2 倍 になる場合があります
  • 本番環境へのデプロイ前に、デバッグステートメントを削除するか、実行を制御してください。
    // Use a custom setting or custom metadata to gate debug output
    if (DebugSettings__c.getInstance().EnableDetailedLogging__c) {
        System.debug(LoggingLevel.FINE, 'Detailed: ' + JSON.serialize(records));
    }
    
本番環境での System.debug()
  • 実行中のユーザーにトレースフラグが有効でない限り、デバッグステートメントは取得されません
  • トレースフラグが設定されているかどうかにかかわらず、CPU 時間は消費されます
  • 機密データ(PII、認証情報、トークン)を含む System.debug() は使用しないでください
  • 本番環境の可観測性には、カスタムのロギングフレームワーク(Platform Events + Big Objects)の使用を推奨します
その他の注意点
  • System.debug() は引数に対して toString() を呼び出します。オブジェクトグラフに null 参照があると、NullPointerException が発生する場合があります
  • 集計クエリ(COUNT()、SUM())は、集計結果ごとに 1 クエリ行を消費します
  • Database.setSavepoint() と Database.rollback() は DML ステートメントとしてカウントされます
  • after トリガー内の Trigger.new は読み取り専用です。変更すると実行時エラーが発生します
  • @isTest(SeeAllData=true) を使用するテストは開発環境では成功しても、データの違いにより CI では失敗する場合があります

9. デバッグのワークフロー

ステップごとの手順
  1. 問題を再現する

    • 失敗するユーザー操作、API 呼び出し、自動プロセスを正確に特定します
    • 発生した時間帯と、問題を経験しているユーザーを記録します
  2. トレースフラグを設定する

    # Ensure trace flag is active for the user
    sf apex tail log --target-org myOrg --color
    
  3. 問題を発生させてログを取得する

    • UI、API、または Execute Anonymous を使用して再現します
    • すぐにログを保存します:sf apex log get --number 1 --target-org myOrg > issue.log
  4. まずエラーを確認する

    • ログ内で EXCEPTION_THROWN、FATAL_ERROR、LIMIT_USAGE を検索します
    • ログが途中で切れている場合は、末尾の CUMULATIVE_LIMIT_USAGE に注目します
  5. 実行パスを追跡する

    • CODE_UNIT_STARTED を見つけて、実行されたトリガー/クラスを特定します
    • 実行順序を追跡します:before トリガー、DML、after トリガー、ワークフロー、プロセスビルダー、フロー
  6. ガバナ制限を確認する

    • LIMIT_USAGE_FOR_NS を確認します。いずれかの制限が 70% を超えていますか?
    • SOQL の実行回数と SOQL_EXECUTE_BEGIN イベントの数を照合します
  7. 根本原因を特定する

    • データの問題ですか?(レコードの欠落、null フィールド)
    • ロジックの問題ですか?(条件の誤り、一括処理対応の不足)
    • 制限の問題ですか?(ループ内の SOQL、ループ内の DML)
    • 同時実行の問題ですか?(レコードロック、競合状態)
    • 設定の問題ですか?(入力規則、共有ルール、権限)
  8. 修正して検証する

    • 正しい修正のうち、最小限のものを適用します
    • トレースフラグを有効にしたまま再実行し、問題が解決したことを確認します
    • ガバナ制限が改善したことを確認します(単にエラーが消えただけでないこと)
診断用のクイックコマンド
# Search for errors in a saved log
grep -E "EXCEPTION_THROWN|FATAL_ERROR|LIMIT_USAGE" debug.log

# Count SOQL queries in log (look for loops)
grep -c "SOQL_EXECUTE_BEGIN" debug.log

# Count DML operations in log
grep -c "DML_BEGIN" debug.log

# Find slow queries (queries returning many rows)
grep "SOQL_EXECUTE_END" debug.log | grep -E "Rows:[0-9]{3,}"

10. スキル間の連携

必要な作業連携先理由
Apex コードの修正sf-apexコード変更の生成とレビュー
テストの作成/実行sf-testingテストの実行、カバレッジ、アサーション
修正のデプロイsf-deployデプロイのオーケストレーション
データの調査sf-data組織データのクエリと確認
セキュリティ監査sf-securityCRUD/FLS と共有のレビュー

参考資料

  • デバッグリファレンス -- Limits クラスのメソッド、ログの解析パターン、Execute Anonymous のパターン、エラー処理、パフォーマンスプロファイリング、Tooling API のトレースフラグ
  • ガバナ制限 -- トランザクションごとの SOQL、DML、CPU、ヒープの制限

コメント