Bug 1721427 - [devtools] Allow filtering frames being processed by the JavaScript tracer. r=devtools-reviewers,nchevobbe

This feature is only exposed to internal usages of tracer.jsm, by passing filterFrameSourceUrl string option:
```
startTracing({ global, filterFrameSourceUrl: "file.js" });
```
This will restrict the tracer to only log traces for the given file URL.
This is a loose URL check, so any source whose URL includes the passed string will be traced.

Differential Revision: https://phabricator.services.mozilla.com/D201979
This commit is contained in:
Alexandre Poirot 2024-02-27 14:52:12 +00:00
parent 750292190a
commit 671ce91a25
2 changed files with 57 additions and 0 deletions

View File

@ -461,4 +461,44 @@ add_task(async function testTracingPauseOnStep() {
Assert.equal(sandbox.counter, 1);
info("The thread should have paused at least the pauseOnStep's duration");
Assert.greater(Cu.now() - startTimestamp, 250);
info("Stop tracing");
stopTracing();
});
add_task(async function testTracingFilterSourceUrl() {
// Test the `filterFrameSourceUrl` flag
const sandbox = Cu.Sandbox("https://example.com");
// Use a unique global (sandbox), but with two distinct scripts (first.js and second.js)
const source1 = `function foo() { bar(); }`;
Cu.evalInSandbox(source1, sandbox, null, "first.js", 1);
// Only code running in that second source should be traced.
const source2 = `function bar() { }`;
Cu.evalInSandbox(source2, sandbox, null, "second.js", 1);
// Pass an override method to catch all strings tentatively logged to stdout
const logs = [];
function loggingMethod(str) {
logs.push(str);
}
info("Start tracing");
startTracing({
global: sandbox,
filterFrameSourceUrl: "second",
loggingMethod,
});
info("Call some code");
sandbox.foo();
Assert.equal(logs.length, 2);
Assert.equal(logs[0], "Start tracing JavaScript\n");
Assert.stringContains(logs[1], "λ bar");
Assert.stringContains(logs[1], "second.js:1:18");
info("Stop tracing");
stopTracing();
});

View File

@ -147,6 +147,9 @@ const customLazy = {
* @param {Boolean} options.traceFunctionReturn
* Optional setting to enable when the tracing should notify about frame exit.
* i.e. when a function call returns or throws.
* @param {String} options.filterFrameSourceUrl
* Optional setting to restrict all traces to only a given source URL.
* This is a loose check, so any source whose URL includes the passed string will be traced.
* @param {Number} options.maxDepth
* Optional setting to ignore frames when depth is greater than the passed number.
* @param {Number} options.maxRecords
@ -213,6 +216,12 @@ class JavaScriptTracer {
}
this.pauseOnStep = options.pauseOnStep;
}
if ("filterFrameSourceUrl" in options) {
if (typeof options.filterFrameSourceUrl != "string") {
throw new Error("'filterFrameSourceUrl' attribute should be a string");
}
this.filterFrameSourceUrl = options.filterFrameSourceUrl;
}
// An increment used to identify function calls and their returned/exit frames
this.frameId = 0;
@ -565,6 +574,14 @@ class JavaScriptTracer {
return;
}
try {
// If an optional filter is passed, ignore frames which aren't matching the filter string
if (
this.filterFrameSourceUrl &&
!frame.script.source.url?.includes(this.filterFrameSourceUrl)
) {
return;
}
// Because of async frame which are popped and entered again on completion of the awaited async task,
// we have to compute the depth from the frame. (and can't use a simple increment on enter/decrement on pop).
const depth = getFrameDepth(frame);