Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 25 additions & 52 deletions packages/node/src/integrations/http/httpServerSpansIntegration.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
/* eslint-disable max-lines */
import { errorMonitor } from 'node:events';
import type { IncomingHttpHeaders } from 'node:http';
import { context } from '@opentelemetry/api';
import type { RPCMetadata } from '@opentelemetry/core';
import { RPCType, setRPCMetadata } from '@opentelemetry/core';
import {
HTTP_CLIENT_IP,
HTTP_FLAVOR,
HTTP_HOST,
HTTP_METHOD,
HTTP_RESPONSE_STATUS_CODE,
HTTP_ROUTE,
HTTP_SCHEME,
HTTP_STATUS_CODE,
HTTP_TARGET,
Expand Down Expand Up @@ -41,7 +37,6 @@ import type {
} from '@sentry/core';
import {
debug,
getIsolationScope,
getSpanStatusFromHttpCode,
httpHeadersToSpanAttributes,
parseStringToURLObject,
Expand Down Expand Up @@ -209,51 +204,36 @@ const _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions
applyCustomAttributesOnSpan?.(span, request, response);
onSpanCreated?.(span, request, response);

const rpcMetadata: RPCMetadata = { type: RPCType.HTTP, span };

return withActiveSpan(span, () => {
// TODO(v11): Get rid of RPC metadata here
return context.with(setRPCMetadata(context.active(), rpcMetadata), () => {
bindScopeToEmitter(request);
bindScopeToEmitter(response);

// Ensure we only end the span once
// E.g. error can be emitted before close is emitted
let isEnded = false;
function endSpan(status: SpanStatus): void {
if (isEnded) {
return;
}

isEnded = true;

const newAttributes = getIncomingRequestAttributesOnResponse(request, response, rpcMetadata);
span.setAttributes(newAttributes);
span.setStatus(status);

// Once the route is resolved, upgrade the name/source from the raw URL to the parameterized route.
const route = newAttributes[HTTP_ROUTE];
if (route) {
const name = `${request.method?.toUpperCase() || 'GET'} ${route}`;
span.updateName(name);
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
getIsolationScope().setTransactionName(name);
}

span.end();
bindScopeToEmitter(request);
bindScopeToEmitter(response);

// Ensure we only end the span once
// E.g. error can be emitted before close is emitted
let isEnded = false;
function endSpan(status: SpanStatus): void {
if (isEnded) {
return;
}

response.on('close', () => {
endSpan(getSpanStatusFromHttpCode(response.statusCode));
});
response.on(errorMonitor, () => {
const httpStatus = getSpanStatusFromHttpCode(response.statusCode);
// Ensure we def. have an error status here
endSpan(httpStatus.code === SPAN_STATUS_ERROR ? httpStatus : { code: SPAN_STATUS_ERROR });
});
isEnded = true;

const newAttributes = getIncomingRequestAttributesOnResponse(request, response);
span.setAttributes(newAttributes);
span.setStatus(status);
span.end();
}

return next();
response.on('close', () => {
endSpan(getSpanStatusFromHttpCode(response.statusCode));
});
response.on(errorMonitor, () => {
const httpStatus = getSpanStatusFromHttpCode(response.statusCode);
// Ensure we def. have an error status here
endSpan(httpStatus.code === SPAN_STATUS_ERROR ? httpStatus : { code: SPAN_STATUS_ERROR });
});

return next();
});
};

Expand Down Expand Up @@ -414,7 +394,6 @@ function isCompressed(headers: IncomingHttpHeaders): boolean {
function getIncomingRequestAttributesOnResponse(
request: HttpIncomingMessage,
response: HttpServerResponse,
rpcMetadata?: RPCMetadata,
): SpanAttributes {
// take socket from the request,
// since it may be detached from the response object in keep-alive mode
Expand Down Expand Up @@ -443,12 +422,6 @@ function getIncomingRequestAttributesOnResponse(
newAttributes[HTTP_STATUS_CODE] = statusCode;
newAttributes['http.status_text'] = (statusMessage || '').toUpperCase();

if (rpcMetadata?.type === RPCType.HTTP && rpcMetadata.route !== undefined) {
const routeName = rpcMetadata.route;
newAttributes[HTTP_ROUTE] = routeName;
newAttributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] = 'route';
}

return newAttributes;
}

Expand Down
Loading