2017-07-18 01:47:12 +02:00
|
|
|
'use strict';
|
|
|
|
|
2019-04-09 09:55:53 +02:00
|
|
|
const { Object, SafeMap, SafeSet } = primordials;
|
|
|
|
|
2018-07-29 22:16:45 +02:00
|
|
|
const { trace } = internalBinding('trace_events');
|
2018-08-21 08:54:02 +02:00
|
|
|
const async_wrap = internalBinding('async_wrap');
|
2018-07-29 22:16:45 +02:00
|
|
|
const async_hooks = require('async_hooks');
|
2018-05-07 00:15:00 +02:00
|
|
|
|
2018-07-29 22:16:45 +02:00
|
|
|
// Use small letters such that chrome://tracing groups by the name.
|
|
|
|
// The behavior is not only useful but the same as the events emitted using
|
|
|
|
// the specific C++ macros.
|
|
|
|
const kBeforeEvent = 'b'.charCodeAt(0);
|
|
|
|
const kEndEvent = 'e'.charCodeAt(0);
|
|
|
|
const kTraceEventCategory = 'node,node.async_hooks';
|
2018-05-07 00:15:00 +02:00
|
|
|
|
2018-07-29 22:16:45 +02:00
|
|
|
const kEnabled = Symbol('enabled');
|
|
|
|
|
|
|
|
// It is faster to emit traceEvents directly from C++. Thus, this happens
|
|
|
|
// in async_wrap.cc. However, events emitted from the JavaScript API or the
|
|
|
|
// Embedder C++ API can't be emitted from async_wrap.cc. Thus they are
|
|
|
|
// emitted using the JavaScript API. To prevent emitting the same event
|
|
|
|
// twice the async_wrap.Providers list is used to filter the events.
|
|
|
|
const nativeProviders = new SafeSet(Object.keys(async_wrap.Providers));
|
|
|
|
const typeMemory = new SafeMap();
|
|
|
|
|
|
|
|
function createHook() {
|
2018-05-07 00:15:00 +02:00
|
|
|
// In traceEvents it is not only the id but also the name that needs to be
|
|
|
|
// repeated. Since async_hooks doesn't expose the provider type in the
|
|
|
|
// non-init events, use a map to manually map the asyncId to the type name.
|
|
|
|
|
2018-07-29 22:16:45 +02:00
|
|
|
const hook = async_hooks.createHook({
|
2018-05-07 00:15:00 +02:00
|
|
|
init(asyncId, type, triggerAsyncId, resource) {
|
|
|
|
if (nativeProviders.has(type)) return;
|
|
|
|
|
|
|
|
typeMemory.set(asyncId, type);
|
2018-07-29 22:16:45 +02:00
|
|
|
trace(kBeforeEvent, kTraceEventCategory,
|
2018-08-04 18:48:50 +02:00
|
|
|
type, asyncId,
|
|
|
|
{
|
|
|
|
triggerAsyncId,
|
|
|
|
executionAsyncId: async_hooks.executionAsyncId()
|
|
|
|
});
|
2018-05-07 00:15:00 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
before(asyncId) {
|
|
|
|
const type = typeMemory.get(asyncId);
|
|
|
|
if (type === undefined) return;
|
|
|
|
|
2018-07-29 22:16:45 +02:00
|
|
|
trace(kBeforeEvent, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
|
2018-05-07 00:15:00 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
after(asyncId) {
|
|
|
|
const type = typeMemory.get(asyncId);
|
|
|
|
if (type === undefined) return;
|
|
|
|
|
2018-07-29 22:16:45 +02:00
|
|
|
trace(kEndEvent, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
|
2018-05-07 00:15:00 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
destroy(asyncId) {
|
|
|
|
const type = typeMemory.get(asyncId);
|
|
|
|
if (type === undefined) return;
|
|
|
|
|
2018-07-29 22:16:45 +02:00
|
|
|
trace(kEndEvent, kTraceEventCategory, type, asyncId);
|
2018-05-07 00:15:00 +02:00
|
|
|
|
2019-03-22 03:44:26 +01:00
|
|
|
// Cleanup asyncId to type map
|
2018-05-07 00:15:00 +02:00
|
|
|
typeMemory.delete(asyncId);
|
|
|
|
}
|
2018-07-29 22:16:45 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
return {
|
|
|
|
enable() {
|
|
|
|
if (this[kEnabled])
|
|
|
|
return;
|
|
|
|
this[kEnabled] = true;
|
|
|
|
hook.enable();
|
|
|
|
},
|
|
|
|
|
|
|
|
disable() {
|
|
|
|
if (!this[kEnabled])
|
|
|
|
return;
|
|
|
|
this[kEnabled] = false;
|
|
|
|
hook.disable();
|
|
|
|
typeMemory.clear();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-02-10 11:39:45 +01:00
|
|
|
exports.createHook = createHook;
|