Skip to content

Commit c4bd8fb

Browse files
authored
Merge branch 'master' into doc-max-span-duration
2 parents 216466e + 6a84486 commit c4bd8fb

File tree

12 files changed

+195
-10
lines changed

12 files changed

+195
-10
lines changed

docs/metrics.asciidoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,25 @@ The current allocated heap size in bytes.
129129

130130
The currently used heap size in bytes.
131131

132+
[float]
133+
[[metric-nodejs.memory.external.bytes]]
134+
=== `nodejs.memory.external.bytes`
135+
136+
* *Type:* Long
137+
* *Format:* Bytes
138+
139+
Memory usage of C++ objects bound to JavaScript objects managed by V8.
140+
141+
[float]
142+
[[metric-nodejs.memory.arrayBuffers.bytes]]
143+
=== `nodejs.memory.arrayBuffers.bytes`
144+
145+
* *Type:* Long
146+
* *Format:* Bytes
147+
148+
Memory allocated for ArrayBuffers and SharedArrayBuffers, including all Node.js Buffers.
149+
This is also included in the `nodejs.memory.external.bytes` value.
150+
132151
[float]
133152
[[metrics-transaction.duration.sum]]
134153
=== `transaction.duration.sum`

lib/instrumentation/context.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict'
2+
3+
var { parseUrl } = require('../parsers')
4+
5+
// Get the port number including the default port for a protocols
6+
function getPortNumber (port, protocol) {
7+
if (port === '') {
8+
port = protocol === 'http:' ? '80' : protocol === 'https:' ? '443' : ''
9+
}
10+
return port
11+
}
12+
13+
exports.getHTTPDestination = function (url, spanType) {
14+
const { port, protocol, hostname, origin } = parseUrl(url)
15+
const portNumber = getPortNumber(port, protocol)
16+
17+
// If hostname begins with [ and ends with ], assume that it's an IPv6 address.
18+
// since address and port are recorded separately, we are recording the
19+
// info in canonical form without square brackets
20+
const ipv6Hostname =
21+
hostname[0] === '[' &&
22+
hostname[hostname.length - 1] === ']'
23+
24+
const address = ipv6Hostname ? hostname.slice(1, -1) : hostname
25+
26+
return {
27+
service: {
28+
name: origin,
29+
resource: hostname + ':' + portNumber,
30+
type: spanType
31+
},
32+
address,
33+
port: Number(portNumber)
34+
}
35+
}

lib/instrumentation/http-shared.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ var endOfStream = require('end-of-stream')
66
var httpRequestToUrl = require('http-request-to-url')
77

88
var { parseUrl } = require('../parsers')
9+
var { getHTTPDestination } = require('./context')
910

1011
const transactionForResponse = new WeakMap()
1112
exports.transactionForResponse = transactionForResponse
@@ -208,6 +209,8 @@ exports.traceOutgoingRequest = function (agent, moduleName, method) {
208209
url
209210
})
210211

212+
span.setDestinationContext(getHTTPDestination(url, span.type))
213+
211214
span.end()
212215
}
213216
}

lib/instrumentation/modules/http2.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var eos = require('end-of-stream')
55
var shimmer = require('../shimmer')
66
var symbols = require('../../symbols')
77
var { parseUrl } = require('../../parsers')
8+
var { getHTTPDestination } = require('../context')
89

910
module.exports = function (http2, agent, { enabled }) {
1011
if (agent._conf.instrumentIncomingHTTPRequests) {
@@ -178,6 +179,8 @@ module.exports = function (http2, agent, { enabled }) {
178179
url
179180
})
180181

182+
span.setDestinationContext(getHTTPDestination(url, span.type))
183+
181184
span.end()
182185
})
183186

