Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
dfbb6c9
feat: add --debug-level and --category-level flags to apex run @W-184…
WillieRuemmele Sep 4, 2026
d91d434
fix: address review findings for debug level flags
WillieRuemmele Sep 4, 2026
28c6752
docs: add 'All' category to --category-level description
WillieRuemmele Sep 8, 2026
69f17e6
chore: bump apx-node
WillieRuemmele Sep 11, 2026
b97ce71
chore: merge main, resolve conflicts
WillieRuemmele Sep 11, 2026
955d02a
docs: apply review suggestions for debug-level flag messaging
WillieRuemmele Sep 16, 2026
80b4d3f
feat: add commands to manage Apex debug log trace flags @W-24222806@
WillieRuemmele Sep 21, 2026
b50d8cd
fix: address review findings for trace flag commands
WillieRuemmele Sep 21, 2026
da987a1
chore: regenerate JSON schemas
WillieRuemmele Sep 21, 2026
531bb08
test: add NUT for trace flag lifecycle (create, list, delete)
WillieRuemmele Sep 21, 2026
6b53350
fix: use unique class names so schema generator produces all 3 schemas
WillieRuemmele Sep 21, 2026
98942b3
refactor: rename trace commands from apex {verb} trace to apex trace …
WillieRuemmele Sep 24, 2026
219d0ef
fix: remove bogus force:apex:trace aliases from new commands @W-24222…
WillieRuemmele Sep 24, 2026
4604fa6
Merge remote-tracking branch 'origin/main' into wr/manageTraceFlags
WillieRuemmele Sep 24, 2026
9cc699e
feat: add Status column to apex trace list output @W-24222806@
WillieRuemmele Sep 28, 2026
9eb23f8
W-24222806: embellish/edit the --help for the 3 new "apex trace" comm…
jshackell-sfdc Sep 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,40 @@
"flags": ["api-version", "color", "debug-level", "flags-dir", "loglevel", "skip-trace-flag", "target-org"],
"plugin": "@salesforce/plugin-apex"
},
{
"alias": [],
"command": "apex:trace:create",
"flagAliases": ["apiversion", "targetusername", "u"],
"flagChars": ["d", "i", "l", "o"],
"flags": [
"api-version",
"debug-level",
"duration",
"flags-dir",
"json",
"log-type",
"loglevel",
"target-org",
"traced-entity-id"
],
"plugin": "@salesforce/plugin-apex"
},
{
"alias": [],
"command": "apex:trace:delete",
"flagAliases": ["apiversion", "targetusername", "u"],
"flagChars": ["i", "o"],
"flags": ["api-version", "flags-dir", "json", "loglevel", "target-org", "trace-flag-id"],
"plugin": "@salesforce/plugin-apex"
},
{
"alias": [],
"command": "apex:trace:list",
"flagAliases": ["apiversion", "targetusername", "u"],
"flagChars": ["o"],
"flags": ["api-version", "flags-dir", "json", "loglevel", "target-org"],
"plugin": "@salesforce/plugin-apex"
},
{
"alias": [],
"command": "logic:get:test",
Expand Down
59 changes: 59 additions & 0 deletions messages/createtrace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# summary

Create a trace flag for a user, Apex class, or Apex trigger.

# description

Use trace flags to set up debug logging for a specified entity (user, Apex class, or Apex trigger). You must specify an existing debug level and the entity to trace. The trace flag expires after the specified duration (default 30 minutes).

To find the list of existing debug levels, run this Tooling API query on your org using the "data query" CLI command: "sf data query --query "SELECT DeveloperName FROM DebugLevel" --use-tooling-api". To create a debug level in your org, see "Set Up Debug Logging" (https://help.salesforce.com/s/articleView?id=xcloud.code_add_users_debug_log.htm)

Use the --log-type flag to specify the type of debug log file to create; you have these two options:

- DEVELOPER_LOG (default) — captures a full debug log, including Apex execution, SOQL, DML, callouts, and so on.
- USER_DEBUG — captures only System.debug() statements and user-generated log lines. Use this option for lighter-weight smaller logs.

After you create the trace flag, follow these steps to use it:

1. Perform the action that you want to debug. For example, if you created a trace flag for an Apex class, run the class.
2. Run the "apex log list" CLI command to get a list of the available debug logs in your org. Make note of the ID of the debug log you're interested in.
3. Run the "apex log get" command and specify this ID log with the --log-id flag. You can also use the --number flag to get the most recent debug logs.
4. Examine the debug log for information about the entity you created a trace flag for. See "Debug Log" (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_debugging_debug_log.htm) for more information.

# examples

- Create a trace flag for a user (ID starts with 005) with the SFDC_DevConsole debug level in your default org:

<%= config.bin %> <%= command.id %> --traced-entity-id 005xx000001Svs8AAC --debug-level SFDC_DevConsole

- Create a USER_DEBUG trace flag that lasts 60 minutes in the org with alias "my-org":

<%= config.bin %> <%= command.id %> --traced-entity-id 005xx000001Svs8AAC --debug-level MyDebugLevel --log-type USER_DEBUG --duration 60 --target-org my-org

# flags.traced-entity-id.summary

ID of the user, Apex class, or Apex trigger to trace.

# flags.debug-level.summary

Developer name of an existing debug level to apply.

# flags.log-type.summary

Type of trace flag to create.

# flags.duration.summary

Duration, in minutes, before the trace flag expires. Maximum is 1440 (24 hours).

# debugLevelNotFound

Debug level "%s" not found. Create one in Setup or specify an existing debug level.

# traceFlagCreateSuccess

Successfully created trace flag %s.

# traceFlagCreateFailed

Failed to create trace flag.
29 changes: 29 additions & 0 deletions messages/deletetrace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# summary

Delete a trace flag in your org.

# description

Remove a trace flag by its ID. Use "<%= config.bin %> apex trace list" to find trace flag IDs in your org.

# examples

- Delete a trace flag by ID in your default org:

<%= config.bin %> <%= command.id %> --trace-flag-id 7tf000000000001AAA

- Delete a trace flag by ID in an org with alias "my-org":

<%= config.bin %> <%= command.id %> --trace-flag-id 7tf000000000001AAA --target-org my-org

# flags.trace-flag-id.summary

ID of the trace flag to delete.

# traceFlagDeleteSuccess

Successfully deleted trace flag %s.

# traceFlagDeleteFailed

Failed to delete trace flag %s.
21 changes: 21 additions & 0 deletions messages/listtrace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# summary

List trace flags in your org.

# description

Display a list of active and recently expired trace flags in your org org. Trace flags control debug logging for a specific user, Apex class, or Apex trigger. Use the "apex trace create" CLI command to create a trace flag.

# examples

- List all trace flags in your default org:

<%= config.bin %> <%= command.id %>

- List trace flags for an org with alias "my-org":

<%= config.bin %> <%= command.id %> --target-org my-org

# noTraceFlagsFound

No trace flags found in org.
19 changes: 19 additions & 0 deletions schemas/apex-trace-create.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/TraceFlagCreateResult",
"definitions": {
"TraceFlagCreateResult": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"success": {
"type": "boolean"
}
},
"required": ["id", "success"],
"additionalProperties": false
}
}
}
19 changes: 19 additions & 0 deletions schemas/apex-trace-delete.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/TraceFlagDeleteResult",
"definitions": {
"TraceFlagDeleteResult": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"success": {
"type": "boolean"
}
},
"required": ["id", "success"],
"additionalProperties": false
}
}
}
85 changes: 85 additions & 0 deletions schemas/apex-trace-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/TraceFlagListResult",
"definitions": {
"TraceFlagListResult": {
"type": "array",
"items": {
"$ref": "#/definitions/TraceFlagRecord"
}
},
"TraceFlagRecord": {
"type": "object",
"properties": {
"Id": {
"type": "string"
},
"TracedEntityId": {
"type": "string"
},
"LogType": {
"type": "string"
},
"DebugLevelId": {
"type": "string"
},
"StartDate": {
"type": "string"
},
"ExpirationDate": {
"type": "string"
},
"Status": {
"type": "string",
"enum": ["Active", "Expired"]
},
"DebugLevel": {
"anyOf": [
{
"type": "object",
"properties": {
"DeveloperName": {
"type": "string"
}
},
"required": ["DeveloperName"],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"TracedEntity": {
"anyOf": [
{
"type": "object",
"properties": {
"Name": {
"type": "string"
}
},
"required": ["Name"],
"additionalProperties": false
},
{
"type": "null"
}
]
}
},
"required": [
"Id",
"TracedEntityId",
"LogType",
"DebugLevelId",
"StartDate",
"ExpirationDate",
"Status",
"DebugLevel",
"TracedEntity"
],
"additionalProperties": false
}
}
}
98 changes: 98 additions & 0 deletions src/commands/apex/trace/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2026, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
Flags,
SfCommand,
requiredOrgFlagWithDeprecations,
orgApiVersionFlagWithDeprecations,
loglevel,
} from '@salesforce/sf-plugins-core';
import { Messages, SfError } from '@salesforce/core';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-apex', 'createtrace');

export type TraceFlagCreateResult = {
id: string;
success: boolean;
};

export default class CreateTrace extends SfCommand<TraceFlagCreateResult> {
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description');
public static readonly examples = messages.getMessages('examples');
public static readonly flags = {
'target-org': requiredOrgFlagWithDeprecations,
'api-version': orgApiVersionFlagWithDeprecations,
loglevel,
'traced-entity-id': Flags.salesforceId({
char: 'i',
required: true,
summary: messages.getMessage('flags.traced-entity-id.summary'),
length: 'both',
}),
'debug-level': Flags.string({
char: 'd',
required: true,
summary: messages.getMessage('flags.debug-level.summary'),
}),
'log-type': Flags.string({
char: 'l',
summary: messages.getMessage('flags.log-type.summary'),
options: ['DEVELOPER_LOG', 'USER_DEBUG'] as const,
default: 'DEVELOPER_LOG',
}),
duration: Flags.integer({
summary: messages.getMessage('flags.duration.summary'),
default: 30,
min: 1,
max: 1440,
}),
};

public async run(): Promise<TraceFlagCreateResult> {
const { flags } = await this.parse(CreateTrace);
const conn = flags['target-org'].getConnection(flags['api-version']);

const escapedName = flags['debug-level'].replace(/'/g, "\\'");
const debugLevelQuery = `SELECT Id FROM DebugLevel WHERE DeveloperName = '${escapedName}'`;
const debugLevelResult = await conn.tooling.query<{ Id: string }>(debugLevelQuery);

if (!debugLevelResult.records?.length) {
throw new SfError(messages.getMessage('debugLevelNotFound', [flags['debug-level']]));
}

const debugLevelId = debugLevelResult.records[0].Id;
const startDate = new Date();
const expirationDate = new Date(startDate.getTime() + flags.duration * 60 * 1000);

const result = (await conn.tooling.create('TraceFlag', {
TracedEntityId: flags['traced-entity-id'],
LogType: flags['log-type'],
DebugLevelId: debugLevelId,
StartDate: startDate.toISOString(),
ExpirationDate: expirationDate.toISOString(),
})) as { id: string; success: boolean; errors: string[] };

if (!result.success) {
throw new SfError(messages.getMessage('traceFlagCreateFailed'), undefined, result.errors);
}

this.log(messages.getMessage('traceFlagCreateSuccess', [result.id]));
return { id: result.id, success: true };
}
}
Loading
Loading