getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.9k stars 1.56k forks source link

Sentry support in Module Federation #3268

Closed rramaa closed 3 months ago

rramaa commented 3 years ago

Webpack recently released module federation. Using this plugin, one can deploy multiple web apps(which may or may not be related framework wise) in a single webpage seamlessly.

Though this is great, it is now not possible to track JS errors as errors may occur in any part of the code. Sentry intercepts errors at a global level. That error is tagged with a release version and the sourcemaps related to that release is used for displaying the real source.

But now since error source can be any part of the code and that part can have different release versions, how can I communicate the release version to sentry so that my error can get successfuly decoded by the sourcemap.

Currently is there any way to tackle this problem?

Issue in webpack's repository https://github.com/webpack/webpack/issues/12706

ScriptedAlchemy commented 3 years ago

Ahhh yes here it is! As the creator of module federation, this is a biiiig area of opportunity to support

devbucket commented 3 years ago

We have the same issue here in our company. We moved our product to full site federation with ModuleFederation. (thank @ScriptedAlchemy for that! Really awesome!)

ScriptedAlchemy commented 3 years ago

Looking to bump this.. is it possible to update the DSN or have a part of the react tree point to another sentry DSN. Since my components are loaded from different teams, I want sentry to report back to the various DSNs that represent the workstreams

For example: I have a product page hosted by one application. It can run "standalone" and SSr itself. I have another app with checkout.

instead of reinstalling a npm package or something to distribute the code, creating drifting duplicates. Im able to use module federation to import the checkout-modal from checkout and render it inside product page. Now id an error is thrown in the checkout modal, the checkout team likely needs to be paged because the consuming team just places the <Modal>

So when a team-owned component fails, I need to report to the owning team that its errored and where.

JoseMartinC commented 3 years ago

Hello there!

Is there any progress or official statement from the Sentry team on giving support to Module Federation any time soon?

Maybe any workaround allowing us to use multiple DSNs within the same app?

Cheers!

ScriptedAlchemy commented 3 years ago

Also looking for an update on this.

kamilogorek commented 3 years ago

We haven't look into this yet, so there's nothing I can say tbh.

Looking to bump this.. is it possible to update the DSN or have a part of the react tree point to another sentry DSN. Since my components are loaded from different teams, I want sentry to report back to the various DSNs that represent the workstreams

This would currently require multiple clients, as detailed here: https://docs.sentry.io/platforms/javascript/troubleshooting/#using-a-client-directly It won't play nicely with propagating breadcrumbs throughout all those clients. This is something that we are working on, and there's currently no easy workaround for this.

ScriptedAlchemy commented 3 years ago

Solved this problem. https://scriptedalchemy.medium.com/distributed-logging-in-federated-applications-with-sentry-f4249aa66e20

mroswald commented 3 years ago

Solved this problem. https://scriptedalchemy.medium.com/distributed-logging-in-federated-applications-with-sentry-f4249aa66e20

We use a similar approach of binding hubs to error boundaries on the micro-frontend level. Does your approach work with breadcrumbs? We managed to send them via integrations and building a custom integration to catch breadcrumbs in hubs instead of the global scope, but it's a lot of custom code. Would be really nice to get such functionality from the library itself.

devbucket commented 2 years ago

Is there any news here? Is this being worked on?

vladanpaunovic commented 2 years ago

@devbucket there are ways on how to go about this. Check out this blog post - https://scriptedalchemy.medium.com/distributed-logging-in-federated-applications-with-sentry-f4249aa66e20

devbucket commented 2 years ago

@vladanpaunovic Thanks. I know about this. But this is not really a solution but a rather complex workaround. It would be great to have an official solution to this problem.

ScriptedAlchemy commented 2 years ago

Agreed. It's a workaround. However if someone reviewed my implementation - it likely could be simplified. I just wrote something that worked in a single pass and moved on to other problems.

