Skip to content

Commit

Permalink
fix: add more telemetry to apex replay debugger (#5724)
Browse files Browse the repository at this point in the history
* fix: add more telemetry to apex replay debugger

* test: fix broken tests. Tests for new telemetry still need to be done

* chore: remove as x

* chore: remove unused imports

* chore: fix setBreakPointsRequest

* chore: add 2 more events and tests

* chore: remove as MetricLaunch in test

* chore: remove unused import

* chore: typo
  • Loading branch information
CristiCanizales authored Aug 16, 2024
1 parent 40b0ad4 commit e50c270
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import {
Variable
} from '@vscode/debugadapter';
import { DebugProtocol } from '@vscode/debugprotocol';
import { MetricError, MetricLaunch } from '..';
import { breakpointUtil, LineBreakpointInfo } from '../breakpoints';
import {
SEND_METRIC_GENERAL_EVENT,
SEND_METRIC_ERROR_EVENT,
SEND_METRIC_LAUNCH_EVENT
} from '../constants';
Expand Down Expand Up @@ -260,16 +260,43 @@ export class ApexReplayDebug extends LoggingDebugSession {
TRACE_CATEGORY_LAUNCH,
`launchRequest: args=${JSON.stringify(args)}`
);
this.sendEvent(
new Event(SEND_METRIC_GENERAL_EVENT, {
subject: `launchRequest: args=${JSON.stringify(args)}`,
type: 'launchApexReplayDebugger'
})
);

this.logContext = new LogContext(args, this);
this.heapDumpService = new HeapDumpService(this.logContext);

if (!this.logContext.hasLogLines()) {
response.message = nls.localize('no_log_file_text');
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: 'No log lines found',
callstack: new Error().stack,
message: response.message
})
);
} else if (!this.logContext.meetsLogLevelRequirements()) {
response.message = nls.localize('incorrect_log_levels_text');
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: 'Incorrect log levels',
callstack: new Error().stack,
message: response.message
})
);
} else if (!lineBreakpointInfoAvailable) {
response.message = nls.localize('session_language_server_error_text');
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: 'No line breakpoint info available',
callstack: new Error().stack,
message: response.message
})
);
} else {
this.printToDebugConsole(
nls.localize('session_started_text', this.logContext.getLogFileName())
Expand All @@ -283,6 +310,13 @@ export class ApexReplayDebug extends LoggingDebugSession {
) {
response.message = nls.localize('heap_dump_error_wrap_up_text');
this.errorToDebugConsole(nls.localize('heap_dump_error_wrap_up_text'));
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: 'Fetching heap dumps failed',
callstack: new Error().stack,
message: response.message
})
);
}
response.success = true;
}
Expand All @@ -294,7 +328,7 @@ export class ApexReplayDebug extends LoggingDebugSession {
error: {
subject: response.message
}
} as MetricLaunch)
})
);
}

Expand Down Expand Up @@ -327,6 +361,12 @@ export class ApexReplayDebug extends LoggingDebugSession {
threadId: ApexReplayDebug.THREAD_ID
});
}
this.sendEvent(
new Event(SEND_METRIC_GENERAL_EVENT, {
subject: 'configurationDoneRequest',
type: 'apexReplayDebuggerConfigurationDone'
})
);
}

public disconnectRequest(
Expand All @@ -336,6 +376,12 @@ export class ApexReplayDebug extends LoggingDebugSession {
this.printToDebugConsole(nls.localize('session_terminated_text'));
response.success = true;
this.sendResponse(response);
this.sendEvent(
new Event(SEND_METRIC_GENERAL_EVENT, {
subject: 'disconnectRequest',
type: 'apexReplayDebuggerDisconnect'
})
);
}

public threadsRequest(response: DebugProtocol.ThreadsResponse): void {
Expand Down Expand Up @@ -369,9 +415,10 @@ export class ApexReplayDebug extends LoggingDebugSession {
} catch (error) {
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: error.message,
callstack: error.stack
} as MetricError)
subject: 'Heap dump processing error',
callstack: error.stack,
message: error.message
})
);
this.logContext.revertStateAfterHeapDump();
this.warnToDebugConsole(
Expand Down Expand Up @@ -424,20 +471,39 @@ export class ApexReplayDebug extends LoggingDebugSession {
);
response.body = { scopes };
this.sendResponse(response);
this.sendEvent(
new Event(SEND_METRIC_GENERAL_EVENT, {
subject: 'scopesRequest',
type: 'apexReplayDebuggerScopesRequest',
numberOfScopes: scopes.length
})
);
}

