fix(instrumentation-http): report error.type metrics attribute (#5647)
This commit is contained in:
parent
336aff9586
commit
bbf9dacdfa
|
|
@ -68,6 +68,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
|
|||
* fix(otlp-transformer): do not throw when deserializing empty JSON response [#5551](https://github.com/open-telemetry/opentelemetry-js/pull/5551) @pichlermarc
|
||||
* fix(instrumentation-http): report stable client metrics response code [#9586](https://github.com/open-telemetry/opentelemetry-js/pull/9586) @jtescher
|
||||
* fix(sdk-node): instantiate baggage processor when env var is set [#5634](https://github.com/open-telemetry/opentelemetry-js/pull/5634) @pichlermarc
|
||||
* fix(instrumentation-http): report `error.type` metrics attribute [#5647](https://github.com/open-telemetry/opentelemetry-js/pull/5647)
|
||||
|
||||
### :house: Internal
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import {
|
|||
} from '@opentelemetry/instrumentation';
|
||||
import { errorMonitor } from 'events';
|
||||
import {
|
||||
ATTR_ERROR_TYPE,
|
||||
ATTR_HTTP_REQUEST_METHOD,
|
||||
ATTR_HTTP_RESPONSE_STATUS_CODE,
|
||||
ATTR_NETWORK_PROTOCOL_VERSION,
|
||||
|
|
@ -516,17 +517,12 @@ export class HttpInstrumentation extends InstrumentationBase<HttpInstrumentation
|
|||
return;
|
||||
}
|
||||
responseFinished = true;
|
||||
setSpanWithError(span, error, this._semconvStability);
|
||||
span.setStatus({
|
||||
code: SpanStatusCode.ERROR,
|
||||
message: error.message,
|
||||
});
|
||||
this._closeHttpSpan(
|
||||
this._onOutgoingRequestError(
|
||||
span,
|
||||
SpanKind.CLIENT,
|
||||
startTime,
|
||||
oldMetricAttributes,
|
||||
stableMetricAttributes
|
||||
stableMetricAttributes,
|
||||
startTime,
|
||||
error
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -551,14 +547,12 @@ export class HttpInstrumentation extends InstrumentationBase<HttpInstrumentation
|
|||
return;
|
||||
}
|
||||
responseFinished = true;
|
||||
setSpanWithError(span, error, this._semconvStability);
|
||||
|
||||
this._closeHttpSpan(
|
||||
this._onOutgoingRequestError(
|
||||
span,
|
||||
SpanKind.CLIENT,
|
||||
startTime,
|
||||
oldMetricAttributes,
|
||||
stableMetricAttributes
|
||||
stableMetricAttributes,
|
||||
startTime,
|
||||
error
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -705,17 +699,12 @@ export class HttpInstrumentation extends InstrumentationBase<HttpInstrumentation
|
|||
() => original.apply(this, [event, ...args]),
|
||||
error => {
|
||||
if (error) {
|
||||
setSpanWithError(
|
||||
instrumentation._onServerResponseError(
|
||||
span,
|
||||
error,
|
||||
instrumentation._semconvStability
|
||||
);
|
||||
instrumentation._closeHttpSpan(
|
||||
span,
|
||||
SpanKind.SERVER,
|
||||
startTime,
|
||||
oldMetricAttributes,
|
||||
stableMetricAttributes
|
||||
stableMetricAttributes,
|
||||
startTime,
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -851,14 +840,12 @@ export class HttpInstrumentation extends InstrumentationBase<HttpInstrumentation
|
|||
},
|
||||
error => {
|
||||
if (error) {
|
||||
setSpanWithError(span, error, instrumentation._semconvStability);
|
||||
|
||||
instrumentation._closeHttpSpan(
|
||||
instrumentation._onOutgoingRequestError(
|
||||
span,
|
||||
SpanKind.CLIENT,
|
||||
startTime,
|
||||
oldMetricAttributes,
|
||||
stableMetricAttributes
|
||||
stableMetricAttributes,
|
||||
startTime,
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -937,6 +924,25 @@ export class HttpInstrumentation extends InstrumentationBase<HttpInstrumentation
|
|||
);
|
||||
}
|
||||
|
||||
private _onOutgoingRequestError(
|
||||
span: Span,
|
||||
oldMetricAttributes: Attributes,
|
||||
stableMetricAttributes: Attributes,
|
||||
startTime: HrTime,
|
||||
error: Err
|
||||
) {
|
||||
setSpanWithError(span, error, this._semconvStability);
|
||||
stableMetricAttributes[ATTR_ERROR_TYPE] = error.name;
|
||||
|
||||
this._closeHttpSpan(
|
||||
span,
|
||||
SpanKind.CLIENT,
|
||||
startTime,
|
||||
oldMetricAttributes,
|
||||
stableMetricAttributes
|
||||
);
|
||||
}
|
||||
|
||||
private _onServerResponseError(
|
||||
span: Span,
|
||||
oldMetricAttributes: Attributes,
|
||||
|
|
@ -945,7 +951,8 @@ export class HttpInstrumentation extends InstrumentationBase<HttpInstrumentation
|
|||
error: Err
|
||||
) {
|
||||
setSpanWithError(span, error, this._semconvStability);
|
||||
// TODO get error attributes for metrics
|
||||
stableMetricAttributes[ATTR_ERROR_TYPE] = error.name;
|
||||
|
||||
this._closeHttpSpan(
|
||||
span,
|
||||
SpanKind.SERVER,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
} from '@opentelemetry/sdk-metrics';
|
||||
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
|
||||
import {
|
||||
ATTR_ERROR_TYPE,
|
||||
ATTR_HTTP_REQUEST_METHOD,
|
||||
ATTR_HTTP_RESPONSE_STATUS_CODE,
|
||||
ATTR_HTTP_ROUTE,
|
||||
|
|
@ -196,10 +197,10 @@ describe('metrics', () => {
|
|||
);
|
||||
}
|
||||
await metricReader.collectAndExport();
|
||||
const resourceMetrics = metricsMemoryExporter.getMetrics();
|
||||
const scopeMetrics = resourceMetrics[0].scopeMetrics;
|
||||
let resourceMetrics = metricsMemoryExporter.getMetrics();
|
||||
let scopeMetrics = resourceMetrics[0].scopeMetrics;
|
||||
assert.strictEqual(scopeMetrics.length, 1, 'scopeMetrics count');
|
||||
const metrics = scopeMetrics[0].metrics;
|
||||
let metrics = scopeMetrics[0].metrics;
|
||||
assert.strictEqual(metrics.length, 2, 'metrics count');
|
||||
assert.strictEqual(metrics[0].dataPointType, DataPointType.HISTOGRAM);
|
||||
assert.strictEqual(
|
||||
|
|
@ -247,6 +248,43 @@ describe('metrics', () => {
|
|||
[ATTR_NETWORK_PROTOCOL_VERSION]: '1.1',
|
||||
[ATTR_HTTP_RESPONSE_STATUS_CODE]: 200,
|
||||
});
|
||||
|
||||
metricsMemoryExporter.reset();
|
||||
|
||||
assert.throws(() =>
|
||||
http.request({
|
||||
hostname,
|
||||
port: serverPort,
|
||||
pathname,
|
||||
headers: { cookie: undefined },
|
||||
})
|
||||
);
|
||||
|
||||
await metricReader.collectAndExport();
|
||||
resourceMetrics = metricsMemoryExporter.getMetrics();
|
||||
scopeMetrics = resourceMetrics[0].scopeMetrics;
|
||||
assert.strictEqual(scopeMetrics.length, 1, 'scopeMetrics count');
|
||||
metrics = scopeMetrics[0].metrics;
|
||||
assert.strictEqual(metrics.length, 1, 'metrics count');
|
||||
assert.strictEqual(metrics[0].dataPointType, DataPointType.HISTOGRAM);
|
||||
assert.strictEqual(
|
||||
metrics[0].descriptor.description,
|
||||
'Duration of HTTP client requests.'
|
||||
);
|
||||
assert.strictEqual(
|
||||
metrics[0].descriptor.name,
|
||||
'http.client.request.duration'
|
||||
);
|
||||
assert.strictEqual(metrics[0].descriptor.unit, 's');
|
||||
assert.strictEqual(metrics[0].dataPoints.length, 1);
|
||||
assert.strictEqual((metrics[0].dataPoints[0].value as any).count, 1);
|
||||
|
||||
assert.deepStrictEqual(metrics[0].dataPoints[0].attributes, {
|
||||
[ATTR_HTTP_REQUEST_METHOD]: 'GET',
|
||||
[ATTR_SERVER_ADDRESS]: 'localhost',
|
||||
[ATTR_SERVER_PORT]: 22346,
|
||||
[ATTR_ERROR_TYPE]: 'TypeError',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -263,10 +301,10 @@ describe('metrics', () => {
|
|||
);
|
||||
}
|
||||
await metricReader.collectAndExport();
|
||||
const resourceMetrics = metricsMemoryExporter.getMetrics();
|
||||
const scopeMetrics = resourceMetrics[0].scopeMetrics;
|
||||
let resourceMetrics = metricsMemoryExporter.getMetrics();
|
||||
let scopeMetrics = resourceMetrics[0].scopeMetrics;
|
||||
assert.strictEqual(scopeMetrics.length, 1, 'scopeMetrics count');
|
||||
const metrics = scopeMetrics[0].metrics;
|
||||
let metrics = scopeMetrics[0].metrics;
|
||||
assert.strictEqual(metrics.length, 4, 'metrics count');
|
||||
|
||||
// old metrics
|
||||
|
|
@ -387,6 +425,64 @@ describe('metrics', () => {
|
|||
[ATTR_NETWORK_PROTOCOL_VERSION]: '1.1',
|
||||
[ATTR_HTTP_RESPONSE_STATUS_CODE]: 200,
|
||||
});
|
||||
|
||||
metricsMemoryExporter.reset();
|
||||
|
||||
assert.throws(() =>
|
||||
http.request({
|
||||
hostname,
|
||||
port: serverPort,
|
||||
pathname,
|
||||
headers: { cookie: undefined },
|
||||
})
|
||||
);
|
||||
|
||||
await metricReader.collectAndExport();
|
||||
resourceMetrics = metricsMemoryExporter.getMetrics();
|
||||
scopeMetrics = resourceMetrics[0].scopeMetrics;
|
||||
assert.strictEqual(scopeMetrics.length, 1, 'scopeMetrics count');
|
||||
metrics = scopeMetrics[0].metrics;
|
||||
assert.strictEqual(metrics.length, 2, 'metrics count');
|
||||
|
||||
// Old metrics
|
||||
assert.strictEqual(metrics[0].dataPointType, DataPointType.HISTOGRAM);
|
||||
assert.strictEqual(
|
||||
metrics[0].descriptor.description,
|
||||
'Measures the duration of outbound HTTP requests.'
|
||||
);
|
||||
assert.strictEqual(metrics[0].descriptor.name, 'http.client.duration');
|
||||
assert.strictEqual(metrics[0].descriptor.unit, 'ms');
|
||||
assert.strictEqual(metrics[0].dataPoints.length, 1);
|
||||
assert.strictEqual((metrics[0].dataPoints[0].value as any).count, 1);
|
||||
assert.strictEqual(
|
||||
metrics[0].dataPoints[0].attributes[ATTR_HTTP_METHOD],
|
||||
'GET'
|
||||
);
|
||||
assert.strictEqual(
|
||||
metrics[0].dataPoints[0].attributes[ATTR_NET_PEER_NAME],
|
||||
'localhost'
|
||||
);
|
||||
|
||||
// Stable metrics
|
||||
assert.strictEqual(metrics[1].dataPointType, DataPointType.HISTOGRAM);
|
||||
assert.strictEqual(
|
||||
metrics[1].descriptor.description,
|
||||
'Duration of HTTP client requests.'
|
||||
);
|
||||
assert.strictEqual(
|
||||
metrics[1].descriptor.name,
|
||||
'http.client.request.duration'
|
||||
);
|
||||
assert.strictEqual(metrics[1].descriptor.unit, 's');
|
||||
assert.strictEqual(metrics[1].dataPoints.length, 1);
|
||||
assert.strictEqual((metrics[1].dataPoints[0].value as any).count, 1);
|
||||
|
||||
assert.deepStrictEqual(metrics[1].dataPoints[0].attributes, {
|
||||
[ATTR_HTTP_REQUEST_METHOD]: 'GET',
|
||||
[ATTR_SERVER_ADDRESS]: 'localhost',
|
||||
[ATTR_SERVER_PORT]: 22346,
|
||||
[ATTR_ERROR_TYPE]: 'TypeError',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue