Skip to content
This repository has been archived by the owner on Aug 4, 2023. It is now read-only.

Commit

Permalink
feat: generate metadata object automatically (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
watson committed Aug 6, 2018
1 parent b71d686 commit 14000de
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 159 deletions.
33 changes: 22 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,10 @@ npm install elastic-apm-http-client --save
const Client = require('elastic-apm-http-client')

const client = new Client({
userAgent: 'My Custom Elastic APM Agent',
meta: function () {
return {
// meta data object sent as the first ndjson object in all HTTP
// requests to the APM Server
}
}
serviceName: 'My App',
agentName: 'my-nodejs-agent',
agentVersion: require('./package.json').version,
userAgent: 'My Custom Elastic APM Agent'
})

const span = {
Expand All @@ -58,14 +55,22 @@ Arguments:

- `options` - An object containing config options (see below)

Data sent to the APM Server as part of the metadata package:

- `agentName` - (required) The APM agent name
- `agentVersion` - (required) The APM agent version
- `serviceName` - (required) The name of the service being instrumented
- `serviceVersion` - The version of the service being instrumented
- `frameworkName` - If the service being instrumented is running a
specific framework, use this config option to log its name
- `frameworkVersion` - If the service being instrumented is running a
specific framework, use this config option to log its version
- `hostname` - Custom hostname (default: OS hostname)

HTTP client configuration:

- `userAgent` - (required) The HTTP user agent that your module should
identify it self as
- `meta` - (required) A function which will be called every time the a
new HTTP request is being made to the APM Server. It's expected that
you return a metadata object. This object will be sent as the first
ndjson object to the API
- `secretToken` - The Elastic APM intake API secret token
- `serverUrl` - The APM Server URL (default: `http://localhost:8200`)
- `headers` - An object containing extra HTTP headers that should be
Expand Down Expand Up @@ -98,6 +103,12 @@ Streaming configuration:
to the APM Server can be ongoing before it's ended (default: `10000`
ms)

Data sanitizing configuration:

- `truncateStringsAt` - Maximum size in bytes for strings stored as
Elasticsearch keywords. Strings larger than this will be trucated
(default: `1024` bytes)

### Event: `close`

The `close` event is emitted when the client and any of its underlying
Expand Down
66 changes: 59 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const util = require('util')
const os = require('os')
const parseUrl = require('url').parse
const zlib = require('zlib')
const Writable = require('readable-stream').Writable
Expand All @@ -10,11 +11,20 @@ const eos = require('end-of-stream')
const safeStringify = require('fast-safe-stringify')
const streamToBuffer = require('fast-stream-to-buffer')
const StreamChopper = require('stream-chopper')
const truncate = require('unicode-byte-truncate')
const pkg = require('./package')

module.exports = Client

const flush = Symbol('flush')

module.exports = Client
const hostname = os.hostname()
const requiredOpts = [
'agentName',
'agentVersion',
'serviceName',
'userAgent'
]

// All sockets on the agent are unreffed when they are created. This means that
// when those are the only handles left, the `beforeExit` event will be
Expand Down Expand Up @@ -155,9 +165,8 @@ Client.prototype.destroy = function (err) {
}

function onStream (opts, client, onerror) {
const meta = opts.meta
const serverTimeout = opts.serverTimeout
opts = getRequestOptions(opts, client._agent)
const requestOpts = getRequestOptions(opts, client._agent)

return function (stream, next) {
const onerrorproxy = (err) => {
Expand All @@ -170,7 +179,7 @@ function onStream (opts, client, onerror) {

client._active = true

const req = client._transport.request(opts, onResult(onerror))
const req = client._transport.request(requestOpts, onResult(onerror))
const compressor = zlib.createGzip()

// Mointor streams for errors so that we can make sure to destory the
Expand Down Expand Up @@ -219,7 +228,7 @@ function onStream (opts, client, onerror) {
})

// All requests to the APM Server must start with a metadata object
stream.write(safeStringify({metadata: meta()}) + '\n')
stream.write(safeStringify({metadata: metadata(opts)}) + '\n')
}
}

Expand All @@ -242,8 +251,8 @@ function onResult (onerror) {
}

function normalizeOptions (opts) {
if (!opts.userAgent) throw new Error('Missing required option: userAgent')
if (!opts.meta) throw new Error('Missing required option: meta')
const missing = requiredOpts.filter(name => !opts[name])
if (missing.length > 0) throw new Error('Missing required option(s): ' + missing.join(', '))

const normalized = Object.assign({}, opts, {objectMode: true})

Expand All @@ -252,6 +261,8 @@ function normalizeOptions (opts) {
if (!normalized.time && normalized.time !== 0) normalized.time = 10000
if (!normalized.serverTimeout && normalized.serverTimeout !== 0) normalized.serverTimeout = 15000
if (!normalized.serverUrl) normalized.serverUrl = 'http://localhost:8200'
if (!normalized.hostname) normalized.hostname = hostname
if (!normalized.truncateStringsAt) normalized.truncateStringsAt = 1024
normalized.keepAlive = normalized.keepAlive !== false

// process
Expand Down Expand Up @@ -282,3 +293,44 @@ function getHeaders (opts) {
headers['User-Agent'] = opts.userAgent + ' ' + pkg.name + '/' + pkg.version
return Object.assign(headers, opts.headers)
}

function metadata (opts) {
var payload = {
service: {
name: opts.serviceName,
runtime: {
name: process.release.name,
version: process.version
},
language: {
name: 'javascript'
},
agent: {
name: opts.agentName,
version: opts.agentVersion
}
},
process: {
pid: process.pid,
ppid: process.ppid,
title: truncate(String(process.title), opts.truncateStringsAt),
argv: process.argv
},
system: {
hostname: opts.hostname,
architecture: process.arch,
platform: process.platform
}
}

if (opts.serviceVersion) payload.service.version = opts.serviceVersion

if (opts.frameworkName || opts.frameworkVersion) {
payload.service.framework = {
name: opts.frameworkName,
version: opts.frameworkVersion
}
}

return payload
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"ndjson": "^1.5.0",
"pump": "^3.0.0",
"readable-stream": "^2.3.6",
"stream-chopper": "^1.1.1"
"stream-chopper": "^1.1.1",
"unicode-byte-truncate": "^1.0.0"
},
"devDependencies": {
"codecov": "^3.0.4",
Expand Down
Loading

0 comments on commit 14000de

Please sign in to comment.