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

feat: generate metadata object automatically #6

Merged
merged 2 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,10 @@ npm install elastic-apm-http-client
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 @@ -57,14 +54,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 @@ -97,6 +102,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 @@ -152,9 +162,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 @@ -167,7 +176,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 @@ -215,7 +224,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 @@ -238,8 +247,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 @@ -248,6 +257,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 @@ -278,3 +289,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