8000 feat: Support ReportingObserver API · rossleonardy/sentry-javascript@aa24f91 · GitHub
[go: up one dir, main page]

Skip to content

Commit aa24f91

Browse files
committed
feat: Support ReportingObserver API
1 parent 991418d commit aa24f91

File tree

4 files changed

+145
-0
lines changed

4 files changed

+145
-0
lines changed

packages/browser/src/integrations/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export { Breadcrumbs } from './breadcrumbs';
66
export { LinkedErrors } from './linkederrors';
77
export { SDKInformation } from './sdkinformation';
88
export { InboundFilters } from './inboundfilters';
9+
export { ReportingObserver } from './reportingobserver';
910

1011
export { Ember } from './pluggable/ember';
1112
export { Vue } from './pluggable/vue';
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { getCurrentHub, Scope } from '@sentry/hub';
2+
import { Integration } from '@sentry/types';
3+
import { getGlobalObject } from '@sentry/utils/misc';
4+
import { supportsReportingObserver } from '@sentry/utils/supports';
5+
6+
/** JSDoc */
7+
interface Report {
8+
[key: string]: any;
9+
type: ReportTypes;
10+
url: string;
11+
body?: ReportBody;
12+
}
13+
14+
/** JSDoc */
15+
enum ReportTypes {
16+
/** JSDoc */
17+
Crash = 'crash',
18+
/** JSDoc */
19+
Deprecation = 'deprecation',
20+
/** JSDoc */
21+
Intervention = 'intervention',
22+
}
23+
24+
/** JSDoc */
25+
type ReportBody = CrashReportBody | DeprecationReportBody | InterventionReportBody;
26+
27+
/** JSDoc */
28+
interface CrashReportBody {
29+
[key: string]: any;
30+
crashId: string;
31+
reason?: string;
32+
}
33+
34+
/** JSDoc */
35+
interface DeprecationReportBody {
36+
[key: string]: any;
37+
id: string;
38+
anticipatedRemoval?: Date;
39+
message: string;
40+
sourceFile?: string;
41+
lineNumber?: number;
42+
columnNumber?: number;
43+
}
44+
45+
/** JSDoc */
46+
interface InterventionReportBody {
47+
[key: string]: any;
48+
id: string;
49+
message: string;
50+
sourceFile?: string;
51+
lineNumber?: number;
52+
columnNumber?: number;
53+
}
< D7AE /code>
54+
55+
/** Reporting API integration - https://w3c.github.io/reporting/ */
56+
export class ReportingObserver implements Integration {
57+
/**
58+
* @inheritDoc
59+
*/
60+
public readonly name: string = 'ReportingObserver';
61+
62+
/**
63+
* @inheritDoc
64+
*/
65+
public constructor(
66+
private readonly config: {
67+
types?: ReportTypes[];
68+
} = {
69+
types: [ReportTypes.Crash, ReportTypes.Deprecation, ReportTypes.Intervention],
70+
},
71+
) {}
72+
73+
/**
74+
* @inheritDoc
75+
*/
76+
public install(): void {
77+
if (!supportsReportingObserver()) {
78+
return;
79+
}
80+
81+
const observer = new (getGlobalObject() as {
82+
ReportingObserver: any;
83+
}).ReportingObserver(this.handler.bind(this), {
84+
buffered: true,
85+
types: this.config.types,
86+
});
87+
88+
observer.observe();
89+
}
90+
91+
/**
92+
* @inheritDoc
93+
*/
94+
public handler(reports: Report[]): void {
95+
for (const report of reports) {
96+
getCurrentHub().withScope(() => {
97+
getCurrentHub().configureScope((scope: Scope) => {
98+
scope.setExtra('url', report.url);
99+
});
100+
101+
const label = `ReportingObserver [${report.type}]`;
102+
let details = 'No details available';
103+
104+
if (report.body) {
105+
// Object.keys doesn't work on ReportBody, as all properties are inheirted
106+
const plainBody: {
107+
[key: string]: any;
108+
} = {};
109+
110+
// tslint:disable-next-line:forin
111+
for (const prop in report.body) {
112+
plainBody[prop] = report.body[prop];
113+
}
114+
115+
getCurrentHub().configureScope((scope: Scope) => {
116+
scope.setExtra('body', plainBody);
117+
});
118+
119+
if (report.type === ReportTypes.Crash) {
120+
const body = report.body as CrashReportBody;
121+
details = `${body.crashId} ${body.reason}`;
122+
} else {
123+
const body = report.body as DeprecationReportBody | InterventionReportBody;
124+
details = body.message;
125+
}
126+
}
127+
128+
getCurrentHub().captureMessage(`${label}: ${details}`);
129+
});
130+
}
131+
}
132+
}

packages/browser/src/sdk.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
GlobalHandlers,
1111
InboundFilters,
1212
LinkedErrors,
13+
ReportingObserver,
1314
SDKInformation,
1415
TryCatch,
1516
} from './integrations';
@@ -21,6 +22,7 @@ export const defaultIntegrations = [
2122
new Breadcrumbs(),
2223
new GlobalHandlers(),
2324
new LinkedErrors(),
25+
new ReportingObserver(),
2426
new SDKInformation(),
2527
new InboundFilters(),
2628
];

packages/utils/src/supports.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,16 @@ export function supportsBeacon(): boolean {
103103
return 'navigator' in global && 'sendBeacon' in global.navigator;
104104
}
105105

106+
/**
107+
* Tells whether current environment supports ReportingObserver API
108+
* {@link supportsReportingObserver}.
109+
*
110+
* @returns Answer to the given question.
111+
*/
112+
export function supportsReportingObserver(): boolean {
113+
return 'ReportingObserver' in getGlobalObject();
114+
}
115+
106116
/**
107117
* Tells whether current environment supports Referrer Policy API
108118
* {@link supportsReferrerPolicy}.

0 commit comments

Comments
 (0)
0