Skip to content

Commit d631127

Browse files
authored
feat(opentelemetry): Update OpenTelemetry dependencies to 1.28.0 (#14547)
Updates all OpenTelemetry dependencies to 1.28.0, as well as all instrumentation except for prisma (which is a major from 5 to 6, so leaving this out for now...) to their latest version.
1 parent 2a41c84 commit d631127

File tree

20 files changed

+417
-248
lines changed

20 files changed

+417
-248
lines changed

.size-limit.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ module.exports = [
228228
import: createImport('init'),
229229
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
230230
gzip: true,
231-
limit: '140 KB',
231+
limit: '160 KB',
232232
},
233233
{
234234
name: '@sentry/node - without tracing',
@@ -260,7 +260,7 @@ module.exports = [
260260
import: createImport('init'),
261261
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
262262
gzip: true,
263-
limit: '130 KB',
263+
limit: '150 KB',
264264
},
265265
];
266266

dev-packages/e2e-tests/test-applications/aws-lambda-layer-cjs/tests/basic.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ test('Lambda layer SDK bundle sends events', async ({ request }) => {
3333
'sentry.op': 'function.aws.lambda',
3434
'cloud.account.id': '123453789012',
3535
'faas.id': 'arn:aws:lambda:us-east-1:123453789012:function:my-lambda',
36+
'faas.coldstart': true,
3637
'otel.kind': 'SERVER',
3738
},
3839
op: 'function.aws.lambda',

dev-packages/e2e-tests/test-applications/aws-serverless-esm/tests/basic.test.ts

+21-4
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,22 @@ test('AWS Serverless SDK sends events in ESM mode', async ({ request }) => {
2828
expect(transactionEvent.contexts?.trace).toEqual({
2929
data: {
3030
'sentry.sample_rate': 1,
31-
'sentry.source': 'component',
32-
'sentry.origin': 'auto.function.serverless',
31+
'sentry.source': 'custom',
32+
'sentry.origin': 'auto.otel.aws-lambda',
3333
'sentry.op': 'function.aws.lambda',
34+
'cloud.account.id': '123453789012',
35+
'faas.id': 'arn:aws:lambda:us-east-1:123453789012:function:my-lambda',
36+
'faas.coldstart': true,
37+
'otel.kind': 'SERVER',
3438
},
3539
op: 'function.aws.lambda',
36-
origin: 'auto.function.serverless',
40+
origin: 'auto.otel.aws-lambda',
3741
span_id: expect.stringMatching(/[a-f0-9]{16}/),
3842
status: 'ok',
3943
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
4044
});
4145

42-
expect(transactionEvent.spans).toHaveLength(2);
46+
expect(transactionEvent.spans).toHaveLength(3);
4347

4448
// shows that the Otel Http instrumentation is working
4549
expect(transactionEvent.spans).toContainEqual(
@@ -54,6 +58,19 @@ test('AWS Serverless SDK sends events in ESM mode', async ({ request }) => {
5458
}),
5559
);
5660

61+
expect(transactionEvent.spans).toContainEqual(
62+
expect.objectContaining({
63+
data: {
64+
'sentry.op': 'function.aws.lambda',
65+
'sentry.origin': 'auto.function.serverless',
66+
'sentry.source': 'component',
67+
},
68+
description: 'my-lambda',
69+
op: 'function.aws.lambda',
70+
origin: 'auto.function.serverless',
71+
}),
72+
);
73+
5774
// shows that the manual span creation is working
5875
expect(transactionEvent.spans).toContainEqual(
5976
expect.objectContaining({

dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/s3/test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const EXPECTED_TRANSCATION = {
1414
'rpc.method': 'PutObject',
1515
'rpc.service': 'S3',
1616
'aws.region': 'us-east-1',
17+
'aws.s3.bucket': 'ot-demo-test',
1718
'otel.kind': 'CLIENT',
1819
},
1920
}),

jest/jest.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module.exports = {
1010
testMatch: ['<rootDir>/**/*.test.ts', '<rootDir>/**/*.test.tsx'],
1111
moduleNameMapper: {
1212
'^axios$': require.resolve('axios'),
13+
'@opentelemetry/semantic-conventions/incubating': require.resolve('@opentelemetry/semantic-conventions/incubating'),
1314
},
1415
globals: {
1516
'ts-jest': {

packages/aws-serverless/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@
6464
"access": "public"
6565
},
6666
"dependencies": {
67-
"@opentelemetry/instrumentation": "^0.54.0",
68-
"@opentelemetry/instrumentation-aws-lambda": "0.44.0",
69-
"@opentelemetry/instrumentation-aws-sdk": "0.45.0",
67+
"@opentelemetry/instrumentation": "^0.55.0",
68+
"@opentelemetry/instrumentation-aws-lambda": "0.48.0",
69+
"@opentelemetry/instrumentation-aws-sdk": "0.47.0",
7070
"@sentry/core": "8.42.0",
7171
"@sentry/node": "8.42.0",
7272
"@types/aws-lambda": "^8.10.62"

packages/aws-serverless/src/sdk.ts

+1
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ export function wrapHandler<TEvent, TResult>(
336336
// Only start a trace and root span if the handler is not already wrapped by Otel instrumentation
337337
// Otherwise, we create two root spans (one from otel, one from our wrapper).
338338
// If Otel instrumentation didn't work or was filtered by users, we still want to trace the handler.
339+
// TODO(v9): Since bumping the OTEL Instrumentation, this is likely not needed anymore, we can possibly remove this
339340
if (options.startTrace && !isWrappedByOtel(handler)) {
340341
const traceData = getAwsTraceData(event as { headers?: Record<string, string> }, context);
341342

packages/nextjs/package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@
7777
},
7878
"dependencies": {
7979
"@opentelemetry/api": "^1.9.0",
80-
"@opentelemetry/instrumentation-http": "0.53.0",
81-
"@opentelemetry/semantic-conventions": "^1.27.0",
80+
"@opentelemetry/semantic-conventions": "^1.28.0",
8281
"@rollup/plugin-commonjs": "28.0.1",
8382
"@sentry-internal/browser-utils": "8.42.0",
8483
"@sentry/core": "8.42.0",

packages/node/package.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,17 @@
6868
"@opentelemetry/api": "^1.9.0",
6969
"@opentelemetry/context-async-hooks": "^1.25.1",
7070
"@opentelemetry/core": "^1.25.1",
71-
"@opentelemetry/instrumentation": "^0.54.0",
72-
"@opentelemetry/instrumentation-amqplib": "^0.43.0",
73-
"@opentelemetry/instrumentation-connect": "0.40.0",
74-
"@opentelemetry/instrumentation-dataloader": "0.12.0",
75-
"@opentelemetry/instrumentation-express": "0.44.0",
76-
"@opentelemetry/instrumentation-fastify": "0.41.0",
77-
"@opentelemetry/instrumentation-fs": "0.16.0",
71+
"@opentelemetry/instrumentation": "^0.55.0",
72+
"@opentelemetry/instrumentation-amqplib": "^0.44.0",
73+
"@opentelemetry/instrumentation-connect": "0.41.0",
74+
"@opentelemetry/instrumentation-dataloader": "0.14.0",
75+
"@opentelemetry/instrumentation-express": "0.45.0",
76+
"@opentelemetry/instrumentation-fastify": "0.42.0",
77+
"@opentelemetry/instrumentation-fs": "0.17.0",
7878
"@opentelemetry/instrumentation-generic-pool": "0.39.0",
7979
"@opentelemetry/instrumentation-graphql": "0.44.0",
8080
"@opentelemetry/instrumentation-hapi": "0.41.0",
81-
"@opentelemetry/instrumentation-http": "0.53.0",
81+
"@opentelemetry/instrumentation-http": "0.55.0",
8282
"@opentelemetry/instrumentation-ioredis": "0.43.0",
8383
"@opentelemetry/instrumentation-kafkajs": "0.4.0",
8484
"@opentelemetry/instrumentation-knex": "0.41.0",
@@ -94,8 +94,8 @@
9494
"@opentelemetry/instrumentation-tedious": "0.15.0",
9595
"@opentelemetry/instrumentation-undici": "0.6.0",
9696
"@opentelemetry/resources": "^1.26.0",
97-
"@opentelemetry/sdk-trace-base": "^1.26.0",
98-
"@opentelemetry/semantic-conventions": "^1.27.0",
97+
"@opentelemetry/sdk-trace-base": "^1.28.0",
98+
"@opentelemetry/semantic-conventions": "^1.28.0",
9999
"@prisma/instrumentation": "5.19.1",
100100
"@sentry/core": "8.42.0",
101101
"@sentry/opentelemetry": "8.42.0",

packages/node/src/integrations/http/SentryHttpInstrumentation.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import type * as https from 'node:https';
44
import { VERSION } from '@opentelemetry/core';
55
import type { InstrumentationConfig } from '@opentelemetry/instrumentation';
66
import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
7-
import { getRequestInfo } from '@opentelemetry/instrumentation-http';
87
import type { RequestEventData, SanitizedRequestData, Scope } from '@sentry/core';
98
import {
109
addBreadcrumb,
@@ -21,7 +20,7 @@ import {
2120
import { DEBUG_BUILD } from '../../debug-build';
2221
import type { NodeClient } from '../../sdk/client';
2322
import { getRequestUrl } from '../../utils/getRequestUrl';
24-
23+
import { getRequestInfo } from './vendor/getRequestInfo';
2524
type Http = typeof http;
2625
type Https = typeof https;
2726

@@ -196,7 +195,7 @@ export class SentryHttpInstrumentation extends InstrumentationBase<SentryHttpIns
196195
? (argsCopy.shift() as http.RequestOptions)
197196
: undefined;
198197

199-
const { optionsParsed } = getRequestInfo(options, extraOptions);
198+
const { optionsParsed } = getRequestInfo(instrumentation._diag, options, extraOptions);
200199

201200
const request = original.apply(this, args) as ReturnType<typeof http.request>;
202201

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/* eslint-disable complexity */
2+
3+
/**
4+
* Vendored in from https://github.com/open-telemetry/opentelemetry-js/commit/87bd98edd24c98a5fbb9a56fed4b673b7f17a724
5+
*/
6+
7+
/*
8+
* Copyright The OpenTelemetry Authors
9+
*
10+
* Licensed under the Apache License, Version 2.0 (the "License");
11+
* you may not use this file except in compliance with the License.
12+
* You may obtain a copy of the License at
13+
*
14+
* https://www.apache.org/licenses/LICENSE-2.0
15+
*
16+
* Unless required by applicable law or agreed to in writing, software
17+
* distributed under the License is distributed on an "AS IS" BASIS,
18+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+
* See the License for the specific language governing permissions and
20+
* limitations under the License.
21+
*/
22+
import type { RequestOptions } from 'node:http';
23+
import * as url from 'url';
24+
import type { DiagLogger } from '@opentelemetry/api';
25+
26+
/**
27+
* Makes sure options is an url object
28+
* return an object with default value and parsed options
29+
* @param logger component logger
30+
* @param options original options for the request
31+
* @param [extraOptions] additional options for the request
32+
*/
33+
export const getRequestInfo = (
34+
logger: DiagLogger,
35+
options: url.URL | RequestOptions | string,
36+
extraOptions?: RequestOptions,
37+
): {
38+
origin: string;
39+
pathname: string;
40+
method: string;
41+
invalidUrl: boolean;
42+
optionsParsed: RequestOptions;
43+
} => {
44+
let pathname: string;
45+
let origin: string;
46+
let optionsParsed: RequestOptions;
47+
let invalidUrl = false;
48+
if (typeof options === 'string') {
49+
try {
50+
const convertedOptions = stringUrlToHttpOptions(options);
51+
optionsParsed = convertedOptions;
52+
pathname = convertedOptions.pathname || '/';
53+
} catch (e) {
54+
invalidUrl = true;
55+
logger.verbose(
56+
'Unable to parse URL provided to HTTP request, using fallback to determine path. Original error:',
57+
e,
58+
);
59+
// for backward compatibility with how url.parse() behaved.
60+
optionsParsed = {
61+
path: options,
62+
};
63+
pathname = optionsParsed.path || '/';
64+
}
65+
66+
origin = `${optionsParsed.protocol || 'http:'}//${optionsParsed.host}`;
67+
if (extraOptions !== undefined) {
68+
Object.assign(optionsParsed, extraOptions);
69+
}
70+
} else if (options instanceof url.URL) {
71+
optionsParsed = {
72+
protocol: options.protocol,
73+
hostname:
74+
typeof options.hostname === 'string' && options.hostname.startsWith('[')
75+
? options.hostname.slice(1, -1)
76+
: options.hostname,
77+
path: `${options.pathname || ''}${options.search || ''}`,
78+
};
79+
if (options.port !== '') {
80+
optionsParsed.port = Number(options.port);
81+
}
82+
if (options.username || options.password) {
83+
optionsParsed.auth = `${options.username}:${options.password}`;
84+
}
85+
pathname = options.pathname;
86+
origin = options.origin;
87+
if (extraOptions !== undefined) {
88+
Object.assign(optionsParsed, extraOptions);
89+
}
90+
} else {
91+
optionsParsed = Object.assign({ protocol: options.host ? 'http:' : undefined }, options);
92+
93+
const hostname =
94+
optionsParsed.host ||
95+
(optionsParsed.port != null ? `${optionsParsed.hostname}${optionsParsed.port}` : optionsParsed.hostname);
96+
origin = `${optionsParsed.protocol || 'http:'}//${hostname}`;
97+
98+
pathname = (options as url.URL).pathname;
99+
if (!pathname && optionsParsed.path) {
100+
try {
101+
const parsedUrl = new URL(optionsParsed.path, origin);
102+
pathname = parsedUrl.pathname || '/';
103+
} catch (e) {
104+
pathname = '/';
105+
}
106+
}
107+
}
108+
109+
// some packages return method in lowercase..
110+
// ensure upperCase for consistency
111+
const method = optionsParsed.method ? optionsParsed.method.toUpperCase() : 'GET';
112+
113+
return { origin, pathname, method, optionsParsed, invalidUrl };
114+
};
115+
116+
/**
117+
* Mimics Node.js conversion of URL strings to RequestOptions expected by
118+
* `http.request` and `https.request` APIs.
119+
*
120+
* See https://github.com/nodejs/node/blob/2505e217bba05fc581b572c685c5cf280a16c5a3/lib/internal/url.js#L1415-L1437
121+
*
122+
* @param stringUrl
123+
* @throws TypeError if the URL is not valid.
124+
*/
125+
function stringUrlToHttpOptions(stringUrl: string): RequestOptions & { pathname: string } {
126+
// This is heavily inspired by Node.js handling of the same situation, trying
127+
// to follow it as closely as possible while keeping in mind that we only
128+
// deal with string URLs, not URL objects.
129+
const { hostname, pathname, port, username, password, search, protocol, hash, href, origin, host } = new URL(
130+
stringUrl,
131+
);
132+
133+
const options: RequestOptions & {
134+
pathname: string;
135+
hash: string;
136+
search: string;
137+
href: string;
138+
origin: string;
139+
} = {
140+
protocol: protocol,
141+
hostname: hostname && hostname[0] === '[' ? hostname.slice(1, -1) : hostname,
142+
hash: hash,
143+
search: search,
144+
pathname: pathname,
145+
path: `${pathname || ''}${search || ''}`,
146+
href: href,
147+
origin: origin,
148+
host: host,
149+
};
150+
if (port !== '') {
151+
options.port = Number(port);
152+
}
153+
if (username || password) {
154+
options.auth = `${decodeURIComponent(username)}:${decodeURIComponent(password)}`;
155+
}
156+
return options;
157+
}

packages/node/src/sdk/initOtel.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,12 @@ export function setupOtel(client: NodeClient): BasicTracerProvider {
136136
[ATTR_SERVICE_VERSION]: SDK_VERSION,
137137
}),
138138
forceFlushTimeoutMillis: 500,
139+
spanProcessors: [
140+
new SentrySpanProcessor({
141+
timeout: client.getOptions().maxSpanWaitDuration,
142+
}),
143+
],
139144
});
140-
provider.addSpanProcessor(
141-
new SentrySpanProcessor({
142-
timeout: client.getOptions().maxSpanWaitDuration,
143-
}),
144-
);
145145

146146
// Initialize the provider
147147
provider.register({

packages/node/test/integration/transactions.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ describe('Integration | Transactions', () => {
680680

681681
expect(spans).toHaveLength(2);
682682

683-
expect(spans[0]!.description).toEqual('inner span 1');
684-
expect(spans[1]!.description).toEqual('inner span 2');
683+
expect(spans).toContainEqual(expect.objectContaining({ description: 'inner span 1' }));
684+
expect(spans).toContainEqual(expect.objectContaining({ description: 'inner span 2' }));
685685
});
686686
});

packages/opentelemetry/package.json

+8-8
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,17 @@
4343
},
4444
"peerDependencies": {
4545
"@opentelemetry/api": "^1.9.0",
46-
"@opentelemetry/core": "^1.25.1",
47-
"@opentelemetry/instrumentation": "^0.54.0",
48-
"@opentelemetry/sdk-trace-base": "^1.26.0",
49-
"@opentelemetry/semantic-conventions": "^1.27.0"
46+
"@opentelemetry/core": "^1.28.0",
47+
"@opentelemetry/instrumentation": "^0.55.0",
48+
"@opentelemetry/sdk-trace-base": "^1.28.0",
49+
"@opentelemetry/semantic-conventions": "^1.28.0"
5050
},
5151
"devDependencies": {
5252
"@opentelemetry/api": "^1.9.0",
53-
"@opentelemetry/context-async-hooks": "^1.25.1",
54-
"@opentelemetry/core": "^1.25.1",
55-
"@opentelemetry/sdk-trace-base": "^1.26.0",
56-
"@opentelemetry/semantic-conventions": "^1.27.0"
53+
"@opentelemetry/context-async-hooks": "^1.28.0",
54+
"@opentelemetry/core": "^1.28.0",
55+
"@opentelemetry/sdk-trace-base": "^1.28.0",
56+
"@opentelemetry/semantic-conventions": "^1.28.0"
5757
},
5858
"scripts": {
5959
"build": "run-p build:transpile build:types",

0 commit comments

Comments
 (0)