sentry icon indicating copy to clipboard operation
sentry copied to clipboard

Sentry JS lazily-loadable loader doesn't work

Open fabis94 opened this issue 5 years ago • 54 comments
trafficstars

Version Information

Version: 20.10.1

Description

According to the documentation (https://docs.sentry.io/platforms/javascript/install/lazy-load-sentry/#sdk-version) Sentry offers a lightweight lazy-loadable version of the Sentry JS SDK which is a lot smaller than the default bundles.

I tried to use it, but when I open the script that's shown inside the "JavaScript Loader" input box as shown in the docs, the entire contents of the script look like this:

function _sentry_noopWarning() {
  console.warn("The Sentry loader you are trying to use isn't working anymore, check your configuration.");
}
var Sentry = {
    addBreadcrumb: _sentry_noopWarning,
    captureEvent: _sentry_noopWarning,
    captureException: _sentry_noopWarning,
    captureMessage: _sentry_noopWarning,
    configureScope: _sentry_noopWarning,
    forceLoad: _sentry_noopWarning,
    init: _sentry_noopWarning,
    onLoad: _sentry_noopWarning,
    showReportDialog: _sentry_noopWarning,
    withScope: _sentry_noopWarning,
};
_sentry_noopWarning();

I tried grep-ing through the Sentry source code about this, but I was only able to find the template that generates this script (https://github.com/getsentry/sentry/blob/master/src/sentry/templates/sentry/js-sdk-loader-noop.js.tmpl) and couldn't figure out further how does Sentry decide to show this broken version instead of the real script.

The documentation isn't helpful either.

Steps to Reproduce

Install Sentry on-premises and check the JavaScript Loader, I guess.

Logs

No logs

fabis94 avatar Nov 12 '20 13:11 fabis94

Hi, I think this is intended to be used by https://sentry.io or when you are using a CDN yourself. The definitions are here: https://github.com/getsentry/sentry/blob/c3da5bd066b6f30358a455b78eab4ba075c0acf9/src/sentry/conf/server.py#L1862-L1870

Can you share where you are seeing this script linked to? Maybe this is just a UI issue that we need to disable for on-premise (or when this setting is not set).

BYK avatar Nov 13 '20 10:11 BYK

@BYK Same place it's shown in the docs, in the Client Keys (DSN) settings, when pressing "Configure" on the DSN key.

image

It would be great if this feature could be used on-premises as well, since there's no other way to lazily load the JS SDK

fabis94 avatar Nov 13 '20 11:11 fabis94

@fabis94 thanks a lot for the quick turn around! I'll be investigating this.

BYK avatar Nov 13 '20 11:11 BYK

I can confirm that I am seeing this is the latest release of on premise as well.

Like the original poster, I followed the same path and was led to this ticket.

I’d be happy to debug or offer feedback.

christopherowen avatar Dec 12 '20 09:12 christopherowen

I've tried a number of attempts at setting system.JS_SDK_LOADER_DEFAULT_SDK_URL in sentry/config.yml and sentry/sentry.conf.py without luck so far.

I receive various versions of "Unknown config option found:" in the logs.

christopherowen avatar Dec 14 '20 13:12 christopherowen

I was able to get this working by setting the following in sentry/sentry.conf.py

JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.tracing.min.js"

May I suggest that this be set as a default in the sentry.conf.example.py?

christopherowen avatar Dec 15 '20 09:12 christopherowen

@christopherowen Is that really lazy loading, though? It looks like it just loads the standard bundle instead of the specialized lazy-loadable version that is supposedly served by the cloud version of Sentry.

fabis94 avatar Dec 15 '20 16:12 fabis94

yes it is, this url is loaded by the lazy loader.

christopherowen avatar Dec 15 '20 21:12 christopherowen

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Accepted, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

github-actions[bot] avatar Jan 06 '21 12:01 github-actions[bot]

Any updates on this? Problem is still here in Sentry 21.4.0.dev07313f65.

maxkachalin avatar Apr 03 '21 22:04 maxkachalin

@maxkachalin it is on our backlog, just didn't have time to get to it yet.

BYK avatar Apr 05 '21 09:04 BYK

@BYK, I see, thank you very much in advance.

I've been tangled by the bot which closed issue due to inactivity.

maxkachalin avatar Apr 05 '21 12:04 maxkachalin

Same here! Following @christopherowen suggestion, it worked! Thanks!

caioricciuti avatar Apr 30 '21 09:04 caioricciuti

Hi all! Any workaround for this issue at this moment?

pauloriply avatar Aug 27 '21 09:08 pauloriply

@pauloriply See https://github.com/getsentry/sentry/issues/22715#issuecomment-745151393

dakur avatar Sep 08 '21 04:09 dakur

I was able to get this working by setting the following in sentry/sentry.conf.py

JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.tracing.min.js"

The downside of this approach is that the SDK is loading from a third-party CDN, which is not ideal in some cases (eg. slower load time due to having to resolve one extra hostname, you can't customize the code at all, regulatory requirements with regards to third-party servers, etc).

Until this is fixed, I'm going to try lazy loading via Webpack's lazy loading support. I've got this so far:

Edit: Code is in a Github repo now: https://github.com/Daniel15/LazySentry

// LazySentryImport.ts
// Only export the things you use, to try and keep bundle size small (tree shaking)

import {Integrations} from '@sentry/tracing';
const {BrowserTracing} = Integrations;

export {
  init,
  ErrorBoundary,
  addBreadcrumb,
  captureMessage,
  captureException,
  captureEvent,
  configureScope,
  withScope,
} from '@sentry/react';
export {BrowserTracing};
// LazySentry.ts

type SentryImportType = typeof import('./LazySentryImports');

const isDev = window.location.hostname.includes('.localdev.');

let queue: Array<(sentry: SentryImportType) => void> = [];
let errorQueue: Array<Parameters<OnErrorEventHandlerNonNull>> = [];
let rejectionQueue: Array<PromiseRejectionEvent> = [];

// Before Sentry has loaded, these functions will push calls into a queue
// After Sentry has loaded, these will be replaced with the real functions
export let addBreadcrumb: SentryImportType['addBreadcrumb'] = (...args) => {
  queue.push(x => x.addBreadcrumb(...args));
};
export let captureMessage: SentryImportType['captureMessage'] = (...args) => {
  queue.push(x => x.captureMessage(...args));
  return '';
};
export let captureException: SentryImportType['captureException'] = (
  ...args
) => {
  queue.push(x => x.captureException(...args));
  return '';
};
export let captureEvent: SentryImportType['captureEvent'] = (...args) => {
  queue.push(x => x.captureEvent(...args));
  return '';
};
export let configureScope: SentryImportType['configureScope'] = (...args) =>
  queue.push(x => x.configureScope(...args));
export let withScope: SentryImportType['withScope'] = (...args) =>
  queue.push(x => x.withScope(...args));

export function initLazy() {
  const oldOnError = window.onerror;
  const oldOnUnhandledRejection = window.onunhandledrejection;
  window.onerror = (...args) => errorQueue.push(args);
  window.onunhandledrejection = (e: PromiseRejectionEvent) =>
    rejectionQueue.push(e);

  import('./LazySentryImports').then(Sentry => {
    window.onerror = oldOnError;
    window.onunhandledrejection = oldOnUnhandledRejection;
    Sentry.init({
      dsn: 'https://xxxxxxxxxx/3',
      debug: isDev,
      environment: isDev ? 'development' : 'production',
      integrations: [new Sentry.BrowserTracing()],
      tracesSampleRate: 1.0,
    });

    // Override the placeholder functions with the real ones
    addBreadcrumb = Sentry.addBreadcrumb;
    captureMessage = Sentry.captureMessage;
    captureException = Sentry.captureException;
    captureEvent = Sentry.captureEvent;
    configureScope = Sentry.configureScope;
    withScope = Sentry.withScope;
    // TODO: React ErrorBoundary

    // Replay queued calls and errors through Sentry's handlers
    queue.forEach(call => call(Sentry));
    errorQueue.forEach(x => window.onerror?.(...x));
    rejectionQueue.forEach(e => window.onunhandledrejection?.(e));
  });
}

Then just use the LazySentry module in your app and call initLazy somewhere (eg after page load, in a requestIdleCallback callback, etc). Basically the same as the Sentry lazy loader (https://github.com/getsentry/sentry-javascript/blob/master/packages/browser/src/loader.js) but with more modern JS, less obfuscated, TypeScript typing, and lazy loading your own built JS file rather than using the Sentry CDN.

No guarantees on the above code and I still need to finish testing it, but on an initial test it seems to work.

Daniel15 avatar Sep 24 '21 06:09 Daniel15

@Daniel15 this is not bad at all!

saint777 avatar Oct 21 '21 17:10 saint777

@Daniel15 this is not bad at all!

Thanks 😃 I started using it on https://dnstools.ws/ (https://github.com/Daniel15/dnstools/blob/9c51a38d1a86b84c9f13f940ff58108bd4468b1d/src/DnsTools.Web/ClientApp/src/index.tsx#L38) and it seems to be working fine.

Daniel15 avatar Oct 21 '21 23:10 Daniel15

I am new to Sentry. But I also ran into a similar issue when using it with Django + Vue.JS. Since in the current project it is necessary that the backend transfer the necessary configuration for the Sentry SDK in advance before returning the statics. When is a patch like this planned to be released?

Stormiks avatar Jan 24 '22 11:01 Stormiks

Have there been any updates? Would be nice to have a working feature without workarounds

makstech avatar Jul 06 '22 14:07 makstech

I was able to get this working by setting the following in sentry/sentry.conf.py

JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.tracing.min.js"

May I suggest that this be set as a default in the sentry.conf.example.py?

Didn't work for me. It correctly lazily loaded the bundle when an error occurred but didn't report the issue (there was no request happening in the browser console and therefore it obviously also didn't show up in sentry).

Got it to work by loading bundle.min.js instead of bundle.tracing.min.js.

JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.min.js"

Aulig avatar Aug 23 '22 08:08 Aulig

I was able to get this working by setting the following in sentry/sentry.conf.py

JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.tracing.min.js"

May I suggest that this be set as a default in the sentry.conf.example.py?

Didn't work for me. It correctly lazily loaded the bundle when an error occurred but didn't report the issue (there was no request happening in the browser console and therefore it obviously also didn't show up in sentry).

Got it to work by loading bundle.min.js instead of bundle.tracing.min.js.

JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.min.js"

That's right

lushi516 avatar Mar 07 '23 06:03 lushi516

Is this still in backlog? 😢

itsmunim avatar Jul 21 '23 07:07 itsmunim

Same problem here. CDN is not an option for me for security and performance reasons.

MoritzGlantz avatar Jul 25 '23 15:07 MoritzGlantz

Yep, still on the backlog

hubertdeng123 avatar Jul 25 '23 17:07 hubertdeng123

Do you have any intention of fixing this in the near future? Asking because otherwise I need to search for another solution.

MoritzGlantz avatar Jul 25 '23 17:07 MoritzGlantz

otherwise I need to search for another solution.

@MoritzGiessmann You could do something similar to what I'm doing, as a workaround: https://github.com/Daniel15/LazySentry. I'm just using Webpack's lazy loading to load the Sentry code, and keeping all errors and calls to Sentry in a queue that's flushed once Sentry finishes loading.

Daniel15 avatar Jul 25 '23 19:07 Daniel15

Do you have any intention of fixing this in the near future? Asking because otherwise I need to search for another solution.

Unfortunately not. You're welcome to try out the workaround mentioned above though and report back.

hubertdeng123 avatar Jul 26 '23 20:07 hubertdeng123

I have the same problem, on the sentry website I can open the js without problems, but on-premise it doesn't let me see the content.

Sentry.io: image image

On-Premise ( Self-hosted):

image

Thanks

victorelec14 avatar Aug 17 '23 07:08 victorelec14

I was able to get this working by setting the following in sentry/sentry.conf.py

JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.tracing.min.js"

May I suggest that this be set as a default in the sentry.conf.example.py?

Now I am having this problem: I had problem on ⁠self-hosted with sentry script being noop functions. But fixed this by adding:

JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.tracing.replay.debug.min.js"

to

sentry/sentry.conf.py

using docker setup and then rerunning ./install.sh, I am on main branch.

But now I am having another issue, which is causing envelope to show 403, read on some github issues, that it is deprecated endpoint or something like that, though using latest bundle.

Any ideas anyone how to fix this? Response on sentry itself is 403 from web server. And when I using script provided by my self-hosted instance. It points to:

{{self-hosted.domain}}/api/1/envelope/?sentry_key={{project_token}}&sentry_version=7&sentry_client=sentry.javascript.browser%2F7.64.0

which responds also with 403 HTTP code. But also provides this payload:

{"detail":"event submission rejected with_reason: Cors"}

In browser response headers seem to allow all origins and all headers. Not sure where this is coming from and how to fix it.

P.S. Script request returns proper header:

curl --head https://{{self-hosted.domain}}/js-sdk-loader/{{project_token}}.min.js | grep -i access
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0  2479    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
Access-Control-Allow-Origin: *

UPDATE: Did everything without loader with script directly from CDN. By configuring everything with Sentry class/prototype. But it seems that it is not sending any requests at all. Even though integrations and specified my self-hosted instance URL. No errors are made, due to the fact, that nothing is sent and I can see it from networks tab, by filtering sentry keyword or domain: *sentry*

SOLVED: Solved by disabling Verify SSL/TLS In projects General Settings. Not sure what is happening, but seems like sentry is unable to verify some ssl certificate. I use Let's Encrypt ones. But they are set at nginx proxy and service that is being monitored. No sure what I have to configure on sentry.conf.py or conf.py so it would work with verifications.

juslintek avatar Aug 25 '23 08:08 juslintek