Reputation: 744
I'm trying to override default angular ErrorHandler
by providing factory function which should have ngrx store injected:
import { ErrorHandler } from "@angular/core";
[...]
{
provide: ErrorHandler,
useFactory: (store: Store<AppState>) => {
return Sentry.createErrorHandler({
showDialog: true,
dialogOptions: {},
});
},
deps: [Store],
},
but I get cyclic dependency error:
main.ts:42 Error: NG0200: Circular dependency in DI detected for Store. Find more at https://angular.io/errors/NG0200
at throwCyclicDependencyError (core.js:216)
at R3Injector.hydrate (core.js:11434)
at R3Injector.get (core.js:11257)
at injectInjectorOnly (core.js:4751)
at ɵɵinject (core.js:4755)
at injectArgs (core.js:4832)
at Object.factory (core.js:11522)
at R3Injector.hydrate (core.js:11438)
at R3Injector.get (core.js:11257)
at injectInjectorOnly (core.js:4751)
How to omit this problem? I need to provide sth from the store to the factory function that creates error handler (Sentry.createErrorHandler
).
Upvotes: 3
Views: 1248
Reputation: 3612
Simplest way Ive found is to implement a custom Error Handler as ngrx-store
uses Angulars EventHandler
eg
SentryErrorHandler
import { ErrorHandler, Injectable } from "@angular/core";
import * as Sentry from "@sentry/angular";
import { Integrations } from "@sentry/tracing";
@Injectable()
export class SentryErrorHandler implements ErrorHandler {
constructor() {
Sentry.init({
dsn: "https://[your-sentry-dsn-here]",
integrations: [
new Integrations.BrowserTracing({
tracingOrigins: ["localhost", "other-test-urls"],
routingInstrumentation: Sentry.routingInstrumentation
})
]
});
}
handleError(error: Error) {
Sentry.captureException(error);
}
}
then in your app.module
providers: [
{
provide: ErrorHandler,
useClass: SentryErrorHandler
}
]
To test an example would be to create an incorrect url in an Effect
that calls a service and NOT catchError
to see if it pops up in Sentry eg
@Injectable()
export class SettingsEffects {
constructor(private actions$: Actions,
private settingsService: settingsService) {
}
loadSettings$ = createEffect(() => this.actions$
.pipe(
ofType(settingsActions.loadSettings),
mergeMap(() => this.settingsService.get()
.pipe(
map((response) => settingsActions.loadSettingsSuccess({ payload: response})),
//catchError((error) => of(settingsActions.loadSettingsFailed({ payload: error}))) //commented out should go to Sentry instead
))
));
}
UPDATE
Seems the ErrorHandler
is created very early in the lifecycle before the providers so tried by adding the Injector
as a constructor parameter
@Injectable()
export class SentryErrorHandler implements ErrorHandler {
//store property to use in handleError
private get _store() {
return this.injector.get(Store);
}
constructor(private injector: Injector) {
}.......
see this answer Injecting services in custom ErrorHandler causes "Cannot instantiate cyclic dependency!" error, how can I fix this?
Upvotes: 4