UNPKG

signalfx-tracing

Version:

Provides auto-instrumentation for JavaScript libraries and frameworks

92 lines (71 loc) 2.19 kB
'use strict' const asyncHooks = require('../async_hooks') const eid = asyncHooks.executionAsyncId || asyncHooks.currentId const Base = require('./base') const platform = require('../../platform') const semver = require('semver') // https://github.com/nodejs/node/issues/19859 const hasKeepAliveBug = !semver.satisfies(process.version, '^8.13 || >=10.14.2') let singleton = null class Scope extends Base { constructor (options) { if (singleton) return singleton super() singleton = this this._spans = Object.create(null) this._types = Object.create(null) this._weaks = new WeakMap() this._hook = asyncHooks.createHook({ init: this._init.bind(this), destroy: this._destroy.bind(this), promiseResolve: this._destroy.bind(this) }) this._hook.enable() } _active () { return this._spans[eid()] || null } _activate (span, callback) { const asyncId = eid() const oldSpan = this._spans[asyncId] this._spans[asyncId] = span try { return callback() } catch (e) { if (span && typeof span.addTags === 'function') { span.addTags({ 'sfx.error.kind': e.name, 'sfx.error.message': e.message, 'sfx.error.stack': e.stack }) } throw e } finally { if (oldSpan) { this._spans[asyncId] = oldSpan } else { delete this._spans[asyncId] } } } _init (asyncId, type, triggerAsyncId, resource) { this._spans[asyncId] = this._active() this._types[asyncId] = type if (hasKeepAliveBug && (type === 'TCPWRAP' || type === 'HTTPPARSER')) { this._destroy(this._weaks.get(resource)) this._weaks.set(resource, asyncId) } platform.metrics().increment('async.resources') platform.metrics().increment('async.resources.by.type', `resource_type:${type}`) } _destroy (asyncId) { const type = this._types[asyncId] if (type) { platform.metrics().decrement('async.resources') platform.metrics().decrement('async.resources.by.type', `resource_type:${type}`) } delete this._spans[asyncId] delete this._types[asyncId] } } module.exports = Scope