Merge pull request #22233 from dannon/feature/sentry-upgrade

Upgrade Sentry JS SDK to v10, add opt-in session replay
This commit is contained in:
Marius van den Beek
2026-03-28 11:10:49 +01:00
committed by GitHub
10 changed files with 178 additions and 149 deletions
+1 -2
View File
@@ -47,8 +47,7 @@
"@johmun/vue-tags-input": "^2.1.0",
"@monaco-editor/loader": "^1.5.0",
"@popperjs/core": "^2.11.8",
"@sentry/browser": "^7.74.1",
"@sentry/vue": "^7.114.0",
"@sentry/vue": "^10.45.0",
"@vueuse/core": "^10.5.0",
"@vueuse/math": "^10.9.0",
"@vueuse/shared": "^10.5.0",
+53 -102
View File
@@ -64,12 +64,9 @@ importers:
'@popperjs/core':
specifier: ^2.11.8
version: 2.11.8
'@sentry/browser':
specifier: ^7.74.1
version: 7.114.0
'@sentry/vue':
specifier: ^7.114.0
version: 7.114.0(vue@2.7.16)
specifier: ^10.45.0
version: 10.45.0(pinia@2.3.1(typescript@5.8.3)(vue@2.7.16))(vue@2.7.16)
'@vueuse/core':
specifier: ^10.5.0
version: 10.5.0(vue@2.7.16)
@@ -1184,47 +1181,42 @@ packages:
cpu: [x64]
os: [win32]
'@sentry-internal/feedback@7.114.0':
resolution: {integrity: sha512-kUiLRUDZuh10QE9JbSVVLgqxFoD9eDPOzT0MmzlPuas8JlTmJuV4FtSANNcqctd5mBuLt2ebNXH0MhRMwyae4A==}
engines: {node: '>=12'}
'@sentry-internal/browser-utils@10.45.0':
resolution: {integrity: sha512-ZPZpeIarXKScvquGx2AfNKcYiVNDA4wegMmjyGVsTA2JPmP0TrJoO3UybJS6KGDeee8V3I3EfD/ruauMm7jOFQ==}
engines: {node: '>=18'}
'@sentry-internal/replay-canvas@7.114.0':
resolution: {integrity: sha512-6rTiqmKi/FYtesdM2TM2U+rh6BytdPjLP65KTUodtxohJ+r/3m+termj2o4BhIYPE1YYOZNmbZfwebkuQPmWeg==}
engines: {node: '>=12'}
'@sentry-internal/feedback@10.45.0':
resolution: {integrity: sha512-vCSurazFVq7RUeYiM5X326jA5gOVrWYD6lYX2fbjBOMcyCEhDnveNxMT62zKkZDyNT/jyD194nz/cjntBUkyWA==}
engines: {node: '>=18'}
'@sentry-internal/tracing@7.114.0':
resolution: {integrity: sha512-dOuvfJN7G+3YqLlUY4HIjyWHaRP8vbOgF+OsE5w2l7ZEn1rMAaUbPntAR8AF9GBA6j2zWNoSo8e7GjbJxVofSg==}
engines: {node: '>=8'}
'@sentry-internal/replay-canvas@10.45.0':
resolution: {integrity: sha512-nvq/AocdZTuD7y0KSiWi3gVaY0s5HOFy86mC/v1kDZmT/jsBAzN5LDkk/f1FvsWma1peqQmpUqxvhC+YIW294Q==}
engines: {node: '>=18'}
'@sentry/browser@7.114.0':
resolution: {integrity: sha512-ijJ0vOEY6U9JJADVYGkUbLrAbpGSQgA4zV+KW3tcsBLX9M1jaWq4BV1PWHdzDPPDhy4OgfOjIfaMb5BSPn1U+g==}
engines: {node: '>=8'}
'@sentry-internal/replay@10.45.0':
resolution: {integrity: sha512-vjosRoGA1bzhVAEO1oce+CsRdd70quzBeo7WvYqpcUnoLe/Rv8qpOMqWX3j26z7XfFHMExWQNQeLxmtYOArvlw==}
engines: {node: '>=18'}
'@sentry/core@7.114.0':
resolution: {integrity: sha512-YnanVlmulkjgZiVZ9BfY9k6I082n+C+LbZo52MTvx3FY6RE5iyiPMpaOh67oXEZRWcYQEGm+bKruRxLVP6RlbA==}
engines: {node: '>=8'}
'@sentry/browser@10.45.0':
resolution: {integrity: sha512-e/a8UMiQhqqv706McSIcG6XK+AoQf9INthi2pD+giZfNRTzXTdqHzUT5OIO5hg8Am6eF63nDJc+vrYNPhzs51Q==}
engines: {node: '>=18'}
'@sentry/integrations@7.114.0':
resolution: {integrity: sha512-BJIBWXGKeIH0ifd7goxOS29fBA8BkEgVVCahs6xIOXBjX1IRS6PmX0zYx/GP23nQTfhJiubv2XPzoYOlZZmDxg==}
engines: {node: '>=8'}
'@sentry/core@10.45.0':
resolution: {integrity: sha512-s69UXxvefeQxuZ5nY7/THtTrIEvJxNVCp3ns4kwoCw1qMpgpvn/296WCKVmM7MiwnaAdzEKnAvLAwaxZc2nM7Q==}
engines: {node: '>=18'}
'@sentry/replay@7.114.0':
resolution: {integrity: sha512-UvEajoLIX9n2poeW3R4Ybz7D0FgCGXoFr/x/33rdUEMIdTypknxjJWxg6fJngIduzwrlrvWpvP8QiZXczYQy2Q==}
engines: {node: '>=12'}
'@sentry/types@7.114.0':
resolution: {integrity: sha512-tsqkkyL3eJtptmPtT0m9W/bPLkU7ILY7nvwpi1hahA5jrM7ppoU0IMaQWAgTD+U3rzFH40IdXNBFb8Gnqcva4w==}
engines: {node: '>=8'}
'@sentry/utils@7.114.0':
resolution: {integrity: sha512-319N90McVpupQ6vws4+tfCy/03AdtsU0MurIE4+W5cubHME08HtiEWlfacvAxX+yuKFhvdsO4K4BB/dj54ideg==}
engines: {node: '>=8'}
'@sentry/vue@7.114.0':
resolution: {integrity: sha512-tHydxMJFpUcsmNCbXo59SqeNImX+3mMO+j3T0eLsDZy1NY2fSDFP6PFvuc72RsqiwCKeCKQmQDtAVa5Vt5ZlQA==}
engines: {node: '>=8'}
'@sentry/vue@10.45.0':
resolution: {integrity: sha512-p6ghTgQtiCBZ+Yw0B2xmC69S8AdCRRsYvbTHW7MJYspwNnJDs7rqgCBqOxNhvr3tsKdDuEOEHLtf/5hbKi+8xQ==}
engines: {node: '>=18'}
peerDependencies:
'@tanstack/vue-router': ^1.64.0
pinia: 2.x || 3.x
vue: 2.7.16
peerDependenciesMeta:
'@tanstack/vue-router':
optional: true
pinia:
optional: true
'@socket.io/component-emitter@3.1.2':
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
@@ -3046,9 +3038,6 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
lie@3.1.1:
resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==}
lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
@@ -3063,9 +3052,6 @@ packages:
linkifyjs@4.3.2:
resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==}
localforage@1.10.0:
resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==}
locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
@@ -5188,68 +5174,41 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.53.3':
optional: true
'@sentry-internal/feedback@7.114.0':
'@sentry-internal/browser-utils@10.45.0':
dependencies:
'@sentry/core': 7.114.0
'@sentry/types': 7.114.0
'@sentry/utils': 7.114.0
'@sentry/core': 10.45.0
'@sentry-internal/replay-canvas@7.114.0':
'@sentry-internal/feedback@10.45.0':
dependencies:
'@sentry/core': 7.114.0
'@sentry/replay': 7.114.0
'@sentry/types': 7.114.0
'@sentry/utils': 7.114.0
'@sentry/core': 10.45.0
'@sentry-internal/tracing@7.114.0':
'@sentry-internal/replay-canvas@10.45.0':
dependencies:
'@sentry/core': 7.114.0
'@sentry/types': 7.114.0
'@sentry/utils': 7.114.0
'@sentry-internal/replay': 10.45.0
'@sentry/core': 10.45.0
'@sentry/browser@7.114.0':
'@sentry-internal/replay@10.45.0':
dependencies:
'@sentry-internal/feedback': 7.114.0
'@sentry-internal/replay-canvas': 7.114.0
'@sentry-internal/tracing': 7.114.0
'@sentry/core': 7.114.0
'@sentry/integrations': 7.114.0
'@sentry/replay': 7.114.0
'@sentry/types': 7.114.0
'@sentry/utils': 7.114.0
'@sentry-internal/browser-utils': 10.45.0
'@sentry/core': 10.45.0
'@sentry/core@7.114.0':
'@sentry/browser@10.45.0':
dependencies:
'@sentry/types': 7.114.0
'@sentry/utils': 7.114.0
'@sentry-internal/browser-utils': 10.45.0
'@sentry-internal/feedback': 10.45.0
'@sentry-internal/replay': 10.45.0
'@sentry-internal/replay-canvas': 10.45.0
'@sentry/core': 10.45.0
'@sentry/integrations@7.114.0':
'@sentry/core@10.45.0': {}
'@sentry/vue@10.45.0(pinia@2.3.1(typescript@5.8.3)(vue@2.7.16))(vue@2.7.16)':
dependencies:
'@sentry/core': 7.114.0
'@sentry/types': 7.114.0
'@sentry/utils': 7.114.0
localforage: 1.10.0
'@sentry/replay@7.114.0':
dependencies:
'@sentry-internal/tracing': 7.114.0
'@sentry/core': 7.114.0
'@sentry/types': 7.114.0
'@sentry/utils': 7.114.0
'@sentry/types@7.114.0': {}
'@sentry/utils@7.114.0':
dependencies:
'@sentry/types': 7.114.0
'@sentry/vue@7.114.0(vue@2.7.16)':
dependencies:
'@sentry/browser': 7.114.0
'@sentry/core': 7.114.0
'@sentry/types': 7.114.0
'@sentry/utils': 7.114.0
'@sentry/browser': 10.45.0
'@sentry/core': 10.45.0
vue: 2.7.16
optionalDependencies:
pinia: 2.3.1(typescript@5.8.3)(vue@2.7.16)
'@socket.io/component-emitter@3.1.2': {}
@@ -7371,10 +7330,6 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
lie@3.1.1:
dependencies:
immediate: 3.0.6
lie@3.3.0:
dependencies:
immediate: 3.0.6
@@ -7389,10 +7344,6 @@ snapshots:
linkifyjs@4.3.2: {}
localforage@1.10.0:
dependencies:
lie: 3.1.1
locate-path@6.0.0:
dependencies:
p-locate: 5.0.0
-43
View File
@@ -1,43 +0,0 @@
import * as Sentry from "@sentry/vue";
import Vue from "vue";
/**
* Initializes Sentry, one of the few functions that should actually be
* in a global init. Transplanted here from js-app.mako
*
* @param {object} config Galaxy configuration object
*/
export async function initSentry(Galaxy, router) {
console.log("initSentry");
const config = Galaxy.config;
if (config.sentry_dsn_public) {
const sentry_dsn_public = config.sentry_dsn_public;
const email = Galaxy.user.get("email");
let release = Galaxy.config.version_major;
if (Galaxy.config.version_minor) {
release += `.${Galaxy.config.version_minor}`;
}
Sentry.init({
Vue,
dsn: sentry_dsn_public,
integrations: [Sentry.browserTracingIntegration({ router })],
release: release,
beforeSend(event, hint) {
const error = hint.originalException;
if (["AdminRequired", "RegisteredUserRequired"].includes(error?.name)) {
// ignore these error events
return null;
}
return event;
},
});
if (email) {
Sentry.configureScope((scope) => {
scope.setUser({
email: email,
});
});
}
Galaxy.Sentry = Sentry;
}
}
+83
View File
@@ -0,0 +1,83 @@
import * as Sentry from "@sentry/vue";
import Vue from "vue";
import type VueRouter from "vue-router";
interface GalaxyConfig {
sentry_dsn_public?: string;
sentry_client_traces_sample_rate?: number;
version_major: string;
version_minor?: string;
}
interface GalaxyUser {
get(attr: string): string | undefined;
attributes?: {
preferences?: {
extra_user_preferences?: string;
};
};
}
interface GalaxyInstance {
config: GalaxyConfig;
user?: GalaxyUser;
}
function isReplayEnabled(user?: GalaxyUser): boolean {
try {
const prefsJson = user?.attributes?.preferences?.extra_user_preferences;
if (!prefsJson) {
return false;
}
const prefs = JSON.parse(prefsJson);
const value = prefs["sentry_replay|enabled"];
return value === true || value === "true";
} catch {
return false;
}
}
export function initSentry(Galaxy: GalaxyInstance, router: VueRouter): void {
const config = Galaxy.config;
if (!config.sentry_dsn_public) {
return;
}
const email = Galaxy.user?.get("email");
let release = config.version_major;
if (config.version_minor) {
release += `.${config.version_minor}`;
}
const replayEnabled = isReplayEnabled(Galaxy.user);
const integrations = [Sentry.browserTracingIntegration({ router })];
if (replayEnabled) {
integrations.push(
Sentry.replayIntegration({
maskAllText: true,
blockAllMedia: true,
}),
);
}
Sentry.init({
Vue,
dsn: config.sentry_dsn_public,
integrations,
release,
tracesSampleRate: config.sentry_client_traces_sample_rate ?? 0,
replaysSessionSampleRate: 0,
replaysOnErrorSampleRate: replayEnabled ? 1.0 : 0,
beforeSend(event, hint) {
const error = hint.originalException;
if (error instanceof Error && ["AdminRequired", "RegisteredUserRequired"].includes(error.name)) {
return null;
}
return event;
},
});
if (email) {
Sentry.setUser({ email });
}
}
+1 -1
View File
@@ -21,7 +21,7 @@ window.addEventListener("load", async () => {
const router = getRouter(Galaxy);
// Initialize globals
await initSentry(Galaxy, router);
initSentry(Galaxy, router);
await initWebhooks(Galaxy);
// Mount application
+13
View File
@@ -3300,6 +3300,19 @@
:Type: float
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``sentry_client_traces_sample_rate``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description:
Sample rate for client-side (browser) performance tracing, between
0 and 1. Controls what fraction of page loads and navigations
generate performance traces sent to Sentry. Independent of
sentry_traces_sample_rate, which controls server-side tracing.
:Default: ``0.0``
:Type: float
~~~~~~~~~~~~~~~~~~~
``sentry_ca_certs``
~~~~~~~~~~~~~~~~~~~
@@ -1911,6 +1911,12 @@ galaxy:
# to Sentry. A value higher than 0 is required to analyze performance.
#sentry_traces_sample_rate: 0.0
# Sample rate for client-side (browser) performance tracing, between 0
# and 1. Controls what fraction of page loads and navigations generate
# performance traces sent to Sentry. Independent of
# sentry_traces_sample_rate, which controls server-side tracing.
#sentry_client_traces_sample_rate: 0.0
# Use this option to provide the path to location of the CA
# (Certificate Authority) certificate file if the sentry server uses a
# self-signed certificate.
@@ -125,7 +125,7 @@ preferences:
label: Creator name to associate with new records (formatted as "Last name, First name"). If left blank "Anonymous Galaxy User" will be used. You can always change this by editing your record directly.
type: text
required: False
dataverse:
description: Your Dataverse Integration Settings
inputs:
@@ -170,6 +170,15 @@ preferences:
required: False
value: False
sentry_replay:
description: Session Replay for error diagnostics
inputs:
- name: enabled
label: Allow session replay recordings to be sent when errors occur. These recordings help administrators diagnose issues but may capture screen content.
type: boolean
required: False
value: False
# Used in file_sources_conf.yml
elabftw:
description: Your eLabFTW Integration Settings
@@ -2431,6 +2431,16 @@ mapping:
will have that percentage chance of being sent to Sentry. A value higher than 0
is required to analyze performance.
sentry_client_traces_sample_rate:
type: float
default: 0.0
required: false
desc: |
Sample rate for client-side (browser) performance tracing, between 0
and 1. Controls what fraction of page loads and navigations generate
performance traces sent to Sentry. Independent of
sentry_traces_sample_rate, which controls server-side tracing.
sentry_ca_certs:
type: str
required: False
+1
View File
@@ -245,6 +245,7 @@ class ConfigSerializer(base.ModelSerializer):
"install_resolver_dependencies": _use_config,
"enable_tool_generated_tours": _use_config,
"sentry_dsn_public": lambda item, key, **context: item.sentry_dsn_public,
"sentry_client_traces_sample_rate": _use_config,
"enable_webhooks": lambda item, key, **context: hasattr(self.app, "webhooks_registry")
and bool(self.app.webhooks_registry.webhooks),
}