Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b4e28a2
perf: switch to monomorphic object for LogLine
lukecotter Jan 7, 2025
0b8839c
fix: package wrapper handlinmg when Enetering managed pkg event has n…
lukecotter Jan 7, 2025
79df111
refactor: rename LogLine to LogEvent
lukecotter Jan 7, 2025
360f74f
Merge branch 'main' into perf-monomorphic-logevent
lukecotter Mar 31, 2025
a11f23b
Merge branch 'certinia:main' into perf-monomorphic-logevent
lukecotter Apr 1, 2025
02c30f7
Merge branch 'main' into perf-monomorphic-logevent
lukecotter Apr 7, 2025
c11599b
Merge branch 'main' into perf-monomorphic-logevent
lukecotter Apr 9, 2025
c055062
perf: speed up + simplify getMaxDepth
lukecotter May 1, 2025
d3819b4
perf: speed up + simplify nodeToRectangles
lukecotter May 1, 2025
3672202
refactor: remove remaining external refs to Method class
lukecotter May 1, 2025
d565e65
refactor: use set for namespace instead of set and array
lukecotter May 1, 2025
dfb5523
refactor: reorder assignments
lukecotter May 1, 2025
da2a6d6
perf: switch to asyn processing of log content
lukecotter May 1, 2025
3478615
perf: reduce calls to get from map
lukecotter May 1, 2025
0180a60
refactor: split ApexLogParser into multiple files
lukecotter May 1, 2025
d4de173
Merge branch 'main' into perf-monomorphic-logevent
lukecotter May 1, 2025
cc18d6f
Merge branch 'main' into perf-monomorphic-logevent
lukecotter May 1, 2025
1088c6e
fix: duplicate declaration after bad merge
lukecotter May 2, 2025
5fde7a1
fix: remove duplicate code after merge
lukecotter May 2, 2025
2890036
Merge branch 'main' into perf-monomorphic-logevent
lukecotter Aug 12, 2025
4cd7dcb
perf: replace Method class with isDetail property
lukecotter Aug 13, 2025
ccaa3a1
refactor: use property initialization instead of constructor
lukecotter Aug 26, 2025
c055e3c
refactor: remove unused properties
lukecotter Aug 28, 2025
266c2c3
refactor: narrow child type for SOQLExecuteBeginLine
lukecotter Aug 28, 2025
597d6d5
refactor: fix type
lukecotter Aug 28, 2025
038b85a
refactor: rename isDetail to isParent
lukecotter Aug 28, 2025
288457a
refactor: rename isDetail to isParent
lukecotter Aug 28, 2025
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
21 changes: 13 additions & 8 deletions log-viewer/modules/Database.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
/*
* Copyright (c) 2020 Certinia Inc. All rights reserved.
*/
import { ApexLog, DMLBeginLine, Method, SOQLExecuteBeginLine } from './parsers/ApexLogParser.js';
import {
type ApexLog,
DMLBeginLine,
type LogEvent,
SOQLExecuteBeginLine,
} from './parsers/LogEvents.js';

export type Stack = Method[];
export type Stack = LogEvent[];

