bugsnag / bugsnag-js

JavaScript error handling tool for BugSnag. Monitor and report JavaScript bugs & errors.
https://docs.bugsnag.com/platforms/javascript
MIT License
854 stars 251 forks source link

Cloudflare Workers Support #637

Open domharrington opened 4 years ago

domharrington commented 4 years ago

Hey! I attempted to use Bugsnag within a Cloudflare Worker: https://www.cloudflare.com/products/cloudflare-workers/. This is like the Service Workers API, but built to run at the CDN layer instead of in a user's browser.

I attempted to bring in both @bugsnag/js (didn't work due to navigator not being set) and @bugsnag/node (didn't work due to no "fs" module). I also tried to use the unofficial https://github.com/jmshal/bugsnag-js-cloudflare-workers but this did not work either.

The way to compile workers is to use webpack + webworker target (https://webpack.js.org/configuration/target/#string), which complicates things even further.

I ended up with a solution that looks something like this (using @bugsnag/core/report + error-stack-parser, thanks to report.test.js in this repo! + your HTTP API):

const Report = require('@bugsnag/core/report');
const ErrorStackParser = require('error-stack-parser')

addEventListener('fetch', event => {
  event.passThroughOnException();

  event.respondWith(respond(event));
});

async function respond(event) {
  try {
    // Some more worker code that may error
    return fetch(event.request);
  } catch(e) {
    const report = new Report(e.name, e.message, ErrorStackParser.parse(e));
    report.updateMetaData('request', {
      method: event.request.method,
      url: event.request.url,
    });
    report.app = {
      id: 'name',
      version: '1.0.0',
    };
    console.log('Sending error to bugsnag', e.name, e.message, ErrorStackParser.parse(e), JSON.stringify(report));

    event.waitUntil(fetch('https://notify.bugsnag.com/', {
      method: 'POST',
      headers: {
        'Bugsnag-Api-Key': 'BUGSNAG_API_KEY',
      },
      body: JSON.stringify({
        notifier: {
          name: 'name',
          version: '1.0.0',
          url: 'https://example.com/',
        },
        events: [
          report,
        ],
      }),
    }))
  }
}

This seems to work, but would be great to have first class support for this! Cheers

bengourley commented 4 years ago

Hey Dom! 👋

We have service worker support on our internal backlog. It seems like supporting service workers would be the first step towards achieving this (removing reliance on parts of the browser environment that doesn't exist etc.) and then direct support for Cloudflare workers would be added via a plugin. I'll add that to the backlog too.

domharrington commented 4 years ago

Hey Ben! :) thanks for the update on this, I'll be sure to follow along here for any future news. Let me know if I can help with testing anything.

Here's our cloudflare worker if you're interested: https://github.com/readmeio/cloudflare-worker. Here's the modified version of the worker to send any errors to Bugsnag: https://github.com/readmeio/cloudflare-worker/blob/144f8c2c16054d110f4e9164e3cfbfdab29ef8bf/debug-template.js#L28-L54.

Cheers!

jamesarosen commented 4 years ago

@bengourley the only blocker to using @bugsnag/core/client in Cloudflare is the use of navigator in @bugsnag/cuid. Cloudflare simply won't let you create a worker that references globals that don't exist. If you could remove that dependency (or just gate it on a typeof check), then the community could create a Cloudflare plugin.

jamesarosen commented 4 years ago

@domharrington if you add a webpack.DefinePlugin to your webpack config, you can have webpack rewrite the navigator global references:

new webpack.DefinePlugin({
  navigator: '{ userAgent: "" }',
}),

It results in some weird but completely functional code:

var mimeTypesLength = {
  userAgent: ''
}.mimeTypes ? {
  userAgent: ''
}.mimeTypes.length : 0;
var clientId = pad((mimeTypesLength + {
  userAgent: ''
}.userAgent.length).toString(36) + globalCount.toString(36), 4);
simplenotezy commented 4 years ago

Would be very awesome to have Cloudflare Workers support. Workers is a really amazing software, but they really lack better debugging options. Currently I am out of luck of integrating bugsnag with cloudflare workers.

jamesarosen commented 4 years ago

I posted a working implementation here.

jamesarosen commented 4 years ago

Cloudflare workers are always a single file. Whether you use Wrangler, Webpack, or something else to compile your files down to a single file, you're going to end up with line-number changes on every release. That makes Bugsnag's default exception group fairly useless. I find this helps a lot:

catch (e) {
  const report = createReportFromError(e, handledState)
  report.groupingHash = e.message || 'Uncaught exception'
  bugsnagClient(event).notify(report)
}

Bugsnag's sourcemap support won't work in the case of Cloudflare workers since neither the compiled JS nor the source is available at any URL.

zorbash commented 3 years ago

@domharrington if you add a webpack.DefinePlugin to your webpack config, you can have webpack rewrite the navigator global references:

new webpack.DefinePlugin({
  navigator: '{ userAgent: "" }',
}),

It looks like '@bugsnag/js' depends on more global properties than navigator.

new webpack.DefinePlugin({
  navigator: JSON.stringify({ userAgent: '' }),
  window: JSON.stringify({}),
  document: JSON.stringify({}),
}),

Currently getting the following error:

TypeError: Cannot read property 'host' of undefined

It'd be great to remove reliance on browser globals.

yousif-bugsnag commented 3 years ago

Hi @zorbash, I'm afraid we don't have any updates on this at present. Does the working implementation posted above work for you?

zorbash commented 3 years ago

Hi @yousif-bugsnag, the working implementation posted above seems incomplete since the createReportFromError function is not defined anywhere.

I'm assuming the missing function is implemented as follows:

const ErrorStackParser = require('error-stack-parser')

function createReportFromError(event, error) {
  const report = new Report(e.name, e.message, ErrorStackParser.parse(e));

  report.updateMetaData('request', {
    method: event.request.method,
    url: event.request.url,
  });

  report.app = {
    id: 'name',
    version: '1.0.0',
  };

  return report;
}

Given our worker is written in TypeScript though, the application won't compile due to errors triggered by the following imports:

import Client from '@bugsnag/core/client'
import payload from '@bugsnag/core/lib/json-payload'
import { schema } from '@bugsnag/core/config'

Errors:

Could not find a declaration file for module '@bugsnag/core/client'.
Could not find a declaration file for module '@bugsnag/core/lib/json-payload'.
Could not find a declaration file for module '@bugsnag/core/config'.

TypeScript's suggestion is to install @types/bugsnag__core which doesn't exist. Any idea how to fix this?

mattdyoung commented 3 years ago

I believe using the require syntax e.g.

var Client = require('@bugsnag/core/client')

should get you past the typescript issues.

I've flagged your interest in official Bugsnag support for Cloudflare workers with our product team, and we'll be sure to post back here if there are any updates.

joshunger commented 3 years ago

The navigator issue still exists in https://github.com/bugsnag/cuid/blob/master/lib/fingerprint.browser.js. Are you open to accepting PRs?

abigailbramble commented 3 years ago

@joshunger In general we're open to accepting PRs, however we'd be unlikely to accept a PR that removes navigator as we use that to help generate device IDs which is something we'd need to consider carefully if changing. Additionally there may be other areas that reference globals in @browser/js so that might not be sufficient. You could create your own fork of the repository for now until we're able to look into adding official support for Cloudflare workers.

joshunger commented 3 years ago

@phillipsam Afternoon! Sounds good, thanks for letting me know. I ended up here because browser was being included in SSR when using rails webpacker. Of course multiple ways to fix but this was the easiest. For anyone else -

environment.plugins.append(
  'define',
  new DefinePlugin({
    navigator: '(typeof navigator !== \'undefined\' ? navigator : { userAgent: "" })'
  })
);
jokedos commented 2 years ago

Hey! Any updates on the official support for Cloudflare workers? Would be awesome to have the official package for them.

hansottowirtz commented 2 years ago

From the Cloudflare Workers docs:

When the global_navigator compatibility flag is set, the navigator.userAgent property is available with the value 'Cloudflare-Workers'. This can be used, for example, to reliably determine that code is running within the Workers environment.

So in your wrangler.toml, you can try adding:

compatibility_flags = ["global_navigator"]

This can at least help to patch the navigator issue. I haven't tried this solution myself though, will update when I have tried it out.

ScottAwesome commented 1 year ago

Biggest issue here for me is next.js and bugsnag. The underlying architecture of the bugsnag plugins just don't play well, and very soon (likely announcing Oct. 25) they'll be encouraging and moving toward the cloudflare runtime underneath, however it remains to be seen if things are going to be compat / configurable.

This means Bugsnag, effectively, will have even worse compatibility with Next.js projects. Is there any way to get visibility for this? Right now I'm looking at recommending moving to a different logging platform entirely due to the limitations of the design.

Even a simple fetch based logger would be good, and would work exceedingly well in all environments.

jclusso commented 1 year ago

Any update on this recently?

johnkiely1 commented 1 year ago

Hi @jclusso, support for Cloudflare workers remains on our backlog. We hope to get to it soon, but at present don't have an ETA. We will post updates as soon as we have them.

Danetag commented 10 months ago

Hey team! Same question, any update on this? Thank you!

clr182 commented 10 months ago

Hi @Danetag This item is still on our backlog. Once we have more information we will be sure to update this thread.

remorses commented 10 months ago

I will be dead before you add workers support 💀

marshallswain commented 3 months ago

Maybe a tail worker with https://docs.bugsnag.com/api/error-reporting/ will do the trick. I haven't tried, yet.

RayBans2111 commented 1 week ago

any updates for this?