Skip to content

Commit 5df0161

Browse files
authored
ref(node): Refactor usage of hrTime utilities from @opentelemetry/core (#21191)
These can easily be rewritten to use our existing utils, actually making things easier often (because it often creates hrTime just to convert it to a number, we can skip this step...). Also removes the core dependency from nestjs package, as this is not actually used there. Also adjusts the vendor-otel skill to be explicit about it being ok to change vendored code afterwards.
1 parent 193a2d7 commit 5df0161

10 files changed

Lines changed: 34 additions & 36 deletions

File tree

.agents/skills/vendor-otel/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ description: Vendor an OpenTelemetry instrumentation package into the Sentry Jav
99

1010
Copy upstream OTel instrumentation TypeScript source into a `vendored/` directory, remove the npm dependency, and ensure builds and tests pass. No logic changes — the vendored code must behave identically to the original.
1111

12+
**Scope of this rule:** "No logic changes" applies **only to the initial vendoring PR**. After a package has been vendored, the `vendored/` directory is Sentry-owned source and follow-up PRs may refactor, simplify, replace upstream utilities with Sentry equivalents (e.g. `@opentelemetry/core``@sentry/core`), or otherwise diverge from upstream. Such cleanup is desired, not discouraged.
13+
1214
## 1. Research
1315

1416
Find upstream source files:

packages/aws-serverless/src/integration/aws/vendored/aws-sdk.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/* eslint-disable */
2121

2222
import { Span, SpanKind, context, trace, diag, SpanStatusCode } from '@opentelemetry/api';
23-
import { hrTime, suppressTracing } from '@opentelemetry/core';
23+
import { suppressTracing } from '@opentelemetry/core';
2424
import { AttributeNames } from './enums';
2525
import { ServicesExtensions } from './services';
2626
import {
@@ -57,7 +57,7 @@ import { propwrap } from './propwrap';
5757
import { RequestMetadata } from './services/ServiceExtension';
5858
import { ATTR_HTTP_STATUS_CODE } from './semconv';
5959
import { ATTR_HTTP_RESPONSE_STATUS_CODE } from '@opentelemetry/semantic-conventions';
60-
import { SDK_VERSION } from '@sentry/core';
60+
import { SDK_VERSION, timestampInSeconds } from '@sentry/core';
6161

6262
const PACKAGE_NAME = '@sentry/instrumentation-aws-sdk';
6363

@@ -298,7 +298,7 @@ export class AwsInstrumentation extends InstrumentationBase<AwsSdkInstrumentatio
298298
self._diag,
299299
self._dbSemconvStability,
300300
);
301-
const startTime = hrTime();
301+
const startTime = timestampInSeconds();
302302
const span = self._startAwsV3Span(normalizedRequest, requestMetadata);
303303
const activeContextWithSpan = trace.setSpan(context.active(), span);
304304

packages/aws-serverless/src/integration/aws/vendored/services/ServiceExtension.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*/
2020
/* eslint-disable */
2121

22-
import { DiagLogger, HrTime, Meter, Span, SpanAttributes, SpanKind, Tracer } from '@opentelemetry/api';
22+
import { DiagLogger, Meter, Span, SpanAttributes, SpanKind, Tracer } from '@opentelemetry/api';
2323
import { SemconvStability } from '@opentelemetry/instrumentation';
2424
import { AwsSdkInstrumentationConfig, NormalizedRequest, NormalizedResponse } from '../types';
2525

@@ -53,7 +53,7 @@ export interface ServiceExtension {
5353
span: Span,
5454
tracer: Tracer,
5555
config: AwsSdkInstrumentationConfig,
56-
startTime: HrTime,
56+
startTime: number,
5757
) => any | undefined;
5858

5959
updateMetricInstruments?: (meter: Meter) => void;

packages/aws-serverless/src/integration/aws/vendored/services/ServicesExtensions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*/
2020
/* eslint-disable */
2121

22-
import { Tracer, Span, DiagLogger, Meter, HrTime } from '@opentelemetry/api';
22+
import { Tracer, Span, DiagLogger, Meter } from '@opentelemetry/api';
2323
import { SemconvStability } from '@opentelemetry/instrumentation';
2424
import { ServiceExtension, RequestMetadata } from './ServiceExtension';
2525
import { SqsServiceExtension } from './sqs';
@@ -77,7 +77,7 @@ export class ServicesExtensions implements ServiceExtension {
7777
span: Span,
7878
tracer: Tracer,
7979
config: AwsSdkInstrumentationConfig,
80-
startTime: HrTime,
80+
startTime: number,
8181
) {
8282
const serviceExtension = this.services.get(response.request.serviceName);
8383

packages/aws-serverless/src/integration/aws/vendored/services/bedrock-runtime.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*/
2020
/* eslint-disable */
2121

22-
import { Attributes, DiagLogger, diag, Histogram, HrTime, Meter, Span, Tracer, ValueType } from '@opentelemetry/api';
22+
import { Attributes, DiagLogger, diag, Histogram, Meter, Span, Tracer, ValueType } from '@opentelemetry/api';
2323
import { RequestMetadata, ServiceExtension } from './ServiceExtension';
2424
import {
2525
ATTR_GEN_AI_SYSTEM,
@@ -41,7 +41,7 @@ import {
4141
METRIC_GEN_AI_CLIENT_TOKEN_USAGE,
4242
} from '../semconv';
4343
import { AwsSdkInstrumentationConfig, NormalizedRequest, NormalizedResponse } from '../types';
44-
import { hrTime, hrTimeDuration, hrTimeToMilliseconds } from '@opentelemetry/core';
44+
import { timestampInSeconds } from '@sentry/core';
4545

4646
// Simplified types inlined from @aws-sdk/client-bedrock-runtime
4747
// Only the fields accessed by this instrumentation are included
@@ -295,7 +295,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension {
295295
span: Span,
296296
tracer: Tracer,
297297
config: AwsSdkInstrumentationConfig,
298-
startTime: HrTime,
298+
startTime: number,
299299
) {
300300
if (!span.isRecording()) {
301301
return;
@@ -318,7 +318,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension {
318318
span: Span,
319319
tracer: Tracer,
320320
config: AwsSdkInstrumentationConfig,
321-
startTime: HrTime,
321+
startTime: number,
322322
) {
323323
const { stopReason, usage } = response.data;
324324

@@ -331,7 +331,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension {
331331
span: Span,
332332
tracer: Tracer,
333333
config: AwsSdkInstrumentationConfig,
334-
startTime: HrTime,
334+
startTime: number,
335335
) {
336336
return {
337337
...response.data,
@@ -345,7 +345,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension {
345345
response: NormalizedResponse,
346346
stream: AsyncIterable<ConverseStreamOutput>,
347347
span: Span,
348-
startTime: HrTime,
348+
startTime: number,
349349
) {
350350
try {
351351
let usage: TokenUsage | undefined;
@@ -366,14 +366,14 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension {
366366
}
367367
}
368368

369-
private setUsage(response: NormalizedResponse, span: Span, usage: TokenUsage | undefined, startTime: HrTime) {
369+
private setUsage(response: NormalizedResponse, span: Span, usage: TokenUsage | undefined, startTime: number) {
370370
const sharedMetricAttrs: Attributes = {
371371
[ATTR_GEN_AI_SYSTEM]: GEN_AI_SYSTEM_VALUE_AWS_BEDROCK,
372372
[ATTR_GEN_AI_OPERATION_NAME]: GEN_AI_OPERATION_NAME_VALUE_CHAT,
373373
[ATTR_GEN_AI_REQUEST_MODEL]: response.request.commandInput.modelId,
374374
};
375375

376-
const durationSecs = hrTimeToMilliseconds(hrTimeDuration(startTime, hrTime())) / 1000;
376+
const durationSecs = timestampInSeconds() - startTime;
377377
this.operationDuration.record(durationSecs, sharedMetricAttrs);
378378

379379
if (usage) {

packages/nestjs/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
},
4646
"dependencies": {
4747
"@opentelemetry/api": "^1.9.1",
48-
"@opentelemetry/core": "^2.6.1",
4948
"@opentelemetry/instrumentation": "^0.214.0",
5049
"@opentelemetry/semantic-conventions": "^1.40.0",
5150
"@sentry/core": "10.55.0",

packages/node/src/integrations/node-fetch/vendored/undici.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import * as diagch from 'diagnostics_channel';
2525
import { URL } from 'url';
2626

2727
import { InstrumentationBase, safeExecuteInTheMiddle } from '@opentelemetry/instrumentation';
28-
import type { Attributes, Histogram, HrTime, Span } from '@opentelemetry/api';
28+
import type { Attributes, Histogram, Span } from '@opentelemetry/api';
2929
import {
3030
context,
3131
INVALID_SPAN_CONTEXT,
@@ -35,7 +35,6 @@ import {
3535
trace,
3636
ValueType,
3737
} from '@opentelemetry/api';
38-
import { hrTime, hrTimeDuration, hrTimeToMilliseconds } from '@opentelemetry/core';
3938
import {
4039
ATTR_ERROR_TYPE,
4140
ATTR_HTTP_REQUEST_METHOD,
@@ -62,12 +61,12 @@ import type {
6261
} from './internal-types';
6362
import type { UndiciInstrumentationConfig, UndiciRequest } from './types';
6463

65-
import { SDK_VERSION } from '@sentry/core';
64+
import { SDK_VERSION, timestampInSeconds } from '@sentry/core';
6665

6766
interface InstrumentationRecord {
6867
span: Span;
6968
attributes: Attributes;
70-
startTime: HrTime;
69+
startTime: number;
7170
}
7271

7372
const PACKAGE_NAME = '@sentry/instrumentation-undici';
@@ -225,7 +224,7 @@ export class UndiciInstrumentation extends InstrumentationBase<UndiciInstrumenta
225224
return;
226225
}
227226

228-
const startTime = hrTime();
227+
const startTime = timestampInSeconds();
229228
let requestUrl;
230229
try {
231230
requestUrl = new URL(request.path, request.origin);
@@ -475,7 +474,7 @@ export class UndiciInstrumentation extends InstrumentationBase<UndiciInstrumenta
475474
this.recordRequestDuration(attributes, startTime);
476475
}
477476

478-
private recordRequestDuration(attributes: Attributes, startTime: HrTime) {
477+
private recordRequestDuration(attributes: Attributes, startTime: number) {
479478
// Time to record metrics
480479
const metricsAttributes: Attributes = {};
481480
// Get the attribs already in span attributes
@@ -494,7 +493,7 @@ export class UndiciInstrumentation extends InstrumentationBase<UndiciInstrumenta
494493
});
495494

496495
// Take the duration and record it
497-
const durationSeconds = hrTimeToMilliseconds(hrTimeDuration(startTime, hrTime())) / 1000;
496+
const durationSeconds = timestampInSeconds() - startTime;
498497
this._httpClientDurationHistogram.record(durationSeconds, metricsAttributes);
499498
}
500499

packages/node/src/integrations/tracing/amqplib/vendored/amqplib.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
Link,
3232
Context,
3333
} from '@opentelemetry/api';
34-
import { hrTime, hrTimeDuration, hrTimeToMilliseconds } from '@opentelemetry/core';
34+
import { timestampInSeconds } from '@sentry/core';
3535
import {
3636
InstrumentationBase,
3737
InstrumentationNodeModuleDefinition,
@@ -376,7 +376,7 @@ export class AmqplibInstrumentation extends InstrumentationBase<AmqplibInstrumen
376376
// store the message on the channel so we can close the span on ackAll etc
377377
channel[CHANNEL_SPANS_NOT_ENDED]!.push({
378378
msg,
379-
timeOfConsume: hrTime(),
379+
timeOfConsume: timestampInSeconds(),
380380
});
381381

382382
// store the span on the message, so we can end it when user call 'ack' on it
@@ -615,14 +615,14 @@ export class AmqplibInstrumentation extends InstrumentationBase<AmqplibInstrumen
615615
}
616616

617617
private checkConsumeTimeoutOnChannel(channel: InstrumentationConsumeChannel) {
618-
const currentTime = hrTime();
618+
const currentTime = timestampInSeconds();
619619
const spansNotEnded = channel[CHANNEL_SPANS_NOT_ENDED] ?? [];
620620
let i: number;
621621
const { consumeTimeoutMs } = this.getConfig();
622622
for (i = 0; i < spansNotEnded.length; i++) {
623623
const currMessage = spansNotEnded[i]!;
624-
const timeFromConsume = hrTimeDuration(currMessage.timeOfConsume, currentTime);
625-
if (hrTimeToMilliseconds(timeFromConsume) < consumeTimeoutMs!) {
624+
const timeFromConsumeMs = (currentTime - currMessage.timeOfConsume) * 1000;
625+
if (timeFromConsumeMs < consumeTimeoutMs!) {
626626
break;
627627
}
628628
this.endConsumerSpan(currMessage.msg, null, EndOperation.InstrumentationTimeout, true);

packages/node/src/integrations/tracing/amqplib/vendored/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121
/* eslint-disable */
2222

23-
import { Context, createContextKey, diag, HrTime, Span, Attributes, AttributeValue } from '@opentelemetry/api';
23+
import { Context, createContextKey, diag, Span, Attributes, AttributeValue } from '@opentelemetry/api';
2424
import { SemconvStability } from '@opentelemetry/instrumentation';
2525
import { ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT } from '@opentelemetry/semantic-conventions';
2626
import { ATTR_MESSAGING_SYSTEM, ATTR_NET_PEER_NAME, ATTR_NET_PEER_PORT } from './semconv';
@@ -45,7 +45,7 @@ export type InstrumentationConsumeChannel = Channel & {
4545
connection: InstrumentationConnection;
4646
[CHANNEL_SPANS_NOT_ENDED]?: {
4747
msg: ConsumeMessage;
48-
timeOfConsume: HrTime;
48+
timeOfConsume: number;
4949
}[];
5050
[CHANNEL_CONSUME_TIMEOUT_TIMER]?: NodeJS.Timeout;
5151
};

packages/node/src/integrations/tracing/postgres/vendored/instrumentation.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import {
3939
Histogram,
4040
ValueType,
4141
Attributes,
42-
HrTime,
4342
UpDownCounter,
4443
} from '@opentelemetry/api';
4544
import type { PgClient } from './pg-types';
@@ -54,10 +53,9 @@ import {
5453
import { PgInstrumentationConfig } from './types';
5554
import * as utils from './utils';
5655
import { addSqlCommenterComment } from '../../utils/sql-common';
57-
import { SDK_VERSION } from '@sentry/core';
56+
import { SDK_VERSION, timestampInSeconds } from '@sentry/core';
5857
const PACKAGE_NAME = '@sentry/instrumentation-pg';
5958
import { SpanNames } from './enums/SpanNames';
60-
import { hrTime, hrTimeDuration, hrTimeToMilliseconds } from '@opentelemetry/core';
6159
import {
6260
ATTR_ERROR_TYPE,
6361
ATTR_SERVER_PORT,
@@ -252,7 +250,7 @@ export class PgInstrumentation extends InstrumentationBase<PgInstrumentationConf
252250
};
253251
}
254252

255-
private recordOperationDuration(attributes: Attributes, startTime: HrTime) {
253+
private recordOperationDuration(attributes: Attributes, startTime: number) {
256254
const metricsAttributes: Attributes = {};
257255
const keysToCopy: string[] = [
258256
ATTR_DB_NAMESPACE,
@@ -274,7 +272,7 @@ export class PgInstrumentation extends InstrumentationBase<PgInstrumentationConf
274272
}
275273
});
276274

277-
const durationSeconds = hrTimeToMilliseconds(hrTimeDuration(startTime, hrTime())) / 1000;
275+
const durationSeconds = timestampInSeconds() - startTime;
278276
this._operationDuration.record(durationSeconds, metricsAttributes);
279277
}
280278

@@ -286,7 +284,7 @@ export class PgInstrumentation extends InstrumentationBase<PgInstrumentationConf
286284
if (utils.shouldSkipInstrumentation(plugin.getConfig())) {
287285
return original.apply(this, args as never);
288286
}
289-
const startTime = hrTime();
287+
const startTime = timestampInSeconds();
290288

291289
// client.query(text, cb?), client.query(text, values, cb?), and
292290
// client.query(configObj, cb?) are all valid signatures. We construct

0 commit comments

Comments
 (0)