export class DatabaseAccess {
private static _instance: DatabaseAccess | null = null;
Expand All @@ -23,13 +28,13 @@ export class DatabaseAccess {
public getStack(
timestamp: number,
stack: Stack = [],
line: Method = DatabaseAccess._treeRoot,
line: LogEvent = DatabaseAccess._treeRoot,
): Stack {
const children = line.children;
const len = children.length;
for (let i = 0; i < len; ++i) {
const child = children[i];
if (child instanceof Method) {
if (child?.isParent) {
stack.push(child);
if (child.timestamp === timestamp) {
return stack;
Expand All @@ -45,7 +50,7 @@ export class DatabaseAccess {
return [];
}

public getSOQLLines(line: Method = DatabaseAccess._treeRoot): SOQLExecuteBeginLine[] {
public getSOQLLines(line: LogEvent = DatabaseAccess._treeRoot): SOQLExecuteBeginLine[] {
const results: SOQLExecuteBeginLine[] = [];

const children = line.children;
Expand All @@ -56,15 +61,15 @@ export class DatabaseAccess {
results.push(child);
}

if (child instanceof Method) {
if (child?.isParent) {
Array.prototype.push.apply(results, this.getSOQLLines(child));
}
}

return results;
}

public getDMLLines(line: Method = DatabaseAccess._treeRoot): DMLBeginLine[] {
public getDMLLines(line: LogEvent = DatabaseAccess._treeRoot): DMLBeginLine[] {
const results: DMLBeginLine[] = [];

const children = line.children;
Expand All @@ -75,7 +80,7 @@ export class DatabaseAccess {
results.push(child);
}

if (child instanceof Method) {
if (child?.isParent) {
// results = results.concat(this.getDMLLines(child));
Array.prototype.push.apply(results, this.getDMLLines(child));
}
Expand Down
92 changes: 47 additions & 45 deletions log-viewer/modules/__tests__/ApexLogParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@
* Copyright (c) 2020 Certinia Inc. All rights reserved.
*/
import {
ApexLogParser,
CodeUnitStartedLine,
ExecutionStartedLine,
LogLine,
Method,
LogEvent,
MethodEntryLine,
SOQLExecuteBeginLine,
SOQLExecuteExplainLine,
TimedNode,
lineTypeMap,
parse,
parseObjectNamespace,
parseRows,
parseVfNamespace,
} from '../parsers/ApexLogParser.js';
} from '../parsers/LogEvents.js';
import { lineTypeMap } from '../parsers/LogLineMapping.js';

import { ApexLogParser, parse } from '../parsers/ApexLogParser.js';

class DummyLine extends LogEvent {
constructor(parser: ApexLogParser, parts: string[]) {
super(parser, parts);
}
}

describe('parseObjectNamespace tests', () => {
it('Should consider no separator to be unmanaged', () => {
Expand Down Expand Up @@ -79,30 +83,30 @@ describe('Pseudo EXIT events', () => {
expect(log1.children.length).toEqual(4);
expect(log1.duration).toEqual({ self: 0, total: 3 });

const approval1 = log1.children[0] as Method;
const approval1 = log1.children[0];
expect(approval1).toMatchObject({
type: 'WF_APPROVAL_SUBMIT',
timestamp: 1,
duration: { self: 1, total: 1 },
});

const processFound1 = log1.children[1] as Method;
const processFound1 = log1.children[1];
expect(processFound1).toMatchObject({
parent: log1,
type: 'WF_PROCESS_FOUND',
timestamp: 2,
duration: { self: 1, total: 1 },
});

const approval2 = log1.children[2] as Method;
const approval2 = log1.children[2];
expect(approval2).toMatchObject({
parent: log1,
type: 'WF_APPROVAL_SUBMIT',
timestamp: 3,
duration: { self: 1, total: 1 },
});

const processFound2 = log1.children[3] as Method;
const processFound2 = log1.children[3];
expect(processFound2).toMatchObject({
parent: log1,
type: 'WF_PROCESS_FOUND',
Expand All @@ -125,22 +129,22 @@ describe('Pseudo EXIT events', () => {
expect(log1.children.length).toEqual(1);
expect(log1.duration).toEqual({ self: 0, total: 6 });

const children = (log1.children[0] as Method).children;
const children = log1.children[0]?.children ?? [];
expect(children.length).toEqual(4);

const child1 = children[0] as Method;
const child1 = children[0]!;
expect(child1.timestamp).toEqual(2);
expect(child1.exitStamp).toEqual(3);

const child2 = children[1] as Method;
const child2 = children[1]!;
expect(child2.timestamp).toEqual(3);
expect(child2.exitStamp).toEqual(4);

const child3 = children[2] as Method;
const child3 = children[2]!;
expect(child3.timestamp).toEqual(4);
expect(child3.exitStamp).toEqual(5);

const child4 = children[3] as Method;
const child4 = children[3]!;
expect(child4.timestamp).toEqual(5);
expect(child4.exitStamp).toEqual(6);
});
Expand All @@ -157,18 +161,18 @@ describe('Pseudo EXIT events', () => {
expect(log1.children.length).toEqual(1);
expect(log1.duration).toEqual({ self: 0, total: 4 });

const children = (log1.children[0] as Method).children;
const children = log1.children[0]?.children ?? [];
expect(children.length).toEqual(3);

const child1 = children[0] as Method;
const child1 = children[0]!;
expect(child1.timestamp).toEqual(2);
expect(child1.exitStamp).toEqual(3);

const child2 = children[1] as Method;
const child2 = children[1]!;
expect(child2.timestamp).toEqual(3);
expect(child2.exitStamp).toEqual(4);

const child3 = children[2] as Method;
const child3 = children[2]!;
expect(child3.timestamp).toEqual(4);
expect(child3.exitStamp).toEqual(5);
});
Expand Down Expand Up @@ -204,7 +208,7 @@ describe('parseLog tests', () => {
expect(logLines.length).toEqual(1);
expect(logLines[0]).toBeInstanceOf(ExecutionStartedLine);

const firstChildren = (logLines[0] as Method).children;
const firstChildren = logLines[0]?.children ?? [];
expect(firstChildren.length).toEqual(1);
expect(firstChildren[0]).toBeInstanceOf(CodeUnitStartedLine);
});
Expand All @@ -222,7 +226,7 @@ describe('parseLog tests', () => {
expect(apexLog.children.length).toEqual(1);
expect(apexLog.children[0]).toBeInstanceOf(ExecutionStartedLine);

const firstChildren = (apexLog.children[0] as Method).children;
const firstChildren = apexLog.children[0]?.children ?? [];
expect(firstChildren.length).toEqual(1);
expect(firstChildren[0]).toBeInstanceOf(CodeUnitStartedLine);
});
Expand All @@ -237,7 +241,7 @@ describe('parseLog tests', () => {
expect(apexLog.children.length).toBe(1);
expect(apexLog.children[0]).toBeInstanceOf(ExecutionStartedLine);

const firstChildren = (apexLog.children[0] as Method).children;
const firstChildren = apexLog.children[0]?.children ?? [];
expect(firstChildren[0]).toBeInstanceOf(CodeUnitStartedLine);
});

Expand Down Expand Up @@ -403,7 +407,7 @@ describe('parseLog tests', () => {

const apexLog = parse(log);

const methods = apexLog.children as Method[];
const methods = apexLog.children;
expect(methods.length).toBe(24);
methods.forEach((line) => {
expect(line.exitTypes.length).toBe(0);
Expand All @@ -420,7 +424,7 @@ describe('parseLog tests', () => {
'09:19:13.82 (51595120059)|EXECUTION_FINISHED\n';

const apexLog = parse(log);
const execEvent = apexLog.children[0] as MethodEntryLine;
const execEvent = <MethodEntryLine>apexLog.children[0];
expect(execEvent).toBeInstanceOf(ExecutionStartedLine);

expect(execEvent.children.length).toEqual(1);
Expand All @@ -433,7 +437,7 @@ describe('parseLog tests', () => {
soqlCount: { self: 1, total: 1 },
});

const soqlExplain = soqlLine.children[0] as SOQLExecuteExplainLine;
const soqlExplain = soqlLine.children[0];
expect(soqlExplain).toMatchObject({
parent: soqlLine,
type: 'SOQL_EXECUTE_EXPLAIN',
Expand Down Expand Up @@ -461,7 +465,7 @@ describe('getRootMethod tests', () => {

const apexLog = parse(log);

const timedLogLines = apexLog.children as TimedNode[];
const timedLogLines = apexLog.children;
expect(timedLogLines.length).toBe(1);
const startLine = timedLogLines[0];
expect(startLine?.type).toBe('EXECUTION_STARTED');
Expand All @@ -475,7 +479,7 @@ describe('getRootMethod tests', () => {
});

expect(unitStart.children.length).toBe(1);
const interViewsBegin = unitStart.children[0] as TimedNode;
const interViewsBegin = unitStart.children[0]!;
expect(interViewsBegin).toMatchObject({
parent: unitStart,
type: 'FLOW_START_INTERVIEWS_BEGIN',
Expand Down Expand Up @@ -505,7 +509,7 @@ describe('getRootMethod tests', () => {

const apexLog = parse(log);

const timedLogLines = apexLog.children as TimedNode[];
const timedLogLines = apexLog.children;
expect(timedLogLines.length).toBe(1);
const startLine = timedLogLines[0];
expect(startLine?.type).toBe('EXECUTION_STARTED');
Expand All @@ -516,7 +520,7 @@ describe('getRootMethod tests', () => {
expect(unitStart.codeUnitType).toBe('Flow');

expect(unitStart.children.length).toBe(1);
const interViewsBegin = unitStart.children[0] as TimedNode;
const interViewsBegin = unitStart.children[0]!;
expect(interViewsBegin.type).toBe('FLOW_START_INTERVIEWS_BEGIN');
expect(interViewsBegin.text).toBe('FLOW_START_INTERVIEWS : Example Flow');
expect(interViewsBegin.suffix).toBe(' (Flow)');
Expand Down Expand Up @@ -544,7 +548,7 @@ describe('getRootMethod tests', () => {

const apexLog = parse(log);

const timedLogLines = apexLog.children as TimedNode[];
const timedLogLines = apexLog.children;
expect(timedLogLines.length).toBe(1);
const startLine = timedLogLines[0];
expect(startLine?.type).toBe('EXECUTION_STARTED');
Expand All @@ -555,17 +559,17 @@ describe('getRootMethod tests', () => {
expect(unitStart.codeUnitType).toBe('Workflow');

expect(unitStart.children.length).toBe(1);
const pbBegin = unitStart.children[0] as TimedNode;
const pbBegin = unitStart.children[0]!;
expect(pbBegin.type).toBe('FLOW_START_INTERVIEWS_BEGIN');
expect(pbBegin.text).toBe('FLOW_START_INTERVIEWS : Example Process Builder');
expect(pbBegin.suffix).toBe(' (Process Builder)');

expect(pbBegin.children.length).toBe(1);
const pbDetail = pbBegin.children[0] as TimedNode;
const pbDetail = pbBegin.children[0]!;
expect(pbDetail.type).toBe('FLOW_START_INTERVIEW_BEGIN');
expect(pbDetail.text).toBe('Example Process Builder');

const interViewsBegin = pbDetail.children[0] as TimedNode;
const interViewsBegin = pbDetail.children[0]!;
expect(interViewsBegin.type).toBe('FLOW_START_INTERVIEWS_BEGIN');
expect(interViewsBegin.text).toBe('FLOW_START_INTERVIEWS : Example Flow');
expect(interViewsBegin.suffix).toBe(' (Flow)');
Expand Down Expand Up @@ -640,9 +644,9 @@ describe('getRootMethod tests', () => {
expect(apexLog.exitStamp).toBe(1100);
expect(apexLog.executionEndTime).toBe(1100);

const rootChildren = apexLog.children as Method[];
const rootChildren = apexLog.children;
const executionStarted = rootChildren[0];
const executionChildren = executionStarted?.children as Method[];
const executionChildren = executionStarted?.children ?? [];
expect(executionChildren.length).toBe(5);

expect(executionChildren[0]).toMatchObject({
Expand Down Expand Up @@ -1115,7 +1119,8 @@ describe('namespace tests', () => {
describe('Recalculate durations tests', () => {
it('Recalculates parent node', () => {
const parser = new ApexLogParser();
const node = new Method(parser, ['14:32:07.563 (1)', 'DUMMY'], [], 'Method', '');
const node = new DummyLine(parser, ['14:32:07.563 (1)', 'DUMMY']);
node.subCategory = 'Method';
node.exitStamp = 3;

node.recalculateDurations();
Expand Down Expand Up @@ -1249,20 +1254,17 @@ describe('Governor Limits Parsing', () => {
describe('Line Type Tests', () => {
it('Lines referenced by exitTypes should be exits', () => {
const parser = new ApexLogParser();
for (const [key, lineType] of lineTypeMap) {
for (const lineType of Object.values(lineTypeMap)) {
const line = new lineType(parser, [
'14:32:07.563 (17358806534)',
'DUMMY',
'[10]',
'Rows:3',
'',
'Rows:5',
]) as LogLine;
if (line instanceof Method) {
expect(line.exitTypes).not.toBe(null);
if (line.isExit) {
expect(line.exitTypes).toEqual([key]);
}
]) as LogEvent;

if (line.isParent) {
line.exitTypes.forEach((exitType) => {
const exitCls = lineTypeMap.get(exitType);
expect(exitCls).not.toBe(null);
Expand All @@ -1274,7 +1276,7 @@ describe('Line Type Tests', () => {
'Rows:3',
'',
'Rows:5',
]) as LogLine;
]) as LogEvent;
expect(exitLine.isExit).toBe(true);
}
});
Expand Down
Loading
Loading