Skip to content

Commit 34003c9

Browse files
mydeatrentm
andauthored
feat(http): Allow to opt-out of instrumenting incoming/outgoing requests (#4643)
* feat(http): Allow to opt-out of instrumenting incoming/outgoing requests * fix tests * PR feedback * add a changelog entry --------- Co-authored-by: Trent Mick <trentm@gmail.com>
1 parent d4035eb commit 34003c9

File tree

6 files changed

+165
-37
lines changed

6 files changed

+165
-37
lines changed

experimental/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ All notable changes to experimental packages in this project will be documented
1111

1212
### :rocket: (Enhancement)
1313

14+
* feat(instrumentation-http): Allow to opt-out of instrumenting incoming/outgoing requests [#4643](https://github.com/open-telemetry/opentelemetry-js/pull/4643) @mydea
15+
1416
### :bug: (Bug Fix)
1517

1618
* fix(instrumentation-http): Ensure instrumentation of `http.get` and `https.get` work when used in ESM code [#4857](https://github.com/open-telemetry/opentelemetry-js/issues/4857) @trentm

experimental/packages/opentelemetry-instrumentation-http/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ Http instrumentation has few options available to choose from. You can set the f
6161
| [`startOutgoingSpanHook`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-http/src/types.ts#L99) | `StartOutgoingSpanCustomAttributeFunction` | Function for adding custom attributes before a span is started in outgoingRequest |
6262
| `ignoreIncomingRequestHook` | `IgnoreIncomingRequestFunction` | Http instrumentation will not trace all incoming requests that matched with custom function |
6363
| `ignoreOutgoingRequestHook` | `IgnoreOutgoingRequestFunction` | Http instrumentation will not trace all outgoing requests that matched with custom function |
64+
| `disableOutgoingRequestInstrumentation` | `boolean` | Set to true to avoid instrumenting outgoing requests at all. This can be helpful when another instrumentation handles outgoing requests. |
65+
| `disableIncomingRequestInstrumentation` | `boolean` | Set to true to avoid instrumenting incoming requests at all. This can be helpful when another instrumentation handles incoming requests. |
6466
| [`serverName`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-http/src/types.ts#L101) | `string` | The primary server name of the matched virtual host. |
6567
| [`requireParentforOutgoingSpans`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-http/src/types.ts#L103) | Boolean | Require that is a parent span to create new span for outgoing requests. |
6668
| [`requireParentforIncomingSpans`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-http/src/types.ts#L105) | Boolean | Require that is a parent span to create new span for incoming requests. |

experimental/packages/opentelemetry-instrumentation-http/src/http.ts

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -110,29 +110,37 @@ export class HttpInstrumentation extends InstrumentationBase<HttpInstrumentation
110110
'http',
111111
['*'],
112112
(moduleExports: Http): Http => {
113-
const patchedRequest = this._wrap(
114-
moduleExports,
115-
'request',
116-
this._getPatchOutgoingRequestFunction('http')
117-
) as unknown as Func<http.ClientRequest>;
118-
this._wrap(
119-
moduleExports,
120-
'get',
121-
this._getPatchOutgoingGetFunction(patchedRequest)
122-
);
123-
this._wrap(
124-
moduleExports.Server.prototype,
125-
'emit',
126-
this._getPatchIncomingRequestFunction('http')
127-
);
113+
if (!this.getConfig().disableOutgoingRequestInstrumentation) {
114+
const patchedRequest = this._wrap(
115+
moduleExports,
116+
'request',
117+
this._getPatchOutgoingRequestFunction('http')
118+
) as unknown as Func<http.ClientRequest>;
119+
this._wrap(
120+
moduleExports,
121+
'get',
122+
this._getPatchOutgoingGetFunction(patchedRequest)
123+
);
124+
}
125+
if (!this.getConfig().disableIncomingRequestInstrumentation) {
126+
this._wrap(
127+
moduleExports.Server.prototype,
128+
'emit',
129+
this._getPatchIncomingRequestFunction('http')
130+
);
131+
}
128132
return moduleExports;
129133
},
130134
(moduleExports: Http) => {
131135
if (moduleExports === undefined) return;
132136

133-
this._unwrap(moduleExports, 'request');
134-
this._unwrap(moduleExports, 'get');
135-
this._unwrap(moduleExports.Server.prototype, 'emit');
137+
if (!this.getConfig().disableOutgoingRequestInstrumentation) {
138+
this._unwrap(moduleExports, 'request');
139+
this._unwrap(moduleExports, 'get');
140+
}
141+
if (!this.getConfig().disableIncomingRequestInstrumentation) {
142+
this._unwrap(moduleExports.Server.prototype, 'emit');
143+
}
136144
}
137145
);
138146
}
@@ -142,30 +150,37 @@ export class HttpInstrumentation extends InstrumentationBase<HttpInstrumentation
142150
'https',
143151
['*'],
144152
(moduleExports: Https): Https => {
145-
const patchedRequest = this._wrap(
146-
moduleExports,
147-
'request',
148-
this._getPatchHttpsOutgoingRequestFunction('https')
149-
) as unknown as Func<http.ClientRequest>;
150-
this._wrap(
151-
moduleExports,
152-
'get',
153-
this._getPatchHttpsOutgoingGetFunction(patchedRequest)
154-
);
155-
156-
this._wrap(
157-
moduleExports.Server.prototype,
158-
'emit',
159-
this._getPatchIncomingRequestFunction('https')
160-
);
153+
if (!this.getConfig().disableOutgoingRequestInstrumentation) {
154+
const patchedRequest = this._wrap(
155+
moduleExports,
156+
'request',
157+
this._getPatchHttpsOutgoingRequestFunction('https')
158+
) as unknown as Func<http.ClientRequest>;
159+
this._wrap(
160+
moduleExports,
161+
'get',
162+
this._getPatchHttpsOutgoingGetFunction(patchedRequest)
163+
);
164+
}
165+
if (!this.getConfig().disableIncomingRequestInstrumentation) {
166+
this._wrap(
167+
moduleExports.Server.prototype,
168+
'emit',
169+
this._getPatchIncomingRequestFunction('https')
170+
);
171+
}
161172
return moduleExports;
162173
},
163174
(moduleExports: Https) => {
164175
if (moduleExports === undefined) return;
165176

166-
this._unwrap(moduleExports, 'request');
167-
this._unwrap(moduleExports, 'get');
168-
this._unwrap(moduleExports.Server.prototype, 'emit');
177+
if (!this.getConfig().disableOutgoingRequestInstrumentation) {
178+
this._unwrap(moduleExports, 'request');
179+
this._unwrap(moduleExports, 'get');
180+
}
181+
if (!this.getConfig().disableIncomingRequestInstrumentation) {
182+
this._unwrap(moduleExports.Server.prototype, 'emit');
183+
}
169184
}
170185
);
171186
}

experimental/packages/opentelemetry-instrumentation-http/src/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ export interface HttpInstrumentationConfig extends InstrumentationConfig {
9898
ignoreOutgoingUrls?: IgnoreMatcher[];
9999
/** Not trace all outgoing requests that matched with custom function */
100100
ignoreOutgoingRequestHook?: IgnoreOutgoingRequestFunction;
101+
/** If set to true, incoming requests will not be instrumented at all. */
102+
disableIncomingRequestInstrumentation?: boolean;
103+
/** If set to true, outgoing requests will not be instrumented at all. */
104+
disableOutgoingRequestInstrumentation?: boolean;
101105
/** Function for adding custom attributes after response is handled */
102106
applyCustomAttributesOnSpan?: HttpCustomAttributeFunction;
103107
/** Function for adding custom attributes before request is handled */

experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,55 @@ describe('HttpInstrumentation', () => {
227227
});
228228
});
229229

230+
describe('partially disable instrumentation', () => {
231+
beforeEach(() => {
232+
memoryExporter.reset();
233+
});
234+
235+
afterEach(() => {
236+
server.close();
237+
instrumentation.disable();
238+
});
239+
240+
it('allows to disable outgoing request instrumentation', () => {
241+
server.close();
242+
instrumentation.disable();
243+
244+
instrumentation.setConfig({
245+
disableOutgoingRequestInstrumentation: true,
246+
});
247+
instrumentation.enable();
248+
server = http.createServer((_request, response) => {
249+
response.end('Test Server Response');
250+
});
251+
252+
server.listen(serverPort);
253+
254+
assert.strictEqual(isWrapped(http.Server.prototype.emit), true);
255+
assert.strictEqual(isWrapped(http.get), false);
256+
assert.strictEqual(isWrapped(http.request), false);
257+
});
258+
259+
it('allows to disable incoming request instrumentation', () => {
260+
server.close();
261+
instrumentation.disable();
262+
263+
instrumentation.setConfig({
264+
disableIncomingRequestInstrumentation: true,
265+
});
266+
instrumentation.enable();
267+
server = http.createServer((_request, response) => {
268+
response.end('Test Server Response');
269+
});
270+
271+
server.listen(serverPort);
272+
273+
assert.strictEqual(isWrapped(http.Server.prototype.emit), false);
274+
assert.strictEqual(isWrapped(http.get), true);
275+
assert.strictEqual(isWrapped(http.request), true);
276+
});
277+
});
278+
230279
describe('with good instrumentation options', () => {
231280
beforeEach(() => {
232281
memoryExporter.reset();

experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ describe('HttpsInstrumentation', () => {
184184
);
185185
});
186186
});
187+
187188
describe('with good instrumentation options', () => {
188189
beforeEach(() => {
189190
memoryExporter.reset();
@@ -704,5 +705,60 @@ describe('HttpsInstrumentation', () => {
704705
req.end();
705706
});
706707
});
708+
709+
describe('partially disable instrumentation', () => {
710+
beforeEach(() => {
711+
memoryExporter.reset();
712+
});
713+
714+
afterEach(() => {
715+
server.close();
716+
instrumentation.disable();
717+
});
718+
719+
it('allows to disable outgoing request instrumentation', () => {
720+
instrumentation.setConfig({
721+
disableOutgoingRequestInstrumentation: true,
722+
});
723+
instrumentation.enable();
724+
server = https.createServer(
725+
{
726+
key: fs.readFileSync('test/fixtures/server-key.pem'),
727+
cert: fs.readFileSync('test/fixtures/server-cert.pem'),
728+
},
729+
(request, response) => {
730+
response.end('Test Server Response');
731+
}
732+
);
733+
734+
server.listen(serverPort);
735+
736+
assert.strictEqual(isWrapped(http.Server.prototype.emit), true);
737+
assert.strictEqual(isWrapped(http.get), false);
738+
assert.strictEqual(isWrapped(http.request), false);
739+
});
740+
741+
it('allows to disable incoming request instrumentation', () => {
742+
instrumentation.setConfig({
743+
disableIncomingRequestInstrumentation: true,
744+
});
745+
instrumentation.enable();
746+
server = https.createServer(
747+
{
748+
key: fs.readFileSync('test/fixtures/server-key.pem'),
749+
cert: fs.readFileSync('test/fixtures/server-cert.pem'),
750+
},
751+
(request, response) => {
752+
response.end('Test Server Response');
753+
}
754+
);
755+
756+
server.listen(serverPort);
757+
758+
assert.strictEqual(isWrapped(http.Server.prototype.emit), false);
759+
assert.strictEqual(isWrapped(http.get), true);
760+
assert.strictEqual(isWrapped(http.request), true);
761+
});
762+
});
707763
});
708764
});

0 commit comments

Comments
 (0)