Still a solution would be nice. Something like a way to register who owns a file even based on document.currentScript.src or at least a even bus so I can throw errors to the singleton with metadata attached and reroute them to the right DSN with a single handler instead of registering multiple clients and doin it at the function level.

AndreiSoroka commented 2 years ago

I just have one question :) Is the Sentry development team looking into the issue already? or is this issue only in the backlog?

yordis commented 2 years ago

@AndreiSoroka I am not part of the Sentry team, but I messed around here https://github.com/getsentry/sentry-javascript/pull/5420 to figure out how to make it work in Sentry.

I left a question there for me to continue moving forward.

AndreiSoroka commented 2 years ago

@yordis Yes, I read your thread. Cool! I'm more to the fact that the issue was opened in 2021. But I didn't see any response/reaction from the Sentry developers [¯_(ツ)_/¯]

vladanpaunovic commented 2 years ago

@AndreiSoroka, a few of us are looking into this one actually :)

We don't have an ETA at the moment as we are focused on resolving other issues. As soon as we know more about this one, we will notify folks here.

ScriptedAlchemy commented 2 years ago

@vladanpaunovic would love to see if we can collaborate on this. Lululemon is a paying customer of sentry and I am the author of Module Federation. I'd be interested to engage with the sentry team and help solve or provide internal knowledge on how we can manipulate MFP if need be. Also have a $40bn company that I'm willing to test this against. In production. 🧑‍🔧

May I be of assistance? How could we connect?

vladanpaunovic commented 2 years ago

@ScriptedAlchemy, sounds amazing!

Can you reach out to me on Sentry discord?

AndreiSoroka commented 2 years ago

@vladanpaunovic @ScriptedAlchemy Hi! Have you contacted each other? Do you have a forecast solution?

ScriptedAlchemy commented 2 years ago

I reached out on discord but no response yet. @vladanpaunovic whats your handle? Maybe I'm Dming someone else lol

gerardcastell commented 2 years ago

I strongly consider this feature a MUST that the Sentry product should adopt in the short-term. Every days more companies such as mine are adopting Microfrontends and the observability by scope is absolutely necessary. Please, if the Sentry could encourage to start work together with @ScriptedAlchemy in an integrated solution we will be very grateful. Thanks! We'll stay tuned

vladanpaunovic commented 2 years ago

Hey folks, I didn't post an update as I had some distractions and frankly, there is nothing to update just yet.

Currently, our team is having various discussions on how to proceed with this topic. Microfrontends are important to us and definitely something we want to better support in the future. However, doing that properly comes with challenges from within our own codebase which we are trying to figure out these days.

@ScriptedAlchemy, yes, the handle is correct. I will get back to you. 😄

ScriptedAlchemy commented 2 years ago

Much love. I'll keep an eye out.

Agree here - this is not something that should be rushed. Distributed logging and observability in 1) MFE and 2) federated applications each present architectural challenges.

Polylith log distribution is not something a tool like sentry has needed to really offer as such capabilities were virtually impossible till recently.

With federation fully supported in node runtimes, the need for observability becomes more apparent.

I think there's Two tracks we can take here. Depending on sentry teams capacity, im more than happy to put my resources behind the efforts.

1: we could document and create a reference repo showcasing how to accomplish distributed logging within the existing constraints of sentry today. I wrote a article a while ago which was just a hour or two of tinkering. That likely can be refined; but it does work and still powers my prod apps. We can overcome alot of setup with a little help from a webpack plugin - allowing a lower barrier to entry for a solution that'll tie us over till sentry core can be adjusted. This would be low effort but would alleviate alot of struggles the community is facing right now.

2: perhaps we could get a working group or collaboration together to talk about the direction or challenges we need deal with in sentry core.

I've got skin in the game & heavily entrenched in sentry ecosystem - no plans to move away so if there's anything i can offer to help... I'm in.

