diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/01_core.js | 23 | ||||
-rw-r--r-- | core/lib.deno_core.d.ts | 23 |
2 files changed, 45 insertions, 1 deletions
diff --git a/core/01_core.js b/core/01_core.js index d9a110eea..3a05a0cff 100644 --- a/core/01_core.js +++ b/core/01_core.js @@ -22,6 +22,8 @@ MapPrototypeDelete, MapPrototypeSet, PromisePrototypeThen, + PromisePrototypeFinally, + StringPrototypeSlice, ObjectAssign, SymbolFor, } = window.__bootstrap.primordials; @@ -48,6 +50,13 @@ // to users. Currently missing bindings. const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId"); + let opCallTracingEnabled = false; + const opCallTraces = new Map(); + + function enableOpCallTracing() { + opCallTracingEnabled = true; + } + function setPromise(promiseId) { const idx = promiseId % RING_SIZE; // Move old promise from ring to map @@ -139,7 +148,17 @@ const maybeError = opcallAsync(opsCache[opName], promiseId, arg1, arg2); // Handle sync error (e.g: error parsing args) if (maybeError) return unwrapOpResult(maybeError); - const p = PromisePrototypeThen(setPromise(promiseId), unwrapOpResult); + let p = PromisePrototypeThen(setPromise(promiseId), unwrapOpResult); + if (opCallTracingEnabled) { + // Capture a stack trace by creating a new `Error` object. We remove the + // first 6 characters (the `Error\n` prefix) to get just the stack trace. + const stack = StringPrototypeSlice(new Error().stack, 6); + MapPrototypeSet(opCallTraces, promiseId, { opName, stack }); + p = PromisePrototypeFinally( + p, + () => MapPrototypeDelete(opCallTraces, promiseId), + ); + } // Save the id on the promise so it can later be ref'ed or unref'ed p[promiseIdSymbol] = promiseId; return p; @@ -226,6 +245,8 @@ BadResourcePrototype, Interrupted, InterruptedPrototype, + enableOpCallTracing, + opCallTraces, }); ObjectAssign(globalThis.__bootstrap, { core }); diff --git a/core/lib.deno_core.d.ts b/core/lib.deno_core.d.ts index 9f554f12b..37cd33190 100644 --- a/core/lib.deno_core.d.ts +++ b/core/lib.deno_core.d.ts @@ -141,5 +141,28 @@ declare namespace Deno { ): undefined | UncaughtExceptionCallback; export type UncaughtExceptionCallback = (err: any) => void; + + /** + * Enables collection of stack traces of all async ops. This allows for + * debugging of where a given async op was started. Deno CLI uses this for + * improving error message in op sanitizer errors for `deno test`. + * + * **NOTE:** enabling tracing has a significant negative performance impact. + * To get high level metrics on async ops with no added performance cost, + * use `Deno.core.metrics()`. + */ + function enableOpCallTracing(): void; + + export interface OpCallTrace { + opName: string; + stack: string; + } + + /** + * A map containing traces for all ongoing async ops. The key is the op id. + * Tracing only occurs when `Deno.core.enableOpCallTracing()` was previously + * enabled. + */ + const opCallTraces: Map<number, OpCallTrace>; } } |