11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  ObjectKeys,
51cb0ef41Sopenharmony_ci  SafeMap,
61cb0ef41Sopenharmony_ci  SafeSet,
71cb0ef41Sopenharmony_ci  Symbol,
81cb0ef41Sopenharmony_ci} = primordials;
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciconst { trace } = internalBinding('trace_events');
111cb0ef41Sopenharmony_ciconst async_wrap = internalBinding('async_wrap');
121cb0ef41Sopenharmony_ciconst async_hooks = require('async_hooks');
131cb0ef41Sopenharmony_ciconst {
141cb0ef41Sopenharmony_ci  CHAR_LOWERCASE_B,
151cb0ef41Sopenharmony_ci  CHAR_LOWERCASE_E,
161cb0ef41Sopenharmony_ci} = require('internal/constants');
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci// Use small letters such that chrome://tracing groups by the name.
191cb0ef41Sopenharmony_ci// The behavior is not only useful but the same as the events emitted using
201cb0ef41Sopenharmony_ci// the specific C++ macros.
211cb0ef41Sopenharmony_ciconst kBeforeEvent = CHAR_LOWERCASE_B;
221cb0ef41Sopenharmony_ciconst kEndEvent = CHAR_LOWERCASE_E;
231cb0ef41Sopenharmony_ciconst kTraceEventCategory = 'node,node.async_hooks';
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciconst kEnabled = Symbol('enabled');
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci// It is faster to emit traceEvents directly from C++. Thus, this happens
281cb0ef41Sopenharmony_ci// in async_wrap.cc. However, events emitted from the JavaScript API or the
291cb0ef41Sopenharmony_ci// Embedder C++ API can't be emitted from async_wrap.cc. Thus they are
301cb0ef41Sopenharmony_ci// emitted using the JavaScript API. To prevent emitting the same event
311cb0ef41Sopenharmony_ci// twice the async_wrap.Providers list is used to filter the events.
321cb0ef41Sopenharmony_ciconst nativeProviders = new SafeSet(ObjectKeys(async_wrap.Providers));
331cb0ef41Sopenharmony_ciconst typeMemory = new SafeMap();
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci// Promises are not AsyncWrap resources so they should emit trace_events here.
361cb0ef41Sopenharmony_cinativeProviders.delete('PROMISE');
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_cifunction createHook() {
391cb0ef41Sopenharmony_ci  // In traceEvents it is not only the id but also the name that needs to be
401cb0ef41Sopenharmony_ci  // repeated. Since async_hooks doesn't expose the provider type in the
411cb0ef41Sopenharmony_ci  // non-init events, use a map to manually map the asyncId to the type name.
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  const hook = async_hooks.createHook({
441cb0ef41Sopenharmony_ci    init(asyncId, type, triggerAsyncId, resource) {
451cb0ef41Sopenharmony_ci      if (nativeProviders.has(type)) return;
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci      typeMemory.set(asyncId, type);
481cb0ef41Sopenharmony_ci      trace(kBeforeEvent, kTraceEventCategory,
491cb0ef41Sopenharmony_ci            type, asyncId,
501cb0ef41Sopenharmony_ci            {
511cb0ef41Sopenharmony_ci              triggerAsyncId,
521cb0ef41Sopenharmony_ci              executionAsyncId: async_hooks.executionAsyncId(),
531cb0ef41Sopenharmony_ci            });
541cb0ef41Sopenharmony_ci    },
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci    before(asyncId) {
571cb0ef41Sopenharmony_ci      const type = typeMemory.get(asyncId);
581cb0ef41Sopenharmony_ci      if (type === undefined) return;
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci      trace(kBeforeEvent, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
611cb0ef41Sopenharmony_ci    },
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci    after(asyncId) {
641cb0ef41Sopenharmony_ci      const type = typeMemory.get(asyncId);
651cb0ef41Sopenharmony_ci      if (type === undefined) return;
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci      trace(kEndEvent, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
681cb0ef41Sopenharmony_ci    },
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci    destroy(asyncId) {
711cb0ef41Sopenharmony_ci      const type = typeMemory.get(asyncId);
721cb0ef41Sopenharmony_ci      if (type === undefined) return;
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci      trace(kEndEvent, kTraceEventCategory, type, asyncId);
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci      // Cleanup asyncId to type map
771cb0ef41Sopenharmony_ci      typeMemory.delete(asyncId);
781cb0ef41Sopenharmony_ci    },
791cb0ef41Sopenharmony_ci  });
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  return {
821cb0ef41Sopenharmony_ci    enable() {
831cb0ef41Sopenharmony_ci      if (this[kEnabled])
841cb0ef41Sopenharmony_ci        return;
851cb0ef41Sopenharmony_ci      this[kEnabled] = true;
861cb0ef41Sopenharmony_ci      hook.enable();
871cb0ef41Sopenharmony_ci    },
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci    disable() {
901cb0ef41Sopenharmony_ci      if (!this[kEnabled])
911cb0ef41Sopenharmony_ci        return;
921cb0ef41Sopenharmony_ci      this[kEnabled] = false;
931cb0ef41Sopenharmony_ci      hook.disable();
941cb0ef41Sopenharmony_ci      typeMemory.clear();
951cb0ef41Sopenharmony_ci    },
961cb0ef41Sopenharmony_ci  };
971cb0ef41Sopenharmony_ci}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ciexports.createHook = createHook;
100