Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1d406de

Browse files
maxkostyvivianyentranLuca Forstner
authored
Simplify/reorganize Micro Frontend Suport (#9215)
* Simplify/reorganize Micro Frontend Suport * Update micro-frontend-support.mdx * default matcher instead of a new method See: getsentry/sentry-javascript#10798 (comment) * Update docs/platforms/javascript/common/configuration/micro-frontend-support.mdx Co-authored-by: vivianyentran <20403606+vivianyentran@users.noreply.github.com> * Update docs/platforms/javascript/common/configuration/micro-frontend-support.mdx Co-authored-by: vivianyentran <20403606+vivianyentran@users.noreply.github.com> * Update docs/platforms/javascript/common/configuration/micro-frontend-support.mdx Co-authored-by: vivianyentran <20403606+vivianyentran@users.noreply.github.com> * Update docs/platforms/javascript/common/configuration/micro-frontend-support.mdx Co-authored-by: vivianyentran <20403606+vivianyentran@users.noreply.github.com> * Update docs/platforms/javascript/common/configuration/micro-frontend-support.mdx Co-authored-by: vivianyentran <20403606+vivianyentran@users.noreply.github.com> * Update docs/platforms/javascript/common/configuration/micro-frontend-support.mdx Co-authored-by: vivianyentran <20403606+vivianyentran@users.noreply.github.com> * Update micro-frontend-support.mdx * Note about calling Sentry.init() only once * Address Luca's comments in micro-frontend-support.mdx * Update docs/platforms/javascript/common/configuration/micro-frontend-support.mdx Co-authored-by: Luca Forstner <luca.forstner@sentry.io> * Update docs/platforms/javascript/common/configuration/micro-frontend-support.mdx Co-authored-by: vivianyentran <20403606+vivianyentran@users.noreply.github.com> --------- Co-authored-by: vivianyentran <20403606+vivianyentran@users.noreply.github.com> Co-authored-by: Luca Forstner <luca.forstner@sentry.io>
1 parent 81d291c commit 1d406de

File tree

1 file changed

+81
-137
lines changed

1 file changed

+81
-137
lines changed

‎docs/platforms/javascript/common/configuration/micro-frontend-support.mdx‎

Lines changed: 81 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,34 @@ keywords:
1414
If your frontend includes JavaScript bundles from multiple sources with
1515
different release cycles, you may want to identify these or route events to specific projects. This is especially useful if you've set up [module federation](https://module-federation.github.io/) or a similar frontend architecture.
1616

17-
## Identifying the source of errors
17+
Below we offer two approaches.
1818

19-
To identify the source of an error, you must inject metadata that helps identify
20-
which bundles were responsible for the error. You can do this with any of the
21-
Sentry bundler plugins by enabling the `_experiments.moduleMetadata` option.
19+
<Note>
20+
In all cases `Sentry.init()` must never be called more than once, doing so will result in undefined behavior.
21+
</Note>
22+
23+
## Automatically Route Errors to Different Projects Depending on Module
24+
25+
`ModuleMetadata` and `makeMultiplexedTransport` can be used together to automatically route
26+
events to different Sentry projects based on the module where the error
27+
occurred.
2228

29+
<Note>
30+
<ul>
31+
<li>
2332
Requires version `2.5.0` or higher of `@sentry/webpack-plugin` or version
2433
`2.7.0` or higher of `@sentry/rollup-plugin`, `@sentry/vite-plugin` or `@sentry/esbuild-plugin`.
34+
</li>
35+
<li>
36+
Requires SDK version `7.59.0` or higher.
37+
</li>
38+
</ul>
39+
</Note>
2540

26-
`moduleMetadata` can be any serializable data or alternatively a function that
27-
returns serializable data. If you supply a function, it will be passed an object
28-
containing the `org`, `project`, and `release` strings.
41+
First, to identify the source of an error, you must inject metadata that helps identify
42+
which bundles were responsible for the error. You can do this with any of the
43+
Sentry bundler plugins by enabling the `_experiments.moduleMetadata` option. The example
44+
below is for Webpack, but this is also supported in Vite, Rollup, and esbuild.
2945

3046
```javascript
3147
// webpack.config.js
@@ -37,61 +53,79 @@ module.exports = {
3753
sentryWebpackPlugin({
3854
/* Other plugin config */
3955
_experiments: {
40-
moduleMetadata: ({ org, project, release }) => {
41-
return { team: "frontend", release };
42-
},
56+
moduleMetadata: ({ release }) => ({ dsn: "__MODULE_DSN__", release }),
4357
},
4458
}),
4559
],
4660
};
4761
```
4862

49-
### `ModuleMetadata` Integration
50-
51-
Requires SDK version `7.59.0` or higher.
52-
5363
Once metadata has been injected into modules, the `moduleMetadataIntegration`
5464
can be used to look up that metadata and attach it to stack frames with
55-
matching file names. This metadata is then available in other integrations or in
56-
the `beforeSend` callback as the `module_metadata` property on each
57-
`StackFrame`. This can be used to identify which bundles may be responsible
58-
for an error and used to tag or route events.
65+
matching file names. This metadata is then available in the `beforeSend` callback
66+
as the `module_metadata` property on each `StackFrame`. This can be used to identify
67+
which bundles may be responsible for an error. Once the destination is determined, you can
68+
store it as a list of DSN-release pairs in `event.extra[MULTIPLEXED_TRANSPORT_EXTRA_KEY]`
69+
for the multiplexed transport to reference for routing.
70+
71+
In practice, here is what your Sentry initialization should look like:
5972

6073
```javascript
61-
import * as Sentry from "@sentry/browser";
74+
import { init, makeFetchTransport, moduleMetadataIntegration, makeMultiplexedTransport } from "@sentry/browser";
75+
76+
const EXTRA_KEY = "ROUTE_TO";
77+
78+
const transport = makeMultiplexedTransport(makeFetchTransport, (args) => {
79+
const event = args.getEvent();
80+
if (
81+
event &&
82+
event.extra &&
83+
EXTRA_KEY in event.extra &&
84+
Array.isArray(event.extra[EXTRA_KEY])
85+
) {
86+
return event.extra[EXTRA_KEY];
87+
}
88+
return [];
89+
});
6290

63-
Sentry.init({
64-
dsn: "___PUBLIC_DSN___",
65-
integrations: [Sentry.moduleMetadataIntegration()],
91+
init({
92+
dsn: "__DEFAULT_DSN__",
93+
integrations: [moduleMetadataIntegration()],
94+
transport,
6695
beforeSend: (event) => {
67-
const frames = event?.exception?.values?.[0].stacktrace.frames || [];
68-
// Get all team names in the stack frames
69-
const teams = frames
70-
.filter((frame) => frame.module_metadata && frame.module_metadata.team)
71-
.map((frame) => frame.module_metadata.team);
72-
// If there are teams, add them as extra data to the event
73-
if (teams.length > 0) {
74-
event.extra = {
75-
...event.extra,
76-
teams,
77-
};
96+
if (event?.exception?.values?.[0].stacktrace.frames) {
97+
const frames = event.exception.values[0].stacktrace.frames;
98+
// Find the last frame with module metadata containing a DSN
99+
const routeTo = frames
100+
.filter((frame) => frame.module_metadata && frame.module_metadata.dsn)
101+
.map((v) => v.module_metadata)
102+
.slice(-1); // using top frame only - you may want to customize this according to your needs
103+
104+
if (routeTo.length) {
105+
event.extra = {
106+
...event.extra,
107+
[EXTRA_KEY]: routeTo,
108+
};
109+
}
78110
}
79111

80112
return event;
81113
},
82114
});
83-
84-
Sentry.captureException(new Error("oh no!"));
85115
```
86116
87-
## Routing events to different projects
117+
Once this is set up, errors - both handled and unhandled - will be automatically routed to the right project.
118+
88119
89-
Once you've identified which module or modules are likely to be responsible for
90-
an error, you may want to send these events to different Sentry projects. The
91-
multiplexed transport can route events to different Sentry projects based on the
92-
attributes on an event.
120+
## Manually Route Errors to Different Projects
93121
122+
If, however, you would like to have more control over the routing of errors to the point
123+
where you explicitly specify the destination for each individual `captureException`,
124+
you can do that with the more advanced interface multiplexed transport offers.
125+
126+
<Note>
94127
Requires SDK version `7.59.0` or higher.
128+
</Note>
95129
96130
The example below uses a `feature` tag to determine which Sentry project to
97131
send the event to. If the event does not have a `feature` tag, we send it to the
@@ -130,107 +164,17 @@ init({
130164
dsn: "__FALLBACK_DSN__",
131165
transport: makeMultiplexedTransport(makeFetchTransport, dsnFromFeature),
132166
});
133-
134-
captureException(new Error("oh no!"), (scope) => {
135-
scope.setTag("feature", "cart");
136-
return scope;
137-
});
138-
```
139-
140-
You can then set tags/contexts on events in individual micro-frontends to decide which Sentry project to send the event to.
141-
142-
### `makeMultiplexedTransport` API
143-
144-
`makeMultiplexedTransport` takes an instance of a transport (we recommend
145-
`makeFetchTransport`) and a matcher function that returns an array of objects
146-
containing the DSN and optionally the release.
147-
148-
```typescript
149-
interface RouteTo {
150-
dsn: string;
151-
release?: string;
152-
}
153-
154-
type Matcher = (param: MatchParam) => RouteTo[];
155-
156-
declare function makeMultiplexedTransport(
157-
transport: (options: TransportOptions) => Transport,
158-
matcher: Matcher
159-
): (options: TransportOptions) => Transport;
160167
```
161168
162-
The matcher function runs after all client processing (`beforeSend` option, event processors from integrations).
163-
164-
## Combining `ModuleMetadata` and `makeMultiplexedTransport`
169+
You can then set tags/contexts on events in individual micro-frontends to decide which Sentry project to send the event to as follows:
165170
166-
`ModuleMetadata` and `makeMultiplexedTransport` can be used together to route
167-
events to different Sentry projects based on the module where the error
168-
occurred.
169-
170-
Ensure your modules have injected metadata containing the project DSN and release:
171-
172-
```javascript
173-
// webpack.config.js
174-
const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");
171+
<Note>
172+
It is important to always use a local scope when setting the tag (either as shown below or using <PlatformLink to="/enriching-events/scopes/#local-scopes">withScope documentation</PlatformLink>). Using a global scope e.g. through `Sentry.setTag()` will result in all subsequent events being routed to the same DSN regardless of where they originate.
173+
</Note>
175174
176-
module.exports = {
177-
devtool: "source-map",
178-
plugins: [
179-
sentryWebpackPlugin({
180-
_experiments: {
181-
moduleMetadata: ({ release }) => ({ dsn: "__MODULE_DSN__", release }),
182-
},
183-
}),
184-
],
185-
};
186175
```
187-
188-
Then when you initialize Sentry:
189-
190-
- Add the `ModuleMetadata` integration so metadata is attached to stack frames
191-
- Add a `beforeSend` callback that sets an `extra` property with the target DSN/release
192-
- Create a transport that routes events when the `extra` property is present
193-
194-
```javascript
195-
import { init, makeFetchTransport, moduleMetadataIntegration, makeMultiplexedTransport } from "@sentry/browser";
196-
197-
const EXTRA_KEY = "ROUTE_TO";
198-
199-
const transport = makeMultiplexedTransport(makeFetchTransport, (args) => {
200-
const event = args.getEvent();
201-
if (
202-
event &&
203-
event.extra &&
204-
EXTRA_KEY in event.extra &&
205-
Array.isArray(event.extra[EXTRA_KEY])
206-
) {
207-
return event.extra[EXTRA_KEY];
208-
}
209-
return [];
210-
});
211-
212-
init({
213-
dsn: "__DEFAULT_DSN__",
214-
integrations: [moduleMetadataIntegration()],
215-
transport,
216-
beforeSend: (event) => {
217-
if (event?.exception?.values?.[0].stacktrace.frames) {
218-
const frames = event.exception.values[0].stacktrace.frames;
219-
// Find the last frame with module metadata containing a DSN
220-
const routeTo = frames
221-
.filter((frame) => frame.module_metadata && frame.module_metadata.dsn)
222-
.map((v) => v.module_metadata)
223-
.slice(-1); // using top frame only - you may want to customize this according to your needs
224-
225-
if (routeTo.length) {
226-
event.extra = {
227-
...event.extra,
228-
[EXTRA_KEY]: routeTo,
229-
};
230-
}
231-
}
232-
233-
return event;
234-
},
176+
captureException(new Error("oh no!"), (scope) => {
177+
scope.setTag("feature", "cart");
178+
return scope;
235179
});
236180
```

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /