mirror of
https://github.com/twentyhq/twenty
synced 2026-04-21 13:37:22 +00:00
* feat: wip add user to sentry * feat: wip interceptor * feat: wip add user to sentry * feat: add user into sentry errors * fix: hide stack trace in production * fix: properly log commands and handle exceptions * fix: filter command exceptions * feat: handle jobs errors
101 lines
2.8 KiB
TypeScript
101 lines
2.8 KiB
TypeScript
import * as Sentry from '@sentry/node';
|
|
import { ProfilingIntegration } from '@sentry/profiling-node';
|
|
|
|
import { ExceptionHandlerUser } from 'src/integrations/exception-handler/interfaces/exception-handler-user.interface';
|
|
import { ExceptionHandlerOptions } from 'src/integrations/exception-handler/interfaces/exception-handler-options.interface';
|
|
|
|
import {
|
|
ExceptionHandlerDriverInterface,
|
|
ExceptionHandlerSentryDriverFactoryOptions,
|
|
} from 'src/integrations/exception-handler/interfaces';
|
|
|
|
export class ExceptionHandlerSentryDriver
|
|
implements ExceptionHandlerDriverInterface
|
|
{
|
|
constructor(options: ExceptionHandlerSentryDriverFactoryOptions['options']) {
|
|
Sentry.init({
|
|
dsn: options.dsn,
|
|
integrations: [
|
|
// enable HTTP calls tracing
|
|
new Sentry.Integrations.Http({ tracing: true }),
|
|
// enable Express.js middleware tracing
|
|
new Sentry.Integrations.Express({ app: options.serverInstance }),
|
|
new Sentry.Integrations.GraphQL(),
|
|
new Sentry.Integrations.Postgres({
|
|
usePgNative: true,
|
|
}),
|
|
new ProfilingIntegration(),
|
|
],
|
|
tracesSampleRate: 1.0,
|
|
profilesSampleRate: 1.0,
|
|
environment: options.debug ? 'development' : 'production',
|
|
debug: options.debug,
|
|
});
|
|
}
|
|
|
|
captureExceptions(
|
|
exceptions: ReadonlyArray<any>,
|
|
options?: ExceptionHandlerOptions,
|
|
) {
|
|
const eventIds: string[] = [];
|
|
|
|
Sentry.withScope((scope) => {
|
|
if (options?.operation) {
|
|
scope.setTag('operation', options.operation.name);
|
|
scope.setTag('operationName', options.operation.name);
|
|
}
|
|
|
|
if (options?.document) {
|
|
scope.setExtra('document', options.document);
|
|
}
|
|
|
|
for (const exception of exceptions) {
|
|
const errorPath = (exception.path ?? [])
|
|
.map((v: string | number) => (typeof v === 'number' ? '$index' : v))
|
|
.join(' > ');
|
|
|
|
if (errorPath) {
|
|
scope.addBreadcrumb({
|
|
category: 'execution-path',
|
|
message: errorPath,
|
|
level: 'debug',
|
|
});
|
|
}
|
|
|
|
const eventId = Sentry.captureException(exception, {
|
|
fingerprint: [
|
|
'graphql',
|
|
errorPath,
|
|
options?.operation?.name,
|
|
options?.operation?.type,
|
|
],
|
|
contexts: {
|
|
GraphQL: {
|
|
operationName: options?.operation?.name,
|
|
operationType: options?.operation?.type,
|
|
},
|
|
},
|
|
});
|
|
|
|
eventIds.push(eventId);
|
|
}
|
|
});
|
|
|
|
return eventIds;
|
|
}
|
|
|
|
captureMessage(message: string, user?: ExceptionHandlerUser) {
|
|
Sentry.captureMessage(message, (scope) => {
|
|
if (user) {
|
|
scope.setUser({
|
|
id: user.id,
|
|
ip_address: user.ipAddress,
|
|
email: user.email,
|
|
username: user.username,
|
|
});
|
|
}
|
|
|
|
return scope;
|
|
});
|
|
}
|
|
}
|