Skip to content

Commit 0e3f03f

Browse files
blumamirvmarchaud
andauthoredJul 17, 2021
fix(instrumentation-http): set outgoing request attributes on start span (#2349)
Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
1 parent 5aabcc7 commit 0e3f03f

File tree

4 files changed

+49
-28
lines changed

4 files changed

+49
-28
lines changed
 

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

+13-14
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import {
3838
HttpInstrumentationConfig,
3939
HttpRequestArgs,
4040
Https,
41-
ParsedRequestOptions,
4241
ResponseEndArgs,
4342
} from './types';
4443
import * as utils from './utils';
@@ -272,20 +271,10 @@ export class HttpInstrumentation extends InstrumentationBase<Http> {
272271
* @param span representing the current operation
273272
*/
274273
private _traceClientRequest(
275-
component: 'http' | 'https',
276274
request: http.ClientRequest,
277-
options: ParsedRequestOptions,
275+
hostname: string,
278276
span: Span
279277
): http.ClientRequest {
280-
const hostname =
281-
options.hostname ||
282-
options.host?.replace(/^(.*)(:[0-9]{1,5})/, '$1') ||
283-
'localhost';
284-
const attributes = utils.getOutgoingRequestAttributes(options, {
285-
component,
286-
hostname,
287-
});
288-
span.setAttributes(attributes);
289278
if (this._getConfig().requestHook) {
290279
this._callRequestHook(span, request);
291280
}
@@ -535,8 +524,19 @@ export class HttpInstrumentation extends InstrumentationBase<Http> {
535524
}
536525

537526
const operationName = `${component.toUpperCase()} ${method}`;
527+
528+
const hostname =
529+
optionsParsed.hostname ||
530+
optionsParsed.host?.replace(/^(.*)(:[0-9]{1,5})/, '$1') ||
531+
'localhost';
532+
const attributes = utils.getOutgoingRequestAttributes(optionsParsed, {
533+
component,
534+
hostname,
535+
});
536+
538537
const spanOptions: SpanOptions = {
539538
kind: SpanKind.CLIENT,
539+
attributes,
540540
};
541541
const span = instrumentation._startHttpSpan(operationName, spanOptions);
542542

@@ -572,9 +572,8 @@ export class HttpInstrumentation extends InstrumentationBase<Http> {
572572
instrumentation._diag.debug('%s instrumentation outgoingRequest', component);
573573
context.bind(parentContext, request);
574574
return instrumentation._traceClientRequest(
575-
component,
576575
request,
577-
optionsParsed,
576+
hostname,
578577
span
579578
);
580579
});

‎packages/opentelemetry-instrumentation-http/src/utils.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,13 @@ export const getAbsoluteUrl = (
6969
* Parse status code from HTTP response. [More details](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-http.md#status)
7070
*/
7171
export const parseResponseStatus = (
72-
statusCode: number
72+
statusCode: number | undefined,
7373
): Omit<SpanStatus, 'message'> => {
74+
75+
if(statusCode === undefined) {
76+
return { code: SpanStatusCode.ERROR };
77+
}
78+
7479
// 1xx, 2xx, 3xx are OK
7580
if (statusCode >= 100 && statusCode < 400) {
7681
return { code: SpanStatusCode.OK };

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

+18-4
Original file line numberDiff line numberDiff line change
@@ -480,12 +480,26 @@ describe('HttpInstrumentation', () => {
480480
}
481481

482482
it('should have 1 ended span when request throw on bad "options" object', () => {
483-
try {
484-
http.request({ protocol: 'telnet' });
485-
} catch (error) {
483+
assert.throws(() => http.request({ headers: { cookie: undefined} }), err => {
486484
const spans = memoryExporter.getFinishedSpans();
487485
assert.strictEqual(spans.length, 1);
488-
}
486+
487+
const validations = {
488+
httpStatusCode: undefined,
489+
httpMethod: 'GET',
490+
resHeaders: {},
491+
hostname: 'localhost',
492+
pathname: '/',
493+
forceStatus: {
494+
code: SpanStatusCode.ERROR,
495+
message: err.message,
496+
},
497+
component: 'http',
498+
noNetPeer: true,
499+
}
500+
assertSpan(spans[0], SpanKind.CLIENT, validations);
501+
return true;
502+
});
489503
});
490504

491505
it('should have 1 ended span when response.end throw an exception', async () => {

‎packages/opentelemetry-instrumentation-http/test/utils/assertSpan.ts

+12-9
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export const assertSpan = (
2727
span: ReadableSpan,
2828
kind: SpanKind,
2929
validations: {
30-
httpStatusCode: number;
30+
httpStatusCode?: number;
3131
httpMethod: string;
3232
resHeaders: http.IncomingHttpHeaders;
3333
hostname: string;
@@ -37,6 +37,7 @@ export const assertSpan = (
3737
forceStatus?: SpanStatus;
3838
serverName?: string;
3939
component: string;
40+
noNetPeer?: boolean; // we don't expect net peer info when request throw before being sent
4041
}
4142
) => {
4243
assert.strictEqual(span.spanContext().traceId.length, 32);
@@ -110,14 +111,16 @@ export const assertSpan = (
110111
validations.hostname,
111112
'must be consistent (PEER_NAME and hostname)'
112113
);
113-
assert.ok(
114-
span.attributes[SemanticAttributes.NET_PEER_IP],
115-
'must have PEER_IP'
116-
);
117-
assert.ok(
118-
span.attributes[SemanticAttributes.NET_PEER_PORT],
119-
'must have PEER_PORT'
120-
);
114+
if(!validations.noNetPeer) {
115+
assert.ok(
116+
span.attributes[SemanticAttributes.NET_PEER_IP],
117+
'must have PEER_IP'
118+
);
119+
assert.ok(
120+
span.attributes[SemanticAttributes.NET_PEER_PORT],
121+
'must have PEER_PORT'
122+
);
123+
}
121124
assert.ok(
122125
(span.attributes[SemanticAttributes.HTTP_URL] as string).indexOf(
123126
span.attributes[SemanticAttributes.NET_PEER_NAME] as string

0 commit comments

Comments
 (0)
Please sign in to comment.