Skip to content

Commit 5a8e33b

Browse files
authored
Merge pull request #8808 from getsentry/prepare-release/7.64.0
2 parents 7ac0000 + 81fbc01 commit 5a8e33b

File tree

20 files changed

+143
-19
lines changed

20 files changed

+143
-19
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7+
## 7.64.0
8+
9+
- feat(core): Add setMeasurement export (#8791)
10+
- fix(nextjs): Check for existence of default export when wrapping pages (#8794)
11+
- fix(nextjs): Ensure imports are valid relative paths (#8799)
12+
- fix(nextjs): Only re-export default export if it exists (#8800)
13+
714
## 7.63.0
815

916
- build(deps): bump @opentelemetry/instrumentation from 0.41.0 to 0.41.2

packages/browser/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export {
2929
export type { RequestInstrumentationOptions } from '@sentry-internal/tracing';
3030
export {
3131
addTracingExtensions,
32+
setMeasurement,
3233
extractTraceparentData,
3334
getActiveTransaction,
3435
spanStatusfromHttpCode,

packages/core/src/tracing/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export { SpanStatus } from './spanstatus';
88
export type { SpanStatusType } from './span';
99
export { trace } from './trace';
1010
export { getDynamicSamplingContextFromClient } from './dynamicSamplingContext';
11+
export { setMeasurement } from './measurement';
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { MeasurementUnit } from '@sentry/types';
2+
3+
import { getActiveTransaction } from './utils';
4+
5+
/**
6+
* Adds a measurement to the current active transaction.
7+
*/
8+
export function setMeasurement(name: string, value: number, unit: MeasurementUnit): void {
9+
const transaction = getActiveTransaction();
10+
if (transaction) {
11+
transaction.setMeasurement(name, value, unit);
12+
}
13+
}

packages/core/src/tracing/span.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ export class Span implements SpanInterface {
152152
if (spanContext.description) {
153153
this.description = spanContext.description;
154154
}
155+
if (spanContext.name) {
156+
this.description = spanContext.name;
157+
}
155158
if (spanContext.data) {
156159
this.data = spanContext.data;
157160
}
@@ -243,6 +246,13 @@ export class Span implements SpanInterface {
243246
return this;
244247
}
245248

249+
/**
250+
* @inheritDoc
251+
*/
252+
public setName(name: string): void {
253+
this.description = name;
254+
}
255+
246256
/**
247257
* @inheritDoc
248258
*/

packages/core/src/tracing/transaction.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export class Transaction extends SpanClass implements TransactionInterface {
4444
*/
4545
public constructor(transactionContext: TransactionContext, hub?: Hub) {
4646
super(transactionContext);
47+
// We need to delete description since it's set by the Span class constructor
48+
// but not needed for transactions.
49+
delete this.description;
4750

4851
this._measurements = {};
4952
this._contexts = {};

packages/nextjs/src/config/loaders/wrappingLoader.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,12 @@ export default function wrappingLoader(
9696
const sentryConfigImportPath = path
9797
.relative(path.dirname(this.resourcePath), sentryConfigFilePath)
9898
.replace(/\\/g, '/');
99-
templateCode = templateCode.replace(/__SENTRY_CONFIG_IMPORT_PATH__/g, sentryConfigImportPath);
99+
100+
// path.relative() may return something like `sentry.server.config.js` which is not allowed. Imports from the
101+
// current directory need to start with './'.This is why we prepend the path with './', which should always again
102+
// be a valid relative path.
103+
// https://github.com/getsentry/sentry-javascript/issues/8798
104+
templateCode = templateCode.replace(/__SENTRY_CONFIG_IMPORT_PATH__/g, `./${sentryConfigImportPath}`);
100105
} else {
101106
// Bail without doing any wrapping
102107
this.callback(null, userCode, userModuleSourceMap);

packages/nextjs/src/config/templates/pageWrapperTemplate.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ import * as Sentry from '@sentry/nextjs';
1414
import type { GetServerSideProps, GetStaticProps, NextPage as NextPageComponent } from 'next';
1515

1616
type NextPageModule = {
17-
default: { getInitialProps?: NextPageComponent['getInitialProps'] };
17+
default?: { getInitialProps?: NextPageComponent['getInitialProps'] };
1818
getStaticProps?: GetStaticProps;
1919
getServerSideProps?: GetServerSideProps;
2020
};
2121

2222
const userPageModule = wrapee as NextPageModule;
2323

24-
const pageComponent = userPageModule.default;
24+
const pageComponent = userPageModule ? userPageModule.default : undefined;
2525

26-
const origGetInitialProps = pageComponent.getInitialProps;
27-
const origGetStaticProps = userPageModule.getStaticProps;
28-
const origGetServerSideProps = userPageModule.getServerSideProps;
26+
const origGetInitialProps = pageComponent ? pageComponent.getInitialProps : undefined;
27+
const origGetStaticProps = userPageModule ? userPageModule.getStaticProps : undefined;
28+
const origGetServerSideProps = userPageModule ? userPageModule.getServerSideProps : undefined;
2929

3030
const getInitialPropsWrappers: Record<string, any> = {
3131
'/_app': Sentry.wrapAppGetInitialPropsWithSentry,
@@ -35,7 +35,7 @@ const getInitialPropsWrappers: Record<string, any> = {
3535

3636
const getInitialPropsWrapper = getInitialPropsWrappers['__ROUTE__'] || Sentry.wrapGetInitialPropsWithSentry;
3737

38-
if (typeof origGetInitialProps === 'function') {
38+
if (pageComponent && typeof origGetInitialProps === 'function') {
3939
pageComponent.getInitialProps = getInitialPropsWrapper(origGetInitialProps) as NextPageComponent['getInitialProps'];
4040
}
4141

packages/nextjs/src/config/templates/sentryInitWrapperTemplate.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@ import '__SENTRY_CONFIG_IMPORT_PATH__';
44

55
// @ts-ignore This is the file we're wrapping
66
// eslint-disable-next-line import/no-unresolved
7-
export * from '__SENTRY_WRAPPING_TARGET_FILE__';
7+
import * as wrappee from '__SENTRY_WRAPPING_TARGET_FILE__';
8+
9+
// @ts-ignore default either exists, or it doesn't - we don't care
10+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
11+
const defaultExport = wrappee.default;
812

913
// @ts-ignore This is the file we're wrapping
1014
// eslint-disable-next-line import/no-unresolved
11-
export { default } from '__SENTRY_WRAPPING_TARGET_FILE__';
15+
export * from '__SENTRY_WRAPPING_TARGET_FILE__';
16+
17+
export default defaultExport;

packages/node-integration-tests/suites/tracing-new/prisma-orm/test.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,21 @@ conditionalTest({ min: 12 })('Prisma ORM Integration', () => {
88
assertSentryTransaction(envelope[2], {
99
transaction: 'Test Transaction',
1010
spans: [
11-
{ description: 'User create', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
12-
{ description: 'User findMany', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
13-
{ description: 'User deleteMany', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
11+
{
12+
description: 'User create',
13+
op: 'db.sql.prisma',
14+
data: { 'db.system': 'postgresql', 'db.operation': 'create', 'db.prisma.version': '3.12.0' },
15+
},
16+
{
17+
description: 'User findMany',
18+
op: 'db.sql.prisma',
19+
data: { 'db.system': 'postgresql', 'db.operation': 'findMany', 'db.prisma.version': '3.12.0' },
20+
},
21+
{
22+
description: 'User deleteMany',
23+
op: 'db.sql.prisma',
24+
data: { 'db.system': 'postgresql', 'db.operation': 'deleteMany', 'db.prisma.version': '3.12.0' },
25+
},
1426
],
1527
});
1628
});

packages/node-integration-tests/suites/tracing/prisma-orm/test.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,21 @@ conditionalTest({ min: 12 })('Prisma ORM Integration', () => {
88
assertSentryTransaction(envelope[2], {
99
transaction: 'Test Transaction',
1010
spans: [
11-
{ description: 'User create', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
12-
{ description: 'User findMany', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
13-
{ description: 'User deleteMany', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
11+
{
12+
description: 'User create',
13+
op: 'db.sql.prisma',
14+
data: { 'db.system': 'postgresql', 'db.operation': 'create', 'db.prisma.version': '3.12.0' },
15+
},
16+
{
17+
description: 'User findMany',
18+
op: 'db.sql.prisma',
19+
data: { 'db.system': 'postgresql', 'db.operation': 'findMany', 'db.prisma.version': '3.12.0' },
20+
},
21+
{
22+
description: 'User deleteMany',
23+
op: 'db.sql.prisma',
24+
data: { 'db.system': 'postgresql', 'db.operation': 'deleteMany', 'db.prisma.version': '3.12.0' },
25+
},
1426
],
1527
});
1628
});

packages/node/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export {
5454
trace,
5555
withScope,
5656
captureCheckIn,
57+
setMeasurement,
5758
} from '@sentry/core';
5859
export type { SpanStatusType } from '@sentry/core';
5960
export { autoDiscoverNodePerformanceMonitoringIntegrations } from './tracing';

packages/serverless/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,5 @@ export {
4949
deepReadDirSync,
5050
Handlers,
5151
Integrations,
52+
setMeasurement,
5253
} from '@sentry/node';

packages/sveltekit/src/server/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export {
4444
deepReadDirSync,
4545
Integrations,
4646
Handlers,
47+
setMeasurement,
4748
} from '@sentry/node';
4849

4950
// We can still leave this for the carrier init and type exports

packages/sveltekit/test/server/handle.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ describe('handleSentry', () => {
201201
expect(ref.spanRecorder.spans).toHaveLength(2);
202202
expect(ref.spanRecorder.spans).toEqual(
203203
expect.arrayContaining([
204-
expect.objectContaining({ op: 'http.server', description: 'GET /users/[id]' }),
204+
expect.objectContaining({ op: 'http.server', name: 'GET /users/[id]' }),
205205
expect.objectContaining({ op: 'http.server', description: 'GET api/users/details/[id]' }),
206206
]),
207207
);

packages/tracing-internal/src/node/integrations/prisma.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ type PrismaMiddleware<T = unknown> = (
3636

3737
interface PrismaClient {
3838
_sentryInstrumented?: boolean;
39+
_engineConfig?: {
40+
activeProvider?: string;
41+
clientVersion?: string;
42+
};
3943
$use: (cb: PrismaMiddleware) => void;
4044
}
4145

@@ -70,15 +74,36 @@ export class Prisma implements Integration {
7074
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7175
addNonEnumerableProperty(options.client as any, '_sentryInstrumented', true);
7276

77+
const clientData: Record<string, string | number> = {};
78+
try {
79+
const engineConfig = (options.client as PrismaClient)._engineConfig;
80+
if (engineConfig) {
81+
const { activeProvider, clientVersion } = engineConfig;
82+
if (activeProvider) {
83+
clientData['db.system'] = activeProvider;
84+
}
85+
if (clientVersion) {
86+
clientData['db.prisma.version'] = clientVersion;
87+
}
88+
}
89+
} catch (e) {
90+
// ignore
91+
}
92+
7393
options.client.$use((params, next: (params: PrismaMiddlewareParams) => Promise<unknown>) => {
7494
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
7595
return next(params);
7696
}
7797

7898
const action = params.action;
7999
const model = params.model;
100+
80101
return trace(
81-
{ name: model ? `${model} ${action}` : action, op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
102+
{
103+
name: model ? `${model} ${action}` : action,
104+
op: 'db.sql.prisma',
105+
data: { ...clientData, 'db.operation': action },
106+
},
82107
() => next(params),
83108
);
84109
});

packages/tracing/test/integrations/node/prisma.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ class PrismaClient {
2525
create: () => this._middleware?.({ action: 'create', model: 'user' }, () => Promise.resolve('result')),
2626
};
2727

28+
public _engineConfig = {
29+
activeProvider: 'postgresql',
30+
clientVersion: '3.1.2',
31+
};
32+
2833
private _middleware?: PrismaMiddleware;
2934

3035
constructor() {
@@ -48,7 +53,11 @@ describe('setupOnce', function () {
4853
void prismaClient.user.create()?.then(() => {
4954
expect(mockTrace).toHaveBeenCalledTimes(1);
5055
expect(mockTrace).toHaveBeenLastCalledWith(
51-
{ name: 'user create', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
56+
{
57+
name: 'user create',
58+
op: 'db.sql.prisma',
59+
data: { 'db.system': 'postgresql', 'db.prisma.version': '3.1.2', 'db.operation': 'create' },
60+
},
5261
expect.any(Function),
5362
);
5463
done();

packages/tracing/test/span.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ describe('Span', () => {
8282
span.setData('foo', true);
8383
expect(span.data.foo).toBe(true);
8484
});
85+
86+
test('setName', () => {
87+
const span = new Span({});
88+
expect(span.description).toBeUndefined();
89+
span.setName('foo');
90+
expect(span.description).toBe('foo');
91+
});
8592
});
8693

8794
describe('status', () => {

packages/types/src/span.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ export interface SpanContext {
99
*/
1010
description?: string;
1111

12+
/**
13+
* Human-readable identifier for the span. Alias for span.description.
14+
*/
15+
name?: string;
16+
1217
/**
1318
* Operation of the Span.
1419
*/
@@ -139,6 +144,11 @@ export interface Span extends SpanContext {
139144
*/
140145
setHttpStatus(httpStatus: number): this;
141146

147+
/**
148+
* Set the name of the span.
149+
*/
150+
setName(name: string): void;
151+
142152
/**
143153
* Creates a new `Span` while setting the current `Span.id` as `parentSpanId`.
144154
* Also the `sampled` decision will be inherited.

packages/types/src/transaction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export type TraceparentData = Pick<TransactionContext, 'traceId' | 'parentSpanId
4242
/**
4343
* Transaction "Class", inherits Span only has `setName`
4444
*/
45-
export interface Transaction extends TransactionContext, Span {
45+
export interface Transaction extends TransactionContext, Omit<Span, 'setName' | 'name'> {
4646
/**
4747
* @inheritDoc
4848
*/

0 commit comments

Comments
 (0)