Skip to content

Commit f3f25dc

Browse files
OlivierAlbertinimayurkale22
authored andcommitted
feat(plugin-http): handle client errors (open-telemetry#374)
* feat(plugin-http): handle client errors closes open-telemetry#347 Signed-off-by: Olivier Albertini <[email protected]> * fix: handling error in line with spec Signed-off-by: Olivier Albertini <[email protected]>
1 parent 75a3297 commit f3f25dc

File tree

5 files changed

+557
-336
lines changed

5 files changed

+557
-336
lines changed

Diff for: packages/opentelemetry-plugin-http/src/http.ts

+64-16
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,16 @@ export class HttpPlugin extends BasePlugin<Http> {
209209
}
210210

211211
if (this._config.applyCustomAttributesOnSpan) {
212-
this._config.applyCustomAttributesOnSpan(span, request, response);
212+
this._safeExecute(
213+
span,
214+
() =>
215+
this._config.applyCustomAttributesOnSpan!(
216+
span,
217+
request,
218+
response
219+
),
220+
false
221+
);
213222
}
214223

215224
span.end();
@@ -248,7 +257,14 @@ export class HttpPlugin extends BasePlugin<Http> {
248257

249258
plugin._logger.debug('%s plugin incomingRequest', plugin.moduleName);
250259

251-
if (Utils.isIgnored(pathname, plugin._config.ignoreIncomingPaths)) {
260+
if (
261+
Utils.isIgnored(
262+
pathname,
263+
plugin._config.ignoreIncomingPaths,
264+
(e: Error) =>
265+
plugin._logger.error('caught ignoreIncomingPaths error: ', e)
266+
)
267+
) {
252268
return original.apply(this, [event, ...args]);
253269
}
254270

@@ -279,9 +295,11 @@ export class HttpPlugin extends BasePlugin<Http> {
279295
response.end = originalEnd;
280296
// Cannot pass args of type ResponseEndArgs,
281297
// tslint complains "Expected 1-2 arguments, but got 1 or more.", it does not make sense to me
282-
// tslint:disable-next-line:no-any
283-
const returned = plugin._safeExecute(span, () =>
284-
response.end.apply(this, arguments as any)
298+
const returned = plugin._safeExecute(
299+
span,
300+
// tslint:disable-next-line:no-any
301+
() => response.end.apply(this, arguments as any),
302+
true
285303
);
286304
const requestUrl = request.url ? url.parse(request.url) : null;
287305
const hostname = headers.host
@@ -315,15 +333,26 @@ export class HttpPlugin extends BasePlugin<Http> {
315333
.setStatus(Utils.parseResponseStatus(response.statusCode));
316334

317335
if (plugin._config.applyCustomAttributesOnSpan) {
318-
plugin._config.applyCustomAttributesOnSpan(span, request, response);
336+
plugin._safeExecute(
337+
span,
338+
() =>
339+
plugin._config.applyCustomAttributesOnSpan!(
340+
span,
341+
request,
342+
response
343+
),
344+
false
345+
);
319346
}
320347

321348
span.end();
322349
return returned;
323350
};
324351

325-
return plugin._safeExecute(span, () =>
326-
original.apply(this, [event, ...args])
352+
return plugin._safeExecute(
353+
span,
354+
() => original.apply(this, [event, ...args]),
355+
true
327356
);
328357
});
329358
};
@@ -353,7 +382,12 @@ export class HttpPlugin extends BasePlugin<Http> {
353382

354383
if (
355384
Utils.isOpenTelemetryRequest(options) ||
356-
Utils.isIgnored(origin + pathname, plugin._config.ignoreOutgoingUrls)
385+
Utils.isIgnored(
386+
origin + pathname,
387+
plugin._config.ignoreOutgoingUrls,
388+
(e: Error) =>
389+
plugin._logger.error('caught ignoreOutgoingUrls error: ', e)
390+
)
357391
) {
358392
return original.apply(this, [options, ...args]);
359393
}
@@ -370,8 +404,10 @@ export class HttpPlugin extends BasePlugin<Http> {
370404
.getHttpTextFormat()
371405
.inject(span.context(), Format.HTTP, options.headers);
372406

373-
const request: ClientRequest = plugin._safeExecute(span, () =>
374-
original.apply(this, [options, ...args])
407+
const request: ClientRequest = plugin._safeExecute(
408+
span,
409+
() => original.apply(this, [options, ...args]),
410+
true
375411
);
376412

377413
plugin._logger.debug('%s plugin outgoingRequest', plugin.moduleName);
@@ -399,16 +435,28 @@ export class HttpPlugin extends BasePlugin<Http> {
399435
.startSpan(name, options)
400436
.setAttribute(AttributeNames.COMPONENT, HttpPlugin.component);
401437
}
402-
438+
private _safeExecute<
439+
T extends (...args: unknown[]) => ReturnType<T>,
440+
K extends boolean
441+
>(
442+
span: Span,
443+
execute: T,
444+
rethrow: K
445+
): K extends true ? ReturnType<T> : (ReturnType<T> | void);
403446
private _safeExecute<T extends (...args: unknown[]) => ReturnType<T>>(
404447
span: Span,
405-
execute: T
406-
): ReturnType<T> {
448+
execute: T,
449+
rethrow: boolean
450+
): ReturnType<T> | void {
407451
try {
408452
return execute();
409453
} catch (error) {
410-
Utils.setSpanWithError(span, error);
411-
throw error;
454+
if (rethrow) {
455+
Utils.setSpanWithError(span, error);
456+
span.end();
457+
throw error;
458+
}
459+
this._logger.error('caught error ', error);
412460
}
413461
}
414462
}

Diff for: packages/opentelemetry-plugin-http/src/utils.ts

+19-8
Original file line numberDiff line numberDiff line change
@@ -125,19 +125,30 @@ export class Utils {
125125

126126
/**
127127
* Check whether the given request is ignored by configuration
128+
* It will not re-throw exceptions from `list` provided by the client
128129
* @param constant e.g URL of request
129-
* @param obj obj to inspect
130-
* @param list List of ignore patterns
130+
* @param [list] List of ignore patterns
131+
* @param [onException] callback for doing something when an exception has occured
131132
*/
132-
static isIgnored(constant: string, list?: IgnoreMatcher[]): boolean {
133+
static isIgnored(
134+
constant: string,
135+
list?: IgnoreMatcher[],
136+
onException?: (error: Error) => void
137+
): boolean {
133138
if (!list) {
134139
// No ignored urls - trace everything
135140
return false;
136141
}
137-
138-
for (const pattern of list) {
139-
if (Utils.satisfiesPattern(constant, pattern)) {
140-
return true;
142+
// Try/catch outside the loop for failing fast
143+
try {
144+
for (const pattern of list) {
145+
if (Utils.satisfiesPattern(constant, pattern)) {
146+
return true;
147+
}
148+
}
149+
} catch (e) {
150+
if (onException) {
151+
onException(e);
141152
}
142153
}
143154

@@ -152,6 +163,7 @@ export class Utils {
152163
static setSpanOnError(span: Span, obj: IncomingMessage | ClientRequest) {
153164
obj.on('error', (error: Err) => {
154165
Utils.setSpanWithError(span, error, obj);
166+
span.end();
155167
});
156168
}
157169

@@ -191,7 +203,6 @@ export class Utils {
191203
status.message = message;
192204

193205
span.setStatus(status);
194-
span.end();
195206
}
196207

197208
/**

0 commit comments

Comments
 (0)