Skip to content

Commit f609bb1

Browse files
rochdevnsavoire
authored andcommitted
add support for global fetch (#3258)
1 parent c1f4d53 commit f609bb1

File tree

10 files changed

+860
-10
lines changed

10 files changed

+860
-10
lines changed

.github/workflows/plugins.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,23 @@ jobs:
332332
uses: ./.github/actions/testagent/logs
333333
- uses: codecov/codecov-action@v2
334334

335+
fetch:
336+
runs-on: ubuntu-latest
337+
env:
338+
PLUGINS: fetch
339+
steps:
340+
- uses: actions/checkout@v2
341+
- uses: ./.github/actions/testagent/start
342+
- uses: ./.github/actions/node/setup
343+
- run: yarn install
344+
- uses: ./.github/actions/node/oldest
345+
- run: yarn test:plugins:ci
346+
- uses: ./.github/actions/node/latest
347+
- run: yarn test:plugins:ci
348+
- if: always()
349+
uses: ./.github/actions/testagent/logs
350+
- uses: codecov/codecov-action@v2
351+
335352
generic-pool:
336353
runs-on: ubuntu-latest
337354
env:

docs/API.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ tracer.use('pg', {
4040
<h5 id="generic-pool"></h5>
4141
<h5 id="google-cloud-pubsub"></h5>
4242
<h5 id="fastify"></h5>
43+
<h5 id="fetch"></h5>
4344
<h5 id="graphql"></h5>
4445
<h5 id="graphql-tags"></h5>
4546
<h5 id="graphql-config"></h5>
@@ -110,6 +111,7 @@ tracer.use('pg', {
110111
* [elasticsearch](./interfaces/plugins.elasticsearch.html)
111112
* [express](./interfaces/plugins.express.html)
112113
* [fastify](./interfaces/plugins.fastify.html)
114+
* [fetch](./interfaces/plugins.fetch.html)
113115
* [generic-pool](./interfaces/plugins.generic_pool.html)
114116
* [google-cloud-pubsub](./interfaces/plugins.google_cloud_pubsub.html)
115117
* [graphql](./interfaces/plugins.graphql.html)

docs/test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ tracer.use('express');
248248
tracer.use('express', httpServerOptions);
249249
tracer.use('fastify');
250250
tracer.use('fastify', httpServerOptions);
251+
tracer.use('fetch');
252+
tracer.use('fetch', httpClientOptions);
251253
tracer.use('generic-pool');
252254
tracer.use('google-cloud-pubsub');
253255
tracer.use('graphql');

index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,7 @@ interface Plugins {
749749
"elasticsearch": plugins.elasticsearch;
750750
"express": plugins.express;
751751
"fastify": plugins.fastify;
752+
"fetch": plugins.fetch;
752753
"generic-pool": plugins.generic_pool;
753754
"google-cloud-pubsub": plugins.google_cloud_pubsub;
754755
"graphql": plugins.graphql;
@@ -1092,6 +1093,12 @@ declare namespace plugins {
10921093
*/
10931094
interface fastify extends HttpServer {}
10941095

1096+
/**
1097+
* This plugin automatically instruments the
1098+
* [fetch](https://nodejs.org/api/globals.html#fetch) global.
1099+
*/
1100+
interface fetch extends HttpClient {}
1101+
10951102
/**
10961103
* This plugin patches the [generic-pool](https://github.com/coopernurse/node-pool)
10971104
* module to bind the callbacks the the caller context.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict'
2+
3+
const shimmer = require('../../datadog-shimmer')
4+
const { channel } = require('./helpers/instrument')
5+
6+
const startChannel = channel('apm:fetch:request:start')
7+
const finishChannel = channel('apm:fetch:request:finish')
8+
const errorChannel = channel('apm:fetch:request:error')
9+
10+
function wrapFetch (fetch, Request) {
11+
if (typeof fetch !== 'function') return fetch
12+
13+
return function (input, init) {
14+
if (!startChannel.hasSubscribers) return fetch.apply(this, arguments)
15+
16+
const req = new Request(input, init)
17+
const headers = req.headers
18+
const message = { req, headers }
19+
20+
startChannel.publish(message)
21+
22+
// Request object is read-only so we need new objects to change headers.
23+
arguments[0] = message.req
24+
arguments[1] = { headers: message.headers }
25+
26+
return fetch.apply(this, arguments)
27+
.then(
28+
res => {
29+
finishChannel.publish({ req, res })
30+
31+
return res
32+
},
33+
err => {
34+
if (err.name !== 'AbortError') {
35+
errorChannel.publish(err)
36+
}
37+
38+
finishChannel.publish({ req })
39+
40+
throw err
41+
}
42+
)
43+
}
44+
}
45+
46+
if (globalThis.fetch) {
47+
globalThis.fetch = shimmer.wrap(fetch, wrapFetch(fetch, globalThis.Request))
48+
}

packages/datadog-instrumentations/src/helpers/register.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ const disabledInstrumentations = new Set(
1919

2020
const loadChannel = channel('dd-trace:instrumentation:load')
2121

22+
// Globals
23+
require('../fetch')
24+
2225
// TODO: make this more efficient
2326

2427
for (const packageName of names) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict'
2+
3+
const HttpClientPlugin = require('../../datadog-plugin-http/src/client')
4+
const { HTTP_HEADERS } = require('../../../ext/formats')
5+
6+
class FetchPlugin extends HttpClientPlugin {
7+
static get id () { return 'fetch' }
8+
9+
addTraceSub (eventName, handler) {
10+
this.addSub(`apm:${this.constructor.id}:${this.operation}:${eventName}`, handler)
11+
}
12+
13+
start (message) {
14+
const req = message.req
15+
const options = new URL(req.url)
16+
const headers = options.headers = Object.fromEntries(req.headers.entries())
17+
18+
const args = { options }
19+
20+
super.start({ args })
21+
22+
message.req = new globalThis.Request(req, { headers })
23+
}
24+
25+
_inject (span, headers) {
26+
const carrier = {}
27+
28+
this.tracer.inject(span, HTTP_HEADERS, carrier)
29+
30+
for (const name in carrier) {
31+
headers.append(name, carrier[name])
32+
}
33+
}
34+
}
35+
36+
module.exports = FetchPlugin

0 commit comments

Comments
 (0)