 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.

  const hook = async_hooks.createHook({
    init(asyncId, type, triggerAsyncId, resource) {
      if (nativeProviders.has(type)) return;

      typeMemory.set(asyncId, type);
      trace(kBeforeEvent, kTraceEventCategory,
            type, asyncId,
            {
              triggerAsyncId,
              executionAsyncId: async_hooks.executionAsyncId()
            });
    },

    before(asyncId) {
      const type = typeMemory.get(asyncId);
      if (type === undefined) return;

      trace(kBeforeEvent, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
    },

    after(asyncId) {
      const type = typeMemory.get(asyncId);
      if (type === undefined) return;

      trace(kEndEvent, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
    },

    destroy(asyncId) {
      const type = typeMemory.get(asyncId);
      if (type === undefined) return;

      trace(kEndEvent, kTraceEventCategory, type, asyncId);

      // Cleanup asyncId to type map
      typeMemory.delete(asyncId);
    }
  });

  return {
    enable() {
      if (this[kEnabled])
        return;
      this[kEnabled] = true;
      hook.enable();
    },

    disable() {
      if (!this[kEnabled])
        return;
      this[kEnabled] = false;
      hook.disable();
      typeMemory.clear();
    }
  };
}

exports.createHook = createHook;
