Skip to content

Instantly share code, notes, and snippets.

@RaschidJFR
Last active December 16, 2022 18:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save RaschidJFR/64a9e6007f59a111094e8b03062daf7f to your computer and use it in GitHub Desktop.
Save RaschidJFR/64a9e6007f59a111094e8b03062daf7f to your computer and use it in GitHub Desktop.
Sentry: Angular ErrorHandler with Custom Errors, Sentry reporting and Version Bumping.
# Add this step to upload sourcemaps to Sentry
# Don't forget to build with `--source-map=true` to generate the sourcemaps.
# It's recommended that you don't upload them to your production hosting
- script: &script-sentry-release
- npm i @sentry/cli@1.66.0
- VERSION=$(npm run --silent version:describe)
- npx sentry-cli --auth-token=$SENTRY_AUTH_TOKEN releases -o $SENTRY_ORG new "$VERSION" --finalize -p $SENTRY_PROJECT
- npx sentry-cli --auth-token=$SENTRY_AUTH_TOKEN releases -o $SENTRY_ORG set-commits --auto $VERSION # make sure to add the repo in Sentry Dashboard
- npx sentry-cli --auth-token=$SENTRY_AUTH_TOKEN releases -o $SENTRY_ORG -p $SENTRY_PROJECT files "$VERSION" upload-sourcemaps ./sourcemaps
- npx sentry-cli --auth-token=$SENTRY_AUTH_TOKEN releases -o $SENTRY_ORG -p $SENTRY_PROJECT files "$VERSION" upload-sourcemaps ./www
- npx sentry-cli --auth-token=$SENTRY_AUTH_TOKEN releases -o $SENTRY_ORG -p $SENTRY_PROJECT files "$VERSION" upload-sourcemaps --ext ts ./src
import { NgModule, ErrorHandler, ModuleWithProviders, Optional, SkipSelf } from '@angular/core';
import * as Sentry from '@sentry/angular';
import { Integrations } from '@sentry/tracing';
import { ErrorHandlerService, Options } from './error-handler.service';
export interface Config {
/** @see {@link https://docs.sentry.io/platforms/javascript/#configure} */
dns: string;
/**
* @see
* {@link https://docs.sentry.io/platforms/javascript/configuration/sampling/#configuring-the-transaction-sample-rate}
*/
tracesSampleRate: number;
/**
* @see
* {@link https://docs.sentry.io/platforms/javascript/performance/instrumentation/automatic-instrumentation/} */
tracingOrigins: string[];
/**
* @see {@link https://docs.sentry.io/platforms/javascript/performance/instrumentation/automatic-instrumentation/}
* Default: `true`
* */
browserTracking?: boolean;
/** {@link https://docs.sentry.io/platforms/javascript/configuration/environments/} */
environment: string;
/** @see {@link https://docs.sentry.io/platforms/javascript/enriching-events/user-feedback/#customizing-the-widget} */
options?: Options;
/**
* String or funcition to pass a release string to Sentry
* @see {@link https://docs.sentry.io/platforms/javascript/configuration/releases/}
*/
release?: string | (() => string);
}
@NgModule({
providers: [
{ provide: ErrorHandler, useExisting: ErrorHandlerService },
],
})
export class ErrorHandlerModule {
constructor(@Optional() @SkipSelf() parentModule?: ErrorHandlerModule) {
if (parentModule) throw new Error('ErrorHandlerModule is already loaded!');
}
static forRoot(config: Config): ModuleWithProviders<ErrorHandlerModule> {
const release = config.release && (typeof config.release === 'string' ? config.release : config.release());
Sentry.init({
release,
environment: config.environment,
dsn: config.dns,
integrations: config.browserTracking !== false ? [
new Integrations.BrowserTracing({
tracingOrigins: config.tracingOrigins,
routingInstrumentation: Sentry.routingInstrumentation,
}),
] : [],
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: config.tracesSampleRate,
});
return {
ngModule: ErrorHandlerModule,
providers: [
{ provide: 'options', useValue: config.options },
],
};
}
}
import { Injectable, Inject, EventEmitter } from '@angular/core';
import { SentryErrorHandler, ErrorHandlerOptions } from '@sentry/angular';
// tslint:disable-next-line: no-empty-interface
export interface Options extends ErrorHandlerOptions { }
@Injectable({ providedIn: 'root' })
export class ErrorHandlerService extends SentryErrorHandler {
/** Emits each time an error is handled by this instance */
onError = new EventEmitter();
constructor(@Inject('options') options?: ErrorHandlerOptions) {
super(options);
this._options.extractor = (e: any) => e.rejection || this._defaultExtractor(e); // tslint:disable-line: no-any
}
setShowDialog(show: boolean) {
this._options.showDialog = show;
}
handleError(e) {
e = this._extractError(e);
this.onError.emit(e);
super.handleError(e);
}
}
/**
* Throw this error to stop a process but without reporting it as a crash in the
* Error Handler service
*/
export class IntentionalError extends Error {
constructor(public message: string) {
super(message);
this.name = 'IntentionalError';
Object.setPrototypeOf(this, IntentionalError.prototype);
}
}
{
"version:describe": "echo \"$(git describe origin/stable)+$(git rev-list --count $(git merge-base HEAD origin/stable)..HEAD).$(git show -s --format=%h).`date +%y%m%d`\"",
"version": "node scripts/version-bump `npm run --silent version:describe`"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment