@platformatic/telemetry 0.46.1 → 0.46.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/telemetry.js
CHANGED
|
@@ -31,8 +31,9 @@ const { name: moduleName, version: moduleVersion } = require('../package.json')
|
|
|
31
31
|
const extractPath = (request) => {
|
|
32
32
|
// We must user RouterPath, because otherwise `/test/123` will be considered as
|
|
33
33
|
// a different operation than `/test/321`. In case is not set (this should actually happen only for HTTP/404) we fallback to the path.
|
|
34
|
-
const {
|
|
34
|
+
const { routeOptions, url } = request
|
|
35
35
|
let path
|
|
36
|
+
const routerPath = routeOptions && routeOptions.url
|
|
36
37
|
if (routerPath) {
|
|
37
38
|
path = formatParamUrl(routerPath)
|
|
38
39
|
} else {
|
package/package.json
CHANGED
package/test/client.test.js
DELETED
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { test } = require('tap')
|
|
4
|
-
const fastify = require('fastify')
|
|
5
|
-
const { SpanStatusCode, SpanKind } = require('@opentelemetry/api')
|
|
6
|
-
const telemetryPlugin = require('../lib/telemetry')
|
|
7
|
-
const { PlatformaticContext } = require('../lib/platformatic-context')
|
|
8
|
-
const { fastifyTextMapGetter } = require('../lib/fastify-text-map')
|
|
9
|
-
|
|
10
|
-
async function setupApp (pluginOpts, routeHandler, teardown) {
|
|
11
|
-
const app = fastify()
|
|
12
|
-
await app.register(telemetryPlugin, pluginOpts)
|
|
13
|
-
app.get('/test', routeHandler)
|
|
14
|
-
app.ready()
|
|
15
|
-
teardown(async () => {
|
|
16
|
-
await app.close()
|
|
17
|
-
const { exporters } = app.openTelemetry
|
|
18
|
-
exporters.forEach(exporter => {
|
|
19
|
-
if (exporter.constructor.name === 'InMemorySpanExporter') {
|
|
20
|
-
exporter.reset()
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
})
|
|
24
|
-
return app
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
test('should add the propagation headers correctly, new propagation started', async ({ equal, same, teardown }) => {
|
|
28
|
-
const handler = async (request, reply) => {
|
|
29
|
-
return { foo: 'bar' }
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const app = await setupApp({
|
|
33
|
-
serviceName: 'test-service',
|
|
34
|
-
exporter: {
|
|
35
|
-
type: 'memory'
|
|
36
|
-
}
|
|
37
|
-
}, handler, teardown)
|
|
38
|
-
|
|
39
|
-
const { startSpanClient } = app.openTelemetry
|
|
40
|
-
|
|
41
|
-
const url = 'http://localhost:3000/test'
|
|
42
|
-
const { span, telemetryHeaders } = startSpanClient(url, 'GET')
|
|
43
|
-
|
|
44
|
-
const spanId = span._spanContext.spanId
|
|
45
|
-
const traceId = span._spanContext.traceId
|
|
46
|
-
same(telemetryHeaders, {
|
|
47
|
-
traceparent: `00-${traceId}-${spanId}-01`
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('should add the propagation headers correctly, with propagation already started', async ({ equal, same, teardown }) => {
|
|
52
|
-
const traceId = '5e994e8fb53b27c91dcd2fec22771d15'
|
|
53
|
-
const spanId = '166f3ab30f21800b'
|
|
54
|
-
const traceparent = `00-${traceId}-${spanId}-01`
|
|
55
|
-
|
|
56
|
-
const handler = async (request, reply) => {
|
|
57
|
-
return { foo: 'bar' }
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const app = await setupApp({
|
|
61
|
-
serviceName: 'test-service',
|
|
62
|
-
version: '1.0.0',
|
|
63
|
-
exporter: {
|
|
64
|
-
type: 'memory'
|
|
65
|
-
}
|
|
66
|
-
}, handler, teardown)
|
|
67
|
-
|
|
68
|
-
const { startSpanClient } = app.openTelemetry
|
|
69
|
-
|
|
70
|
-
const url = 'http://localhost:3000/test'
|
|
71
|
-
const incomingHeaders = {
|
|
72
|
-
host: 'test',
|
|
73
|
-
traceparent
|
|
74
|
-
}
|
|
75
|
-
const { propagator } = app.openTelemetry
|
|
76
|
-
const context = propagator.extract(new PlatformaticContext(), { headers: incomingHeaders }, fastifyTextMapGetter)
|
|
77
|
-
|
|
78
|
-
const { span, telemetryHeaders } = startSpanClient(url, 'GET', context)
|
|
79
|
-
|
|
80
|
-
const spanId2 = span._spanContext.spanId
|
|
81
|
-
const traceId2 = span._spanContext.traceId
|
|
82
|
-
|
|
83
|
-
// We preserved the tracedId
|
|
84
|
-
same(traceId, traceId2)
|
|
85
|
-
same(telemetryHeaders, {
|
|
86
|
-
traceparent: `00-${traceId}-${spanId2}-01`
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
test('should trace a client request', async ({ equal, same, teardown }) => {
|
|
91
|
-
let receivedHeaders = null
|
|
92
|
-
const handler = async (request, reply) => {
|
|
93
|
-
receivedHeaders = request.headers
|
|
94
|
-
return { foo: 'bar' }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const app = await setupApp({
|
|
98
|
-
serviceName: 'test-service',
|
|
99
|
-
version: '1.0.0',
|
|
100
|
-
exporter: {
|
|
101
|
-
type: 'memory'
|
|
102
|
-
}
|
|
103
|
-
}, handler, teardown)
|
|
104
|
-
|
|
105
|
-
const { startSpanClient, endSpanClient } = app.openTelemetry
|
|
106
|
-
|
|
107
|
-
const url = 'http://localhost:3000/test'
|
|
108
|
-
|
|
109
|
-
const { propagator } = app.openTelemetry
|
|
110
|
-
const context = propagator.extract(new PlatformaticContext(), { headers: {} }, fastifyTextMapGetter)
|
|
111
|
-
|
|
112
|
-
const { span, telemetryHeaders } = startSpanClient(url, 'GET', context)
|
|
113
|
-
const args = {
|
|
114
|
-
method: 'GET',
|
|
115
|
-
url: '/test',
|
|
116
|
-
headers: {
|
|
117
|
-
...telemetryHeaders
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const response = await app.inject(args)
|
|
122
|
-
endSpanClient(span, response)
|
|
123
|
-
|
|
124
|
-
const { exporters } = app.openTelemetry
|
|
125
|
-
const exporter = exporters[0]
|
|
126
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
127
|
-
equal(finishedSpans.length, 2)
|
|
128
|
-
// We have two one for the client and one for the server
|
|
129
|
-
const spanServer = finishedSpans[0]
|
|
130
|
-
equal(spanServer.name, 'GET /test')
|
|
131
|
-
equal(spanServer.kind, SpanKind.SERVER)
|
|
132
|
-
equal(spanServer.status.code, SpanStatusCode.OK)
|
|
133
|
-
equal(spanServer.attributes['http.request.method'], 'GET')
|
|
134
|
-
equal(spanServer.attributes['url.path'], '/test')
|
|
135
|
-
equal(spanServer.attributes['http.response.status_code'], 200)
|
|
136
|
-
|
|
137
|
-
const spanClient = finishedSpans[1]
|
|
138
|
-
equal(spanClient.name, 'GET http://localhost:3000/test')
|
|
139
|
-
equal(spanClient.kind, SpanKind.CLIENT)
|
|
140
|
-
equal(spanClient.status.code, SpanStatusCode.OK)
|
|
141
|
-
equal(spanClient.attributes['url.full'], 'http://localhost:3000/test')
|
|
142
|
-
equal(spanClient.attributes['http.response.status_code'], 200)
|
|
143
|
-
equal(spanClient.attributes['server.port'], 3000)
|
|
144
|
-
equal(spanClient.attributes['server.address'], 'localhost')
|
|
145
|
-
equal(spanClient.attributes['url.path'], '/test')
|
|
146
|
-
|
|
147
|
-
// The traceparent header is added to the request and propagated to the server
|
|
148
|
-
equal(receivedHeaders.traceparent, telemetryHeaders.traceparent)
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
test('should trace a client request failing', async ({ equal, same, teardown }) => {
|
|
152
|
-
const handler = async (request, reply) => {
|
|
153
|
-
return { foo: 'bar' }
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const app = await setupApp({
|
|
157
|
-
serviceName: 'test-service',
|
|
158
|
-
version: '1.0.0',
|
|
159
|
-
exporter: {
|
|
160
|
-
type: 'memory'
|
|
161
|
-
}
|
|
162
|
-
}, handler, teardown)
|
|
163
|
-
|
|
164
|
-
const { startSpanClient, endSpanClient } = app.openTelemetry
|
|
165
|
-
|
|
166
|
-
const { propagator } = app.openTelemetry
|
|
167
|
-
const context = propagator.extract(new PlatformaticContext(), { headers: {} }, fastifyTextMapGetter)
|
|
168
|
-
|
|
169
|
-
const url = 'http://localhost:3000/test'
|
|
170
|
-
const { span, telemetryHeaders } = startSpanClient(url, 'GET', context)
|
|
171
|
-
const args = {
|
|
172
|
-
method: 'GET',
|
|
173
|
-
url: '/wrong',
|
|
174
|
-
headers: telemetryHeaders
|
|
175
|
-
}
|
|
176
|
-
const response = await app.inject(args)
|
|
177
|
-
endSpanClient(span, response)
|
|
178
|
-
|
|
179
|
-
const { exporters } = app.openTelemetry
|
|
180
|
-
const exporter = exporters[0]
|
|
181
|
-
|
|
182
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
183
|
-
equal(finishedSpans.length, 2)
|
|
184
|
-
// We have two one for the client and one for the server
|
|
185
|
-
const spanServer = finishedSpans[0]
|
|
186
|
-
equal(spanServer.name, 'GET /wrong')
|
|
187
|
-
equal(spanServer.kind, SpanKind.SERVER)
|
|
188
|
-
equal(spanServer.status.code, SpanStatusCode.ERROR)
|
|
189
|
-
equal(spanServer.attributes['http.request.method'], 'GET')
|
|
190
|
-
equal(spanServer.attributes['url.path'], '/wrong')
|
|
191
|
-
equal(spanServer.attributes['http.response.status_code'], 404)
|
|
192
|
-
|
|
193
|
-
const spanClient = finishedSpans[1]
|
|
194
|
-
equal(spanClient.name, 'GET http://localhost:3000/test')
|
|
195
|
-
equal(spanClient.kind, SpanKind.CLIENT)
|
|
196
|
-
equal(spanClient.status.code, SpanStatusCode.ERROR)
|
|
197
|
-
equal(spanClient.attributes['url.full'], 'http://localhost:3000/test')
|
|
198
|
-
equal(spanClient.attributes['http.response.status_code'], 404)
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
test('should trace a client request failing (no HTTP error)', async ({ equal, same, teardown }) => {
|
|
202
|
-
const handler = async (request, reply) => {
|
|
203
|
-
return { foo: 'bar' }
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const app = await setupApp({
|
|
207
|
-
serviceName: 'test-service',
|
|
208
|
-
version: '1.0.0',
|
|
209
|
-
exporter: {
|
|
210
|
-
type: 'memory'
|
|
211
|
-
}
|
|
212
|
-
}, handler, teardown)
|
|
213
|
-
|
|
214
|
-
const { startSpanClient, endSpanClient, setErrorInSpanClient } = app.openTelemetry
|
|
215
|
-
|
|
216
|
-
const url = 'http://localhost:3000/test'
|
|
217
|
-
const { span } = startSpanClient(url, 'GET')
|
|
218
|
-
try {
|
|
219
|
-
throw new Error('KABOOM!!!')
|
|
220
|
-
} catch (err) {
|
|
221
|
-
setErrorInSpanClient(span, err)
|
|
222
|
-
} finally {
|
|
223
|
-
endSpanClient(span)
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const { exporters } = app.openTelemetry
|
|
227
|
-
const exporter = exporters[0]
|
|
228
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
229
|
-
equal(finishedSpans.length, 1)
|
|
230
|
-
|
|
231
|
-
const spanClient = finishedSpans[0]
|
|
232
|
-
equal(spanClient.name, 'GET http://localhost:3000/test')
|
|
233
|
-
equal(spanClient.status.code, SpanStatusCode.ERROR)
|
|
234
|
-
equal(spanClient.attributes['url.full'], 'http://localhost:3000/test')
|
|
235
|
-
equal(spanClient.attributes['error.name'], 'Error')
|
|
236
|
-
equal(spanClient.attributes['error.message'], 'KABOOM!!!')
|
|
237
|
-
equal(spanClient.attributes['error.stack'].includes('Error: KABOOM!!!'), true)
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
test('should not add the query in span name', async ({ equal, same, teardown }) => {
|
|
241
|
-
const handler = async (request, reply) => {
|
|
242
|
-
return { foo: 'bar' }
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const app = await setupApp({
|
|
246
|
-
serviceName: 'test-service',
|
|
247
|
-
exporter: {
|
|
248
|
-
type: 'memory'
|
|
249
|
-
}
|
|
250
|
-
}, handler, teardown)
|
|
251
|
-
|
|
252
|
-
const { startSpanClient } = app.openTelemetry
|
|
253
|
-
|
|
254
|
-
const url = 'http://localhost:3000/test?foo=bar'
|
|
255
|
-
const { span } = startSpanClient(url, 'GET')
|
|
256
|
-
same(span.name, 'GET http://localhost:3000/test')
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
test('should ignore the skipped operations', async ({ equal, same, ok, teardown }) => {
|
|
260
|
-
const handler = async (request, reply) => {
|
|
261
|
-
return { foo: 'bar' }
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const app = await setupApp({
|
|
265
|
-
serviceName: 'test-service',
|
|
266
|
-
skip: [
|
|
267
|
-
{
|
|
268
|
-
path: '/skipme',
|
|
269
|
-
method: 'POST'
|
|
270
|
-
}
|
|
271
|
-
],
|
|
272
|
-
exporter: {
|
|
273
|
-
type: 'memory'
|
|
274
|
-
}
|
|
275
|
-
}, handler, teardown)
|
|
276
|
-
|
|
277
|
-
const { startSpanClient } = app.openTelemetry
|
|
278
|
-
|
|
279
|
-
const url = 'http://localhost:3000/skipme'
|
|
280
|
-
const ret = startSpanClient(url, 'POST')
|
|
281
|
-
// no spam should be created
|
|
282
|
-
ok(!ret)
|
|
283
|
-
})
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { test } = require('tap')
|
|
4
|
-
const { MultiSpanProcessor } = require('../lib/multispan-processor')
|
|
5
|
-
|
|
6
|
-
test('should add multiple processors', async ({ equal, same, teardown }) => {
|
|
7
|
-
const mockSpanProcessor = {
|
|
8
|
-
onStart: () => {},
|
|
9
|
-
onEnd: () => {},
|
|
10
|
-
shutdown: async () => {},
|
|
11
|
-
forceFlush: async () => {}
|
|
12
|
-
}
|
|
13
|
-
const processor = new MultiSpanProcessor()
|
|
14
|
-
equal(processor._spanProcessors.length, 0)
|
|
15
|
-
|
|
16
|
-
{
|
|
17
|
-
const processor = new MultiSpanProcessor([mockSpanProcessor, mockSpanProcessor])
|
|
18
|
-
equal(processor._spanProcessors.length, 2)
|
|
19
|
-
}
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
test('should call onStart on every processor', async ({ equal, same, teardown }) => {
|
|
23
|
-
let called1 = false
|
|
24
|
-
let called2 = false
|
|
25
|
-
const mockSpanProcessor1 = {
|
|
26
|
-
onStart: () => { called1 = true }
|
|
27
|
-
}
|
|
28
|
-
const mockSpanProcessor2 = {
|
|
29
|
-
called: false,
|
|
30
|
-
onStart: () => { called2 = true }
|
|
31
|
-
}
|
|
32
|
-
const processor = new MultiSpanProcessor([mockSpanProcessor1, mockSpanProcessor2])
|
|
33
|
-
processor.onStart()
|
|
34
|
-
equal(called1, true)
|
|
35
|
-
equal(called2, true)
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test('should call onEnd on every processor', async ({ equal, same, teardown }) => {
|
|
39
|
-
let called1 = false
|
|
40
|
-
let called2 = false
|
|
41
|
-
const mockSpanProcessor1 = {
|
|
42
|
-
onEnd: () => { called1 = true }
|
|
43
|
-
}
|
|
44
|
-
const mockSpanProcessor2 = {
|
|
45
|
-
onEnd: () => { called2 = true }
|
|
46
|
-
}
|
|
47
|
-
const processor = new MultiSpanProcessor([mockSpanProcessor1, mockSpanProcessor2])
|
|
48
|
-
processor.onEnd()
|
|
49
|
-
equal(called1, true)
|
|
50
|
-
equal(called2, true)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test('should call shutdown on every processor', async ({ equal, same, teardown }) => {
|
|
54
|
-
let called1 = false
|
|
55
|
-
let called2 = false
|
|
56
|
-
const mockSpanProcessor1 = {
|
|
57
|
-
shutdown: async () => { called1 = true }
|
|
58
|
-
}
|
|
59
|
-
const mockSpanProcessor2 = {
|
|
60
|
-
shutdown: async () => { called2 = true }
|
|
61
|
-
}
|
|
62
|
-
const processor = new MultiSpanProcessor([mockSpanProcessor1, mockSpanProcessor2])
|
|
63
|
-
await processor.shutdown()
|
|
64
|
-
equal(called1, true)
|
|
65
|
-
equal(called2, true)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('should call forceFlush on every processor', async ({ equal, same, teardown }) => {
|
|
69
|
-
let called1 = false
|
|
70
|
-
let called2 = false
|
|
71
|
-
const mockSpanProcessor1 = {
|
|
72
|
-
forceFlush: async () => { called1 = true }
|
|
73
|
-
}
|
|
74
|
-
const mockSpanProcessor2 = {
|
|
75
|
-
forceFlush: async () => { called2 = true }
|
|
76
|
-
}
|
|
77
|
-
const processor = new MultiSpanProcessor([mockSpanProcessor1, mockSpanProcessor2])
|
|
78
|
-
await processor.forceFlush()
|
|
79
|
-
equal(called1, true)
|
|
80
|
-
equal(called2, true)
|
|
81
|
-
})
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { test } = require('tap')
|
|
4
|
-
const { PlatformaticTracerProvider } = require('../lib/platformatic-trace-provider')
|
|
5
|
-
|
|
6
|
-
test('should propagate forceFlush to all registered processors ', async ({ equal, same, teardown }) => {
|
|
7
|
-
let called1 = false
|
|
8
|
-
let called2 = false
|
|
9
|
-
const mockSpanProcessor1 = {
|
|
10
|
-
forceFlush: async () => { called1 = true }
|
|
11
|
-
}
|
|
12
|
-
const mockSpanProcessor2 = {
|
|
13
|
-
forceFlush: async () => { called2 = true }
|
|
14
|
-
}
|
|
15
|
-
const provider = new PlatformaticTracerProvider()
|
|
16
|
-
equal(provider._registeredSpanProcessors.length, 0)
|
|
17
|
-
|
|
18
|
-
provider.addSpanProcessor(mockSpanProcessor1)
|
|
19
|
-
provider.addSpanProcessor(mockSpanProcessor2)
|
|
20
|
-
|
|
21
|
-
equal(provider._registeredSpanProcessors.length, 2)
|
|
22
|
-
await provider.forceFlush()
|
|
23
|
-
equal(called1, true)
|
|
24
|
-
equal(called2, true)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
test('should propagate shutdown to the active span processor, which should propagate to all the processors ', async ({ equal, same, teardown }) => {
|
|
28
|
-
let called1 = false
|
|
29
|
-
let called2 = false
|
|
30
|
-
const mockSpanProcessor1 = {
|
|
31
|
-
shutdown: async () => { called1 = true }
|
|
32
|
-
}
|
|
33
|
-
const mockSpanProcessor2 = {
|
|
34
|
-
shutdown: async () => { called2 = true }
|
|
35
|
-
}
|
|
36
|
-
const provider = new PlatformaticTracerProvider()
|
|
37
|
-
equal(provider._registeredSpanProcessors.length, 0)
|
|
38
|
-
|
|
39
|
-
provider.addSpanProcessor(mockSpanProcessor1)
|
|
40
|
-
provider.addSpanProcessor(mockSpanProcessor2)
|
|
41
|
-
|
|
42
|
-
equal(provider._registeredSpanProcessors.length, 2)
|
|
43
|
-
await provider.shutdown()
|
|
44
|
-
equal(called1, true)
|
|
45
|
-
equal(called2, true)
|
|
46
|
-
})
|
package/test/telemetry.test.js
DELETED
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { test } = require('tap')
|
|
4
|
-
const fastify = require('fastify')
|
|
5
|
-
const { SpanStatusCode, SpanKind } = require('@opentelemetry/api')
|
|
6
|
-
const telemetryPlugin = require('../lib/telemetry')
|
|
7
|
-
|
|
8
|
-
async function setupApp (pluginOpts, routeHandler, teardown) {
|
|
9
|
-
const app = fastify()
|
|
10
|
-
await app.register(telemetryPlugin, pluginOpts)
|
|
11
|
-
app.get('/test', routeHandler)
|
|
12
|
-
app.get('/test/:id', routeHandler)
|
|
13
|
-
app.ready()
|
|
14
|
-
teardown(async () => {
|
|
15
|
-
await app.close()
|
|
16
|
-
const { exporters } = app.openTelemetry
|
|
17
|
-
exporters.forEach(exporter => {
|
|
18
|
-
if (exporter.constructor.name === 'InMemorySpanExporter') {
|
|
19
|
-
exporter.reset()
|
|
20
|
-
}
|
|
21
|
-
})
|
|
22
|
-
})
|
|
23
|
-
return app
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const injectArgs = {
|
|
27
|
-
method: 'GET',
|
|
28
|
-
url: '/test',
|
|
29
|
-
headers: {
|
|
30
|
-
host: 'test'
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
test('should trace a request not failing', async ({ equal, same, teardown }) => {
|
|
35
|
-
const handler = async (request, reply) => {
|
|
36
|
-
return { foo: 'bar' }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const app = await setupApp({
|
|
40
|
-
serviceName: 'test-service',
|
|
41
|
-
version: '1.0.0',
|
|
42
|
-
exporter: {
|
|
43
|
-
type: 'memory'
|
|
44
|
-
}
|
|
45
|
-
}, handler, teardown)
|
|
46
|
-
|
|
47
|
-
await app.inject(injectArgs)
|
|
48
|
-
const { exporters } = app.openTelemetry
|
|
49
|
-
const exporter = exporters[0]
|
|
50
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
51
|
-
equal(finishedSpans.length, 1)
|
|
52
|
-
const span = finishedSpans[0]
|
|
53
|
-
equal(span.kind, SpanKind.SERVER)
|
|
54
|
-
equal(span.name, 'GET /test')
|
|
55
|
-
equal(span.status.code, SpanStatusCode.OK)
|
|
56
|
-
equal(span.attributes['http.request.method'], 'GET')
|
|
57
|
-
equal(span.attributes['url.path'], '/test')
|
|
58
|
-
equal(span.attributes['http.response.status_code'], 200)
|
|
59
|
-
equal(span.attributes['url.scheme'], 'http')
|
|
60
|
-
equal(span.attributes['server.address'], 'test')
|
|
61
|
-
const resource = span.resource
|
|
62
|
-
same(resource.attributes['service.name'], 'test-service')
|
|
63
|
-
same(resource.attributes['service.version'], '1.0.0')
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
test('should not put query in `url.path', async ({ equal, same, teardown }) => {
|
|
67
|
-
const handler = async (request, reply) => {
|
|
68
|
-
return { foo: 'bar' }
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const injectArgs = {
|
|
72
|
-
method: 'GET',
|
|
73
|
-
url: '/test?foo=bar',
|
|
74
|
-
headers: {
|
|
75
|
-
host: 'test'
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const app = await setupApp({
|
|
80
|
-
serviceName: 'test-service',
|
|
81
|
-
version: '1.0.0',
|
|
82
|
-
exporter: {
|
|
83
|
-
type: 'memory'
|
|
84
|
-
}
|
|
85
|
-
}, handler, teardown)
|
|
86
|
-
|
|
87
|
-
await app.inject(injectArgs)
|
|
88
|
-
const { exporters } = app.openTelemetry
|
|
89
|
-
const exporter = exporters[0]
|
|
90
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
91
|
-
equal(finishedSpans.length, 1)
|
|
92
|
-
const span = finishedSpans[0]
|
|
93
|
-
equal(span.kind, SpanKind.SERVER)
|
|
94
|
-
equal(span.name, 'GET /test')
|
|
95
|
-
equal(span.status.code, SpanStatusCode.OK)
|
|
96
|
-
equal(span.attributes['http.request.method'], 'GET')
|
|
97
|
-
equal(span.attributes['url.path'], '/test')
|
|
98
|
-
equal(span.attributes['http.response.status_code'], 200)
|
|
99
|
-
equal(span.attributes['url.scheme'], 'http')
|
|
100
|
-
equal(span.attributes['server.address'], 'test')
|
|
101
|
-
const resource = span.resource
|
|
102
|
-
same(resource.attributes['service.name'], 'test-service')
|
|
103
|
-
same(resource.attributes['service.version'], '1.0.0')
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
test('request should add attribute to a span', async ({ equal, same, teardown }) => {
|
|
107
|
-
const handler = async (request, reply) => {
|
|
108
|
-
request.span.setAttribute('foo', 'bar')
|
|
109
|
-
return { foo: 'bar' }
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const app = await setupApp({
|
|
113
|
-
serviceName: 'test-service',
|
|
114
|
-
version: '1.0.0',
|
|
115
|
-
exporter: {
|
|
116
|
-
type: 'memory'
|
|
117
|
-
}
|
|
118
|
-
}, handler, teardown)
|
|
119
|
-
|
|
120
|
-
await app.inject(injectArgs)
|
|
121
|
-
const { exporters } = app.openTelemetry
|
|
122
|
-
const exporter = exporters[0]
|
|
123
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
124
|
-
equal(finishedSpans.length, 1)
|
|
125
|
-
const span = finishedSpans[0]
|
|
126
|
-
equal(span.name, 'GET /test')
|
|
127
|
-
equal(span.status.code, SpanStatusCode.OK)
|
|
128
|
-
equal(span.attributes['http.request.method'], 'GET')
|
|
129
|
-
equal(span.attributes['url.path'], '/test')
|
|
130
|
-
equal(span.attributes['http.response.status_code'], 200)
|
|
131
|
-
// This is the attribute we added
|
|
132
|
-
equal(span.attributes.foo, 'bar')
|
|
133
|
-
const resource = span.resource
|
|
134
|
-
same(resource.attributes['service.name'], 'test-service')
|
|
135
|
-
same(resource.attributes['service.version'], '1.0.0')
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
test('should be able to set the W3C trace context', async ({ equal, same, teardown, ok }) => {
|
|
139
|
-
const handler = async (request, reply) => {
|
|
140
|
-
const context = request.openTelemetry().span.context
|
|
141
|
-
const newContext = context.setValue('foo', 'bar')
|
|
142
|
-
request.openTelemetry().span.context = newContext
|
|
143
|
-
return { foo: 'bar' }
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const app = await setupApp({
|
|
147
|
-
serviceName: 'test-service',
|
|
148
|
-
version: '1.0.0',
|
|
149
|
-
exporter: {
|
|
150
|
-
type: 'memory'
|
|
151
|
-
}
|
|
152
|
-
}, handler, teardown)
|
|
153
|
-
|
|
154
|
-
const response = await app.inject(injectArgs)
|
|
155
|
-
// see: https://www.w3.org/TR/trace-context/#design-overview
|
|
156
|
-
ok(response.headers.traceparent)
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
test('should trace a request that fails', async ({ equal, same, teardown }) => {
|
|
160
|
-
const handler = async (request, reply) => {
|
|
161
|
-
throw new Error('booooom!!!')
|
|
162
|
-
}
|
|
163
|
-
const app = await setupApp({
|
|
164
|
-
serviceName: 'test-service',
|
|
165
|
-
version: '1.0.0',
|
|
166
|
-
exporter: {
|
|
167
|
-
type: 'memory'
|
|
168
|
-
}
|
|
169
|
-
}, handler, teardown)
|
|
170
|
-
|
|
171
|
-
await app.inject(injectArgs)
|
|
172
|
-
const { exporters } = app.openTelemetry
|
|
173
|
-
const exporter = exporters[0]
|
|
174
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
175
|
-
equal(finishedSpans.length, 1)
|
|
176
|
-
const span = finishedSpans[0]
|
|
177
|
-
equal(span.name, 'GET /test')
|
|
178
|
-
equal(span.status.code, SpanStatusCode.ERROR)
|
|
179
|
-
equal(span.attributes['http.request.method'], 'GET')
|
|
180
|
-
equal(span.attributes['url.path'], '/test')
|
|
181
|
-
equal(span.attributes['http.response.status_code'], 500)
|
|
182
|
-
equal(span.attributes['error.message'], 'booooom!!!')
|
|
183
|
-
const resource = span.resource
|
|
184
|
-
same(resource.attributes['service.name'], 'test-service')
|
|
185
|
-
same(resource.attributes['service.version'], '1.0.0')
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
test('if no exporter is configured, should default to console', async ({ equal, same, teardown }) => {
|
|
189
|
-
const handler = async (request, reply) => {
|
|
190
|
-
return {}
|
|
191
|
-
}
|
|
192
|
-
const app = await setupApp({
|
|
193
|
-
serviceName: 'test-service',
|
|
194
|
-
version: '1.0.0'
|
|
195
|
-
}, handler, teardown)
|
|
196
|
-
|
|
197
|
-
await app.inject(injectArgs)
|
|
198
|
-
const { exporters } = app.openTelemetry
|
|
199
|
-
const exporter = exporters[0]
|
|
200
|
-
same(exporter.constructor.name, 'ConsoleSpanExporter')
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
test('should configure OTLP correctly', async ({ equal, same, teardown }) => {
|
|
204
|
-
const handler = async (request, reply) => {
|
|
205
|
-
return {}
|
|
206
|
-
}
|
|
207
|
-
const app = await setupApp({
|
|
208
|
-
serviceName: 'test-service',
|
|
209
|
-
version: '1.0.0',
|
|
210
|
-
exporter: {
|
|
211
|
-
type: 'otlp',
|
|
212
|
-
options: {
|
|
213
|
-
url: 'http://localhost:4317'
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}, handler, teardown)
|
|
217
|
-
|
|
218
|
-
const { exporters } = app.openTelemetry
|
|
219
|
-
const exporter = exporters[0]
|
|
220
|
-
same(exporter.constructor.name, 'OTLPTraceExporter')
|
|
221
|
-
same(exporter.url, 'http://localhost:4317')
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
test('should configure Zipkin correctly', async ({ equal, same, teardown }) => {
|
|
225
|
-
const handler = async (request, reply) => {
|
|
226
|
-
return {}
|
|
227
|
-
}
|
|
228
|
-
const app = await setupApp({
|
|
229
|
-
serviceName: 'test-service',
|
|
230
|
-
version: '1.0.0',
|
|
231
|
-
exporter: {
|
|
232
|
-
type: 'zipkin',
|
|
233
|
-
options: {
|
|
234
|
-
url: 'http://localhost:9876'
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}, handler, teardown)
|
|
238
|
-
|
|
239
|
-
const { exporters } = app.openTelemetry
|
|
240
|
-
const exporter = exporters[0]
|
|
241
|
-
same(exporter.constructor.name, 'ZipkinExporter')
|
|
242
|
-
same(exporter._urlStr, 'http://localhost:9876')
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
test('wrong exporter is configured, should default to console', async ({ equal, same, teardown }) => {
|
|
246
|
-
const handler = async (request, reply) => {
|
|
247
|
-
return {}
|
|
248
|
-
}
|
|
249
|
-
const app = await setupApp({
|
|
250
|
-
serviceName: 'test-service',
|
|
251
|
-
version: '1.0.0',
|
|
252
|
-
exporter: {
|
|
253
|
-
type: 'wrong-exporter'
|
|
254
|
-
}
|
|
255
|
-
}, handler, teardown)
|
|
256
|
-
|
|
257
|
-
await app.inject(injectArgs)
|
|
258
|
-
const { exporters } = app.openTelemetry
|
|
259
|
-
const exporter = exporters[0]
|
|
260
|
-
same(exporter.constructor.name, 'ConsoleSpanExporter')
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
test('should not trace if the operation is skipped', async ({ equal, same, teardown }) => {
|
|
264
|
-
const handler = async (request, reply) => {
|
|
265
|
-
return { foo: 'bar' }
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const app = await setupApp({
|
|
269
|
-
serviceName: 'test-service',
|
|
270
|
-
version: '1.0.0',
|
|
271
|
-
skip: [{
|
|
272
|
-
path: '/documentation/json',
|
|
273
|
-
method: 'GET'
|
|
274
|
-
}],
|
|
275
|
-
exporter: {
|
|
276
|
-
type: 'memory'
|
|
277
|
-
}
|
|
278
|
-
}, handler, teardown)
|
|
279
|
-
|
|
280
|
-
const injectArgs = {
|
|
281
|
-
method: 'GET',
|
|
282
|
-
url: '/documentation/json',
|
|
283
|
-
headers: {
|
|
284
|
-
host: 'test'
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
await app.inject(injectArgs)
|
|
289
|
-
const { exporters } = app.openTelemetry
|
|
290
|
-
const exporter = exporters[0]
|
|
291
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
292
|
-
equal(finishedSpans.length, 0)
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
test('should not put the URL param in path', async ({ equal, same, teardown }) => {
|
|
296
|
-
const handler = async (request, reply) => {
|
|
297
|
-
return { foo: 'bar' }
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const injectArgs = {
|
|
301
|
-
method: 'GET',
|
|
302
|
-
url: '/test/123',
|
|
303
|
-
headers: {
|
|
304
|
-
host: 'test'
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const app = await setupApp({
|
|
309
|
-
serviceName: 'test-service',
|
|
310
|
-
version: '1.0.0',
|
|
311
|
-
exporter: {
|
|
312
|
-
type: 'memory'
|
|
313
|
-
}
|
|
314
|
-
}, handler, teardown)
|
|
315
|
-
|
|
316
|
-
await app.inject(injectArgs)
|
|
317
|
-
const { exporters } = app.openTelemetry
|
|
318
|
-
const exporter = exporters[0]
|
|
319
|
-
const finishedSpans = exporter.getFinishedSpans()
|
|
320
|
-
equal(finishedSpans.length, 1)
|
|
321
|
-
const span = finishedSpans[0]
|
|
322
|
-
equal(span.kind, SpanKind.SERVER)
|
|
323
|
-
equal(span.name, 'GET /test/{id}')
|
|
324
|
-
equal(span.status.code, SpanStatusCode.OK)
|
|
325
|
-
equal(span.attributes['http.request.method'], 'GET')
|
|
326
|
-
equal(span.attributes['url.path'], '/test/{id}')
|
|
327
|
-
equal(span.attributes['http.response.status_code'], 200)
|
|
328
|
-
equal(span.attributes['url.scheme'], 'http')
|
|
329
|
-
equal(span.attributes['server.address'], 'test')
|
|
330
|
-
const resource = span.resource
|
|
331
|
-
same(resource.attributes['service.name'], 'test-service')
|
|
332
|
-
same(resource.attributes['service.version'], '1.0.0')
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
test('should configure an exporter as an array', async ({ equal, same, teardown }) => {
|
|
336
|
-
const handler = async (request, reply) => {
|
|
337
|
-
return {}
|
|
338
|
-
}
|
|
339
|
-
const app = await setupApp({
|
|
340
|
-
serviceName: 'test-service',
|
|
341
|
-
version: '1.0.0',
|
|
342
|
-
exporter: [{
|
|
343
|
-
type: 'otlp',
|
|
344
|
-
options: {
|
|
345
|
-
url: 'http://localhost:4317'
|
|
346
|
-
}
|
|
347
|
-
}]
|
|
348
|
-
}, handler, teardown)
|
|
349
|
-
const { exporters } = app.openTelemetry
|
|
350
|
-
const exporter = exporters[0]
|
|
351
|
-
same(exporter.constructor.name, 'OTLPTraceExporter')
|
|
352
|
-
same(exporter.url, 'http://localhost:4317')
|
|
353
|
-
})
|
|
354
|
-
|
|
355
|
-
test('should use multiple exporters and sent traces to all the exporters', async ({ equal, same, teardown }) => {
|
|
356
|
-
const handler = async (request, reply) => {
|
|
357
|
-
return {}
|
|
358
|
-
}
|
|
359
|
-
const app = await setupApp({
|
|
360
|
-
serviceName: 'test-service',
|
|
361
|
-
version: '1.0.0',
|
|
362
|
-
exporter: [{
|
|
363
|
-
type: 'memory'
|
|
364
|
-
}, {
|
|
365
|
-
type: 'memory'
|
|
366
|
-
}]
|
|
367
|
-
}, handler, teardown)
|
|
368
|
-
const { exporters } = app.openTelemetry
|
|
369
|
-
|
|
370
|
-
await app.inject(injectArgs)
|
|
371
|
-
|
|
372
|
-
const finishedSpans0 = exporters[0].getFinishedSpans()
|
|
373
|
-
equal(finishedSpans0.length, 1)
|
|
374
|
-
const span0 = finishedSpans0[0]
|
|
375
|
-
equal(span0.name, 'GET /test')
|
|
376
|
-
equal(span0.status.code, SpanStatusCode.OK)
|
|
377
|
-
|
|
378
|
-
const finishedSpans1 = exporters[1].getFinishedSpans()
|
|
379
|
-
equal(finishedSpans1.length, 1)
|
|
380
|
-
const span1 = finishedSpans1[0]
|
|
381
|
-
equal(span1.name, 'GET /test')
|
|
382
|
-
equal(span1.status.code, SpanStatusCode.OK)
|
|
383
|
-
})
|