sentry-electron
sentry-electron copied to clipboard
What is the right way to setup Sentry Electron SDK with Vite & Vue 3
Versions + Platform
- [x] SDK version -
@sentry/[email protected] - [x] Electron version -
[email protected] - [x] Platform -
macOS
Description
I am using @sentry/vue package to collect exceptions from renderer process, it is not very straightforward and I have to revise the Sentry event before sending it to server, otherwise source mapping doesn't work.
import * as Sentry from '@sentry/vue';
Sentry.init({
app,
dsn: __SENTRY_DSN__,
release: __SENTRY_RELEASE__,
beforeSend: (event: Sentry.Event, hint: Sentry.EventHint) => {
// update the stacktrace before sending it to Sentry, this will strip out the asar path - i.e. those between two brackets:
// file:///[myapp.app/Contents/Resources/app.asar/]packages/renderer/dist/index.f3984842.js
if (event.exception?.values) {
event.exception.values = event.exception.values.map(e => {
if (e.stacktrace?.frames) {
e.stacktrace.frames = e.stacktrace.frames.map(f => {
if (f.filename) {
f.filename = f.filename.replace(/.*app\.asar/, 'app://');
}
return f;
});
}
return e;
});
}
return event;
},
});
It works with this approach but I would like to check if there is an easier / better way available. I firstly tried @sentry/electron package but it doesn't capture exceptions in renderer process for me, maybe it is because I am using Vue 3 and not vanilla.
My other question is, it seems the exceptions in renderer process won't be printed in console anymore once they are reported to Sentry, is this an intended behavior?
In the renderer, the Electron SDK is a thin wrapper around @sentry/browser. It adds a couple of integrations that pass events and scope to the main process where it is merged, extra context is added and normalisation of things like paths takes place.
It's worth noting a couple of other features we disable that don't make as much sense with multiple windows/processes.
I've not had a chance to test this yet but something like this should work in the renderer:
import * as Sentry from '@sentry/vue';
import { Integrations } from '@sentry/electron/renderer';
Sentry.init({
app,
dsn: __SENTRY_DSN__,
release: __SENTRY_RELEASE__,
// We capture sessions from the Electron main process
autoSessionTracking: false,
// Everything is sent from the main process
sendClientReports: false,
integrations: [ new Integrations.ScopeToMain(), new Integrations.EventToMain() ]
});
I will add a Vue app to our examples because this is not obvious.
For this to work you'll need to ensure you init the Electron SDK in the main process too!
Thanks @timfish , I can confirm your code above works!
As everything is now sent from the main process, would BrowserTracing still work? I honestly don't know if I need tracing, I added simply because it was in the example of @sentry/vue document.
Also, there is a TypeScript error in your code, I am using @sentry/vue 7.5.1 and @sentry/electron 3.0.7:
Type 'EventToMain' is not assignable to type 'Integration'.
Types of property 'setupOnce' are incompatible.
Type '(addGlobalEventProcessor: (callback: EventProcessor) => void) => void' is not assignable to type '(addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub) => void'.
Here is my code:
import * as Sentry from '@sentry/vue';
import { Integrations } from '@sentry/electron/renderer';
import { BrowserTracing } from '@sentry/tracing';
Sentry.init({
app,
dsn: __SENTRY_DSN__,
release: __SENTRY_RELEASE__,
autoSessionTracking: false, // We capture sessions from the Electron main process
sendClientReports: false, // Everything is sent from the main process
integrations: [
// eslint-disable-next-line @typescript-eslint/no-explicit-any
new Integrations.EventToMain() as any,
new Integrations.ScopeToMain(),
new BrowserTracing({
routingInstrumentation: Sentry.vueRouterInstrumentation(router),
tracingOrigins: ['localhost', /^\//],
}),
],
tracesSampleRate: 0.8, // 80% chance that a given trace being sent
});
As everything is now sent from the main process, would BrowserTracing still work?
Yes, BrowserTracing still works, the transaction is just passed through the main process.
Type 'EventToMain' is not assignable to type 'Integration'.
This suggest that you have multiple versions of Sentry SDKs in your dependencies.
@sentry/electron is pinned to a specific version of the underlying JavaScript SDKs because it uses internal APIs that don't follow semantic versioning.
If you are using the latest Electron SDK release (v3.0.7), you should use v6.19.2 of the @sentry/vue SDK.
v4 of the Electron SDK is on the way (watch this issue to get notified when the beta is published) and this is pinned to v7.3.1 on the JavaScript SDKs.
Unfortunately npm doesn't appear to surface the dependency versions so the only easy way to get this version is to check package.json at a specific Git tag. I will add the underlying SDK version to the README so this level of digging isn't required.
Awesome, thanks a ton! Feel free to close this ticket if you like, or you may leave it open in case if you want to use it as a TODO for improving Vue related document.
I will add a Vue app to our examples because this is not obvious.
I'm going to do this before closing this issue!
Hey @timfish,
Today I upgraded @sentry/electron to 4.0.0, and sentry/vue to 7.12.1, and the error below came back:
Type 'EventToMain' is not assignable to type 'Integration'.
Here is my code:
// main and preload
Sentry.init({
dsn: __SENTRY_DSN__,
release: __SENTRY_RELEASE__,
});
// renderer (Vue 3)
Sentry.init({
app,
dsn: __SENTRY_DSN__,
release: __SENTRY_RELEASE__,
autoSessionTracking: false, // We capture sessions from the Electron main process
sendClientReports: false, // Everything is sent from the main process
integrations: [
new Integrations.EventToMain(),
new Integrations.ScopeToMain(),
new BrowserTracing({
routingInstrumentation: Sentry.vueRouterInstrumentation(router),
tracingOrigins: ['localhost', /^\//],
}),
],
tracesSampleRate: 0.8, // 80% chance that a given trace being sent
});
Would you please review the code below and provide any guidance? Thank you!
Today I upgraded
@sentry/electronto4.0.0, andsentry/vueto7.12.1
v4.0.0 of the Electron SDK uses 7.8.1 of the JavaScript SDKs.
We should probably include this version in the readme so it's obvious from npm!
Hey @timfish, I still receive the same error after downgrading to 7.8.1:
Type 'EventToMain' is not assignable to type 'Integration'.
Types of property 'setupOnce' are incompatible.
Type '(addGlobalEventProcessor: (callback: EventProcessor) => void) => void' is not assignable to type '(addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub) => void'.
Types of parameters 'addGlobalEventProcessor' and 'addGlobalEventProcessor' are incompatible.
Here is the setupOnce definition in @sentry/javascript 7.8.1:
https://github.com/getsentry/sentry-javascript/blob/85026d7345bbffee5b96a8b6f5d48cf3c966a421/packages/types/src/integration.ts#L25
Here is the setupOnce definition in @sentry/electron 4.0.0:
https://github.com/getsentry/sentry-electron/blob/44513544c76df4b0ca6f1ca1b0dc776f9ebc546c/src/renderer/integrations/event-to-main.ts#L17
Both parameters for setupOnce are optional and this API hasn't changed for a few major versions.
Look through your lock file and ensure all the sentry dependencies are v7.8.1, remove node_modules and reinstall and everything should then be ok.
Thanks! You're right, I restarted VS code and the error is gone.
However, how can you guys make the parameters optional without a question mark, I was thinking the setupOnce needs to be defined like:
setupOnce(addGlobalEventProcessor?: (callback: EventProcessor) => void, getCurrentHub?: () => Hub): void;
To use the init scripts of both the electron and the vue SDKs – and simplify the code –, I did:
import { init as initSentryElectron } from '@sentry/electron/renderer';
import { init as initSentryVue } from '@sentry/vue';
initSentryElectron({ app }, initSentryVue)}
It avoids having to duplicate the init code (eg. integrations, sendClientReports…) of @sentry/vue like done in the snippet of https://github.com/getsentry/sentry-electron/issues/506#issuecomment-1179522290.
The app parameter passed to initSentryElectron will be passed to initSentryVue (cf. init() of @sentry/electron/renderer).
But TS will complain because it's not in the definition of the function, so you'll need a // @ts-ignore.