I mostly work on the webpack core. We can make a powerful integration with federated applications BUT whatever we put forward needs to be agnostic. I'm working on bundler agnostic Federation & beyond my tech - there's others like single spa that we would want to ensure elegant solutions for.

From a webpack standpoint though, I can likely build out a great integration which would be a cherry on top of a solid core implementation that's not coupled to a compiler

najie commented 1 year ago

I would be very interested in this reference repo that you mentioned @ScriptedAlchemy if it's ever come to life :) As I'm looking for a better integration than our current Datadog solution which doesn't seems to consider microfrontend yet. Thanks !

maksnester commented 1 year ago

@ScriptedAlchemy hey, have anything of what you described in the last message been done?

Thanks for your article btw 🙂

timfish commented 1 year ago

For the backend, we've recently added runWithAsyncContext to @sentry/node which gives full scope isolation across async contexts via AsyncLocalStorage in Node >= v14. While the primary use case for this is to isolate Sentry scope between requests, It could probably be used to isolate scope between components during SSR too.

If the tc39 async context proposal makes it into browsers we'll be able to support the same runWithAsyncContext API there too...

I don't think it's made it into a release yet, but we've just added a means to route events to different DSNs depending on your own custom logic. It's pretty bare-bones for now and not tailored to any specific use case but with some code it could for example allow you to route events from different error boundaries to different DSNs without creating multiple clients.

For uncaught errors, and errors not caught by error boundaries, @ScriptedAlchemy highlighted docuement.currentScript.src and I managed to put a basic PoC together which links uncaught errors to the module they came from via script URLs.

With the following shared code:

import { EventProcessor, Exception, Integration } from "@sentry/types";

declare global {
  interface Window {
    __SMF_MODULES__?: Record<string, string>;
  }
}

export function registerModule(moduleName: string, moduleUrl: string) {
  if (!window.__SMF_MODULES__) {
    window.__SMF_MODULES__ = {};
  }

  window.__SMF_MODULES__[moduleUrl] = moduleName;
}

function getFirstModuleFromException(exception: Exception): string | undefined {
  // Sentry frames have the top of the stack at the end of the array
  const reverseFrames = exception.stacktrace?.frames.reverse();

  for (const frame of reverseFrames) {
    const mod = window.__SMF_MODULES__[frame.filename];

    if (mod) {
      return mod;
    }
  }
}

export class ModuleFederationIntegration implements Integration {
  public static id: string = "ModuleFederationIntegration";
  public name: string = ModuleFederationIntegration.id;

  public setupOnce(
    addGlobalEventProcessor: (callback: EventProcessor) => void
  ) {
    addGlobalEventProcessor((event) => {
      if (event.exception?.values[0]) {
        const mod = getFirstModuleFromException(event.exception?.values[0]);

        if (mod) {
          event.tags = {...event.tags, module: mod};
        }
      }
      return event;
    });
  }
}

Add the integration in your root app:

Sentry.init({
  dsn: '__DSN__',
  integrations: [ new ModuleFederationIntegration() ]
}); 

In the top of every exposed module, register the module name and script src URL:

registerModule('component-1', document.currentScript.src);

Then once an uncaught error comes through the Sentry event pipeline, the ModuleFederationIntegration inspects the stack frames and adds a module tag for the first registered module found.

If you then want to route these to different DSNs, the newly added multiplexed transport could convert tags to DSNs.

smeubank commented 1 year ago

Hi all,

We have been taking some steps in recent months to investigate how we can provide better support not just through our SDK but also looking at webpack and module federation. Please see the work here and we'd love to hear your thoughts!

https://github.com/getsentry/sentry-javascript-bundler-plugins/issues/323

AbhiPrasad commented 3 months ago

This is now documented with https://docs.sentry.io/platforms/javascript/best-practices/micro-frontends/

If you have any questions - please open a new issue! Things have changed a lot since this was originally created so a new issue will be easier for us to track and triage accordingly.

AndreiSoroka commented 3 months ago

could I leave you a small comment: guys, you are awesome!