Skip to content

Commit

Permalink
feat: support APM Server intake API version 2 (elastic#465)
Browse files Browse the repository at this point in the history
  • Loading branch information
watson authored and Stephen Belanger committed Sep 13, 2018
1 parent 1498c56 commit 6097731
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 0 deletions.
35 changes: 35 additions & 0 deletions lib/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var Instrumentation = require('./instrumentation')
var parsers = require('./parsers')
var stackman = require('./stackman')
var symbols = require('./symbols')
var truncate = require('./truncate')

var IncomingMessage = http.IncomingMessage
var ServerResponse = http.ServerResponse
Expand All @@ -30,9 +31,13 @@ function Agent () {
this.middleware = { connect: connect.bind(this) }

this._instrumentation = new Instrumentation(this)
<<<<<<< HEAD
this._errorFilters = new Filters()
this._transactionFilters = new Filters()
this._spanFilters = new Filters()
=======
this._filters = new Filters()
>>>>>>> feat: support APM Server intake API version 2 (#465)
this._apmServer = null

this._conf = null
Expand Down Expand Up @@ -149,8 +154,12 @@ Agent.prototype.start = function (opts) {
hostname: this._conf.hostname,

// Sanitize conf
<<<<<<< HEAD
truncateKeywordsAt: config.INTAKE_STRING_MAX_SIZE,
truncateErrorMessagesAt: this._conf.errorMessageMaxLength,
=======
truncateStringsAt: config.INTAKE_STRING_MAX_SIZE, // TODO: Do we need to set this (it's the default value)
>>>>>>> feat: support APM Server intake API version 2 (#465)

// HTTP conf
secretToken: this._conf.secretToken,
Expand All @@ -161,17 +170,26 @@ Agent.prototype.start = function (opts) {

// Streaming conf
size: this._conf.apiRequestSize,
<<<<<<< HEAD
time: this._conf.apiRequestTime * 1000,

// Debugging
payloadLogFile: this._conf.payloadLogFile
})
this._apmServer.on('error', err => {
this.logger.error('An error occrued while communicating with the APM Server:', err.message)
=======
time: this._conf.apiRequestTime * 1000
>>>>>>> feat: support APM Server intake API version 2 (#465)
})
this._apmServer.on('error', err => {
this.logger.error('An error occrued while communicating with the APM Server:', err.message)
})

this._instrumentation.start()

this._instrumentation.start()

Error.stackTraceLimit = this._conf.stackTraceLimit
if (this._conf.captureExceptions) this.handleUncaughtExceptions()

Expand Down Expand Up @@ -342,6 +360,7 @@ Agent.prototype.captureError = function (err, opts, cb) {
}

function send (error) {
<<<<<<< HEAD
error = agent._errorFilters.process(error)

if (!error) {
Expand All @@ -350,12 +369,28 @@ Agent.prototype.captureError = function (err, opts, cb) {
return
}

=======
error = agent._filters.process(error) // TODO: Update filter to expect this format

if (!error) {
agent.logger.debug('error ignored by filter %o', { id: id })
cb()
return
}

truncate.error(error, agent._conf)

>>>>>>> feat: support APM Server intake API version 2 (#465)
if (agent._apmServer) {
agent.logger.info(`Sending error ${id} to Elastic APM`)
agent._apmServer.sendError(error, function () {
agent._apmServer.flush(cb)
})
<<<<<<< HEAD
} else if (cb) {
=======
} else {
>>>>>>> feat: support APM Server intake API version 2 (#465)
// TODO: Swallow this error just as it's done in agent.flush()?
process.nextTick(cb.bind(null, new Error('cannot capture error before agent is started')))
}
Expand Down
1 change: 1 addition & 0 deletions lib/instrumentation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var hook = require('require-in-the-middle')
var semver = require('semver')

var Transaction = require('./transaction')
var truncate = require('../truncate')
var shimmer = require('./shimmer')

var MODULES = [
Expand Down
127 changes: 127 additions & 0 deletions lib/truncate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
'use strict'

var truncate = require('unicode-byte-truncate')

var config = require('./config')

exports.transaction = truncTransaction
exports.span = truncSpan
exports.error = truncError

function truncTransaction (trans) {
trans.name = truncate(String(trans.name), config.INTAKE_STRING_MAX_SIZE)
trans.type = truncate(String(trans.type), config.INTAKE_STRING_MAX_SIZE)
trans.result = truncate(String(trans.result), config.INTAKE_STRING_MAX_SIZE)

// Unless sampled, context will be null
if (trans.sampled) truncContext(trans.context)
}

function truncSpan (span) {
span.name = truncate(String(span.name), config.INTAKE_STRING_MAX_SIZE)
span.type = truncate(String(span.type), config.INTAKE_STRING_MAX_SIZE)
if (span.stacktrace) span.stacktrace = truncFrames(span.stacktrace)
}

function truncError (error, conf) {
if (error.log) {
if (error.log.level) {
error.log.level = truncate(String(error.log.level), config.INTAKE_STRING_MAX_SIZE)
}
if (error.log.logger_name) {
error.log.logger_name = truncate(String(error.log.logger_name), config.INTAKE_STRING_MAX_SIZE)
}
if (error.log.message && conf.errorMessageMaxLength >= 0) {
error.log.message = truncate(String(error.log.message), conf.errorMessageMaxLength)
}
if (error.log.param_message) {
error.log.param_message = truncate(String(error.log.param_message), config.INTAKE_STRING_MAX_SIZE)
}
if (error.log.stacktrace) {
error.log.stacktrace = truncFrames(error.log.stacktrace)
}
}

if (error.exception) {
if (error.exception.message && conf.errorMessageMaxLength >= 0) {
error.exception.message = truncate(String(error.exception.message), conf.errorMessageMaxLength)
}
if (error.exception.type) {
error.exception.type = truncate(String(error.exception.type), config.INTAKE_STRING_MAX_SIZE)
}
if (error.exception.code) {
error.exception.code = truncate(String(error.exception.code), config.INTAKE_STRING_MAX_SIZE)
}
if (error.exception.module) {
error.exception.module = truncate(String(error.exception.module), config.INTAKE_STRING_MAX_SIZE)
}
if (error.exception.stacktrace) {
error.exception.stacktrace = truncFrames(error.exception.stacktrace)
}
}

truncContext(error.context)
}

function truncContext (context) {
if (!context) return

if (context.request) {
if (context.request.method) {
context.request.method = truncate(String(context.request.method), config.INTAKE_STRING_MAX_SIZE)
}
if (context.request.url) {
if (context.request.url.protocol) {
context.request.url.protocol = truncate(String(context.request.url.protocol), config.INTAKE_STRING_MAX_SIZE)
}
if (context.request.url.hostname) {
context.request.url.hostname = truncate(String(context.request.url.hostname), config.INTAKE_STRING_MAX_SIZE)
}
if (context.request.url.port) {
context.request.url.port = truncate(String(context.request.url.port), config.INTAKE_STRING_MAX_SIZE)
}
if (context.request.url.pathname) {
context.request.url.pathname = truncate(String(context.request.url.pathname), config.INTAKE_STRING_MAX_SIZE)
}
if (context.request.url.search) {
context.request.url.search = truncate(String(context.request.url.search), config.INTAKE_STRING_MAX_SIZE)
}
if (context.request.url.hash) {
context.request.url.hash = truncate(String(context.request.url.hash), config.INTAKE_STRING_MAX_SIZE)
}
if (context.request.url.raw) {
context.request.url.raw = truncate(String(context.request.url.raw), config.INTAKE_STRING_MAX_SIZE)
}
if (context.request.url.full) {
context.request.url.full = truncate(String(context.request.url.full), config.INTAKE_STRING_MAX_SIZE)
}
}
}
if (context.user) {
if (context.user.id) {
context.user.id = truncate(String(context.user.id), config.INTAKE_STRING_MAX_SIZE)
}
if (context.user.email) {
context.user.email = truncate(String(context.user.email), config.INTAKE_STRING_MAX_SIZE)
}
if (context.user.username) {
context.user.username = truncate(String(context.user.username), config.INTAKE_STRING_MAX_SIZE)
}
}
}

function truncFrames (frames) {
frames.forEach(function (frame, i) {
if (frame.pre_context) frame.pre_context = truncEach(frame.pre_context, 1000)
if (frame.context_line) frame.context_line = truncate(String(frame.context_line), 1000)
if (frame.post_context) frame.post_context = truncEach(frame.post_context, 1000)
})

return frames
}

function truncEach (arr, len) {
return arr.map(function (str) {
return truncate(String(str), len)
})
}

0 comments on commit 6097731

Please sign in to comment.