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

Commit be7bb12

Browse files
authored
feat: generate metadata object automatically (#6)
1 parent 488502f commit be7bb12

File tree

6 files changed

+378
-159
lines changed

6 files changed

+378
-159
lines changed

README.md

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,10 @@ npm install elastic-apm-http-client
2626
const Client = require('elastic-apm-http-client')
2727

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

3835
const span = {
@@ -57,14 +54,22 @@ Arguments:
5754

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

57+
Data sent to the APM Server as part of the metadata package:
58+
59+
- `agentName` - (required) The APM agent name
60+
- `agentVersion` - (required) The APM agent version
61+
- `serviceName` - (required) The name of the service being instrumented
62+
- `serviceVersion` - The version of the service being instrumented
63+
- `frameworkName` - If the service being instrumented is running a
64+
specific framework, use this config option to log its name
65+
- `frameworkVersion` - If the service being instrumented is running a
66+
specific framework, use this config option to log its version
67+
- `hostname` - Custom hostname (default: OS hostname)
68+
6069
HTTP client configuration:
6170

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

105+
Data sanitizing configuration:
106+
107+
- `truncateStringsAt` - Maximum size in bytes for strings stored as
108+
Elasticsearch keywords. Strings larger than this will be trucated
109+
(default: `1024` bytes)
110+
100111
### Event: `close`
101112

102113
The `close` event is emitted when the client and any of its underlying

index.js

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22

33
const util = require('util')
4+
const os = require('os')
45
const parseUrl = require('url').parse
56
const zlib = require('zlib')
67
const Writable = require('readable-stream').Writable
@@ -10,11 +11,20 @@ const eos = require('end-of-stream')
1011
const safeStringify = require('fast-safe-stringify')
1112
const streamToBuffer = require('fast-stream-to-buffer')
1213
const StreamChopper = require('stream-chopper')
14+
const truncate = require('unicode-byte-truncate')
1315
const pkg = require('./package')
1416

17+
module.exports = Client
18+
1519
const flush = Symbol('flush')
1620

17-
module.exports = Client
21+
const hostname = os.hostname()
22+
const requiredOpts = [
23+
'agentName',
24+
'agentVersion',
25+
'serviceName',
26+
'userAgent'
27+
]
1828

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

157167
function onStream (opts, client, onerror) {
158-
const meta = opts.meta
159168
const serverTimeout = opts.serverTimeout
160-
opts = getRequestOptions(opts, client._agent)
169+
const requestOpts = getRequestOptions(opts, client._agent)
161170

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

171180
client._active = true
172181

173-
const req = client._transport.request(opts, onResult(onerror))
182+
const req = client._transport.request(requestOpts, onResult(onerror))
174183
const compressor = zlib.createGzip()
175184

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

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

@@ -242,8 +251,8 @@ function onResult (onerror) {
242251
}
243252

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

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

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

257268
// process
@@ -282,3 +293,44 @@ function getHeaders (opts) {
282293
headers['User-Agent'] = opts.userAgent + ' ' + pkg.name + '/' + pkg.version
283294
return Object.assign(headers, opts.headers)
284295
}
296+
297+
function metadata (opts) {
298+
var payload = {
299+
service: {
300+
name: opts.serviceName,
301+
runtime: {
302+
name: process.release.name,
303+
version: process.version
304+
},
305+
language: {
306+
name: 'javascript'
307+
},
308+
agent: {
309+
name: opts.agentName,
310+
version: opts.agentVersion
311+
}
312+
},
313+
process: {
314+
pid: process.pid,
315+
ppid: process.ppid,
316+
title: truncate(String(process.title), opts.truncateStringsAt),
317+
argv: process.argv
318+
},
319+
system: {
320+
hostname: opts.hostname,
321+
architecture: process.arch,
322+
platform: process.platform
323+
}
324+
}
325+
326+
if (opts.serviceVersion) payload.service.version = opts.serviceVersion
327+
328+
if (opts.frameworkName || opts.frameworkVersion) {
329+
payload.service.framework = {
330+
name: opts.frameworkName,
331+
version: opts.frameworkVersion
332+
}
333+
}
334+
335+
return payload
336+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"ndjson": "^1.5.0",
2323
"pump": "^3.0.0",
2424
"readable-stream": "^2.3.6",
25-
"stream-chopper": "^1.1.1"
25+
"stream-chopper": "^1.1.1",
26+
"unicode-byte-truncate": "^1.0.0"
2627
},
2728
"devDependencies": {
2829
"codecov": "^3.0.4",

0 commit comments

Comments
 (0)