Skip to content

Commit ae24555

Browse files
Merge pull request #448 from lukecotter/feat-debug-only
feat: Call Tree debug only filter
2 parents 0fd82e0 + 1e82155 commit ae24555

2 files changed

Lines changed: 150 additions & 41 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- Debug Only Call Tree filtering ([#86][#86])
13+
- Filters the Call Tree to show only debug statments with the context of the Call Stack.
1214
- Show Log Parsing issues via notification bell ([#209][#209])
1315
- Shows unsupported log event names + invalid log lines
1416

@@ -293,6 +295,7 @@ Skipped due to adopting odd numbering for pre releases and even number for relea
293295

294296
<!-- Unreleased -->
295297

298+
[#86]: https://github.com/certinia/debug-log-analyzer/issues/86
296299
[#115]: https://github.com/certinia/debug-log-analyzer/issues/115
297300
[#423]: https://github.com/certinia/debug-log-analyzer/issues/423
298301
[#209]: https://github.com/certinia/debug-log-analyzer/issues/209

log-viewer/modules/components/calltree-view/CalltreeView.ts

Lines changed: 147 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ provideVSCodeDesignSystem().register(vsCodeCheckbox());
3131
let calltreeTable: Tabulator;
3232
let tableContainer: HTMLDivElement | null;
3333
let rootMethod: ApexLog | null;
34+
const debugOnlyFilterCache = new Map<number, boolean>();
35+
const showDetailsFilterCache = new Map<number, boolean>();
3436

3537
@customElement('call-tree-view')
3638
export class CalltreeView extends LitElement {
3739
@property()
3840
timelineRoot: ApexLog | null = null;
3941

42+
filterState = { showDetails: false, debugOnly: false };
43+
4044
get _callTreeTableWrapper(): HTMLDivElement | null {
4145
return (tableContainer = this.renderRoot?.querySelector('#call-tree-table') ?? null);
4246
}
@@ -81,10 +85,20 @@ export class CalltreeView extends LitElement {
8185
vertical-align: bottom;
8286
}
8387
84-
.filter-container {
88+
.header-bar {
8589
display: flex;
8690
gap: 10px;
8791
}
92+
93+
.filter-container {
94+
display: flex;
95+
gap: 5px;
96+
align-items: end;
97+
}
98+
99+
.filter-section {
100+
display: block;
101+
}
88102
`,
89103
];
90104

@@ -94,17 +108,27 @@ export class CalltreeView extends LitElement {
94108
return html`
95109
<div id="call-tree-container">
96110
<div>
97-
<strong>Filter</strong>
98-
<div class="filter-container">
99-
<vscode-button appearance="secondary" @click="${this._expandButtonClick}"
100-
>Expand</vscode-button
101-
>
102-
<vscode-button appearance="secondary" @click="${this._collapseButtonClick}"
103-
>Collapse</vscode-button
104-
>
105-
<vscode-checkbox class="checkbox__middle" @change="${this._handleShowDetailsChange}"
106-
>Show Details</vscode-checkbox
107-
>
111+
<div class="header-bar">
112+
<div class="filter-container">
113+
<vscode-button appearance="secondary" @click="${this._expandButtonClick}"
114+
>Expand</vscode-button
115+
>
116+
<vscode-button appearance="secondary" @click="${this._collapseButtonClick}"
117+
>Collapse</vscode-button
118+
>
119+
</div>
120+
121+
<div class="filter-section">
122+
<strong>Filter</strong>
123+
<div class="filter-container">
124+
<vscode-checkbox class="checkbox__middle" @change="${this._handleShowDetailsChange}"
125+
>Details</vscode-checkbox
126+
>
127+
<vscode-checkbox class="checkbox__middle" @change="${this._handleDebugOnlyChange}"
128+
>Debug Only</vscode-checkbox
129+
>
130+
</div>
131+
</div>
108132
</div>
109133
</div>
110134
<div id="call-tree-table-container">
@@ -117,21 +141,47 @@ export class CalltreeView extends LitElement {
117141

118142
_handleShowDetailsChange(event: Event) {
119143
const target = event.target as HTMLInputElement;
120-
const showDetails = target.checked;
121-
calltreeTable.setFilter((data, _filterParams) => {
122-
return showDetails || data.originalData.duration || data.originalData.discontinuity;
123-
});
144+
this.filterState.showDetails = target.checked;
145+
this._updateFiltering();
146+
}
147+
148+
_handleDebugOnlyChange(event: Event) {
149+
const target = event.target as HTMLInputElement;
150+
this.filterState.debugOnly = target.checked;
151+
this._updateFiltering();
152+
}
153+
154+
_updateFiltering() {
155+
calltreeTable.blockRedraw();
156+
if (this.filterState.showDetails) {
157+
// @ts-expect-error valid
158+
calltreeTable.removeFilter(showDetailsFilter);
159+
} else if (!this.filterState.showDetails) {
160+
// @ts-expect-error valid
161+
calltreeTable.addFilter(showDetailsFilter);
162+
}
163+
164+
if (this.filterState.debugOnly) {
165+
calltreeTable.clearFilter(false);
166+
// @ts-expect-error valid
167+
calltreeTable.addFilter(debugFilter);
168+
} else if (!this.filterState.debugOnly) {
169+
// @ts-expect-error valid
170+
calltreeTable.removeFilter(debugFilter);
171+
}
172+
173+
calltreeTable.restoreRedraw();
124174
}
125175

126176
_expandButtonClick() {
127177
calltreeTable.blockRedraw();
128-
expandAll(calltreeTable.getRows());
178+
expandCollapseAll(calltreeTable.getRows(), true);
129179
calltreeTable.restoreRedraw();
130180
}
131181

132182
_collapseButtonClick() {
133183
calltreeTable.blockRedraw();
134-
collapseAll(calltreeTable.getRows());
184+
expandCollapseAll(calltreeTable.getRows(), false);
135185
calltreeTable.restoreRedraw();
136186
}
137187

@@ -151,6 +201,34 @@ export class CalltreeView extends LitElement {
151201
}
152202
}
153203

204+
function deepFilter(
205+
rowData: CalltreeRow,
206+
filterFunction: (rowData: CalltreeRow) => boolean,
207+
filterParams: { filterCache: Map<number, boolean> },
208+
): boolean {
209+
const cachedMatch = filterParams.filterCache.get(rowData.id);
210+
if (cachedMatch !== null && cachedMatch !== undefined) {
211+
return cachedMatch;
212+
}
213+
214+
let childMatch = false;
215+
for (const childRow of rowData._children || []) {
216+
const match = deepFilter(childRow, filterFunction, filterParams);
217+
218+
if (match) {
219+
childMatch = true;
220+
break;
221+
}
222+
}
223+
224+
filterParams.filterCache.set(rowData.id, childMatch);
225+
if (childMatch) {
226+
return true;
227+
}
228+
229+
return filterFunction(rowData);
230+
}
231+
154232
export async function renderCallTree(
155233
callTreeTableContainer: HTMLDivElement,
156234
rootMethod: ApexLog,
@@ -283,7 +361,7 @@ export async function renderCallTree(
283361
width: 60,
284362
hozAlign: 'right',
285363
headerHozAlign: 'right',
286-
bottomCalc: 'sum',
364+
bottomCalc: 'max',
287365
},
288366
{
289367
title: 'SOQL Count',
@@ -292,7 +370,7 @@ export async function renderCallTree(
292370
width: 60,
293371
hozAlign: 'right',
294372
headerHozAlign: 'right',
295-
bottomCalc: 'sum',
373+
bottomCalc: 'max',
296374
},
297375
{
298376
title: 'Throws Count',
@@ -301,7 +379,7 @@ export async function renderCallTree(
301379
width: 60,
302380
hozAlign: 'right',
303381
headerHozAlign: 'right',
304-
bottomCalc: 'sum',
382+
bottomCalc: 'max',
305383
},
306384
{
307385
title: 'Rows',
@@ -310,7 +388,7 @@ export async function renderCallTree(
310388
width: 60,
311389
hozAlign: 'right',
312390
headerHozAlign: 'right',
313-
bottomCalc: 'sum',
391+
bottomCalc: 'max',
314392
},
315393
{
316394
title: 'Total Time (ms)',
@@ -326,7 +404,7 @@ export async function renderCallTree(
326404
precision: 3,
327405
},
328406
bottomCalcFormatter: NumberFormat,
329-
bottomCalc: 'sum',
407+
bottomCalc: 'max',
330408
bottomCalcParams: { precision: 3 },
331409
headerFilter: MinMaxEditor,
332410
headerFilterFunc: MinMaxFilter,
@@ -360,37 +438,30 @@ export async function renderCallTree(
360438
calltreeTable.on('dataFiltered', () => {
361439
totalTimeFilterCache.clear();
362440
selfTimeFilterCache.clear();
441+
debugOnlyFilterCache.clear();
442+
showDetailsFilterCache.clear();
363443
});
364444

365445
calltreeTable.on('tableBuilt', () => {
366446
resolve();
367-
calltreeTable.setFilter((data, _filterParams) => {
368-
return data.originalData.duration || data.originalData.discontinuity;
369-
});
447+
//@ts-expect-error valid
448+
calltreeTable.addFilter(showDetailsFilter);
370449
});
371450
});
372451
}
373452

374-
function expandAll(rows: RowComponent[]) {
375-
const len = rows.length;
376-
for (let i = 0; i < len; i++) {
377-
const row = rows[i];
378-
if (row) {
379-
row.treeExpand();
380-
381-
expandAll(row.getTreeChildren());
382-
}
383-
}
384-
}
385-
386-
function collapseAll(rows: RowComponent[]) {
453+
function expandCollapseAll(rows: RowComponent[], expand: boolean = true) {
387454
const len = rows.length;
388455
for (let i = 0; i < len; i++) {
389456
const row = rows[i];
390457
if (row) {
391-
row.treeCollapse();
458+
if (expand) {
459+
row.treeExpand();
460+
} else {
461+
row.treeCollapse();
462+
}
392463

393-
collapseAll(row.getTreeChildren());
464+
expandCollapseAll(row.getTreeChildren(), expand);
394465
}
395466
}
396467
}
@@ -486,3 +557,38 @@ interface CalltreeRow {
486557
totalThrownCount: number;
487558
rows: number;
488559
}
560+
561+
const showDetailsFilter = (data: CalltreeRow) => {
562+
return deepFilter(
563+
data,
564+
(rowData) => {
565+
return rowData.originalData.duration > 0 || rowData.originalData.discontinuity;
566+
},
567+
{
568+
filterCache: showDetailsFilterCache,
569+
},
570+
);
571+
};
572+
573+
const debugFilter = (data: CalltreeRow) => {
574+
return deepFilter(
575+
data,
576+
(rowData) => {
577+
const debugValues = [
578+
'USER_DEBUG',
579+
'DATAWEAVE_USER_DEBUG',
580+
'USER_DEBUG_FINER',
581+
'USER_DEBUG_FINEST',
582+
'USER_DEBUG_FINE',
583+
'USER_DEBUG_DEBUG',
584+
'USER_DEBUG_INFO',
585+
'USER_DEBUG_WARN',
586+
'USER_DEBUG_ERROR',
587+
];
588+
return debugValues.includes(rowData.originalData.type || '');
589+
},
590+
{
591+
filterCache: debugOnlyFilterCache,
592+
},
593+
);
594+
};

0 commit comments

Comments
 (0)