sentry-electron icon indicating copy to clipboard operation
sentry-electron copied to clipboard

What is the right way to setup Sentry Electron SDK with Vite & Vue 3

Open haoxi911 opened this issue 3 years ago • 10 comments

Versions + Platform

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?

haoxi911 avatar Jul 08 '22 17:07 haoxi911

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!

timfish avatar Jul 09 '22 10:07 timfish

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
});

haoxi911 avatar Jul 09 '22 12:07 haoxi911

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.

timfish avatar Jul 09 '22 12:07 timfish

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.

haoxi911 avatar Jul 09 '22 12:07 haoxi911

I will add a Vue app to our examples because this is not obvious.

I'm going to do this before closing this issue!

timfish avatar Jul 28 '22 14:07 timfish

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!

haoxi911 avatar Sep 06 '22 20:09 haoxi911

Today I upgraded @sentry/electron to 4.0.0, and sentry/vue to 7.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!

timfish avatar Sep 07 '22 09:09 timfish

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

haoxi911 avatar Sep 07 '22 14:09 haoxi911

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.

timfish avatar Sep 07 '22 14:09 timfish

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;

haoxi911 avatar Sep 07 '22 14:09 haoxi911

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.

hulius avatar Dec 28 '22 16:12 hulius