Skip to content

Commit 176c372

Browse files
andreiborzaLms24
andcommitted
feat(scope): Bring back lastEventId on isolation scope (#11951) (#12022)
Co-authored-by: Lukas Stracke <lukas.stracke@sentry.io>
1 parent 792a3b6 commit 176c372

File tree

19 files changed

+97
-57
lines changed

19 files changed

+97
-57
lines changed

MIGRATION.md

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ To make sure these integrations work properly you'll have to change how you
375375
### General
376376

377377
Removed top-level exports: `tracingOrigins`, `MetricsAggregator`, `metricsAggregatorIntegration`, `Severity`,
378-
`Sentry.configureScope`, `Span`, `spanStatusfromHttpCode`, `makeMain`, `lastEventId`, `pushScope`, `popScope`,
378+
`Sentry.configureScope`, `Span`, `spanStatusfromHttpCode`, `makeMain`, `pushScope`, `popScope`,
379379
`addGlobalEventProcessor`, `timestampWithMs`, `addExtensionMethods`, `addGlobalEventProcessor`, `getActiveTransaction`
380380

381381
Removed `@sentry/utils` exports: `timestampWithMs`, `addOrUpdateIntegration`, `tracingContextFromHeaders`, `walk`
@@ -389,7 +389,6 @@ Removed `@sentry/utils` exports: `timestampWithMs`, `addOrUpdateIntegration`, `t
389389
- [Removal of `Span` class export from SDK packages](./MIGRATION.md#removal-of-span-class-export-from-sdk-packages)
390390
- [Removal of `spanStatusfromHttpCode` in favour of `getSpanStatusFromHttpCode`](./MIGRATION.md#removal-of-spanstatusfromhttpcode-in-favour-of-getspanstatusfromhttpcode)
391391
- [Removal of `addGlobalEventProcessor` in favour of `addEventProcessor`](./MIGRATION.md#removal-of-addglobaleventprocessor-in-favour-of-addeventprocessor)
392-
- [Removal of `lastEventId()` method](./MIGRATION.md#deprecate-lasteventid)
393392
- [Remove `void` from transport return types](./MIGRATION.md#remove-void-from-transport-return-types)
394393
- [Remove `addGlobalEventProcessor` in favor of `addEventProcessor`](./MIGRATION.md#remove-addglobaleventprocessor-in-favor-of-addeventprocessor)
395394

@@ -568,10 +567,6 @@ Sentry.getGlobalScope().addEventProcessor(event => {
568567
});
569568
```
570569

571-
#### Removal of `lastEventId()` method
572-
573-
The `lastEventId` function has been removed. See [below](./MIGRATION.md#deprecate-lasteventid) for more details.
574-
575570
#### Removal of `void` from transport return types
576571

577572
The `send` method on the `Transport` interface now always requires a `TransportMakeRequestResponse` to be returned in
@@ -1576,7 +1571,7 @@ If you are using the `Hub` right now, see the following table on how to migrate
15761571
| captureException() | `Sentry.captureException()` |
15771572
| captureMessage() | `Sentry.captureMessage()` |
15781573
| captureEvent() | `Sentry.captureEvent()` |
1579-
| lastEventId() | REMOVED - Use event processors or beforeSend instead |
1574+
| lastEventId() | `Sentry.lastEventId()` |
15801575
| addBreadcrumb() | `Sentry.addBreadcrumb()` |
15811576
| setUser() | `Sentry.setUser()` |
15821577
| setTags() | `Sentry.setTags()` |
@@ -1697,35 +1692,6 @@ app.get('/your-route', req => {
16971692
});
16981693
```
16991694

1700-
## Deprecate `Sentry.lastEventId()` and `hub.lastEventId()`
1701-
1702-
`Sentry.lastEventId()` sometimes causes race conditions, so we are deprecating it in favour of the `beforeSend`
1703-
callback.
1704-
1705-
```js
1706-
// Before
1707-
Sentry.init({
1708-
beforeSend(event, hint) {
1709-
const lastCapturedEventId = Sentry.lastEventId();
1710-
1711-
// Do something with `lastCapturedEventId` here
1712-
1713-
return event;
1714-
},
1715-
});
1716-
1717-
// After
1718-
Sentry.init({
1719-
beforeSend(event, hint) {
1720-
const lastCapturedEventId = event.event_id;
1721-
1722-
// Do something with `lastCapturedEventId` here
1723-
1724-
return event;
1725-
},
1726-
});
1727-
```
1728-
17291695
## Deprecated fields on `Span` and `Transaction`
17301696

17311697
In v8, the Span class is heavily reworked. The following properties & methods are thus deprecated:
@@ -1793,25 +1759,6 @@ Instead, import this directly from `@sentry/utils`.
17931759
Generally, in most cases you should probably use `continueTrace` instead, which abstracts this away from you and handles
17941760
scope propagation for you.
17951761

1796-
## Deprecate `lastEventId()`
1797-
1798-
Instead, if you need the ID of a recently captured event, we recommend using `beforeSend` instead:
1799-
1800-
```ts
1801-
import * as Sentry from '@sentry/browser';
1802-
1803-
Sentry.init({
1804-
dsn: '__DSN__',
1805-
beforeSend(event, hint) {
1806-
const lastCapturedEventId = event.event_id;
1807-
1808-
// Do something with `lastCapturedEventId` here
1809-
1810-
return event;
1811-
},
1812-
});
1813-
```
1814-
18151762
## Deprecate `timestampWithMs` export - #7878
18161763

18171764
The `timestampWithMs` util is deprecated in favor of using `timestampInSeconds`.

packages/astro/src/index.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export {
4040
makeNodeTransport,
4141
getDefaultIntegrations,
4242
defaultStackParser,
43+
lastEventId,
4344
flush,
4445
close,
4546
getSentryRelease,

packages/aws-serverless/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export {
3535
makeNodeTransport,
3636
NodeClient,
3737
defaultStackParser,
38+
lastEventId,
3839
flush,
3940
close,
4041
getSentryRelease,

packages/browser/src/exports.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export {
2828
captureMessage,
2929
close,
3030
createTransport,
31+
lastEventId,
3132
flush,
3233
// eslint-disable-next-line deprecation/deprecation
3334
getCurrentHub,

packages/bun/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export {
5555
makeNodeTransport,
5656
NodeClient,
5757
defaultStackParser,
58+
lastEventId,
5859
flush,
5960
close,
6061
getSentryRelease,

packages/core/src/baseclient.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,10 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
650650

651651
this.emit('preprocessEvent', event, hint);
652652

653+
if (!event.type) {
654+
isolationScope.setLastEventId(event.event_id || hint.event_id);
655+
}
656+
653657
return prepareEvent(options, event, hint, currentScope, this, isolationScope).then(evt => {
654658
if (evt === null) {
655659
return evt;

packages/core/src/exports.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,21 @@ export function setUser(user: User | null): void {
120120
getIsolationScope().setUser(user);
121121
}
122122

123+
/**
124+
* The last error event id of the isolation scope.
125+
*
126+
* Warning: This function really returns the last recorded error event id on the current
127+
* isolation scope. If you call this function after handling a certain error and another error
128+
* is captured in between, the last one is returned instead of the one you might expect.
129+
* Also, ids of events that were never sent to Sentry (for example because
130+
* they were dropped in `beforeSend`) could be returned.
131+
*
132+
* @returns The last event id of the isolation scope.
133+
*/
134+
export function lastEventId(): string | undefined {
135+
return getIsolationScope().lastEventId();
136+
}
137+
123138
/**
124139
* Create a cron monitor check in and send it to Sentry.
125140
*

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export {
1515
captureException,
1616
captureEvent,
1717
captureMessage,
18+
lastEventId,
1819
close,
1920
flush,
2021
setContext,

packages/core/src/scope.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ export class Scope implements ScopeInterface {
9494
/** The client on this scope */
9595
protected _client?: Client;
9696

97+
/** Contains the last event id of a captured event. */
98+
protected _lastEventId?: string;
99+
97100
// NOTE: Any field which gets added here should get added not only to the constructor but also to the `clone` method.
98101

99102
public constructor() {
@@ -130,6 +133,7 @@ export class Scope implements ScopeInterface {
130133
newScope._sdkProcessingMetadata = { ...this._sdkProcessingMetadata };
131134
newScope._propagationContext = { ...this._propagationContext };
132135
newScope._client = this._client;
136+
newScope._lastEventId = this._lastEventId;
133137

134138
_setSpanForScope(newScope, _getSpanForScope(this));
135139

@@ -143,13 +147,27 @@ export class Scope implements ScopeInterface {
143147
this._client = client;
144148
}
145149

150+
/**
151+
* @inheritDoc
152+
*/
153+
public setLastEventId(lastEventId: string | undefined): void {
154+
this._lastEventId = lastEventId;
155+
}
156+
146157
/**
147158
* @inheritDoc
148159
*/
149160
public getClient<C extends Client>(): C | undefined {
150161
return this._client as C | undefined;
151162
}
152163

164+
/**
165+
* @inheritDoc
166+
*/
167+
public lastEventId(): string | undefined {
168+
return this._lastEventId;
169+
}
170+
153171
/**
154172
* @inheritDoc
155173
*/

packages/core/test/lib/base.test.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import type { Client, Envelope, ErrorEvent, Event, TransactionEvent } from '@sentry/types';
22
import { SentryError, SyncPromise, dsnToString, logger } from '@sentry/utils';
33

4-
import { Scope, addBreadcrumb, getCurrentScope, getIsolationScope, makeSession, setCurrentClient } from '../../src';
4+
import {
5+
Scope,
6+
addBreadcrumb,
7+
getCurrentScope,
8+
getIsolationScope,
9+
lastEventId,
10+
makeSession,
11+
setCurrentClient,
12+
} from '../../src';
513
import * as integrationModule from '../../src/integration';
614
import { TestClient, getDefaultTestClientOptions } from '../mocks/client';
715
import { AdHocIntegration, TestIntegration } from '../mocks/integration';
@@ -226,7 +234,6 @@ describe('BaseClient', () => {
226234
const client = new TestClient(options);
227235

228236
client.captureException(new Error('test exception'));
229-
230237
expect(TestClient.instance!.event).toEqual(
231238
expect.objectContaining({
232239
environment: 'production',
@@ -244,6 +251,14 @@ describe('BaseClient', () => {
244251
);
245252
});
246253

254+
test('sets the correct lastEventId', () => {
255+
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
256+
const client = new TestClient(options);
257+
258+
const eventId = client.captureException(new Error('test exception'));
259+
expect(eventId).toEqual(lastEventId());
260+
});
261+
247262
test('allows for providing explicit scope', () => {
248263
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
249264
const client = new TestClient(options);
@@ -343,6 +358,14 @@ describe('BaseClient', () => {
343358
);
344359
});
345360

361+
test('sets the correct lastEventId', () => {
362+
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
363+
const client = new TestClient(options);
364+
365+
const eventId = client.captureMessage('test message');
366+
expect(eventId).toEqual(lastEventId());
367+
});
368+
346369
test('should call `eventFromException` if input to `captureMessage` is not a primitive', () => {
347370
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
348371
const client = new TestClient(options);
@@ -444,6 +467,14 @@ describe('BaseClient', () => {
444467
);
445468
});
446469

470+
test('sets the correct lastEventId', () => {
471+
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN });
472+
const client = new TestClient(options);
473+
474+
const eventId = client.captureEvent({ message: 'message' }, undefined);
475+
expect(eventId).toEqual(lastEventId());
476+
});
477+
447478
test('does not overwrite existing timestamp', () => {
448479
expect.assertions(2);
449480

packages/deno/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export {
3030
close,
3131
createTransport,
3232
continueTrace,
33+
lastEventId,
3334
flush,
3435
getClient,
3536
isInitialized,

packages/google-cloud-serverless/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export {
3535
makeNodeTransport,
3636
NodeClient,
3737
defaultStackParser,
38+
lastEventId,
3839
flush,
3940
close,
4041
getSentryRelease,

packages/node/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export {
5757
addBreadcrumb,
5858
isInitialized,
5959
getGlobalScope,
60+
lastEventId,
6061
close,
6162
createTransport,
6263
flush,

packages/remix/src/index.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export {
4343
makeNodeTransport,
4444
getDefaultIntegrations,
4545
defaultStackParser,
46+
lastEventId,
4647
flush,
4748
close,
4849
getSentryRelease,

packages/remix/src/index.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ export declare const continueTrace: typeof clientSdk.continueTrace;
3030

3131
export const close = runtime === 'client' ? clientSdk.close : serverSdk.close;
3232
export const flush = runtime === 'client' ? clientSdk.flush : serverSdk.flush;
33+
export const lastEventId = runtime === 'client' ? clientSdk.lastEventId : serverSdk.lastEventId;
3334

3435
export declare const metrics: typeof clientSdk.metrics & typeof serverSdk.metrics;

packages/sveltekit/src/index.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export declare const getCurrentHub: typeof clientSdk.getCurrentHub;
4848

4949
export declare function close(timeout?: number | undefined): PromiseLike<boolean>;
5050
export declare function flush(timeout?: number | undefined): PromiseLike<boolean>;
51+
export declare function lastEventId(): string | undefined;
5152

5253
export declare const continueTrace: typeof clientSdk.continueTrace;
5354

packages/sveltekit/src/server/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export {
3636
makeNodeTransport,
3737
getDefaultIntegrations,
3838
defaultStackParser,
39+
lastEventId,
3940
flush,
4041
close,
4142
getSentryRelease,

packages/types/src/scope.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ export interface Scope {
5959
*/
6060
getClient<C extends Client>(): C | undefined;
6161

62+
/**
63+
* Sets the last event id on the scope.
64+
* @param lastEventId The last event id of a captured event.
65+
*/
66+
setLastEventId(lastEventId: string | undefined): void;
67+
68+
/**
69+
* This is the getter for lastEventId.
70+
* @returns The last event id of a captured event.
71+
*/
72+
lastEventId(): string | undefined;
73+
6274
/**
6375
* Add internal on change listener. Used for sub SDKs that need to store the scope.
6476
* @hidden

packages/vercel-edge/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export {
3030
captureFeedback,
3131
close,
3232
createTransport,
33+
lastEventId,
3334
flush,
3435
getClient,
3536
isInitialized,

0 commit comments

Comments
 (0)