public async variablesRequest(
response: DebugProtocol.VariablesResponse,
args: DebugProtocol.VariablesArguments
): Promise<void> {
response.success = true;
const scopesContainer = this.logContext
.getVariableHandler()
.get(args.variablesReference);
response.body = {
variables: scopesContainer ? scopesContainer.getAllVariables() : []
};
this.sendResponse(response);
try {
const scopesContainer = this.logContext
.getVariableHandler()
.get(args.variablesReference);
response.body = {
variables: scopesContainer ? scopesContainer.getAllVariables() : []
};
this.sendResponse(response);
} catch (error) {
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: 'Error in variablesRequest',
callstack: error.stack,
message: error.message
})
);
response.success = false;
this.sendResponse(response);
}
}

protected evaluateRequest(
Expand Down Expand Up @@ -486,28 +552,39 @@ export class ApexReplayDebug extends LoggingDebugSession {
): void {
response.success = true;
this.sendResponse(response);
const prevNumOfFrames = this.logContext.getNumOfFrames();
while (this.logContext.hasLogLines()) {
this.logContext.updateFrames();
const curNumOfFrames = this.logContext.getNumOfFrames();
if (
(stepType === Step.Over &&
curNumOfFrames !== 0 &&
curNumOfFrames <= prevNumOfFrames) ||
(stepType === Step.In && curNumOfFrames >= prevNumOfFrames) ||
(stepType === Step.Out &&
curNumOfFrames !== 0 &&
curNumOfFrames < prevNumOfFrames)
) {
return this.sendEvent(
new StoppedEvent('step', ApexReplayDebug.THREAD_ID)
);
}
if (this.shouldStopForBreakpoint()) {
return;
try {
const prevNumOfFrames = this.logContext.getNumOfFrames();
while (this.logContext.hasLogLines()) {
this.logContext.updateFrames();
const curNumOfFrames = this.logContext.getNumOfFrames();
if (
(stepType === Step.Over &&
curNumOfFrames !== 0 &&
curNumOfFrames <= prevNumOfFrames) ||
(stepType === Step.In && curNumOfFrames >= prevNumOfFrames) ||
(stepType === Step.Out &&
curNumOfFrames !== 0 &&
curNumOfFrames < prevNumOfFrames)
) {
return this.sendEvent(
new StoppedEvent('step', ApexReplayDebug.THREAD_ID)
);
}
if (this.shouldStopForBreakpoint()) {
return;
}
}
this.sendEvent(new TerminatedEvent());
} catch (error) {
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: 'Error during step execution',
callstack: error.stack,
message: error.message
})
);
throw error;
}
this.sendEvent(new TerminatedEvent());
}

protected shouldStopForBreakpoint(): boolean {
Expand Down Expand Up @@ -560,6 +637,15 @@ export class ApexReplayDebug extends LoggingDebugSession {
this.breakpoints
.get(uri)!
.push(this.convertClientLineToDebugger(bp.line));
} else {
// Report an error metric when a breakpoint fails to verify
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: 'Failed to set breakpoint',
callstack: new Error().stack,
message: `Failed to set breakpoint at line ${bp.line} in ${args.source.path}`
})
);
}
}
this.log(
Expand All @@ -568,6 +654,22 @@ export class ApexReplayDebug extends LoggingDebugSession {
args.source.path
} verified lines=${this.breakpoints.get(uri)!.join(',')}`
);
this.sendEvent(
new Event(SEND_METRIC_GENERAL_EVENT, {
subject: 'setBreakPointsRequest',
type: 'apexReplayDebuggerSetBreakpoints',
numberOfVerifiedBreakpoints: response.body.breakpoints.filter(
bp => bp.verified
).length
})
);
} else {
this.sendEvent(
new Event(SEND_METRIC_ERROR_EVENT, {
subject: 'setBreakPointsRequest - path or breakpoints invalid',
type: 'apexReplayDebuggerSetBreakpoints'
})
);
}
response.success = true;
this.sendResponse(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const EVENT_VARIABLE_ASSIGNMENT = 'VARIABLE_ASSIGNMENT';
export const EXEC_ANON_SIGNATURE = 'execute_anonymous_apex';
export const FIELD_INTEGRITY_EXCEPTION = 'FIELD_INTEGRITY_EXCEPTION';
export const INVALID_CROSS_REFERENCE_KEY = 'INVALID_CROSS_REFERENCE_KEY';
export const SEND_METRIC_GENERAL_EVENT = 'sendMetricGeneral';
export const SEND_METRIC_ERROR_EVENT = 'sendMetricError';
export const SEND_METRIC_LAUNCH_EVENT = 'sendMetricLaunch';
export const LAST_OPENED_LOG_FOLDER_KEY = 'LAST_OPENED_LOG_FOLDER_KEY';
Expand Down
6 changes: 6 additions & 0 deletions packages/salesforcedx-apex-replay-debugger/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@ export type MetricError = {
subject: string;
callstack: string;
};

export type MetricGeneral = {
subject: string;
type: string;
qty?: number;
};
Loading

0 comments on commit e50c270

Please sign in to comment.