Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/db/migrations/004_sentry_sdk_init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- Sentry SDK init duration, sourced from the test app's User Timing API.
--
-- The instrumented apps emit a `performance.measure('sentry-sdk-init-duration')`
-- spanning SDK initialisation. Lighthouse surfaces it in the `user-timings`
-- audit, and the worker denormalises the measure's duration here (like the
-- other scalar metrics) so the publisher can ship it to Sentry.
--
-- NULL means the measure was absent from the run (e.g. no-sentry cells, or the
-- mark fired after Lighthouse's trace window closed).

ALTER TABLE runs ADD COLUMN sentry_sdk_init_ms INTEGER;
16 changes: 15 additions & 1 deletion src/publisher/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function pickUnpublishedCells() {
function loadRunsForCell(cellId) {
return getDb().prepare(`
SELECT run_id, run_index, performance_score, lcp_ms, fcp_ms, tbt_ms,
cls, total_bytes, collected_at
cls, total_bytes, sentry_sdk_init_ms, collected_at
FROM runs WHERE cell_id = ? ORDER BY run_index
`).all(cellId);
}
Expand Down Expand Up @@ -147,6 +147,11 @@ function emitRunMetrics(run, baseAttrs) {
// to a string-typed field and refuse to compute p50/p90 over it. Score
// and CLS therefore both go through the numeric path below.

// collect number of runs as a metric (only as attributes doesn't allow for visualization in Sentry)
Sentry.metrics.count('lighthouse.run.completed', 1, {
attributes: attrs,
});

if (run.performance_score != null) {
// LHR scores are 0..1 floats; Lighthouse's own UI shows them as 0..100.
// We multiply here so Sentry dashboards render '78%' instead of '0.78'
Expand Down Expand Up @@ -188,4 +193,13 @@ function emitRunMetrics(run, baseAttrs) {
attributes: attrs,
});
}
if (run.sentry_sdk_init_ms != null) {
// `performance.measure('sentry-sdk-init-duration')` from the instrumented
// test app, surfaced by Lighthouse's user-timings audit. Null for
// no-sentry cells, so the dashboard only sees it where it's meaningful.
Sentry.metrics.distribution('lighthouse.sentry_sdk_init', run.sentry_sdk_init_ms, {
unit: 'millisecond',
attributes: attrs,
});
}
}
14 changes: 14 additions & 0 deletions src/worker/lighthouse.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,19 @@ export function extractMetrics(lhr) {
tbtMs: round(audit('total-blocking-time')),
cls: audit('cumulative-layout-shift'),
bytes: round(audit('total-byte-weight')),
sentrySdkInitMs: round(userTimingMeasure(lhr, 'sentry-sdk-init-duration')),
};
}

/**
* Pull a single `performance.measure()` duration (ms) out of Lighthouse's
* `user-timings` audit by name. Returns null if the measure isn't present —
* which happens for no-sentry cells, or if the measure fired after the trace
* window closed. Only `timingType: 'Measure'` entries carry a duration; marks
* are ignored.
*/
function userTimingMeasure(lhr, name) {
const items = lhr?.audits?.['user-timings']?.details?.items ?? [];
const measure = items.find(i => i.name === name && i.timingType === 'Measure');
return measure?.duration ?? null;
}
4 changes: 3 additions & 1 deletion src/worker/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,9 @@ function writeRunsToDb({ cell, persisted }) {
INSERT INTO runs (
run_id, cell_id, run_index, is_representative,
performance_score, lcp_ms, fcp_ms, tbt_ms, cls, total_bytes,
sentry_sdk_init_ms,
lhr_json_path, report_html_path, collected_at
) VALUES (?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?)
) VALUES (?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
const completedIso = new Date().toISOString();

Expand All @@ -237,6 +238,7 @@ function writeRunsToDb({ cell, persisted }) {
r.runId, cell.cell_id, r.runIndex,
r.metrics.score, r.metrics.lcpMs, r.metrics.fcpMs, r.metrics.tbtMs,
r.metrics.cls, r.metrics.bytes,
r.metrics.sentrySdkInitMs,
r.jsonPath, r.htmlPath, completedIso,
);
}
Expand Down
Loading