Skip to content

Commit 8f98686

Browse files
committed
feat: Report Web Vitals metrics on pageload transactions
Web Vitals is an initiative by Google to provide unified guidance for quality signals that are essential to delivering a great user experience on the web. https://web.dev/vitals/ Instead of a manual implementation targeting the performance API directly, this commit adds metrics by using the web-vitals library. Using web-vitals allows us to easily report on all supported metrics at the cost of ~1kb in the minified @sentry/apm bundle. Core Web Vitals - Cumulative Layout Shift (CLS) - First Input Delay (FID) - Largest Contentful Paint (LCP) Other Web Vitals - First Contentful Paint (FCP) - Time to First Byte (TTFB)
1 parent 1fb0580 commit 8f98686

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

packages/apm/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"@sentry/minimal": "5.16.1",
2222
"@sentry/types": "5.16.1",
2323
"@sentry/utils": "5.16.1",
24-
"tslib": "^1.9.3"
24+
"tslib": "^1.9.3",
25+
"web-vitals": "^0.2.2"
2526
},
2627
"devDependencies": {
2728
"@types/express": "^4.17.1",

packages/apm/src/integrations/tracing.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
timestampWithMs,
1111
} from '@sentry/utils';
1212

13+
import { getLCP } from 'web-vitals';
14+
1315
import { Span as SpanClass } from '../span';
1416
import { SpanStatus } from '../spanstatus';
1517
import { Transaction } from '../transaction';
@@ -155,6 +157,9 @@ export class Tracing implements Integration {
155157

156158
private static _heartbeatCounter: number = 0;
157159

160+
/** Holds the latest LargestContentfulPaint value (it changes during page load). */
161+
private static _lcp: { [key: string]: any };
162+
158163
/**
159164
* Constructor for Tracing
160165
*
@@ -163,6 +168,16 @@ export class Tracing implements Integration {
163168
public constructor(_options?: Partial<TracingOptions>) {
164169
if (global.performance) {
165170
global.performance.mark('sentry-tracing-init');
171+
getLCP(({ entries, value }) => {
172+
const lastEntry = entries[entries.length - 1];
173+
Tracing._lcp = {
174+
// @ts-ignore
175+
elementId: lastEntry.id,
176+
// @ts-ignore
177+
elementSize: lastEntry.size,
178+
largestContentfulPaint: value,
179+
};
180+
}, true /* reportAllChanges, necessary to be able to send the last seen LCP before the pageload transaction is sent */);
166181
}
167182
const defaults = {
168183
debug: {
@@ -447,7 +462,7 @@ export class Tracing implements Integration {
447462
}
448463

449464
/**
450-
* Finshes the current active transaction
465+
* Finishes the current active transaction
451466
*/
452467
public static finishIdleTransaction(endTimestamp: number): void {
453468
const active = Tracing._activeTransaction;
@@ -505,6 +520,14 @@ export class Tracing implements Integration {
505520

506521
Tracing._log('[Tracing] Adding & adjusting spans using Performance API');
507522

523+
// FIXME: depending on the 'op' directly is brittle.
524+
if (transactionSpan.op === 'pageload') {
525+
if (Tracing._lcp) {
526+
// Set the last observed LCP score.
527+
transactionSpan.setData('_sentry_extra_metrics', JSON.stringify({ lcp: Tracing._lcp }));
528+
}
529+
}
530+
508531
const timeOrigin = Tracing._msToSec(performance.timeOrigin);
509532

510533
// tslint:disable-next-line: completed-docs

yarn.lock

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1690,11 +1690,32 @@ [email protected]:
16901690
version "0.8.2"
16911691
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
16921692

1693-
agent-base@4, agent-base@5, agent-base@6, agent-base@^4.3.0, agent-base@~4.2.0:
1693+
agent-base@4, agent-base@^4.3.0:
1694+
version "4.3.0"
1695+
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
1696+
integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
1697+
dependencies:
1698+
es6-promisify "^5.0.0"
1699+
1700+
agent-base@5:
16941701
version "5.1.1"
16951702
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
16961703
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
16971704

1705+
agent-base@6:
1706+
version "6.0.0"
1707+
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a"
1708+
integrity sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==
1709+
dependencies:
1710+
debug "4"
1711+
1712+
agent-base@~4.2.0:
1713+
version "4.2.1"
1714+
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
1715+
integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==
1716+
dependencies:
1717+
es6-promisify "^5.0.0"
1718+
16981719
agentkeepalive@^3.4.1:
16991720
version "3.5.2"
17001721
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67"
@@ -4361,6 +4382,18 @@ es-to-primitive@^1.1.1, es-to-primitive@^1.2.0:
43614382
is-date-object "^1.0.1"
43624383
is-symbol "^1.0.2"
43634384

4385+
es6-promise@^4.0.3:
4386+
version "4.2.8"
4387+
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
4388+
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
4389+
4390+
es6-promisify@^5.0.0:
4391+
version "5.0.0"
4392+
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
4393+
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
4394+
dependencies:
4395+
es6-promise "^4.0.3"
4396+
43644397
escape-html@~1.0.3:
43654398
version "1.0.3"
43664399
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@@ -11367,6 +11400,11 @@ wcwidth@^1.0.0, wcwidth@^1.0.1:
1136711400
dependencies:
1136811401
defaults "^1.0.3"
1136911402

11403+
web-vitals@^0.2.2:
11404+
version "0.2.2"
11405+
resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-0.2.2.tgz#365d361590bf1a707c484d1196bd3c69e65523e0"
11406+
integrity sha512-6xR6kxa70XXnSHV4sZMDXKPvcrUfl2xaNUN1ENedcDbvcinzlWgaDD5Hn5mAnfHfKZVlSHe2/XCXKweuRnfWqw==
11407+
1137011408
webidl-conversions@^4.0.2:
1137111409
version "4.0.2"
1137211410
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"

0 commit comments

Comments
 (0)