mattermost-mobile/app/utils/sentry.ts
Avinash Lingaloo 987d024708
Gekidou Sentry Installation (#6726)
* Sentry - Clean Install

* Update config.yml

* update CI to install Sentry CLI

* update CI to install Sentry CLI

* Squashed commit of the following:

commit e1996e59de8e135b19957dc9b0a0677f8b851c8b
Merge: 87cc8d6f2 2e8352f3e
Author: Avinash Lingaloo <avinashlng1080@gmail.com>
Date:   Fri Nov 4 20:59:29 2022 +0400

    Merge branch 'android-pr-sentry-clean' of https://github.com/mattermost/mattermost-mobile into android-pr-sentry-clean

commit 2e8352f3e15527c73ec3a634eae32b29aa6a9faf
Author: Elias Nahum <nahumhbl@gmail.com>
Date:   Fri Nov 4 15:48:24 2022 +0200

    update CI to install Sentry CLI

commit 87cc8d6f2b06945a4d0a2d4373836fd261b62c15
Author: Elias Nahum <nahumhbl@gmail.com>
Date:   Fri Nov 4 15:48:24 2022 +0200

    update CI to install Sentry CLI

commit 8dca885a0204c894bfcf544807976bac766b3b99
Author: Avinash Lingaloo <avinashlng1080@gmail.com>
Date:   Fri Nov 4 16:48:47 2022 +0400

    Update config.yml

commit 684bbb4aef
Author: Mylon Suren <23694620+mylonsuren@users.noreply.github.com>
Date:   Thu Nov 3 11:37:58 2022 -0400

    Remove down arrow next to team name and make team name unclickable (#6715)

commit 88ff8fac30
Author: Jason Frerich <jason.frerich@mattermost.com>
Date:   Wed Nov 2 19:35:23 2022 -0500

    [Bug] Emit boolean with "of" operator (#6729)

commit debcc99480
Author: Jason Frerich <jason.frerich@mattermost.com>
Date:   Wed Nov 2 12:15:54 2022 -0500

    [Gekidou MM-48006] Show keyboard when select a modifier (#6714)

* Delete @sentry+react-native+4.6.1.patch

* correction from PR review

* Add logError to DatabaseManager

* removes sentry context from android build job

* removes team+channel data

* shift active server listener to home/index

* Revert "shift active server listener to home/index"

This reverts commit 75e26faadd8c4359dd4d02c30375c03fadcc91bd.

* refactor after PR Review

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2022-11-11 22:48:38 +04:00

204 lines
5.5 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Database} from '@nozbe/watermelondb';
import {Breadcrumb} from '@sentry/types';
import {Platform} from 'react-native';
import {Navigation} from 'react-native-navigation';
import Config from '@assets/config.json';
import DatabaseManager from '@database/manager';
import {getConfig} from '@queries/servers/system';
import {getCurrentUser} from '@queries/servers/user';
import {ClientError} from './client_error';
import {logWarning} from './log';
export const BREADCRUMB_UNCAUGHT_APP_ERROR = 'uncaught-app-error';
export const BREADCRUMB_UNCAUGHT_NON_ERROR = 'uncaught-non-error';
export const LOGGER_EXTENSION = 'extension';
export const LOGGER_JAVASCRIPT = 'javascript';
export const LOGGER_JAVASCRIPT_WARNING = 'javascript_warning';
export const LOGGER_NATIVE = 'native';
let Sentry: any;
export function initializeSentry() {
if (!Config.SentryEnabled) {
return;
}
if (!Sentry) {
Sentry = require('@sentry/react-native');
}
const dsn = getDsn();
if (!dsn) {
logWarning('Sentry is enabled, but not configured on this platform');
return;
}
Sentry.init({
dsn,
tracesSampleRate: 0.2,
integrations: [
new Sentry.ReactNativeTracing({
// Pass instrumentation to be used as `routingInstrumentation`
routingInstrumentation: new Sentry.ReactNativeNavigationInstrumentation(
Navigation,
),
}),
],
sendDefaultPii: false,
...Config.SentryOptions,
});
}
function getDsn() {
if (Platform.OS === 'android') {
return Config.SentryDsnAndroid;
} else if (Platform.OS === 'ios') {
return Config.SentryDsnIos;
}
return '';
}
export function captureException(error: Error | string, logger: string) {
if (!Config.SentryEnabled) {
return;
}
if (!error || !logger) {
logWarning('captureException called with missing arguments', error, logger);
return;
}
Sentry.captureException(error, {logger});
}
export function captureJSException(error: Error | ClientError, isFatal: boolean) {
if (!Config.SentryEnabled) {
return;
}
if (!error) {
logWarning('captureJSException called with missing arguments', error);
return;
}
if (error instanceof ClientError) {
captureClientErrorAsBreadcrumb(error, isFatal);
} else {
captureException(error, LOGGER_JAVASCRIPT);
}
}
function captureClientErrorAsBreadcrumb(error: ClientError, isFatal: boolean) {
const isAppError = Boolean(error.server_error_id);
const breadcrumb: Breadcrumb = {
category: isAppError ? BREADCRUMB_UNCAUGHT_APP_ERROR : BREADCRUMB_UNCAUGHT_NON_ERROR,
data: {
isFatal: String(isFatal),
},
level: 'warning',
};
if (error.intl?.defaultMessage) {
breadcrumb.message = error.intl.defaultMessage;
} else {
breadcrumb.message = error.message;
}
if (breadcrumb.data) {
if (error.server_error_id) {
breadcrumb.data.server_error_id = error.server_error_id;
}
if (error.status_code) {
breadcrumb.data.status_code = error.status_code;
}
const match = (/^(?:https?:\/\/)[^/]+(\/.*)$/).exec(error.url);
if (match && match.length >= 2) {
breadcrumb.data.url = match[1];
}
}
try {
Sentry.addBreadcrumb(breadcrumb);
} catch (e) {
// Do nothing since this is only here to make sure we don't crash when handling an exception
logWarning('Failed to capture breadcrumb of non-error', e);
}
}
const getUserContext = async (database: Database) => {
const currentUser = {
id: 'currentUserId',
locale: 'en',
roles: 'multi-server-test-role',
};
const user = await getCurrentUser(database);
return {
userID: user?.id ?? currentUser.id,
email: '',
username: '',
locale: user?.locale ?? currentUser.locale,
roles: user?.roles ?? currentUser.roles,
};
};
const getExtraContext = async (database: Database) => {
const context = {
config: {},
currentChannel: {},
currentTeam: {},
};
const config = await getConfig(database);
if (config) {
context.config = {
BuildDate: config.BuildDate,
BuildEnterpriseReady: config.BuildEnterpriseReady,
BuildHash: config.BuildHash,
BuildHashEnterprise: config.BuildHashEnterprise,
BuildNumber: config.BuildNumber,
};
}
return context;
};
const getBuildTags = async (database: Database) => {
const tags = {
serverBuildHash: '',
serverBuildNumber: '',
};
const config = await getConfig(database);
if (config) {
tags.serverBuildHash = config.BuildHash;
tags.serverBuildNumber = config.BuildNumber;
}
return tags;
};
export const addSentryContext = async (serverUrl: string) => {
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
if (database) {
const userContext = await getUserContext(database);
Sentry.setContext('User-Information', userContext);
const buildContext = await getBuildTags(database);
Sentry.setContext('App-Build Information', buildContext);
const extraContext = await getExtraContext(database);
Sentry.setContext('Server-Information', extraContext);
}
};