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