Reliably catch all JS/Blaze/Meteor/React errors on client side?

I know, that there is a lot of discussions about this topic. But instead of it, I still did not found the solution. Therefore I would like to kindky ask, how to reliably catch all errors on client side?

I tested Sentry and also Meteor-Logger, but the problems seems to be the same:

Probably, both of the solution are trying to catch errors with the following way:

/* Store original window.onerror */
const _GlobalErrorHandler = window.onerror;

window.onerror = function (msg, url, line) {
  log.error(msg, {file: url, onLine: line});
  if (_GlobalErrorHandler) {
    _GlobalErrorHandler.apply(this, arguments);
  }
};

But If I will try to make a mistake for example in Blaze, the Blaze render method in FlowRouter is async and Meteor-Logger and also Sentry does not catch this error.

Blaze template:

Template.projects.onRendered(() => {
     foooo();
});

Router:

loggedRoutes.route('/', {
    name: 'home',
    action: function () {
        this.render('layout', 'projects');
    },
    waitOn() {
        return [
            import('./views/projects/projects_script'),
            Meteor.subscribe('projects_published_list')
        ];
    }
});

Browser console

ReferenceError: foooo is not defined
    at Blaze.TemplateInstance.eval (projects_script.js:16)
    at template.js:119
   ...
...
...

How can I catch all errors on client side?


Note:
If I will be able to catch errors from Router (from importing and rendering the Blaze templates), I will take under control biggerst part of Meteor client side (I think).

Thanks a lot for each idea.

1 Like

I created the following Sentry configuration, which is working perfectly!!! It’s able to log all console errors and also React errors (We are rewriting app from Blaze to React, therefore we are using both together).

import {Meteor} from 'meteor/meteor';
import { Integrations } from "@sentry/tracing";
import { CaptureConsole, ReportingObserver } from '@sentry/integrations';
import * as Sentry from "@sentry/react";

let _initialized = false;

Tracker.autorun(() => {
    Tracker.dependencies.settings.depend();
    if (Meteor.settings && Meteor.settings.public && Meteor.settings.public['SENTRY'] && Meteor.settings.public['SENTRY'].enabled) {
        let settings = Meteor.settings.public['SENTRY'];
        if (settings.dsn) {
            let options = {};
            options.dsn = settings.dsn;
            options.integrations = [new Integrations.BrowserTracing(), new CaptureConsole({
                levels: ['warn', 'error', 'debug', 'assert'] // an array of methods that should be captured, defaults to ['log', 'info', 'warn', 'error', 'debug', 'assert']
            }), new ReportingObserver()];
            if (settings.tracesSampleRate) {
                options.tracesSampleRate = settings.tracesSampleRate;
            }

            if (!_initialized) {
                Sentry.init(options);
                console.info('Error logger initialized...');
            }
        }
    }
});
1 Like

Does it catch errors, when surrounding the render function in the router?

action: function () {
  try {
    this.render('layout', 'projects');
  } catch (e) {
    // log e
  }
}

Apart from that you can actually override any Blaze Template lifecycle method and hook in there:


const originalOnCreated = Template.prototype.onCreated

Template.prototype.onCreated = function (cb) {
    const instance = this
    const { viewName } = instance
    
    try {
      originalOnCreated.call(instance, cb)
    } catch (e) {
      console.error(`Error in ${viewName}`)
      console.error(e)
    }
  }

Take a look at this package, which hooks into all lifecycle methods for measuring Template performance.

1 Like

Hi @jkuester Thanks a lot for your help and answer. From our last communication, we completely leaved from Blaze and rewrite whole app into React (lot of reasons). We will see, if it was a good decision.

The try-catch inside route does not catch the exception.