Skip to content

Commit fb275c6

Browse files
committed
diagnostics_channel: add iterator support to tracing channel
1 parent 8c32389 commit fb275c6

1 file changed

Lines changed: 80 additions & 0 deletions

File tree

lib/diagnostics_channel.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ function tracingChannelFrom(nameOrChannels, name) {
281281
}
282282

283283
class TracingChannel {
284+
#generatorChannel
285+
284286
constructor(nameOrChannels) {
285287
for (let i = 0; i < traceEvents.length; ++i) {
286288
const eventName = traceEvents[i];
@@ -428,6 +430,84 @@ class TracingChannel {
428430
}
429431
});
430432
}
433+
434+
traceIterator(fn, context = {}, thisArg, ...args) {
435+
if (!this.hasSubscribers) {
436+
return ReflectApply(fn, thisArg, args);
437+
}
438+
439+
const { channel, start, end, asyncStart, asyncEnd, error } = this;
440+
441+
if (!this.#nextChannel) {
442+
this.#nextChannel = this.tracingChannel({
443+
start: channel(start.name.slice(0, -6) + ':next:start'),
444+
end: channel(end.name.slice(0, -4) + ':next:end'),
445+
asyncStart: channel(asyncStart.name.slice(0, -11) + ':next:asyncStart'),
446+
asyncEnd: channel(asyncEnd.name.slice(0, -9) + ':next:asyncEnd'),
447+
error: channel(error.name.slice(0, -6) + ':next:error'),
448+
});
449+
}
450+
451+
const iter = this.#traceMaybePromise(fn, context, thisArg, ...args);
452+
453+
return iter instanceof Promise
454+
? iter.then((iter, method) => {
455+
const { next: iterNext, return: iterReturn, throw: iterThrow } = iter;
456+
457+
iter.next = (...args) =>
458+
this.#nextChannel.#traceMaybePromise(iterNext, ctx, iter, ...args);
459+
iter.return = (...args) =>
460+
this.#nextChannel.#traceMaybePromise(iterReturn, ctx, iter, ...args);
461+
iter.throw = (...args) =>
462+
this.#nextChannel.#traceMaybePromise(iterThrow, ctx, iter, ...args);
463+
464+
return iter;
465+
})
466+
: iter;
467+
}
468+
469+
#traceMaybePromise(fn, context = {}, thisArg, ...args) {
470+
if (!this.hasSubscribers) {
471+
return ReflectApply(fn, thisArg, args);
472+
}
473+
474+
const { start, end, asyncStart, asyncEnd, error } = this;
475+
476+
function reject(err) {
477+
context.error = err;
478+
error.publish(context);
479+
asyncStart.publish(context);
480+
// TODO: Is there a way to have asyncEnd _after_ the continuation?
481+
asyncEnd.publish(context);
482+
return PromiseReject(err);
483+
}
484+
485+
function resolve(result) {
486+
context.result = result;
487+
asyncStart.publish(context);
488+
// TODO: Is there a way to have asyncEnd _after_ the continuation?
489+
asyncEnd.publish(context);
490+
return result;
491+
}
492+
493+
return start.runStores(context, () => {
494+
try {
495+
const result = ReflectApply(fn, thisArg, args);
496+
// TODO: Should tracePromise just always do this?
497+
if (!(result instanceof Promise)) {
498+
context.result = result
499+
return result
500+
}
501+
return PromisePrototypeThen(result, resolve, reject);
502+
} catch (err) {
503+
context.error = err;
504+
error.publish(context);
505+
throw err;
506+
} finally {
507+
end.publish(context);
508+
}
509+
});
510+
}
431511
}
432512

433513
function tracingChannel(nameOrChannels) {

0 commit comments

Comments
 (0)