Any way to detect an async stack trace (like Chrome devtools does)?
#!/JoePea
joe at trusktr.io
Sat Jul 11 04:21:51 UTC 2020
Hello Kai! That example is so meta with its own output showing the
numbers relative to the code including its own output! :)
That's what I originally wanted to do, but that doesn't give us an
async stack trace, it only gives a sync stack trace (I presume within
the current event loop task).
For example:
```js
const originalFetch = globalThis.fetch
globalThis.fetch = function(...args) {
const stack = new Error().stack
console.log(stack)
return originalFetch.apply(globalThis, args)
}
const sleep = t => new Promise(r => setTimeout(r, t))
async function one() {
console.log('1')
await sleep(10)
two()
}
async function two() {
console.log('2')
await sleep(10)
three()
}
async function three() {
console.log('3')
await sleep(10)
return await fetch('https://unpkg.com/three@0.118.3')
}
async function main() {
await one()
}
main()
```
Output:
```
1
2
3
Error
at globalThis.fetch (pen.js:5)
at three (pen.js:27)
```
Live example:
https://codepen.io/trusktr/pen/b8fd92752b4671268f516ad3804869e4?editors=1010
I opened a request for this over here:
https://github.com/tc39/proposal-error-stacks/issues/34
#!/JoePea
On Fri, Jul 10, 2020 at 1:21 PM kai zhu <kaizhu256 at gmail.com> wrote:
>
> > (I want to detect traces in third-party code installed locally).
>
> 1. here's 15-line javascript-hack to trace async-fetch-calls from 3rd-party-cdn-library
>
> ```html
> <!doctype html>
> <html lang="en">
> <body>
> <h1>test.html</h1>
> <script>
> (function () {
> /*
> * 15-line-javascript-hack to trace async-fetch-calls
> * enable hack by adding search-query "?modeDebugFetch=1" to web-url
> */
> "use strict";
> if ((/\bmodeDebugFetch=1\b/).test(location.search)) {
> let fetch0;
> fetch0 = globalThis.fetch;
> globalThis.fetch = function (...argList) {
> let errStack = new Error().stack;
> console.error("\n\nfetch-call-arguments:");
> console.error(JSON.stringify(argList, undefined, 4));
> console.error("\n\nfetch-call-trace:");
> console.error(errStack);
> return fetch0(...argList);
> };
> }
> }());
> </script>
> <!-- 3rd-party-cdn-library -->
> <script src="https://unpkg.com/http-client/umd/http-client.js"></script>
> <script>
> (async function foo() {
> "use strict";
> let thirdParty = window.HTTPClient;
> let myFetch = thirdParty.createFetch(
> thirdParty.base("https://api.stripe.com/v1"),
> thirdParty.accept("application/json")
> );
> let response = await myFetch("/customers/5");
> console.log(response.jsonData);
> /*
> dev-console-output - http://localhost:8081/test.html?modeDebugFetch=1
> fetch-call-arguments:
> [
> "https://api.stripe.com/v1/customers/5",
> {
> "headers": {
> "Accept": "application/json"
> },
> "responseHandlers": [
> null
> ]
> }
> ]
> fetch-call-trace:
> Error
> at globalThis.fetch (test.html?modeDebugFetch=1:16)
> at http-client.js:194
> at http-client.js:127
> at http-client.js:217
> at http-client.js:126
> at http-client.js:154
> at http-client.js:95
> at foo (test.html?modeDebugFetch=1:35)
> at test.html?modeDebugFetch=1:64
> */
> }());
> </script>
> </body>
> ```
>
>
> 2. here's real-world-hack added to npm-cli.js to debug its http-requests
>
> ```diff
> C:\Program Files\nodejs\node_modules\npm>git diff
> diff --git a/bin/npm-cli.js b/bin/npm-cli.js
> index 561dec0..98cafb8 100644
> --- a/bin/npm-cli.js
> +++ b/bin/npm-cli.js
> @@ -2,17 +2,6 @@
> ;(function () { // wrapper in case we're in module_context mode
> +// hack - debug http-request
> +let httpRequest;
> +httpRequest = require("https").request.bind(require("https"));
> +require("https").request = function (...argList) {
> + if (process.env.NPM_DEBUG) {
> + console.error(
> + "npm - httpRequest - " + JSON.stringify(argList.slice(0, 2), undefined, 4)
> + );
> + }
> + return httpRequest(...argList);
> +};
> // windows: running "npm blah" in this folder will invoke WSH, not node.
>
> C:\Program Files\nodejs\node_modules\npm>
> ```
>
> ```mingw-bash
> $ NPM_DEBUG=1 npm publish foo
> # console-ouput:
> # npm - httpRequest - [
> # {
> # "protocol": "https:",
> # "href": "https://registry.npmjs.org/foo",
> # "method": "GET",
> # "headers": {
> # "connection": [
> # "keep-alive"
> # ],
> # "user-agent": [
> # "npm/6.13.4 node/v12.16.1 win32 x64"
> # ],
> # ...
> ```
>
>
>
>
>
> On Fri, Jul 10, 2020 at 3:34 AM #!/JoePea <joe at trusktr.io> wrote:
>>
>> Thanks for the idea! That's similar to what I thought would be necessary. I was hoping to monkey patch `fetch()` to have it get the trace if any `fetch` call, but they would not be async stack traces. For async traces it would require instrumentation by injecting code similar to yours (I want to detect traces in third-party code installed locally).
>>
>> #!/JoePea
>>
>> On Wed, Jul 8, 2020, 2:13 AM kai zhu <kaizhu256 at gmail.com> wrote:
>>>
>>> here's a simple throwaway-function you can wrap around promises like fetch
>>> to get the caller's async-stack-trace `promiseWithErrorStack`:
>>>
>>> ```html
>>> <!doctype html>
>>> <html lang="en">
>>> <body>
>>> <h1>test.html</h1>
>>> <script>
>>> (async function foo() {
>>> function promiseWithErrorStack(promise) {
>>> /*
>>> * this function will append current-stack to any err caught from <promise>
>>> */
>>> let errStack;
>>> errStack = new Error().stack;
>>> return new Promise(function (resolve, reject) {
>>> promise.then(resolve).catch(function (err) {
>>> // append current errStack to err.stack
>>> if (err && typeof err.stack === "string") {
>>> err.stack += "\n" + errStack;
>>> }
>>> reject(err);
>>> });
>>> });
>>> }
>>> await promiseWithErrorStack(fetch("https://example.com")); // at foo (test.html:23)
>>>
>>> /*
>>> console-output:
>>>
>>> Uncaught (in promise) TypeError: Failed to fetch
>>> Error
>>> at promiseWithErrorStack (test.html:12)
>>> at foo (test.html:23) // async-stack-trace
>>> at test.html:32
>>> */
>>> }());
>>> </script>
>>> </body>
>>> ```
>>>
>>> On Tue, Jul 7, 2020 at 11:54 PM #!/JoePea <joe at trusktr.io> wrote:
>>>>
>>>> Is there some way (perhaps by patching methods on objects?) so we can
>>>> track async call stacks?
>>>>
>>>> When we pause code in devtools, we are able to see the async stack
>>>> trace of the code.
>>>>
>>>> What I'd like to do is to effectively detect the same thing as
>>>> devtools does at some point in any code. As a specific example, I'd
>>>> like to detect the async stack trace of any call to `fetch`.
>>>>
>>>> Is such a thing possible with runtime code?
>>>>
>>>> Or would it require instrumentation of the source code?
>>>>
>>>> #!/JoePea
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
More information about the es-discuss
mailing list