lib/instrumentation/span.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ function Span (transaction, name, ...args) {
3131

3232
this._db = null
3333
this._http = null
34+
this._destination = null
3435
this._stackObj = null
3536

3637
this.transaction = transaction
@@ -87,6 +88,10 @@ Span.prototype.setHttpContext = function (context) {
8788
this._http = Object.assign(this._http || {}, context)
8889
}
8990

91+
Span.prototype.setDestinationContext = function (context) {
92+
this._destination = Object.assign(this._destination || {}, context)
93+
}
94+
9095
Span.prototype._recordStackTrace = function (obj) {
9196
if (!obj) {
9297
obj = {}
@@ -151,11 +156,12 @@ Span.prototype._encode = function (cb) {
151156
sync: self.sync
152157
}
153158

154-
if (self._db || self._http || self._labels) {
159+
if (self._db || self._http || self._labels || self._destination) {
155160
payload.context = {
156161
db: self._db || undefined,
157162
http: self._http || undefined,
158-
tags: self._labels || undefined
163+
tags: self._labels || undefined,
164+
destination: self._destination || undefined
159165
}
160166
}
161167

lib/metrics/runtime.js

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

3-
const v8 = require('v8')
4-
53
const eventLoopMonitor = require('monitor-event-loop-delay')
64

75
const activeHandles = typeof process._getActiveHandles === 'function'
@@ -21,7 +19,9 @@ class RuntimeCollector {
2119
'nodejs.requests.active': 0,
2220
'nodejs.eventloop.delay.ns': 0,
2321
'nodejs.memory.heap.allocated.bytes': 0,
24-
'nodejs.memory.heap.used.bytes': 0
22+
'nodejs.memory.heap.used.bytes': 0,
23+
'nodejs.memory.external.bytes': 0,
24+
'nodejs.memory.arrayBuffers.bytes': 0
2525
}
2626

2727
const monitor = eventLoopMonitor({
@@ -43,10 +43,13 @@ class RuntimeCollector {
4343
this.stats['nodejs.eventloop.delay.avg.ms'] = loopDelay
4444
this.loopMonitor.reset()
4545

46-
// Heap
47-
const heap = v8.getHeapStatistics()
48-
this.stats['nodejs.memory.heap.allocated.bytes'] = heap.total_heap_size
49-
this.stats['nodejs.memory.heap.used.bytes'] = heap.used_heap_size
46+
// Memory / Heap
47+
const memoryUsage = process.memoryUsage()
48+
this.stats['nodejs.memory.heap.allocated.bytes'] = memoryUsage.heapTotal
49+
this.stats['nodejs.memory.heap.used.bytes'] = memoryUsage.heapUsed
50+
51+
this.stats['nodejs.memory.external.bytes'] = memoryUsage.external
52+
this.stats['nodejs.memory.arrayBuffers.bytes'] = memoryUsage.arrayBuffers || 0 // Only available in NodeJS +13.0
5053

5154
if (cb) process.nextTick(cb)
5255
}

test/instrumentation/context.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
'use strict'
2+
3+
var test = require('tape')
4+
var { getHTTPDestination } = require('../../lib/instrumentation/context')
5+
6+
test('#getHTTPDestination', function (t) {
7+
t.test('username and pass', (t) => {
8+
const url = 'http://user:pass@testing.local:1234/path?query'
9+
t.deepEqual(getHTTPDestination(url, 'external'), {
10+
service: {
11+
name: 'http://testing.local:1234',
12+
resource: 'testing.local:1234',
13+
type: 'external'
14+
},
15+
address: 'testing.local',
16+
port: 1234
17+
})
18+
t.end()
19+
})
20+
21+
t.test('https with custom port', () => {
22+
const url = 'https://example.com:2222'
23+
t.deepEqual(getHTTPDestination(url, 'external'), {
24+
service:
25+
{
26+
name: 'https://example.com:2222',
27+
resource: 'example.com:2222',
28+
type: 'external'
29+
},
30+
address: 'example.com',
31+
port: 2222
32+
})
33+
t.end()
34+
})
35+
36+
t.test('https default port', (t) => {
37+
const url = 'https://www.elastic.co/products/apm'
38+
t.deepEqual(getHTTPDestination(url, 'external'), {
39+
service: {
40+
name: 'https://www.elastic.co',
41+
resource: 'www.elastic.co:443',
42+
type: 'external'
43+
},
44+
address: 'www.elastic.co',
45+
port: 443
46+
})
47+
t.end()
48+
})
49+
50+
t.test('http default port', (t) => {
51+
const url = 'http://www.elastic.co/products/apm'
52+
t.deepEqual(getHTTPDestination(url, 'external'), {
53+
service: {
54+
name: 'http://www.elastic.co',
55+
resource: 'www.elastic.co:80',
56+
type: 'external'
57+
},
58+
address: 'www.elastic.co',
59+
port: 80
60+
})
61+
t.end()
62+
})
63+
64+
t.test('ipv6', (t) => {
65+
const url = 'http://[::1]'
66+
t.deepEqual(getHTTPDestination(url, 'external'), {
67+
service: {
68+
name: 'http://[::1]',
69+
resource: '[::1]:80',
70+
type: 'external'
71+
},
72+
address: '::1',
73+
port: 80
74+
})
75+
t.end()
76+
})
77+
78+
t.test('ipv6 https custom port', (t) => {
79+
const url = 'https://[::1]:80/'
80+
t.deepEqual(getHTTPDestination(url, 'external'), {
81+
service: {
82+
name: 'https://[::1]:80',
83+
resource: '[::1]:80',
84+
type: 'external'
85+
},
86+
address: '::1',
87+
port: 80
88+
})
89+
t.end()
90+
})
91+
})

test/instrumentation/modules/http/outgoing.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ function echoTest (type, opts, handler) {
138138
status_code: 200,
139139
url: `${type}://127.0.0.1:${port}/`
140140
})
141+
t.deepEqual(data.spans[0].context.destination, {
142+
service: {
143+
name: `${type}://127.0.0.1:${port}`,
144+
resource: `127.0.0.1:${port}`,
145+
type: data.spans[0].type
146+
},
147+
address: '127.0.0.1',
148+
port: Number(port)
149+
})
141150
t.end()
142151
cp.kill()
143152
})

test/instrumentation/modules/http2.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,15 @@ isSecure.forEach(secure => {
288288
status_code: 200,
289289
url: `http${secure ? 's' : ''}://localhost:${port}/sub`
290290
})
291+
t.deepEqual(span.context.destination, {
292+
service: {
293+
name: `http${secure ? 's' : ''}://localhost:${port}`,
294+
resource: `localhost:${port}`,
295+
type: span.type
296+
},
297+
address: 'localhost',
298+
port
299+
})
291300

292301
server.close()
293302
t.end()

test/instrumentation/span.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ test('#_encode() - with meta data', function myTest2 (t) {
240240
t.equal(payload.type, 'bar')
241241
t.equal(payload.timestamp, span._timer.start)
242242
t.ok(payload.duration > 0)
243-
t.deepEqual(payload.context, { db: { statement: 'foo', type: 'bar' }, http: undefined, tags: { baz: '1' } })
243+
t.deepEqual(payload.context, { db: { statement: 'foo', type: 'bar' }, http: undefined, tags: { baz: '1' }, destination: undefined })
244244
assert.stacktrace(t, 'myTest2', __filename, payload.stacktrace, agent)
245245
t.end()
246246
})

0 commit comments

Comments
 (0)