DataDog / browser-sdk

Datadog Browser SDK
Apache License 2.0
301 stars 132 forks source link

Multiple SDK instances on a single page #1225

Open snaumov opened 2 years ago

snaumov commented 2 years ago

Hi!

We're looking to use datadog-logs in a microfrontend application. Is it possible to have a several instances of datadog-logs on a single page (so the logs would be sent to different applicationIds)?

UPD: we might be able to get away with a single instance of DD, and contextualize the logging with the application name, so it's logged in a central place, but we can filter out by the application.

bcaudan commented 2 years ago

Hello @snaumov,

We don't allow to use several instances of the SDK on the same page.

However, we are planning to address some use cases related to micro frontend approaches. The general idea would be to have a single instance of the SDK on the page tracking a single application but several services.

We'll keep you posted when we we'll have more details on that.

XiaofengXie16 commented 2 years ago

Any updates on this issue?

I am currently using module federation to build microfrontend. One issue I have is that DD_RUM context gets reloaded and loses its internal context in child app. Similar to the approach above, I will have to set datadog/browser-rum as a singleton in order to get around this issue.

BenoitZugmeyer commented 2 years ago

We are still working on improving the sub-app use cases.

One issue I have is that DD_RUM context gets reloaded and loses its internal context in child app

I'm not sure to see why. Care to provide more context on your application? Are you using iframes?

I will have to set datadog/browser-rum as a singleton in order to get around this issue.

DD_RUM should already be a singleton.

XiaofengXie16 commented 2 years ago

We are still working on improving the sub-app use cases.

One issue I have is that DD_RUM context gets reloaded and loses its internal context in child app

I'm not sure to see why. Care to provide more context on your application? Are you using iframes?

I will have to set datadog/browser-rum as a singleton in order to get around this issue.

DD_RUM should already be a singleton.

Hello @BenoitZugmeyer , I use webpack module federation for microfrontend.

This is the minimum reproducible , you can start the code by calling "yarn start" at the root level and then go to http://localhost:3001.

Link to repo: https://github.com/XiaofengXie16/module-federation

You can see that I initiate datadog in app1's index.js and then I call datadogRum.setGlobalContext in app2's button.js.

Now, if I go to the console(chrome devtool) and run DD_RUM.getInternalContext(), I will get an undefined value.

Let me know if you need any additional info (I am also in the public datadog channel and I am happy to hop on a call if needed)

Note:

  1. if i remove the datadog import in app2 , then the datadog context is preserved
  2. The way module federation works is that app1 dynamically pull the app2's button component at runtime
BenoitZugmeyer commented 2 years ago

Thanks for the project example! Really useful.

So it seems that the Browser SDK is included twice in the resulting bundles

Is this intended? It seems like a lot of unneeded duplicated code.

Because the Browser SDK keeps a module-local state, including it twice on the same page won't work. So now I understand your initial plan of having "to set datadog/browser-rum as a singleton in order to get around this issue." If you have the possibility to do so, it would be a great solution.

XiaofengXie16 commented 2 years ago

Thanks for taking a look, i think that's how module federation works. If you don't mark your dependencies as singleton, it will include its own copy of dependency.

To your point, yes, I can run it as singleton by using the singleton property listed in here : https://webpack.js.org/plugins/module-federation-plugin/#singleton

It will probably be great if this use case is documented in the datadog documentation.

Update: This branch contains the code that illustrates the solution: https://github.com/XiaofengXie16/module-federation/tree/fix-dd-issue

PaulKujawa commented 2 years ago

Is there any updates on this, @bcaudan ?

bcaudan commented 2 years ago

Hi,

No updates on this topic and given the underlying complexity, it is probably not something that we will address soon. Some issues could be solved with this approach if it is one day available but we may have workaround for issues that you are facing.

Please open an issue describing what you are trying to achieve and we would be happy to help there.

naserghiasisis commented 1 year ago

I see this issue has been open since 2021. do you have any update for it, please?

