Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
mydea committed Sep 26, 2023
1 parent e8442a7 commit 412b45c
Show file tree
Hide file tree
Showing 46 changed files with 3,470 additions and 311 deletions.
1 change: 1 addition & 0 deletions packages/node-experimental/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},
"dependencies": {
"@opentelemetry/api": "~1.6.0",
"@opentelemetry/core": "~1.17.0",
"@opentelemetry/context-async-hooks": "~1.17.0",
"@opentelemetry/instrumentation": "~0.43.0",
"@opentelemetry/instrumentation-express": "~0.33.1",
Expand Down
13 changes: 13 additions & 0 deletions packages/node-experimental/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import { createContextKey } from '@opentelemetry/api';

export const OTEL_CONTEXT_HUB_KEY = createContextKey('sentry_hub');

export const OTEL_ATTR_ORIGIN = 'sentry.origin';
export const OTEL_ATTR_OP = 'sentry.op';
export const OTEL_ATTR_SOURCE = 'sentry.source';

export const OTEL_ATTR_PARENT_SAMPLED = 'sentry.parentSampled';
export const OTEL_ATTR_DROP_SPAN = 'sentry.dropSpan';

export const OTEL_ATTR_BREADCRUMB_TYPE = 'sentry.breadcrumb.type';
export const OTEL_ATTR_BREADCRUMB_LEVEL = 'sentry.breadcrumb.level';
export const OTEL_ATTR_BREADCRUMB_EVENT_ID = 'sentry.breadcrumb.event_id';
export const OTEL_ATTR_BREADCRUMB_CATEGORY = 'sentry.breadcrumb.category';
export const OTEL_ATTR_BREADCRUMB_DATA = 'sentry.breadcrumb.data';
2 changes: 1 addition & 1 deletion packages/node-experimental/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export { INTEGRATIONS as Integrations };
export { getAutoPerformanceIntegrations } from './integrations/getAutoPerformanceIntegrations';
export * as Handlers from './sdk/handlers';
export * from './sdk/trace';
export { getActiveSpan } from './utils/getActiveSpan';
export { getCurrentHub, getHubFromCarrier } from './sdk/hub';

export {
Expand Down Expand Up @@ -39,7 +40,6 @@ export {
makeMain,
runWithAsyncContext,
Scope,
startTransaction,
SDK_VERSION,
setContext,
setExtra,
Expand Down
70 changes: 19 additions & 51 deletions packages/node-experimental/src/integrations/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { SpanKind } from '@opentelemetry/api';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
import { hasTracingEnabled, Transaction } from '@sentry/core';
import { getCurrentHub } from '@sentry/node';
import { _INTERNAL_getSentrySpan } from '@sentry/opentelemetry-node';
import { hasTracingEnabled } from '@sentry/core';
import type { EventProcessor, Hub, Integration } from '@sentry/types';
import type { ClientRequest, IncomingMessage, ServerResponse } from 'http';

import { OTEL_ATTR_DROP_SPAN, OTEL_ATTR_ORIGIN } from '../constants';
import { setOtelSpanMetadata } from '../opentelemetry/spanData';
import { getCurrentHub } from '../sdk/hub';
import type { NodeExperimentalClient, OtelSpan } from '../types';
import { getRequestSpanData } from '../utils/getRequestSpanData';

Expand Down Expand Up @@ -110,7 +111,7 @@ export class Http implements Integration {
requireParentforOutgoingSpans: true,
requireParentforIncomingSpans: false,
requestHook: (span, req) => {
this._updateSentrySpan(span as unknown as OtelSpan, req);
this._updateSpan(span as unknown as OtelSpan, req);
},
responseHook: (span, res) => {
this._addRequestBreadcrumb(span as unknown as OtelSpan, res);
Expand All @@ -122,8 +123,6 @@ export class Http implements Integration {
this._shouldCreateSpanForRequest =
// eslint-disable-next-line deprecation/deprecation
this._shouldCreateSpanForRequest || clientOptions?.shouldCreateSpanForRequest;

client?.on?.('otelSpanEnd', this._onSpanEnd);
}

/**
Expand All @@ -133,64 +132,33 @@ export class Http implements Integration {
this._unload?.();
}

private _onSpanEnd: (otelSpan: unknown, mutableOptions: { drop: boolean }) => void = (
otelSpan: unknown,
mutableOptions: { drop: boolean },
) => {
/** If the span for this request should be dropped (=not sent to Sentry). */
private _shouldDropSpan(otelSpan: OtelSpan): boolean {
if (!this._shouldCreateSpans) {
mutableOptions.drop = true;
return;
return true;
}

if (this._shouldCreateSpanForRequest) {
const url = getHttpUrl((otelSpan as OtelSpan).attributes);
const url = getHttpUrl(otelSpan.attributes);
if (url && !this._shouldCreateSpanForRequest(url)) {
mutableOptions.drop = true;
return;
return true;
}
}

return;
};

/** Update the Sentry span data based on the OTEL span. */
private _updateSentrySpan(span: OtelSpan, request: ClientRequest | IncomingMessage): void {
const data = getRequestSpanData(span);
const { attributes } = span;

const sentrySpan = _INTERNAL_getSentrySpan(span.spanContext().spanId);
if (!sentrySpan) {
return;
}

sentrySpan.origin = 'auto.http.otel.http';

const additionalData: Record<string, unknown> = {
url: data.url,
};

if (sentrySpan instanceof Transaction && span.kind === SpanKind.SERVER) {
sentrySpan.setMetadata({ request });
}
return false;
}

if (attributes[SemanticAttributes.HTTP_STATUS_CODE]) {
const statusCode = attributes[SemanticAttributes.HTTP_STATUS_CODE] as string;
additionalData['http.response.status_code'] = statusCode;
/** Update the span with data we need. */
private _updateSpan(span: OtelSpan, request: ClientRequest | IncomingMessage): void {
span.setAttribute(OTEL_ATTR_ORIGIN, 'auto.http.otel.http');

sentrySpan.setTag('http.status_code', statusCode);
if (span.kind === SpanKind.SERVER) {
setOtelSpanMetadata(span, { request });
}

if (data['http.query']) {
additionalData['http.query'] = data['http.query'].slice(1);
if (this._shouldDropSpan(span as unknown as OtelSpan)) {
span.setAttribute(OTEL_ATTR_DROP_SPAN, true);
}
if (data['http.fragment']) {
additionalData['http.fragment'] = data['http.fragment'].slice(1);
}

Object.keys(additionalData).forEach(prop => {
const value = additionalData[prop];
sentrySpan.setData(prop, value);
});
}

/** Add a breadcrumb for outgoing requests. */
Expand Down
50 changes: 50 additions & 0 deletions packages/node-experimental/src/opentelemetry/spanData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { Span as OtelSpan } from '@opentelemetry/api';
import type { Hub, Scope, TransactionMetadata } from '@sentry/types';

// We store the parent span, scope & metadata in separate weakmaps, so we can access them for a given span
// This way we can enhance the data that an OTEL Span natively gives us
// and since we are using weakmaps, we do not need to clean up after ourselves
const otelSpanScope = new WeakMap<OtelSpan, Scope>();
const otelSpanHub = new WeakMap<OtelSpan, Hub>();
const otelSpanParent = new WeakMap<OtelSpan, OtelSpan>();
const otelSpanMetadata = new WeakMap<OtelSpan, Partial<TransactionMetadata>>();

/** Set the Sentry scope on an OTEL span. */
export function setOtelSpanScope(span: OtelSpan, scope: Scope): void {
otelSpanScope.set(span, scope);
}

/** Get the Sentry scope of an OTEL span. */
export function getOtelSpanScope(span: OtelSpan): Scope | undefined {
return otelSpanScope.get(span);
}

/** Set the Sentry hub on an OTEL span. */
export function setOtelSpanHub(span: OtelSpan, hub: Hub): void {
otelSpanHub.set(span, hub);
}

/** Get the Sentry hub of an OTEL span. */
export function getOtelSpanHub(span: OtelSpan): Hub | undefined {
return otelSpanHub.get(span);
}

/** Set the parent OTEL span on an OTEL span. */
export function setOtelSpanParent(span: OtelSpan, parentSpan: OtelSpan): void {
otelSpanParent.set(span, parentSpan);
}

/** Get the parent OTEL span of an OTEL span. */
export function getOtelSpanParent(span: OtelSpan): OtelSpan | undefined {
return otelSpanParent.get(span);
}

/** Set metadata for an OTEL span. */
export function setOtelSpanMetadata(span: OtelSpan, metadata: Partial<TransactionMetadata>): void {
otelSpanMetadata.set(span, metadata);
}

/** Get metadata for an OTEL span. */
export function getOtelSpanMetadata(span: OtelSpan): Partial<TransactionMetadata> | undefined {
return otelSpanMetadata.get(span);
}
Loading

0 comments on commit 412b45c

Please sign in to comment.