Skip to content

meta(changelog): Update changelog for 7.64.0 #8808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 14, 2023
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

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

## 7.64.0

- feat(core): Add setMeasurement export (#8791)
- fix(nextjs): Check for existence of default export when wrapping pages (#8794)
- fix(nextjs): Ensure imports are valid relative paths (#8799)
- fix(nextjs): Only re-export default export if it exists (#8800)

## 7.63.0

- build(deps): bump @opentelemetry/instrumentation from 0.41.0 to 0.41.2
Expand Down
1 change: 1 addition & 0 deletions packages/browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export {
export type { RequestInstrumentationOptions } from '@sentry-internal/tracing';
export {
addTracingExtensions,
setMeasurement,
extractTraceparentData,
getActiveTransaction,
spanStatusfromHttpCode,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/tracing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export { SpanStatus } from './spanstatus';
export type { SpanStatusType } from './span';
export { trace } from './trace';
export { getDynamicSamplingContextFromClient } from './dynamicSamplingContext';
export { setMeasurement } from './measurement';
13 changes: 13 additions & 0 deletions packages/core/src/tracing/measurement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { MeasurementUnit } from '@sentry/types';

import { getActiveTransaction } from './utils';

/**
* Adds a measurement to the current active transaction.
*/
export function setMeasurement(name: string, value: number, unit: MeasurementUnit): void {
const transaction = getActiveTransaction();
if (transaction) {
transaction.setMeasurement(name, value, unit);
}
}
10 changes: 10 additions & 0 deletions packages/core/src/tracing/span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ export class Span implements SpanInterface {
if (spanContext.description) {
this.description = spanContext.description;
}
if (spanContext.name) {
this.description = spanContext.name;
}
if (spanContext.data) {
this.data = spanContext.data;
}
Expand Down Expand Up @@ -243,6 +246,13 @@ export class Span implements SpanInterface {
return this;
}

/**
* @inheritDoc
*/
public setName(name: string): void {
this.description = name;
}

/**
* @inheritDoc
*/
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/tracing/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export class Transaction extends SpanClass implements TransactionInterface {
*/
public constructor(transactionContext: TransactionContext, hub?: Hub) {
super(transactionContext);
// We need to delete description since it's set by the Span class constructor
// but not needed for transactions.
delete this.description;

this._measurements = {};
this._contexts = {};
Expand Down
7 changes: 6 additions & 1 deletion packages/nextjs/src/config/loaders/wrappingLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ export default function wrappingLoader(
const sentryConfigImportPath = path
.relative(path.dirname(this.resourcePath), sentryConfigFilePath)
.replace(/\\/g, '/');
templateCode = templateCode.replace(/__SENTRY_CONFIG_IMPORT_PATH__/g, sentryConfigImportPath);

// path.relative() may return something like `sentry.server.config.js` which is not allowed. Imports from the
// current directory need to start with './'.This is why we prepend the path with './', which should always again
// be a valid relative path.
// https://github.com/getsentry/sentry-javascript/issues/8798
templateCode = templateCode.replace(/__SENTRY_CONFIG_IMPORT_PATH__/g, `./${sentryConfigImportPath}`);
} else {
// Bail without doing any wrapping
this.callback(null, userCode, userModuleSourceMap);
Expand Down
12 changes: 6 additions & 6 deletions packages/nextjs/src/config/templates/pageWrapperTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ import * as Sentry from '@sentry/nextjs';
import type { GetServerSideProps, GetStaticProps, NextPage as NextPageComponent } from 'next';

type NextPageModule = {
default: { getInitialProps?: NextPageComponent['getInitialProps'] };
default?: { getInitialProps?: NextPageComponent['getInitialProps'] };
getStaticProps?: GetStaticProps;
getServerSideProps?: GetServerSideProps;
};

const userPageModule = wrapee as NextPageModule;

const pageComponent = userPageModule.default;
const pageComponent = userPageModule ? userPageModule.default : undefined;

const origGetInitialProps = pageComponent.getInitialProps;
const origGetStaticProps = userPageModule.getStaticProps;
const origGetServerSideProps = userPageModule.getServerSideProps;
const origGetInitialProps = pageComponent ? pageComponent.getInitialProps : undefined;
const origGetStaticProps = userPageModule ? userPageModule.getStaticProps : undefined;
const origGetServerSideProps = userPageModule ? userPageModule.getServerSideProps : undefined;

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

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

if (typeof origGetInitialProps === 'function') {
if (pageComponent && typeof origGetInitialProps === 'function') {
pageComponent.getInitialProps = getInitialPropsWrapper(origGetInitialProps) as NextPageComponent['getInitialProps'];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ import '__SENTRY_CONFIG_IMPORT_PATH__';

// @ts-ignore This is the file we're wrapping
// eslint-disable-next-line import/no-unresolved
export * from '__SENTRY_WRAPPING_TARGET_FILE__';
import * as wrappee from '__SENTRY_WRAPPING_TARGET_FILE__';

// @ts-ignore default either exists, or it doesn't - we don't care
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const defaultExport = wrappee.default;

// @ts-ignore This is the file we're wrapping
// eslint-disable-next-line import/no-unresolved
export { default } from '__SENTRY_WRAPPING_TARGET_FILE__';
export * from '__SENTRY_WRAPPING_TARGET_FILE__';

export default defaultExport;
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@ conditionalTest({ min: 12 })('Prisma ORM Integration', () => {
assertSentryTransaction(envelope[2], {
transaction: 'Test Transaction',
spans: [
{ description: 'User create', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
{ description: 'User findMany', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
{ description: 'User deleteMany', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
{
description: 'User create',
op: 'db.sql.prisma',
data: { 'db.system': 'postgresql', 'db.operation': 'create', 'db.prisma.version': '3.12.0' },
},
{
description: 'User findMany',
op: 'db.sql.prisma',
data: { 'db.system': 'postgresql', 'db.operation': 'findMany', 'db.prisma.version': '3.12.0' },
},
{
description: 'User deleteMany',
op: 'db.sql.prisma',
data: { 'db.system': 'postgresql', 'db.operation': 'deleteMany', 'db.prisma.version': '3.12.0' },
},
],
});
});
Expand Down
18 changes: 15 additions & 3 deletions packages/node-integration-tests/suites/tracing/prisma-orm/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@ conditionalTest({ min: 12 })('Prisma ORM Integration', () => {
assertSentryTransaction(envelope[2], {
transaction: 'Test Transaction',
spans: [
{ description: 'User create', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
{ description: 'User findMany', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
{ description: 'User deleteMany', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
{
description: 'User create',
op: 'db.sql.prisma',
data: { 'db.system': 'postgresql', 'db.operation': 'create', 'db.prisma.version': '3.12.0' },
},
{
description: 'User findMany',
op: 'db.sql.prisma',
data: { 'db.system': 'postgresql', 'db.operation': 'findMany', 'db.prisma.version': '3.12.0' },
},
{
description: 'User deleteMany',
op: 'db.sql.prisma',
data: { 'db.system': 'postgresql', 'db.operation': 'deleteMany', 'db.prisma.version': '3.12.0' },
},
],
});
});
Expand Down
1 change: 1 addition & 0 deletions packages/node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export {
trace,
withScope,
captureCheckIn,
setMeasurement,
} from '@sentry/core';
export type { SpanStatusType } from '@sentry/core';
export { autoDiscoverNodePerformanceMonitoringIntegrations } from './tracing';
Expand Down
1 change: 1 addition & 0 deletions packages/serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,5 @@ export {
deepReadDirSync,
Handlers,
Integrations,
setMeasurement,
} from '@sentry/node';
1 change: 1 addition & 0 deletions packages/sveltekit/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export {
deepReadDirSync,
Integrations,
Handlers,
setMeasurement,
} from '@sentry/node';

// We can still leave this for the carrier init and type exports
Expand Down
2 changes: 1 addition & 1 deletion packages/sveltekit/test/server/handle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ describe('handleSentry', () => {
expect(ref.spanRecorder.spans).toHaveLength(2);
expect(ref.spanRecorder.spans).toEqual(
expect.arrayContaining([
expect.objectContaining({ op: 'http.server', description: 'GET /users/[id]' }),
expect.objectContaining({ op: 'http.server', name: 'GET /users/[id]' }),
expect.objectContaining({ op: 'http.server', description: 'GET api/users/details/[id]' }),
]),
);
Expand Down
27 changes: 26 additions & 1 deletion packages/tracing-internal/src/node/integrations/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ type PrismaMiddleware<T = unknown> = (

interface PrismaClient {
_sentryInstrumented?: boolean;
_engineConfig?: {
activeProvider?: string;
clientVersion?: string;
};
$use: (cb: PrismaMiddleware) => void;
}

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

const clientData: Record<string, string | number> = {};
try {
const engineConfig = (options.client as PrismaClient)._engineConfig;
if (engineConfig) {
const { activeProvider, clientVersion } = engineConfig;
if (activeProvider) {
clientData['db.system'] = activeProvider;
}
if (clientVersion) {
clientData['db.prisma.version'] = clientVersion;
}
}
} catch (e) {
// ignore
}

options.client.$use((params, next: (params: PrismaMiddlewareParams) => Promise<unknown>) => {
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
return next(params);
}

const action = params.action;
const model = params.model;

return trace(
{ name: model ? `${model} ${action}` : action, op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
{
name: model ? `${model} ${action}` : action,
op: 'db.sql.prisma',
data: { ...clientData, 'db.operation': action },
},
() => next(params),
);
});
Expand Down
11 changes: 10 additions & 1 deletion packages/tracing/test/integrations/node/prisma.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ class PrismaClient {
create: () => this._middleware?.({ action: 'create', model: 'user' }, () => Promise.resolve('result')),
};

public _engineConfig = {
activeProvider: 'postgresql',
clientVersion: '3.1.2',
};

private _middleware?: PrismaMiddleware;

constructor() {
Expand All @@ -48,7 +53,11 @@ describe('setupOnce', function () {
void prismaClient.user.create()?.then(() => {
expect(mockTrace).toHaveBeenCalledTimes(1);
expect(mockTrace).toHaveBeenLastCalledWith(
{ name: 'user create', op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
{
name: 'user create',
op: 'db.sql.prisma',
data: { 'db.system': 'postgresql', 'db.prisma.version': '3.1.2', 'db.operation': 'create' },
},
expect.any(Function),
);
done();
Expand Down
7 changes: 7 additions & 0 deletions packages/tracing/test/span.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ describe('Span', () => {
span.setData('foo', true);
expect(span.data.foo).toBe(true);
});

test('setName', () => {
const span = new Span({});
expect(span.description).toBeUndefined();
span.setName('foo');
expect(span.description).toBe('foo');
});
});

describe('status', () => {
Expand Down
10 changes: 10 additions & 0 deletions packages/types/src/span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ export interface SpanContext {
*/
description?: string;

/**
* Human-readable identifier for the span. Alias for span.description.
*/
name?: string;

/**
* Operation of the Span.
*/
Expand Down Expand Up @@ -139,6 +144,11 @@ export interface Span extends SpanContext {
*/
setHttpStatus(httpStatus: number): this;

/**
* Set the name of the span.
*/
setName(name: string): void;

/**
* Creates a new `Span` while setting the current `Span.id` as `parentSpanId`.
* Also the `sampled` decision will be inherited.
Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export type TraceparentData = Pick<TransactionContext, 'traceId' | 'parentSpanId
/**
* Transaction "Class", inherits Span only has `setName`
*/
export interface Transaction extends TransactionContext, Span {
export interface Transaction extends TransactionContext, Omit<Span, 'setName' | 'name'> {
/**
* @inheritDoc
*/
Expand Down