elastic-apm-node
Advanced tools
Comparing version 3.26.0 to 3.27.0
@@ -129,2 +129,5 @@ 'use strict' | ||
} | ||
if (this._instrumentation._runCtxMgr && this._instrumentation._runCtxMgr._runContextFromAsyncId) { | ||
stats.runContextFromAsyncIdSize = this._instrumentation._runCtxMgr._runContextFromAsyncId.size | ||
} | ||
if (this._transport && typeof this._transport._getStats === 'function') { | ||
@@ -438,2 +441,8 @@ stats.apmclient = this._transport._getStats() | ||
const traceContext = (span || trans || {})._context | ||
const req = (opts.request instanceof IncomingMessage | ||
? opts.request | ||
: trans && trans.req) | ||
const res = (opts.response instanceof ServerResponse | ||
? opts.response | ||
: trans && trans.res) | ||
@@ -468,8 +477,2 @@ // As an added feature, for *some* cases, we capture a stacktrace at the point | ||
// Gather `error.context.*`. | ||
const req = (opts.request instanceof IncomingMessage | ||
? opts.request | ||
: trans && trans.req) | ||
const res = (opts.response instanceof ServerResponse | ||
? opts.response | ||
: trans && trans.res) | ||
const errorContext = { | ||
@@ -476,0 +479,0 @@ user: Object.assign( |
@@ -26,2 +26,3 @@ 'use strict' | ||
this.ended = false | ||
this._duration = null // Duration in milliseconds. Set on `.end()`. | ||
@@ -87,3 +88,3 @@ this.outcome = constants.OUTCOME_UNKNOWN | ||
// duration is returned as an int representing the time in milliseconds | ||
// The duration of the span, in milliseconds. | ||
GenericSpan.prototype.duration = function () { | ||
@@ -95,3 +96,3 @@ if (!this.ended) { | ||
return this._timer.duration | ||
return this._duration | ||
} | ||
@@ -98,0 +99,0 @@ |
'use strict' | ||
const constants = require('../../../constants') | ||
const TYPE = 'db' | ||
@@ -66,8 +66,5 @@ const SUBTYPE = 'dynamodb' | ||
const type = TYPE | ||
const subtype = SUBTYPE | ||
const action = ACTION | ||
const ins = agent._instrumentation | ||
const name = getSpanNameFromRequest(request) | ||
const span = agent.startSpan(name, type, subtype, action) | ||
const span = ins.createSpan(name, TYPE, SUBTYPE, ACTION) | ||
if (!span) { | ||
@@ -95,15 +92,19 @@ return orig.apply(request, origArguments) | ||
request.on('complete', function (response) { | ||
const onComplete = function (response) { | ||
if (response && response.error) { | ||
const errOpts = { | ||
skipOutcome: true | ||
} | ||
agent.captureError(response.error, errOpts) | ||
span._setOutcomeFromErrorCapture(constants.OUTCOME_FAILURE) | ||
agent.captureError(response.error) | ||
} | ||
span.end() | ||
}) | ||
} | ||
// Bind onComplete to the span's run context so that `captureError` picks | ||
// up the correct currentSpan. | ||
const parentRunContext = ins.currRunContext() | ||
const spanRunContext = parentRunContext.enterSpan(span) | ||
request.on('complete', ins.bindFunctionToRunContext(spanRunContext, onComplete)) | ||
return orig.apply(request, origArguments) | ||
const cb = origArguments[origArguments.length - 1] | ||
if (typeof cb === 'function') { | ||
origArguments[origArguments.length - 1] = ins.bindFunctionToRunContext(parentRunContext, cb) | ||
} | ||
return ins.withRunContext(spanRunContext, orig, request, ...origArguments) | ||
} | ||
@@ -110,0 +111,0 @@ |
@@ -5,28 +5,51 @@ 'use strict' | ||
module.exports = function (graphqlHTTP, agent, { version, enabled }) { | ||
if (!enabled) return graphqlHTTP | ||
const shimmer = require('../shimmer') | ||
if (!semver.satisfies(version, '>=0.6.1 <0.10.0') || typeof graphqlHTTP !== 'function') { | ||
agent.logger.debug('express-graphql version %s not supported - aborting...', version) | ||
return graphqlHTTP | ||
module.exports = function (expressGraphql, agent, { version, enabled }) { | ||
if (!enabled) { | ||
return expressGraphql | ||
} | ||
for (const key of Object.keys(graphqlHTTP)) { | ||
wrappedGraphqlHTTP[key] = graphqlHTTP[key] | ||
if (semver.satisfies(version, '>=0.10.0 <0.13.0')) { | ||
// https://github.com/graphql/express-graphql/pull/626 changed `graphqlHTTP` | ||
// to no longer be the top-level export: | ||
// { | ||
// graphqlHTTP: [Function: graphqlHTTP], | ||
// getGraphQLParams: [AsyncFunction: getGraphQLParams] | ||
// } | ||
shimmer.wrap(expressGraphql, 'graphqlHTTP', wrapGraphqlHTTP) | ||
return expressGraphql | ||
} else if (semver.satisfies(version, '>=0.6.1 <0.10.0') && typeof expressGraphql === 'function') { | ||
// Up to and including 0.9.x, `require('express-graphql')` is: | ||
// [Function: graphqlHTTP] { | ||
// getGraphQLParams: [AsyncFunction: getGraphQLParams] | ||
// } | ||
const wrappedGraphqlHTTP = wrapGraphqlHTTP(expressGraphql) | ||
for (const key of Object.keys(expressGraphql)) { | ||
wrappedGraphqlHTTP[key] = expressGraphql[key] | ||
} | ||
return wrappedGraphqlHTTP | ||
} else { | ||
agent.logger.debug('express-graphql@%s not supported: skipping instrumentation', version) | ||
return expressGraphql | ||
} | ||
return wrappedGraphqlHTTP | ||
function wrapGraphqlHTTP (origGraphqlHTTP) { | ||
return function wrappedGraphqlHTTP () { | ||
var orig = origGraphqlHTTP.apply(this, arguments) | ||
function wrappedGraphqlHTTP () { | ||
var orig = graphqlHTTP.apply(this, arguments) | ||
if (typeof orig !== 'function') { | ||
return orig | ||
} | ||
if (typeof orig !== 'function') return orig | ||
// Express is very particular with the number of arguments! | ||
return function (req, res) { | ||
var trans = agent._instrumentation.currTransaction() | ||
if (trans) trans._graphqlRoute = true | ||
return orig.apply(this, arguments) | ||
// Express is very particular with the number of arguments! | ||
return function (req, res) { | ||
var trans = agent._instrumentation.currTransaction() | ||
if (trans) { | ||
trans._graphqlRoute = true | ||
} | ||
return orig.apply(this, arguments) | ||
} | ||
} | ||
} | ||
} |
@@ -20,2 +20,4 @@ 'use strict' | ||
const ins = agent._instrumentation | ||
return clone({}, graphql, { | ||
@@ -44,12 +46,5 @@ graphql (descriptor) { | ||
return function wrappedGraphql (schema, requestString, rootValue, contextValue, variableValues, operationName) { | ||
var trans = agent._instrumentation.currTransaction() | ||
var span = agent.startSpan('GraphQL: Unknown Query', 'db', 'graphql', 'execute') | ||
var id = span && span.transaction.id | ||
agent.logger.debug('intercepted call to graphql.graphql %o', { id: id }) | ||
// As of now, the only reason why there might be a transaction but no | ||
// span is if the transaction have ended. But just to be sure this | ||
// doesn't break in the future we add the extra `!span` guard as well | ||
if (!trans || trans.ended || !span) { | ||
agent.logger.debug('no active transaction found - skipping graphql tracing') | ||
agent.logger.debug('intercepted call to graphql.graphql') | ||
const span = ins.createSpan('GraphQL: Unknown Query', 'db', 'graphql', 'execute') | ||
if (!span) { | ||
return orig.apply(this, arguments) | ||
@@ -79,3 +74,4 @@ } | ||
var p = orig.apply(this, arguments) | ||
const spanRunContext = ins.currRunContext().enterSpan(span) | ||
const p = ins.withRunContext(spanRunContext, orig, this, ...arguments) | ||
p.then(function () { | ||
@@ -90,11 +86,5 @@ span.end() | ||
function wrappedExecuteImpl (schema, document, rootValue, contextValue, variableValues, operationName) { | ||
var trans = agent._instrumentation.currTransaction() | ||
var span = agent.startSpan('GraphQL: Unknown Query', 'db', 'graphql', 'execute') | ||
var id = span && span.transaction.id | ||
agent.logger.debug('intercepted call to graphql.execute %o', { id: id }) | ||
// As of now, the only reason why there might be a transaction but no | ||
// span is if the transaction have ended. But just to be sure this | ||
// doesn't break in the future we add the extra `!span` guard as well | ||
if (!trans || trans.ended || !span) { | ||
agent.logger.debug('intercepted call to graphql.execute') | ||
const span = ins.createSpan('GraphQL: Unknown Query', 'db', 'graphql', 'execute') | ||
if (!span) { | ||
agent.logger.debug('no active transaction found - skipping graphql tracing') | ||
@@ -107,4 +97,10 @@ return orig.apply(this, arguments) | ||
operationName = operationName || (details.operation && details.operation.name && details.operation.name.value) | ||
if (queries.length > 0) span.name = 'GraphQL: ' + (operationName ? operationName + ' ' : '') + queries.join(', ') | ||
if (queries.length > 0) { | ||
span.name = 'GraphQL: ' + (operationName ? operationName + ' ' : '') + queries.join(', ') | ||
} | ||
// `_graphqlRoute` is a boolean set in instrumentations of other modules | ||
// that specify 'graphql' in peerDependencies (e.g. 'express-graphql') to | ||
// indicate that this transaction is for a GraphQL request. | ||
const trans = span.transaction | ||
if (trans._graphqlRoute) { | ||
@@ -120,3 +116,4 @@ var name = queries.length > 0 ? queries.join(', ') : 'Unknown GraphQL query' | ||
var p = orig.apply(this, arguments) | ||
const spanRunContext = ins.currRunContext().enterSpan(span) | ||
const p = ins.withRunContext(spanRunContext, orig, this, ...arguments) | ||
if (typeof p.then === 'function') { | ||
@@ -123,0 +120,0 @@ p.then(function () { |
@@ -60,2 +60,6 @@ 'use strict' | ||
trans.type = 'request' | ||
// `trans.req` and `trans.res` are fake representations of Node.js's | ||
// core `http.IncomingMessage` and `http.ServerResponse` objects, | ||
// sufficient for `parsers.getContextFromRequest()` and | ||
// `parsers.getContextFromResponse()`, respectively. | ||
trans.req = { | ||
@@ -168,3 +172,9 @@ headers, | ||
var trans = agent._instrumentation.currTransaction() | ||
if (trans) trans.res.finished = true | ||
// `trans.res` might be removed, because before | ||
// https://github.com/nodejs/node/pull/20084 (e.g. in node v10.0.0) the | ||
// 'end' event could be called multiple times for the same Http2Stream, | ||
// and the `trans.res` ref is removed when the Transaction is ended. | ||
if (trans && trans.res) { | ||
trans.res.finished = true | ||
} | ||
return original.apply(this, arguments) | ||
@@ -171,0 +181,0 @@ } |
'use strict' | ||
const semver = require('semver') | ||
const { getDBDestination } = require('../context') | ||
const shimmer = require('../shimmer') | ||
@@ -17,6 +19,7 @@ // Match expected `<hostname>:<port>`, e.g. "mongo:27017", "::1:27017", | ||
const ins = agent._instrumentation | ||
const activeSpans = new Map() | ||
if (mongodb.instrument) { | ||
const listener = mongodb.instrument() | ||
listener.on('started', onStart) | ||
@@ -27,12 +30,16 @@ listener.on('succeeded', onEnd) | ||
// mongodb 4.0+ removed the instrument() method in favor of | ||
// listeners on the instantiated client objects. | ||
class MongoClient extends mongodb.MongoClient { | ||
// listeners on the instantiated client objects. There are two mechanisms | ||
// to get a client: | ||
// 1. const client = new mongodb.MongoClient(...) | ||
// 2. const client = await MongoClient.connect(...) | ||
class MongoClientTraced extends mongodb.MongoClient { | ||
constructor () { | ||
// The `command*` events are only sent if `monitorCommands: true`. | ||
if (!arguments[1]) { | ||
arguments[1] = { monitorCommands: true } | ||
} else if (arguments[1].monitorCommands !== true) { | ||
arguments[1] = Object.assign({}, arguments[1], { monitorCommands: true }) | ||
// The `command*` events are only emitted if `options.monitorCommands: true`. | ||
const args = Array.prototype.slice.call(arguments) | ||
if (!args[1]) { | ||
args[1] = { monitorCommands: true } | ||
} else if (args[1].monitorCommands !== true) { | ||
args[1] = Object.assign({}, args[1], { monitorCommands: true }) | ||
} | ||
super(...arguments) | ||
super(...args) | ||
this.on('commandStarted', onStart) | ||
@@ -49,9 +56,49 @@ this.on('commandSucceeded', onEnd) | ||
get: function () { | ||
return MongoClient | ||
return MongoClientTraced | ||
} | ||
} | ||
) | ||
shimmer.wrap(mongodb.MongoClient, 'connect', wrapConnect) | ||
} else { | ||
agent.logger.warn('could not instrument mongodb@%s', version) | ||
} | ||
return mongodb | ||
// Wrap the MongoClient.connect(url, options?, callback?) static method. | ||
// It calls back with `function (err, client)` or returns a Promise that | ||
// resolves to the client. | ||
// https://github.com/mongodb/node-mongodb-native/blob/v4.2.1/src/mongo_client.ts#L503-L511 | ||
function wrapConnect (origConnect) { | ||
return function wrappedConnect (url, options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options | ||
options = {} | ||
} | ||
options = options || {} | ||
if (!options.monitorCommands) { | ||
options.monitorCommands = true | ||
} | ||
if (typeof callback === 'function') { | ||
return origConnect.call(this, url, options, function wrappedCallback (err, client) { | ||
if (err) { | ||
callback(err) | ||
} else { | ||
client.on('commandStarted', onStart) | ||
client.on('commandSucceeded', onEnd) | ||
client.on('commandFailed', onEnd) | ||
callback(err, client) | ||
} | ||
}) | ||
} else { | ||
const p = origConnect.call(this, url, options, callback) | ||
p.then(client => { | ||
client.on('commandStarted', onStart) | ||
client.on('commandSucceeded', onEnd) | ||
client.on('commandFailed', onEnd) | ||
}) | ||
return p | ||
} | ||
} | ||
} | ||
function onStart (event) { | ||
@@ -76,3 +123,3 @@ // `event` is a `CommandStartedEvent` | ||
const span = agent.startSpan(name, 'db', 'mongodb', 'query') | ||
const span = ins.createSpan(name, 'db', 'mongodb', 'query') | ||
if (span) { | ||
@@ -79,0 +126,0 @@ activeSpans.set(event.requestId, span) |
@@ -13,2 +13,5 @@ 'use strict' | ||
module.exports = function (pg, agent, { version, enabled }) { | ||
if (!enabled) { | ||
return pg | ||
} | ||
if (!semver.satisfies(version, '>=4.0.0 <9.0.0')) { | ||
@@ -19,3 +22,3 @@ agent.logger.debug('pg version %s not supported - aborting...', version) | ||
patchClient(pg.Client, 'pg.Client', agent, enabled) | ||
patchClient(pg.Client, 'pg.Client', agent) | ||
@@ -34,3 +37,3 @@ // Trying to access the pg.native getter will trigger and log the warning | ||
if (native && native.Client) { | ||
patchClient(native.Client, 'pg.native.Client', agent, enabled) | ||
patchClient(native.Client, 'pg.native.Client', agent) | ||
} | ||
@@ -44,5 +47,3 @@ return native | ||
function patchClient (Client, klass, agent, enabled) { | ||
if (!enabled) return | ||
function patchClient (Client, klass, agent) { | ||
agent.logger.debug('shimming %s.prototype.query', klass) | ||
@@ -53,74 +54,73 @@ shimmer.wrap(Client.prototype, 'query', wrapQuery) | ||
return function wrappedFunction (sql) { | ||
var span = agent.startSpan('SQL', 'db', 'postgresql', 'query') | ||
var id = span && span.transaction.id | ||
agent.logger.debug('intercepted call to %s.prototype.%s', klass, name) | ||
const ins = agent._instrumentation | ||
const span = ins.createSpan('SQL', 'db', 'postgresql', 'query') | ||
if (!span) { | ||
return orig.apply(this, arguments) | ||
} | ||
if (sql && typeof sql.text === 'string') sql = sql.text | ||
let sqlText = sql | ||
if (sql && typeof sql.text === 'string') { | ||
sqlText = sql.text | ||
} | ||
if (typeof sqlText === 'string') { | ||
span.setDbContext({ statement: sqlText, type: 'sql' }) | ||
span.name = sqlSummary(sqlText) | ||
} else { | ||
agent.logger.debug('unable to parse sql form pg module (type: %s)', typeof sqlText) | ||
} | ||
agent.logger.debug('intercepted call to %s.prototype.%s %o', klass, name, { id: id, sql: sql }) | ||
// Get connection parameters from Client. | ||
let host, port | ||
if (typeof this.connectionParameters === 'object') { | ||
({ host, port } = this.connectionParameters) | ||
} | ||
span.setDestinationContext(getDBDestination(span, host, port)) | ||
if (span) { | ||
// get connection parameters from Client | ||
let host, port | ||
if (typeof this.connectionParameters === 'object') { | ||
({ host, port } = this.connectionParameters) | ||
} | ||
span.setDestinationContext(getDBDestination(span, host, port)) | ||
if (this[symbols.knexStackObj]) { | ||
span.customStackTrace(this[symbols.knexStackObj]) | ||
this[symbols.knexStackObj] = null | ||
} | ||
var args = arguments | ||
var index = args.length - 1 | ||
var cb = args[index] | ||
let index = arguments.length - 1 | ||
let cb = arguments[index] | ||
if (Array.isArray(cb)) { | ||
index = cb.length - 1 | ||
cb = cb[index] | ||
} | ||
if (this[symbols.knexStackObj]) { | ||
span.customStackTrace(this[symbols.knexStackObj]) | ||
this[symbols.knexStackObj] = null | ||
} | ||
const spanRunContext = ins.currRunContext().enterSpan(span) | ||
const onQueryEnd = ins.bindFunctionToRunContext(spanRunContext, (_err) => { | ||
agent.logger.debug('intercepted end of %s.prototype.%s', klass, name) | ||
span.end() | ||
}) | ||
if (Array.isArray(cb)) { | ||
index = cb.length - 1 | ||
cb = cb[index] | ||
} | ||
if (typeof cb === 'function') { | ||
arguments[index] = ins.bindFunction((err, res) => { | ||
onQueryEnd(err) | ||
return cb(err, res) | ||
}) | ||
return orig.apply(this, arguments) | ||
} else { | ||
var queryOrPromise = orig.apply(this, arguments) | ||
if (typeof sql === 'string') { | ||
span.setDbContext({ statement: sql, type: 'sql' }) | ||
span.name = sqlSummary(sql) | ||
// It is important to prefer `.on` to `.then` for pg <7 >=6.3.0, because | ||
// `query.then` is broken in those versions. See | ||
// https://github.com/brianc/node-postgres/commit/b5b49eb895727e01290e90d08292c0d61ab86322#r23267714 | ||
if (typeof queryOrPromise.on === 'function') { | ||
queryOrPromise.on('end', onQueryEnd) | ||
queryOrPromise.on('error', onQueryEnd) | ||
if (queryOrPromise instanceof EventEmitter) { | ||
ins.bindEmitter(queryOrPromise) | ||
} | ||
} else if (typeof queryOrPromise.then === 'function') { | ||
queryOrPromise.then( | ||
() => { onQueryEnd() }, | ||
onQueryEnd | ||
) | ||
} else { | ||
agent.logger.debug('unable to parse sql form pg module (type: %s)', typeof sql) | ||
agent.logger.debug('ERROR: unknown pg query type: %s', typeof queryOrPromise) | ||
} | ||
const onQueryEnd = (_err) => { | ||
agent.logger.debug('intercepted end of %s.prototype.%s %o', klass, name, { id: id }) | ||
span.end() | ||
} | ||
if (typeof cb === 'function') { | ||
args[index] = agent._instrumentation.bindFunction((err, res) => { | ||
onQueryEnd(err) | ||
return cb(err, res) | ||
}) | ||
return orig.apply(this, arguments) | ||
} else { | ||
var queryOrPromise = orig.apply(this, arguments) | ||
// It is import to prefer `.on` to `.then` for pg <7 >=6.3.0, because | ||
// `query.then` is broken in those versions. See | ||
// https://github.com/brianc/node-postgres/commit/b5b49eb895727e01290e90d08292c0d61ab86322#r23267714 | ||
if (typeof queryOrPromise.on === 'function') { | ||
queryOrPromise.on('end', onQueryEnd) | ||
queryOrPromise.on('error', onQueryEnd) | ||
if (queryOrPromise instanceof EventEmitter) { | ||
agent._instrumentation.bindEmitter(queryOrPromise) | ||
} | ||
} else if (typeof queryOrPromise.then === 'function') { | ||
queryOrPromise.then( | ||
() => { onQueryEnd() }, | ||
onQueryEnd | ||
) | ||
} else { | ||
agent.logger.debug('ERROR: unknown pg query type: %s %o', typeof queryOrPromise, { id: id }) | ||
} | ||
return queryOrPromise | ||
} | ||
} else { | ||
return orig.apply(this, arguments) | ||
return queryOrPromise | ||
} | ||
@@ -127,0 +127,0 @@ } |
@@ -77,2 +77,3 @@ 'use strict' | ||
this._timer.end(endTime) | ||
this._duration = this._timer.duration | ||
if (executionAsyncId() !== this._startXid) { | ||
@@ -88,3 +89,3 @@ this.sync = false | ||
// TODO: This is expensive! Consider if there's a way to cache some of this | ||
if (this._capturedStackTrace !== null && this._agent._conf.spanFramesMinDuration !== 0 && this.duration() / 1000 > this._agent._conf.spanFramesMinDuration) { | ||
if (this._capturedStackTrace !== null && this._agent._conf.spanFramesMinDuration !== 0 && this._duration / 1000 > this._agent._conf.spanFramesMinDuration) { | ||
// NOTE: This uses a promise-like thing and not a *real* promise | ||
@@ -110,2 +111,15 @@ // because passing error stacks into a promise context makes it | ||
this.transaction._captureBreakdown(this) | ||
// Reduce this span's memory usage by dropping references, except to fields | ||
// required to support `interface Span`. | ||
// Span fields: | ||
this._db = null | ||
this._http = null | ||
this._destination = null | ||
this._message = null | ||
this._capturedStackTrace = null | ||
// GenericSpan fields: | ||
// - Cannot drop `this._context` because it is used for traceparent and ids. | ||
this._timer = null | ||
this._labels = null | ||
} | ||
@@ -197,2 +211,35 @@ | ||
const payload = { | ||
id: self.id, | ||
transaction_id: self.transaction.id, | ||
parent_id: self.parentId, | ||
trace_id: self.traceId, | ||
name: self.name, | ||
type: self.type || 'custom', | ||
subtype: self.subtype, | ||
action: self.action, | ||
timestamp: self.timestamp, | ||
duration: self._duration, | ||
context: undefined, | ||
stacktrace: undefined, | ||
sync: self.sync, | ||
outcome: self.outcome | ||
} | ||
// if a valid sample rate is set (truthy or zero), set the property | ||
const sampleRate = self.sampleRate | ||
if (sampleRate !== null) { | ||
payload.sample_rate = sampleRate | ||
} | ||
if (self._db || self._http || self._labels || self._destination || self._message) { | ||
payload.context = { | ||
db: self._db || undefined, | ||
http: self._http || undefined, | ||
tags: self._labels || undefined, | ||
destination: self._destination || undefined, | ||
message: self._message || undefined | ||
} | ||
} | ||
if (this._agent._conf.captureSpanStackTraces && this._stackObj) { | ||
@@ -210,37 +257,5 @@ this._stackObj.then( | ||
self._agent.logger.debug('could not capture stack trace for span %o', { span: self.id, parent: self.parentId, trace: self.traceId, name: self.name, type: self.type, subtype: self.subtype, action: self.action, err: err.message }) | ||
} else if (frames) { | ||
payload.stacktrace = frames | ||
} | ||
var payload = { | ||
id: self.id, | ||
transaction_id: self.transaction.id, | ||
parent_id: self.parentId, | ||
trace_id: self.traceId, | ||
name: self.name, | ||
type: self.type || 'custom', | ||
subtype: self.subtype, | ||
action: self.action, | ||
timestamp: self.timestamp, | ||
duration: self.duration(), | ||
context: undefined, | ||
stacktrace: frames, | ||
sync: self.sync, | ||
outcome: self.outcome | ||
} | ||
// if a valid sample rate is set (truthy or zero), set the property | ||
const sampleRate = self.sampleRate | ||
if (sampleRate !== null) { | ||
payload.sample_rate = sampleRate | ||
} | ||
if (self._db || self._http || self._labels || self._destination || self._message) { | ||
payload.context = { | ||
db: self._db || undefined, | ||
http: self._http || undefined, | ||
tags: self._labels || undefined, | ||
destination: self._destination || undefined, | ||
message: self._message || undefined | ||
} | ||
} | ||
cb(null, payload) | ||
@@ -247,0 +262,0 @@ } |
@@ -32,3 +32,2 @@ 'use strict' | ||
this._droppedSpans = 0 | ||
this._abortTime = 0 | ||
this._breakdownTimings = new ObjectIdentityMap() | ||
@@ -38,2 +37,3 @@ this._faas = undefined | ||
this._message = undefined | ||
this._cloud = undefined | ||
this.outcome = constants.OUTCOME_UNKNOWN | ||
@@ -151,2 +151,4 @@ } | ||
// Note that this only returns a complete result when called *during* the call | ||
// to `transaction.end()`. | ||
Transaction.prototype.toJSON = function () { | ||
@@ -159,3 +161,3 @@ var payload = { | ||
type: this.type || 'custom', | ||
duration: this.duration(), | ||
duration: this._duration, | ||
timestamp: this.timestamp, | ||
@@ -216,2 +218,4 @@ result: String(this.result), | ||
// Note that this only returns a complete result when called *during* the call | ||
// to `transaction.end()`. | ||
Transaction.prototype._encode = function () { | ||
@@ -270,2 +274,3 @@ if (!this.ended) { | ||
this._timer.end(endTime) | ||
this._duration = this._timer.duration | ||
this._captureBreakdown(this) | ||
@@ -276,2 +281,22 @@ this.ended = true | ||
this._agent.logger.debug('ended transaction %o', { trans: this.id, parent: this.parentId, trace: this.traceId, type: this.type, result: this.result, name: this.name }) | ||
// Reduce this transaction's memory usage by dropping references except to | ||
// fields required to support `interface Transaction`. | ||
// Transaction fields: | ||
this._customName = this.name // Short-circuit the `name` getter. | ||
this._defaultName = '' | ||
this.req = null | ||
this.res = null | ||
this._user = null | ||
this._custom = null | ||
this._breakdownTimings = null | ||
this._faas = undefined | ||
this._service = undefined | ||
this._message = undefined | ||
this._cloud = undefined | ||
// GenericSpan fields: | ||
// - Cannot drop `this._context` because it is used for `traceparent`, `ids`, | ||
// and `.sampled` (when capturing breakdown metrics for child spans). | ||
this._timer = null | ||
this._labels = null | ||
} | ||
@@ -278,0 +303,0 @@ |
{ | ||
"name": "elastic-apm-node", | ||
"version": "3.26.0", | ||
"version": "3.27.0", | ||
"description": "The official Elastic APM agent for Node.js", | ||
@@ -143,3 +143,3 @@ "main": "index.js", | ||
"express": "^4.17.1", | ||
"express-graphql": "^0.9.0", | ||
"express-graphql": "^0.12.0", | ||
"express-queue": "^0.0.12", | ||
@@ -152,3 +152,3 @@ "fastify": "^2.12.0", | ||
"got": "^9.6.0", | ||
"graphql": "^15.3.0", | ||
"graphql": "^15.8.0", | ||
"handlebars": "^4.7.3", | ||
@@ -168,3 +168,3 @@ "hapi": "^18.1.0", | ||
"module-details-from-path": "^1.0.3", | ||
"mongodb": "^4.1.0", | ||
"mongodb": "^4.2.1", | ||
"mongodb-core": "^3.2.7", | ||
@@ -171,0 +171,0 @@ "mysql": "^2.18.1", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
475195
11335