@platformatic/telemetry 0.34.0 → 0.35.0
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/schema.js +7 -0
- package/lib/telemetry.js +54 -22
- package/package.json +2 -1
- package/test/client.test.js +59 -13
- package/test/telemetry.test.js +82 -10
package/lib/schema.js
CHANGED
|
@@ -12,6 +12,13 @@ const TelemetrySchema = {
|
|
|
12
12
|
type: 'string',
|
|
13
13
|
description: 'The version of the service (optional)'
|
|
14
14
|
},
|
|
15
|
+
skip: {
|
|
16
|
+
type: 'array',
|
|
17
|
+
description: 'An array of paths to skip when creating spans. Useful for health checks and other endpoints that do not need to be traced.',
|
|
18
|
+
items: {
|
|
19
|
+
type: 'string'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
15
22
|
exporter: {
|
|
16
23
|
type: 'object',
|
|
17
24
|
properties: {
|
package/lib/telemetry.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const fp = require('fastify-plugin')
|
|
4
|
-
const { SpanStatusCode } = require('@opentelemetry/api')
|
|
4
|
+
const { SpanStatusCode, SpanKind } = require('@opentelemetry/api')
|
|
5
5
|
const { ConsoleSpanExporter, BatchSpanProcessor, SimpleSpanProcessor, InMemorySpanExporter } = require('@opentelemetry/sdk-trace-base')
|
|
6
6
|
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions')
|
|
7
7
|
const { Resource } = require('@opentelemetry/resources')
|
|
8
8
|
const { PlatformaticTracerProvider } = require('./platformatic-trace-provider')
|
|
9
9
|
const { PlatformaticContext } = require('./platformatic-context')
|
|
10
10
|
const { fastifyTextMapGetter, fastifyTextMapSetter } = require('./fastify-text-map')
|
|
11
|
+
const fastUri = require('fast-uri')
|
|
11
12
|
|
|
12
13
|
// Platformatic telemetry plugin.
|
|
13
14
|
// Supported Exporters:
|
|
@@ -32,16 +33,22 @@ function formatSpanName (request) {
|
|
|
32
33
|
return routerPath ? `${method} ${routerPath}` : method
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
const
|
|
36
|
+
const formatSpanAttributes = {
|
|
36
37
|
request (request) {
|
|
38
|
+
const { hostname, method, url, protocol } = request
|
|
39
|
+
// Inspired by: https://github.com/fastify/fastify-url-data/blob/master/plugin.js#L11
|
|
40
|
+
const urlData = fastUri.parse(`${protocol}://${hostname}${url}`)
|
|
37
41
|
return {
|
|
38
|
-
'
|
|
39
|
-
'
|
|
42
|
+
'server.address': hostname,
|
|
43
|
+
'server.port': urlData.port,
|
|
44
|
+
'http.request.method': method,
|
|
45
|
+
'url.path': urlData.path,
|
|
46
|
+
'url.scheme': protocol
|
|
40
47
|
}
|
|
41
48
|
},
|
|
42
49
|
reply (reply) {
|
|
43
50
|
return {
|
|
44
|
-
'
|
|
51
|
+
'http.response.status_code': reply.statusCode
|
|
45
52
|
}
|
|
46
53
|
},
|
|
47
54
|
error (error) {
|
|
@@ -60,7 +67,7 @@ const setupProvider = (app, opts) => {
|
|
|
60
67
|
app.log.warn('No exporter configured, defaulting to console.')
|
|
61
68
|
exporter = { type: 'console' }
|
|
62
69
|
}
|
|
63
|
-
app.log.info(`Setting up telemetry for service: ${serviceName} version:
|
|
70
|
+
app.log.info(`Setting up telemetry for service: ${serviceName}${version ? ' version: ' + version : ''} with exporter of type ${exporter.type}`)
|
|
64
71
|
const provider = new PlatformaticTracerProvider({
|
|
65
72
|
resource: new Resource({
|
|
66
73
|
[SemanticResourceAttributes.SERVICE_NAME]: serviceName,
|
|
@@ -101,16 +108,17 @@ async function setupTelemetry (app, opts) {
|
|
|
101
108
|
// const { serviceName, version } = opts
|
|
102
109
|
const openTelemetryAPIs = setupProvider(app, opts)
|
|
103
110
|
const { tracer, propagator, provider } = openTelemetryAPIs
|
|
104
|
-
|
|
105
|
-
const formatSpanAttributes = {
|
|
106
|
-
...defaultFormatSpanAttributes,
|
|
107
|
-
...(opts.formatSpanAttributes || {})
|
|
108
|
-
}
|
|
111
|
+
const skipOperations = opts.skip || []
|
|
109
112
|
|
|
110
113
|
// expose the span as a request decorator
|
|
111
114
|
app.decorateRequest('span')
|
|
112
115
|
|
|
113
116
|
const startSpan = async (request) => {
|
|
117
|
+
if (skipOperations.includes(`${request.method}${request.url}`)) {
|
|
118
|
+
request.log.debug({ operation: `${request.method}${request.url}` }, 'Skipping telemetry')
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
114
122
|
// We populate the context with the incoming request headers
|
|
115
123
|
let context = propagator.extract(new PlatformaticContext(), request, fastifyTextMapGetter)
|
|
116
124
|
|
|
@@ -119,6 +127,7 @@ async function setupTelemetry (app, opts) {
|
|
|
119
127
|
{},
|
|
120
128
|
context
|
|
121
129
|
)
|
|
130
|
+
span.kind = SpanKind.SERVER
|
|
122
131
|
// Next 2 lines are needed by W3CTraceContextPropagator
|
|
123
132
|
context = context.setSpan(span)
|
|
124
133
|
span.setAttributes(formatSpanAttributes.request(request))
|
|
@@ -132,19 +141,23 @@ async function setupTelemetry (app, opts) {
|
|
|
132
141
|
}
|
|
133
142
|
|
|
134
143
|
const injectPropagationHeadersInReply = async (request, reply) => {
|
|
135
|
-
|
|
136
|
-
|
|
144
|
+
if (request.span) {
|
|
145
|
+
const context = request.span.context
|
|
146
|
+
propagator.inject(context, reply, fastifyTextMapSetter)
|
|
147
|
+
}
|
|
137
148
|
}
|
|
138
149
|
|
|
139
150
|
const endSpan = async (request, reply) => {
|
|
140
151
|
const span = request.span
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
152
|
+
if (span) {
|
|
153
|
+
const spanStatus = { code: SpanStatusCode.OK }
|
|
154
|
+
if (reply.statusCode >= 400) {
|
|
155
|
+
spanStatus.code = SpanStatusCode.ERROR
|
|
156
|
+
}
|
|
157
|
+
span.setAttributes(formatSpanAttributes.reply(reply))
|
|
158
|
+
span.setStatus(spanStatus)
|
|
159
|
+
span.end()
|
|
144
160
|
}
|
|
145
|
-
span.setAttributes(formatSpanAttributes.reply(reply))
|
|
146
|
-
span.setStatus(spanStatus)
|
|
147
|
-
span.end()
|
|
148
161
|
}
|
|
149
162
|
|
|
150
163
|
app.addHook('onRequest', startSpan)
|
|
@@ -174,11 +187,30 @@ async function setupTelemetry (app, opts) {
|
|
|
174
187
|
// - closing the span
|
|
175
188
|
const startSpanClient = (url, method, ctx) => {
|
|
176
189
|
let context = ctx || new PlatformaticContext()
|
|
190
|
+
const urlObj = fastUri.parse(url)
|
|
191
|
+
|
|
192
|
+
if (skipOperations.includes(`${method}${urlObj.path}`)) {
|
|
193
|
+
app.log.debug({ operation: `${method}${urlObj.path}` }, 'Skipping telemetry')
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
|
|
177
197
|
/* istanbul ignore next */
|
|
178
198
|
method = method || ''
|
|
179
|
-
const
|
|
199
|
+
const name = `${method} ${urlObj.scheme}://${urlObj.host}:${urlObj.port}${urlObj.path}`
|
|
200
|
+
|
|
201
|
+
const span = tracer.startSpan(name, {}, context)
|
|
202
|
+
span.kind = SpanKind.CLIENT
|
|
203
|
+
|
|
180
204
|
/* istanbul ignore next */
|
|
181
|
-
const attributes = url
|
|
205
|
+
const attributes = url
|
|
206
|
+
? {
|
|
207
|
+
'server.address': urlObj.host,
|
|
208
|
+
'server.port': urlObj.port,
|
|
209
|
+
'http.request.method': method,
|
|
210
|
+
'url.full': url,
|
|
211
|
+
'url.path': urlObj.path
|
|
212
|
+
}
|
|
213
|
+
: {}
|
|
182
214
|
span.setAttributes(attributes)
|
|
183
215
|
|
|
184
216
|
// Next 2 lines are needed by W3CTraceContextPropagator
|
|
@@ -200,7 +232,7 @@ async function setupTelemetry (app, opts) {
|
|
|
200
232
|
spanStatus.code = SpanStatusCode.ERROR
|
|
201
233
|
}
|
|
202
234
|
span.setAttributes({
|
|
203
|
-
'response.
|
|
235
|
+
'http.response.status_code': response.statusCode
|
|
204
236
|
})
|
|
205
237
|
span.setStatus(spanStatus)
|
|
206
238
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/telemetry",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "OpenTelemetry integration for Platformatic",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Marco Piraccini <marco.piraccini@gmail.com>",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"@opentelemetry/resources": "^1.15.0",
|
|
24
24
|
"@opentelemetry/sdk-trace-base": "^1.15.0",
|
|
25
25
|
"@opentelemetry/semantic-conventions": "^1.15.0",
|
|
26
|
+
"fast-uri": "^2.2.0",
|
|
26
27
|
"fastify-plugin": "^4.5.0"
|
|
27
28
|
},
|
|
28
29
|
"scripts": {
|
package/test/client.test.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { test } = require('tap')
|
|
4
4
|
const fastify = require('fastify')
|
|
5
|
-
const { SpanStatusCode } = require('@opentelemetry/api')
|
|
5
|
+
const { SpanStatusCode, SpanKind } = require('@opentelemetry/api')
|
|
6
6
|
const telemetryPlugin = require('../lib/telemetry')
|
|
7
7
|
const { PlatformaticContext } = require('../lib/platformatic-context')
|
|
8
8
|
const { fastifyTextMapGetter } = require('../lib/fastify-text-map')
|
|
@@ -29,7 +29,6 @@ test('should add the propagation headers correctly, new propagation started', as
|
|
|
29
29
|
|
|
30
30
|
const app = await setupApp({
|
|
31
31
|
serviceName: 'test-service',
|
|
32
|
-
version: '1.0.0',
|
|
33
32
|
exporter: {
|
|
34
33
|
type: 'memory'
|
|
35
34
|
}
|
|
@@ -126,16 +125,21 @@ test('should trace a client request', async ({ equal, same, teardown }) => {
|
|
|
126
125
|
// We have two one for the client and one for the server
|
|
127
126
|
const spanServer = finishedSpans[0]
|
|
128
127
|
equal(spanServer.name, 'GET /test')
|
|
128
|
+
equal(spanServer.kind, SpanKind.SERVER)
|
|
129
129
|
equal(spanServer.status.code, SpanStatusCode.OK)
|
|
130
|
-
equal(spanServer.attributes['
|
|
131
|
-
equal(spanServer.attributes['
|
|
132
|
-
equal(spanServer.attributes['
|
|
130
|
+
equal(spanServer.attributes['http.request.method'], 'GET')
|
|
131
|
+
equal(spanServer.attributes['url.path'], '/test')
|
|
132
|
+
equal(spanServer.attributes['http.response.status_code'], 200)
|
|
133
133
|
|
|
134
134
|
const spanClient = finishedSpans[1]
|
|
135
135
|
equal(spanClient.name, 'GET http://localhost:3000/test')
|
|
136
|
+
equal(spanClient.kind, SpanKind.CLIENT)
|
|
136
137
|
equal(spanClient.status.code, SpanStatusCode.OK)
|
|
137
|
-
equal(spanClient.attributes['
|
|
138
|
-
equal(spanClient.attributes['response.
|
|
138
|
+
equal(spanClient.attributes['url.full'], 'http://localhost:3000/test')
|
|
139
|
+
equal(spanClient.attributes['http.response.status_code'], 200)
|
|
140
|
+
equal(spanClient.attributes['server.port'], 3000)
|
|
141
|
+
equal(spanClient.attributes['server.address'], 'localhost')
|
|
142
|
+
equal(spanClient.attributes['url.path'], '/test')
|
|
139
143
|
|
|
140
144
|
// The traceparent header is added to the request and propagated to the server
|
|
141
145
|
equal(receivedHeaders.traceparent, telemetryHeaders.traceparent)
|
|
@@ -175,16 +179,18 @@ test('should trace a client request failing', async ({ equal, same, teardown })
|
|
|
175
179
|
// We have two one for the client and one for the server
|
|
176
180
|
const spanServer = finishedSpans[0]
|
|
177
181
|
equal(spanServer.name, 'GET')
|
|
182
|
+
equal(spanServer.kind, SpanKind.SERVER)
|
|
178
183
|
equal(spanServer.status.code, SpanStatusCode.ERROR)
|
|
179
|
-
equal(spanServer.attributes['
|
|
180
|
-
equal(spanServer.attributes['
|
|
181
|
-
equal(spanServer.attributes['
|
|
184
|
+
equal(spanServer.attributes['http.request.method'], 'GET')
|
|
185
|
+
equal(spanServer.attributes['url.path'], '/wrong')
|
|
186
|
+
equal(spanServer.attributes['http.response.status_code'], 404)
|
|
182
187
|
|
|
183
188
|
const spanClient = finishedSpans[1]
|
|
184
189
|
equal(spanClient.name, 'GET http://localhost:3000/test')
|
|
190
|
+
equal(spanClient.kind, SpanKind.CLIENT)
|
|
185
191
|
equal(spanClient.status.code, SpanStatusCode.ERROR)
|
|
186
|
-
equal(spanClient.attributes['
|
|
187
|
-
equal(spanClient.attributes['response.
|
|
192
|
+
equal(spanClient.attributes['url.full'], 'http://localhost:3000/test')
|
|
193
|
+
equal(spanClient.attributes['http.response.status_code'], 404)
|
|
188
194
|
})
|
|
189
195
|
|
|
190
196
|
test('should trace a client request failing (no HTTP error)', async ({ equal, same, teardown }) => {
|
|
@@ -219,8 +225,48 @@ test('should trace a client request failing (no HTTP error)', async ({ equal, sa
|
|
|
219
225
|
const spanClient = finishedSpans[0]
|
|
220
226
|
equal(spanClient.name, 'GET http://localhost:3000/test')
|
|
221
227
|
equal(spanClient.status.code, SpanStatusCode.ERROR)
|
|
222
|
-
equal(spanClient.attributes['
|
|
228
|
+
equal(spanClient.attributes['url.full'], 'http://localhost:3000/test')
|
|
223
229
|
equal(spanClient.attributes['error.name'], 'Error')
|
|
224
230
|
equal(spanClient.attributes['error.message'], 'KABOOM!!!')
|
|
225
231
|
equal(spanClient.attributes['error.stack'].includes('Error: KABOOM!!!'), true)
|
|
226
232
|
})
|
|
233
|
+
|
|
234
|
+
test('should not add the query in span name', async ({ equal, same, teardown }) => {
|
|
235
|
+
const handler = async (request, reply) => {
|
|
236
|
+
return { foo: 'bar' }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const app = await setupApp({
|
|
240
|
+
serviceName: 'test-service',
|
|
241
|
+
exporter: {
|
|
242
|
+
type: 'memory'
|
|
243
|
+
}
|
|
244
|
+
}, handler, teardown)
|
|
245
|
+
|
|
246
|
+
const { startSpanClient } = app.openTelemetry
|
|
247
|
+
|
|
248
|
+
const url = 'http://localhost:3000/test?foo=bar'
|
|
249
|
+
const { span } = startSpanClient(url, 'GET')
|
|
250
|
+
same(span.name, 'GET http://localhost:3000/test')
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
test('should ignore the skipped operations', async ({ equal, same, ok, teardown }) => {
|
|
254
|
+
const handler = async (request, reply) => {
|
|
255
|
+
return { foo: 'bar' }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const app = await setupApp({
|
|
259
|
+
serviceName: 'test-service',
|
|
260
|
+
skip: ['POST/skipme'],
|
|
261
|
+
exporter: {
|
|
262
|
+
type: 'memory'
|
|
263
|
+
}
|
|
264
|
+
}, handler, teardown)
|
|
265
|
+
|
|
266
|
+
const { startSpanClient } = app.openTelemetry
|
|
267
|
+
|
|
268
|
+
const url = 'http://localhost:3000/skipme'
|
|
269
|
+
const ret = startSpanClient(url, 'POST')
|
|
270
|
+
// no spam should be created
|
|
271
|
+
ok(!ret)
|
|
272
|
+
})
|
package/test/telemetry.test.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { test } = require('tap')
|
|
4
4
|
const fastify = require('fastify')
|
|
5
|
-
const { SpanStatusCode } = require('@opentelemetry/api')
|
|
5
|
+
const { SpanStatusCode, SpanKind } = require('@opentelemetry/api')
|
|
6
6
|
const telemetryPlugin = require('../lib/telemetry')
|
|
7
7
|
|
|
8
8
|
async function setupApp (pluginOpts, routeHandler, teardown) {
|
|
@@ -46,11 +46,53 @@ test('should trace a request not failing', async ({ equal, same, teardown }) =>
|
|
|
46
46
|
const finishedSpans = exporter.getFinishedSpans()
|
|
47
47
|
equal(finishedSpans.length, 1)
|
|
48
48
|
const span = finishedSpans[0]
|
|
49
|
+
equal(span.kind, SpanKind.SERVER)
|
|
49
50
|
equal(span.name, 'GET /test')
|
|
50
51
|
equal(span.status.code, SpanStatusCode.OK)
|
|
51
|
-
equal(span.attributes['
|
|
52
|
-
equal(span.attributes['
|
|
53
|
-
equal(span.attributes['
|
|
52
|
+
equal(span.attributes['http.request.method'], 'GET')
|
|
53
|
+
equal(span.attributes['url.path'], '/test')
|
|
54
|
+
equal(span.attributes['http.response.status_code'], 200)
|
|
55
|
+
equal(span.attributes['url.scheme'], 'http')
|
|
56
|
+
equal(span.attributes['server.address'], 'test')
|
|
57
|
+
const resource = span.resource
|
|
58
|
+
same(resource.attributes['service.name'], 'test-service')
|
|
59
|
+
same(resource.attributes['service.version'], '1.0.0')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('should not put query in `url.path', async ({ equal, same, teardown }) => {
|
|
63
|
+
const handler = async (request, reply) => {
|
|
64
|
+
return { foo: 'bar' }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const injectArgs = {
|
|
68
|
+
method: 'GET',
|
|
69
|
+
url: '/test?foo=bar',
|
|
70
|
+
headers: {
|
|
71
|
+
host: 'test'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const app = await setupApp({
|
|
76
|
+
serviceName: 'test-service',
|
|
77
|
+
version: '1.0.0',
|
|
78
|
+
exporter: {
|
|
79
|
+
type: 'memory'
|
|
80
|
+
}
|
|
81
|
+
}, handler, teardown)
|
|
82
|
+
|
|
83
|
+
await app.inject(injectArgs)
|
|
84
|
+
const { exporter } = app.openTelemetry
|
|
85
|
+
const finishedSpans = exporter.getFinishedSpans()
|
|
86
|
+
equal(finishedSpans.length, 1)
|
|
87
|
+
const span = finishedSpans[0]
|
|
88
|
+
equal(span.kind, SpanKind.SERVER)
|
|
89
|
+
equal(span.name, 'GET /test')
|
|
90
|
+
equal(span.status.code, SpanStatusCode.OK)
|
|
91
|
+
equal(span.attributes['http.request.method'], 'GET')
|
|
92
|
+
equal(span.attributes['url.path'], '/test')
|
|
93
|
+
equal(span.attributes['http.response.status_code'], 200)
|
|
94
|
+
equal(span.attributes['url.scheme'], 'http')
|
|
95
|
+
equal(span.attributes['server.address'], 'test')
|
|
54
96
|
const resource = span.resource
|
|
55
97
|
same(resource.attributes['service.name'], 'test-service')
|
|
56
98
|
same(resource.attributes['service.version'], '1.0.0')
|
|
@@ -77,9 +119,9 @@ test('request should add attribute to a span', async ({ equal, same, teardown })
|
|
|
77
119
|
const span = finishedSpans[0]
|
|
78
120
|
equal(span.name, 'GET /test')
|
|
79
121
|
equal(span.status.code, SpanStatusCode.OK)
|
|
80
|
-
equal(span.attributes['
|
|
81
|
-
equal(span.attributes['
|
|
82
|
-
equal(span.attributes['
|
|
122
|
+
equal(span.attributes['http.request.method'], 'GET')
|
|
123
|
+
equal(span.attributes['url.path'], '/test')
|
|
124
|
+
equal(span.attributes['http.response.status_code'], 200)
|
|
83
125
|
// This is the attribute we added
|
|
84
126
|
equal(span.attributes.foo, 'bar')
|
|
85
127
|
const resource = span.resource
|
|
@@ -127,9 +169,9 @@ test('should trace a request that fails', async ({ equal, same, teardown }) => {
|
|
|
127
169
|
const span = finishedSpans[0]
|
|
128
170
|
equal(span.name, 'GET /test')
|
|
129
171
|
equal(span.status.code, SpanStatusCode.ERROR)
|
|
130
|
-
equal(span.attributes['
|
|
131
|
-
equal(span.attributes['
|
|
132
|
-
equal(span.attributes['
|
|
172
|
+
equal(span.attributes['http.request.method'], 'GET')
|
|
173
|
+
equal(span.attributes['url.path'], '/test')
|
|
174
|
+
equal(span.attributes['http.response.status_code'], 500)
|
|
133
175
|
equal(span.attributes['error.message'], 'booooom!!!')
|
|
134
176
|
const resource = span.resource
|
|
135
177
|
same(resource.attributes['service.name'], 'test-service')
|
|
@@ -206,3 +248,33 @@ test('wrong exporter is configured, should default to console', async ({ equal,
|
|
|
206
248
|
const { exporter } = app.openTelemetry
|
|
207
249
|
same(exporter.constructor.name, 'ConsoleSpanExporter')
|
|
208
250
|
})
|
|
251
|
+
|
|
252
|
+
test('should not trace if the operation is skipped', async ({ equal, same, teardown }) => {
|
|
253
|
+
const handler = async (request, reply) => {
|
|
254
|
+
return { foo: 'bar' }
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const app = await setupApp({
|
|
258
|
+
serviceName: 'test-service',
|
|
259
|
+
version: '1.0.0',
|
|
260
|
+
skip: [
|
|
261
|
+
'GET/documentation/json'
|
|
262
|
+
],
|
|
263
|
+
exporter: {
|
|
264
|
+
type: 'memory'
|
|
265
|
+
}
|
|
266
|
+
}, handler, teardown)
|
|
267
|
+
|
|
268
|
+
const injectArgs = {
|
|
269
|
+
method: 'GET',
|
|
270
|
+
url: '/documentation/json',
|
|
271
|
+
headers: {
|
|
272
|
+
host: 'test'
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
await app.inject(injectArgs)
|
|
277
|
+
const { exporter } = app.openTelemetry
|
|
278
|
+
const finishedSpans = exporter.getFinishedSpans()
|
|
279
|
+
equal(finishedSpans.length, 0)
|
|
280
|
+
})
|