BenoitZugmeyer commented 1 year ago

No update yet. Loading the SDK code multiple times on the same page would not be practical. If you have a specific use case in mind that is not yet listed in our issues, feel free to open a new one.

elenasch commented 8 months ago

One use case is the ability to correlate logs with their services (micro frontends). If a browser client gets initialized only once, only the first micro frontend will initialize it and set the service (Logger Name) value. This renders the service catalog in datadog less useful for frontend code. In this view https://app.datadoghq.com/services , the logs get associated with a service only when initial service tag matches the service name.

I have tried to override the service tag when sending specific log lines to DD, but that doesn't allow for APM and log correlation. May be the correlation logic could be fixed, to allow correlation by additional tags?

deanshelton commented 8 months ago

I have a use case: If you build a JS sdk and want to log/track method invocation counts or metrics telemetry style data.

If the host site uses datadog, you can not use data-dog for browser logging in your SDK. I do not understand the need to make this object a global singleton because it prevents this use case.

Zyclotrop-j commented 8 months ago

Comment on "use a Singleton" discussed above: Not a solution, because not always possible. We have a micro frontend setup and each host page pulls in the DD SDK. Depending on the exact page, they pull in different major versions - that means, the version that would be shared with my team's micro frontend included on the host page, could be a diff major version depending on page we're on - and that obviously doesn't work, as the major versions are incompatible with each other!

That, of cause, in addition to the above mentioned limitations when using a Singleton, such as not being able to change certain fields and correlate/trace services e2e which we've been encountering, too.

deanshelton commented 7 months ago

@BenoitZugmeyer thoughts?

BenoitZugmeyer commented 7 months ago

I have a use case: If you build a JS sdk and want to log/track method invocation counts or metrics telemetry style data.

I'm sorry but the SDK is not designed for this use-case, at least for now.

We are still evaluating how to better support MFE use cases. That being said, having multiple SDK instances on a single page presents a few drawbacks and should probably be avoided:

elenasch commented 7 months ago

Wouldn't both of these drawbacks be the responsibility of the developers to keep in mind and be aware of, not the library sdk?

deanshelton commented 7 months ago

I think there are two flawed assumptions on behalf of the SDK here.

  1. that the logger should act as agent/daemon in the browser. (this requires polluting the global scope, yeah?)
  2. that 100% of client-side logging needs are for a single company. (not the case for me)
kangn-li commented 6 months ago

So for MFE use cases, is it feasible to have a global datadog rum instance but changes the service tag in each micro frontend service with the same instance by using startView?

BenoitZugmeyer commented 6 months ago

So for MFE use cases, is it feasible to have a global datadog rum instance but changes the service tag in each micro frontend service with the same instance by using startView?

If each MFE are running one after the other, yes it's possible (doc)

michalkotas commented 6 months ago

@BenoitZugmeyer what if we want to use a different application (by changing the applicationId and clientToken properties) for each microfrontend?

Logging all events to a single DD application could be problematic for security reasons, as each microfrontend is managed by different teams.

amortemousque commented 6 months ago

Hi @michalkotas, Currently, for a single SDK instance, the microfrontend ownership is down by service. You can define a service for each view (doc) If you want a different app per microfrontend, you need to have one microfrontend per page load, so you can initialize the SDK with the correct app configuration.

dgreene1 commented 3 months ago

So to be clear, for those of us (in the majority) that have more than 1 microfrontend on the page at a given time... there is no way to set the service for each addError such that two errors happening at the same time have different service names right?

Because from what I can tell, setting the service (via what... startView?) is a global affair which means that we're in a race-condition as to which microfrontend set the view name most recently.

tiborpilz commented 1 month ago

@dgreene1 What we're doing as a workaround is wrapping each addError call in a function that first does a startView({ service, version }), then a call to addError and immediately afterwards datadogRum.startView({}) to reset the service/version.

This way there shouldn't ™️ be any race conditions as this all happens in a single execution loop.