关于 sf-debug
面向 Salesforce 开发者的调试与故障排查指南,可分析日志、异常和性能瓶颈,并给出根因排查方向与修复建议。内容包括 governor limit、CLI 日志操作和性能剖析。
主要功能
- 01分析 Salesforce 调试日志与执行过程
- 02检查 governor limit 使用情况
- 03诊断常见异常并定位根因
- 04使用 sf CLI 获取和跟踪日志
- 05通过检查点与查询计划排查问题
- 06分析 CPU、堆内存及代码性能
适用场景
- 01排查 Apex 异常和触发器失败
- 02定位 SOQL 或 DML 超限
- 03跟踪 Salesforce 组织中的实时日志
- 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_code | Apex 执行、System.debug() 输出、变量赋值 |
Apex_profiling | 累积资源使用情况——SOQL、DML、CPU、堆 |
Database | SOQL 查询、DML 操作、查询计划、行数 |
System | 系统方法、平台事件、公式计算 |
Validation | 验证规则、工作流字段更新 |
Workflow | 工作流规则、流程构建器、流执行 |
Callout | HTTP 调用、SOAP 调用、外部服务响应 |
Visualforce | VF 页面渲染、视图状态、控制器操作 |
NBA | Next 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
日志结构
调试日志按以下顺序记录:
EXECUTION_STARTED— 事务开始CODE_UNIT_STARTED— 触发器或入口点触发- 前置触发器逻辑(验证、字段更新)
- DML 执行和后置触发器逻辑
- 工作流规则、流程构建器、流
- 如果工作流导致字段更新,则重新评估前置/后置触发器
- 提交或回滚
CUMULATIVE_LIMIT_USAGE— 最终治理限制摘要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 查询 | 100 | 200 |
| DML 语句 | 150 | 150 |
| CPU 时间 | 10,000 ms | 60,000 ms |
| 堆大小 | 6 MB | 12 MB |
| 查询行数 | 50,000 | 50,000 |
| 调用次数 | 100 | 100 |
| DML 行数 | 10,000 | 10,000 |
3. 常见错误诊断
| 错误 | 可能原因 | 修复方向 |
|---|---|---|
UNABLE_TO_LOCK_ROW | 同一记录或主从关系中的父记录遭到并发更新 | 使用 FOR UPDATE 重试,缩小批次范围,使用异步处理,避免不必要地更新父记录 |
ENTITY_IS_DELETED | 在同一事务中或由其他用户删除记录后,又对其执行了 DML | 执行 DML 前检查 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.CalloutException | HTTP 调用失败——超时、端点无效或证书问题 | 检查 Named Credential 配置,验证端点 URL,处理超时并重试,检查远程站点设置 |
System.NullPointerException | 在空引用上访问方法或属性 | 访问前添加空值检查,使用安全导航运算符 ?.,访问前确认 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.SerializationException | Queueable 或 Platform Event 中包含无法序列化的对象 | 移除瞬态引用,避免在序列化状态中使用带有关系字段的 SObject 类型 |
STRING_TOO_LONG | 字段值超过最大长度 | 在执行 DML 前使用 .abbreviate(maxLength) 验证或截断 |
错误诊断工作流
- 阅读完整错误消息 — Salesforce 错误采用
STATUS_CODE: message格式 - 找到错误源代码行 — 在堆栈跟踪中查找
Class.MethodName: line X, column Y - 确定触发器上下文 — 当前是 before/after insert/update?检查
CODE_UNIT_STARTED - 检查级联故障 — 一个触发器失败可能导致父触发器中出现
CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY - 使用最少数据重现问题 — 使用 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');
检查点(开发者控制台)
- 在开发者控制台的特定行上设置检查点
- 检查点会捕获该执行点的堆状态、局部变量和静态变量
- 同时最多激活 5 个检查点
- 检查点会在 30 分钟后过期
- 结果会显示在 Checkpoint Inspector 选项卡中
- 当 System.debug() 不够用时,请使用检查点——它们会捕获完整的对象图
在开发者控制台中调试 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_USAGECPU 时间过高 - 循环中出现大量
HEAP_ALLOCATE
常见的性能反模式
| 反模式 | 日志信号 | 修复方法 |
|---|---|---|
| 在循环中执行 SOQL | 同一代码单元中重复出现 SOQL_EXECUTE_BEGIN | 在循环前查询,使用 Map 进行查找 |
| 在循环中执行 DML | 同一代码单元中重复出现 DML_BEGIN | 收集到 List 中,在循环结束后一次性执行 DML |
| 大量分配堆内存 | 循环中出现带有较大字节数的 HEAP_ALLOCATE | 使用 SOQL for 循环,分批处理 |
| 昂贵的 describe 调用 | 重复调用 Schema.getGlobalDescribe() | 缓存到静态变量中 |
| 在循环中拼接字符串 | 堆内存和 CPU 时间持续上升 | 使用 String.join() 或 List<String> |
| 未筛选的 SOQL | SOQL_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 | 当前开发者控制台会话 |
通过 Setup UI 设置跟踪标志
- Setup > Debug Logs > New
- 选择跟踪对象(User、Apex Class、Apex Trigger)
- 设置开始/结束时间(最长 24 小时)
- 选择调试级别
- 保存——日志会持续捕获,直到过期或生成 20 条日志(以先发生者为准)
8. 注意事项
调试日志截断
- 调试日志会在 20 MB 处截断——大型事务会丢失日志开头部分
- 截断时,日志会显示
*** Skipped N bytes of detailed log - 为避免此情况:降低不需要的类别的日志级别,将非必要类别设为 NONE 或 ERROR
- 截断的日志仍会在末尾包含
CUMULATIVE_LIMIT_USAGE
日志保留
- 调试日志仅保留 24 小时(或直到每个跟踪标志累计 20 条日志)
- 请立即下载关键日志,以便进行事后分析
- 使用
sf apex log get在日志过期前将其保存到本地文件
跟踪标志过期
- 跟踪标志的最长有效时间为 24 小时
- 过期后会静默停止捕获日志,不会发出警告
- 在复现间歇性问题前,请重新创建跟踪标志
- 每个 org 最多可保存 250 MB 的调试日志(优先清除最旧的日志)
调试的性能影响
- 即使在生产环境中,
System.debug()语句也会消耗 CPU 时间 - 写入调试日志会增加开销——较高的日志级别会减慢执行速度
- 对于复杂事务,FINEST 日志级别可能会使 CPU 时间翻倍
- 部署到生产环境前,请移除或加防护条件的调试语句:
// 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 时间
- 切勿使用
System.debug()记录敏感数据(PII、凭据、令牌) - 在生产环境中进行可观测性监控时,优先使用自定义日志框架(Platform Events + Big Objects)
其他注意事项
System.debug()会对参数调用toString()——如果对象图中存在空引用,这可能会抛出 NullPointerException- 聚合查询(
COUNT()、SUM())每个聚合结果消耗 1 条查询记录 Database.setSavepoint()和Database.rollback()计为 DML 语句- 在 after 触发器中,Trigger.new 是只读的——修改它会抛出运行时错误
- 使用
@isTest(SeeAllData=true)的测试在开发环境中可能通过,但由于数据差异,在 CI 中可能失败
9. 调试工作流
分步流程
-
复现问题
- 找出失败的具体用户操作、API 调用或自动化流程
- 记录时间范围以及遇到问题的用户
-
设置跟踪标志
# Ensure trace flag is active for the user sf apex tail log --target-org myOrg --color -
触发问题并捕获日志
- 通过 UI、API 或 Execute Anonymous 复现
- 立即保存日志:
sf apex log get --number 1 --target-org myOrg > issue.log
-
先扫描错误
- 在日志中搜索
EXCEPTION_THROWN、FATAL_ERROR和LIMIT_USAGE - 如果日志被截断,请重点查看末尾的
CUMULATIVE_LIMIT_USAGE
- 在日志中搜索
-
追踪执行路径
- 查找
CODE_UNIT_STARTED,以确定执行了哪些触发器/类 - 追踪执行顺序:before 触发器、DML、after 触发器、工作流、流程构建器、流程
- 查找
-
检查治理限制
- 查看
LIMIT_USAGE_FOR_NS——是否有任何限制超过 70%? - 将 SOQL 计数与
SOQL_EXECUTE_BEGIN事件数进行交叉核对
- 查看
-
找出根本原因
- 是数据问题吗?(缺少记录、字段为空)
- 是逻辑问题吗?(条件错误、缺少批量处理)
- 是限制问题吗?(循环中的 SOQL、循环中的 DML)
- 是并发问题吗?(记录锁定、竞态条件)
- 是配置问题吗?(验证规则、共享规则、权限)
-
修复并验证
- 应用最小且正确的修复
- 在跟踪标志启用时重新运行,以确认问题已解决
- 检查治理限制是否有所改善(而不只是错误消失)
快速诊断命令
# 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-security | CRUD/FLS 和共享审查 |
参考资料
评论
支持 Markdown