* 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>
204 lines
5.5 KiB
TypeScript
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);
|
|
}
|
|
};
|