mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
console: Add Sentry
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5699 Co-authored-by: Rishichandra Wawhal <27274869+wawhal@users.noreply.github.com> Co-authored-by: Daniel Harvey <4729125+danieljharvey@users.noreply.github.com> GitOrigin-RevId: 00f2c5d25012b21f4e8763ef578598a3a11896e4
This commit is contained in:
parent
913f3f12e4
commit
a0f4f00bfd
5
console/cypress/global.d.ts
vendored
5
console/cypress/global.d.ts
vendored
@ -18,6 +18,11 @@ interface Env {
|
||||
serverVersion: string;
|
||||
telemetryTopic: string;
|
||||
urlPrefix: string;
|
||||
|
||||
/**
|
||||
* Corresponds to the HASURA_CONSOLE_SENTRY_DSN environment variable
|
||||
*/
|
||||
consoleSentryDsn: string;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
|
@ -11,7 +11,7 @@ export {
|
||||
export { fetchConsoleNotifications } from '../src/components/Main/Actions';
|
||||
export { default as NotificationSection } from '../src/components/Main/NotificationSection';
|
||||
export { default as Onboarding } from '../src/components/Common/Onboarding';
|
||||
export { analyticsToolsUtils } from '../src/features/AnalyticsToolsUtils';
|
||||
export { tracingTools } from '../src/features/TracingTools';
|
||||
export { OnboardingWizard } from '../src/features/OnboardingWizard';
|
||||
export { makeGrowthExperimentsClient } from '../src/features/GrowthExperiments';
|
||||
export { default as PageNotFound } from '../src/components/Error/PageNotFound';
|
||||
|
251
console/package-lock.json
generated
251
console/package-lock.json
generated
@ -21,6 +21,8 @@
|
||||
"@radix-ui/react-tabs": "^1.0.0",
|
||||
"@radix-ui/react-tooltip": "^1.0.0",
|
||||
"@reduxjs/toolkit": "^1.5.1",
|
||||
"@sentry/react": "7.11.1",
|
||||
"@sentry/tracing": "7.11.1",
|
||||
"@types/lodash.get": "^4.4.6",
|
||||
"@xstate/react": "^2.0.0",
|
||||
"ace-builds": "^1.4.11",
|
||||
@ -5507,6 +5509,129 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.11.1.tgz",
|
||||
"integrity": "sha512-k2XHuzPfnm8VJPK5eWd1+Y5VCgN42sLveb8Qxc3prb5PSL416NWMLZaoB7RMIhy430fKrSFiosnm6QDk2M6pbA==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.11.1",
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.11.1.tgz",
|
||||
"integrity": "sha512-kaDSZ6VNuO4ZZdqUOOX6XM6x+kjo2bMnDQ3IJG51FPvVjr8lXYhXj1Ccxcot3pBYAIWPPby2+vNDOXllmXqoBA==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "7.11.1",
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/hub": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.11.1.tgz",
|
||||
"integrity": "sha512-M6ClgdXdptS0lUBKB5KpXXe2qMQhsoiEN2pEGRI6+auqhfHCUQB1ZXsfjiOYexKC9fwx7TyFyZ9Jcaf2DTxEhw==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/hub/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/react": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.11.1.tgz",
|
||||
"integrity": "sha512-kp/vBgwNrlFEtW3e6DY9T4s3di9peL66n5UIY5n6dYkiN7A7D6/Kz1WJ/ZCL82DvaCMEY577wNyr2C+442l7fw==",
|
||||
"dependencies": {
|
||||
"@sentry/browser": "7.11.1",
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "15.x || 16.x || 17.x || 18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/react/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/tracing": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.11.1.tgz",
|
||||
"integrity": "sha512-ilgnHfpdYUWKG/5yAXIfIbPVsCfrC4ONFBR/wN25/hdAyVfXMa3AJx7NCCXxZBOPDWH3hMW8rl4La5yuDbXofg==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "7.11.1",
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/tracing/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/types": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.11.1.tgz",
|
||||
"integrity": "sha512-gIEhOPxC2cjrxQ0+K2SFJ1P6e/an5osSxVc9OOtekN28eHtVsXFCLB8XVWeNQnS7N2VkrVrkqORMBz1kvIcvVQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.11.1.tgz",
|
||||
"integrity": "sha512-tRVXNT5O9ilkV31pyHeTqA1PcPQfMV/2OR6yUYM4ah+QVISovC0f0ybhByuH5nYg6x/Gsnx1o7pc8L1GE3+O7A==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sinonjs/commons": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
|
||||
@ -6022,6 +6147,21 @@
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/addon-interactions/node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"extraneous": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/addon-links": {
|
||||
"version": "6.5.10",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.5.10.tgz",
|
||||
@ -45705,6 +45845,117 @@
|
||||
"any-observable": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.11.1.tgz",
|
||||
"integrity": "sha512-k2XHuzPfnm8VJPK5eWd1+Y5VCgN42sLveb8Qxc3prb5PSL416NWMLZaoB7RMIhy430fKrSFiosnm6QDk2M6pbA==",
|
||||
"requires": {
|
||||
"@sentry/core": "7.11.1",
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.11.1.tgz",
|
||||
"integrity": "sha512-kaDSZ6VNuO4ZZdqUOOX6XM6x+kjo2bMnDQ3IJG51FPvVjr8lXYhXj1Ccxcot3pBYAIWPPby2+vNDOXllmXqoBA==",
|
||||
"requires": {
|
||||
"@sentry/hub": "7.11.1",
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.11.1.tgz",
|
||||
"integrity": "sha512-M6ClgdXdptS0lUBKB5KpXXe2qMQhsoiEN2pEGRI6+auqhfHCUQB1ZXsfjiOYexKC9fwx7TyFyZ9Jcaf2DTxEhw==",
|
||||
"requires": {
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/react": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.11.1.tgz",
|
||||
"integrity": "sha512-kp/vBgwNrlFEtW3e6DY9T4s3di9peL66n5UIY5n6dYkiN7A7D6/Kz1WJ/ZCL82DvaCMEY577wNyr2C+442l7fw==",
|
||||
"requires": {
|
||||
"@sentry/browser": "7.11.1",
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/tracing": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.11.1.tgz",
|
||||
"integrity": "sha512-ilgnHfpdYUWKG/5yAXIfIbPVsCfrC4ONFBR/wN25/hdAyVfXMa3AJx7NCCXxZBOPDWH3hMW8rl4La5yuDbXofg==",
|
||||
"requires": {
|
||||
"@sentry/hub": "7.11.1",
|
||||
"@sentry/types": "7.11.1",
|
||||
"@sentry/utils": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.11.1.tgz",
|
||||
"integrity": "sha512-gIEhOPxC2cjrxQ0+K2SFJ1P6e/an5osSxVc9OOtekN28eHtVsXFCLB8XVWeNQnS7N2VkrVrkqORMBz1kvIcvVQ=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.11.1.tgz",
|
||||
"integrity": "sha512-tRVXNT5O9ilkV31pyHeTqA1PcPQfMV/2OR6yUYM4ah+QVISovC0f0ybhByuH5nYg6x/Gsnx1o7pc8L1GE3+O7A==",
|
||||
"requires": {
|
||||
"@sentry/types": "7.11.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sinonjs/commons": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
|
||||
|
@ -89,6 +89,8 @@
|
||||
"@radix-ui/react-tabs": "^1.0.0",
|
||||
"@radix-ui/react-tooltip": "^1.0.0",
|
||||
"@reduxjs/toolkit": "^1.5.1",
|
||||
"@sentry/react": "7.11.1",
|
||||
"@sentry/tracing": "7.11.1",
|
||||
"@types/lodash.get": "^4.4.6",
|
||||
"@xstate/react": "^2.0.0",
|
||||
"ace-builds": "^1.4.11",
|
||||
|
@ -1,8 +1,11 @@
|
||||
/* eslint no-underscore-dangle: 0 */
|
||||
import { SERVER_CONSOLE_MODE } from './constants';
|
||||
import { getFeaturesCompatibility } from './helpers/versionUtils';
|
||||
import { stripTrailingSlash } from './components/Common/utils/urlUtils';
|
||||
|
||||
import { sentry } from './features/TracingTools/sentry';
|
||||
import { isEmpty } from './components/Common/utils/jsUtils';
|
||||
import { stripTrailingSlash } from './components/Common/utils/urlUtils';
|
||||
|
||||
import { SERVER_CONSOLE_MODE } from './constants';
|
||||
|
||||
type ConsoleType = 'oss' | 'cloud' | 'pro' | 'pro-lite';
|
||||
|
||||
@ -18,6 +21,7 @@ type OSSServerEnv = {
|
||||
serverVersion: string; // e.g. "v2.7.0"
|
||||
urlPrefix: string; // e.g. "/console"
|
||||
cdnAssets: boolean;
|
||||
consoleSentryDsn?: string; // Corresponds to the HASURA_CONSOLE_SENTRY_DSN environment variable
|
||||
};
|
||||
|
||||
type ProServerEnv = {
|
||||
@ -30,6 +34,7 @@ type ProServerEnv = {
|
||||
isAdminSecretSet: boolean;
|
||||
serverVersion: string;
|
||||
urlPrefix: string;
|
||||
consoleSentryDsn?: string; // Corresponds to the HASURA_CONSOLE_SENTRY_DSN environment variable
|
||||
};
|
||||
|
||||
type ProLiteServerEnv = {
|
||||
@ -42,6 +47,7 @@ type ProLiteServerEnv = {
|
||||
isAdminSecretSet: boolean;
|
||||
serverVersion: string;
|
||||
urlPrefix: string;
|
||||
consoleSentryDsn?: string; // Corresponds to the HASURA_CONSOLE_SENTRY_DSN environment variable
|
||||
};
|
||||
|
||||
type CloudUserRole = 'owner' | 'user';
|
||||
@ -64,6 +70,8 @@ type CloudServerEnv = {
|
||||
tenantID: UUID;
|
||||
urlPrefix: string;
|
||||
userRole: CloudUserRole;
|
||||
userId?: string;
|
||||
consoleSentryDsn?: string; // Corresponds to the HASURA_CONSOLE_SENTRY_DSN environment variable
|
||||
};
|
||||
|
||||
type OSSCliEnv = {
|
||||
@ -78,6 +86,7 @@ type OSSCliEnv = {
|
||||
enableTelemetry: boolean;
|
||||
serverVersion: string;
|
||||
urlPrefix: string;
|
||||
consoleSentryDsn?: string; // Corresponds to the HASURA_CONSOLE_SENTRY_DSN environment variable
|
||||
};
|
||||
|
||||
export type CloudCliEnv = {
|
||||
@ -100,6 +109,7 @@ export type CloudCliEnv = {
|
||||
pro: true;
|
||||
projectId: UUID;
|
||||
isAdminSecretSet: boolean;
|
||||
consoleSentryDsn?: string; // Corresponds to the HASURA_CONSOLE_SENTRY_DSN environment variable
|
||||
};
|
||||
|
||||
type ProCliEnv = CloudCliEnv;
|
||||
@ -124,6 +134,9 @@ export type EnvVars = {
|
||||
eeMode?: string;
|
||||
consoleId?: string;
|
||||
userRole?: string;
|
||||
userId?: string;
|
||||
cdnAssets?: boolean;
|
||||
consoleSentryDsn?: string; // Corresponds to the HASURA_CONSOLE_SENTRY_DSN environment variable
|
||||
} & (
|
||||
| OSSServerEnv
|
||||
| CloudServerEnv
|
||||
@ -138,6 +151,11 @@ export type EnvVars = {
|
||||
declare global {
|
||||
interface Window {
|
||||
__env: EnvVars;
|
||||
/**
|
||||
* Consuming Heap is allowed only through the TracingTools/heap module, never directly.
|
||||
* @deprecated (when marked as deprecated, the IDE shows it as strikethrough'ed, helping the
|
||||
* developers realize that they should not use it)
|
||||
*/
|
||||
heap?: {
|
||||
addUserProperties: (properties: Record<string, string>) => void;
|
||||
};
|
||||
@ -154,6 +172,7 @@ const globals = {
|
||||
apiPort: window.__env?.apiPort,
|
||||
dataApiUrl: stripTrailingSlash(window.__env?.dataApiUrl || ''), // overridden below if server mode
|
||||
urlPrefix: stripTrailingSlash(window.__env?.urlPrefix || '/'), // overridden below if server mode in production
|
||||
consoleSentryDsn: sentry.parseSentryDsn(window.__env?.consoleSentryDsn),
|
||||
adminSecret: window.__env?.adminSecret || null, // gets updated after login/logout in server mode
|
||||
isAdminSecretSet:
|
||||
window.__env?.isAdminSecretSet ||
|
||||
@ -178,6 +197,7 @@ const globals = {
|
||||
cloudDataApiUrl: `${window.location?.protocol}//data.${window.__env?.cloudRootDomain}`,
|
||||
luxDataHost: window.__env?.luxDataHost,
|
||||
userRole: window.__env?.userRole || undefined,
|
||||
userId: window.__env?.userId || undefined,
|
||||
consoleType: window.__env?.consoleType || '',
|
||||
eeMode: window.__env?.eeMode === 'true',
|
||||
};
|
||||
|
@ -4,20 +4,22 @@
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { useBasename } from 'history';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { Router, browserHistory } from 'react-router';
|
||||
import { syncHistoryWithStore } from 'react-router-redux';
|
||||
import { useBasename } from 'history';
|
||||
import { ReactQueryProvider } from './lib/reactQuery';
|
||||
|
||||
import './theme/tailwind.css';
|
||||
import './theme/legacy-boostrap.css';
|
||||
|
||||
import getRoutes from './routes';
|
||||
import { tracingTools } from './features/TracingTools';
|
||||
import { ReactQueryProvider } from './lib/reactQuery';
|
||||
|
||||
import globals from './Globals';
|
||||
import { store } from './store';
|
||||
import getRoutes from './routes';
|
||||
|
||||
tracingTools.sentry.startTracing(globals, window.__env);
|
||||
|
||||
const hashLinkScroll = () => {
|
||||
const { hash } = window.location;
|
||||
|
@ -1,8 +0,0 @@
|
||||
import { heap } from './heap';
|
||||
|
||||
/**
|
||||
* Common utils for analytics tools, could be extended to export functions for other tools like Sentry, etc.
|
||||
*/
|
||||
export const analyticsToolsUtils = {
|
||||
heap,
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
/**
|
||||
* A heap object that attempts to mirror the actual heap API, while handling the nullability check
|
||||
* Currently only implements `addUserProperties`. More functions: identify, track etc can be added
|
||||
* A heap object that attempts to mirror the actual heap API, while handling the nullability check.
|
||||
*/
|
||||
export const heap = {
|
||||
addUserProperties: (props: Record<string, string>) => {
|
10
console/src/features/TracingTools/index.ts
Normal file
10
console/src/features/TracingTools/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { heap } from './heap';
|
||||
import { sentry } from './sentry';
|
||||
|
||||
/**
|
||||
* Common utils for tracing tools.
|
||||
*/
|
||||
export const tracingTools = {
|
||||
heap,
|
||||
sentry,
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
import { getSentryEnvironment } from './getSentryEnvironment';
|
||||
|
||||
describe('getSentryEnvironment', () => {
|
||||
it.each`
|
||||
hostname | expectedEnvironment
|
||||
${'localhost'} | ${'local'}
|
||||
${'stagingHostname'} | ${'stagingHostname'}
|
||||
${'unmanagedHostname'} | ${'unmanagedHostname'}
|
||||
${'hge-mono-pr-3792.herokuapp.com'} | ${'hge-mono-pr.herokuapp.com'}
|
||||
`(
|
||||
`When invoked with '$hostname', then should return '$expectedEnvironment'`,
|
||||
({ hostname, expectedEnvironment }) => {
|
||||
expect(getSentryEnvironment(hostname)).toEqual(expectedEnvironment);
|
||||
}
|
||||
);
|
||||
});
|
@ -0,0 +1,17 @@
|
||||
export function getSentryEnvironment(windowLocationHostname: string) {
|
||||
if (windowLocationHostname === 'localhost') {
|
||||
return 'local';
|
||||
}
|
||||
|
||||
if (windowLocationHostname.startsWith('hge-mono-pr')) {
|
||||
// Allow grouping all the PRs under the same environment in Sentry
|
||||
return 'hge-mono-pr.herokuapp.com';
|
||||
}
|
||||
|
||||
/*
|
||||
Please note that returning the hostname allows
|
||||
1. Not to expose the staging URL in the OSS repo
|
||||
2. Easily detect unmanaged hosts in Sentry
|
||||
*/
|
||||
return windowLocationHostname;
|
||||
}
|
104
console/src/features/TracingTools/sentry/core/getSentryTags.ts
Normal file
104
console/src/features/TracingTools/sentry/core/getSentryTags.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import type { EnvVars } from '../../../../Globals';
|
||||
|
||||
/**
|
||||
* Return the tags to be used in Sentry.
|
||||
*
|
||||
* ATTENTION: To avoid leaking sensitive data, it's better to whitelist vars instead of
|
||||
* blacklisting them. It would be easier to filter out the adminSecret and tracking whatever
|
||||
* else, but what happens if in the future some more secret-like vars will be added? They would
|
||||
* accidentally be sent to Sentry, something that we should avoid.
|
||||
*/
|
||||
export function getSentryTags(envVars: EnvVars) {
|
||||
if (envVars.consoleMode === 'cli') {
|
||||
if ('pro' in envVars) {
|
||||
return {
|
||||
pro: envVars.pro,
|
||||
apiHost: envVars.apiHost,
|
||||
apiPort: envVars.apiPort,
|
||||
cliUUID: envVars.cliUUID,
|
||||
urlPrefix: envVars.urlPrefix,
|
||||
projectId: envVars.projectId,
|
||||
assetsPath: envVars.assetsPath,
|
||||
dataApiUrl: envVars.dataApiUrl,
|
||||
consoleMode: envVars.consoleMode,
|
||||
adminSecret: envVars.adminSecret,
|
||||
consolePath: envVars.consolePath,
|
||||
serverVersion: envVars.serverVersion,
|
||||
enableTelemetry: envVars.enableTelemetry,
|
||||
isAdminSecretSet: envVars.isAdminSecretSet,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
apiHost: envVars.apiHost,
|
||||
apiPort: envVars.apiPort,
|
||||
cliUUID: envVars.cliUUID,
|
||||
urlPrefix: envVars.urlPrefix,
|
||||
assetsPath: envVars.assetsPath,
|
||||
dataApiUrl: envVars.dataApiUrl,
|
||||
consoleMode: envVars.consoleMode,
|
||||
consolePath: envVars.consolePath,
|
||||
serverVersion: envVars.serverVersion,
|
||||
enableTelemetry: envVars.enableTelemetry,
|
||||
};
|
||||
}
|
||||
|
||||
switch (envVars.consoleType) {
|
||||
case 'oss':
|
||||
return {
|
||||
urlPrefix: envVars.urlPrefix,
|
||||
cdnAssets: envVars.cdnAssets,
|
||||
assetsPath: envVars.assetsPath,
|
||||
consoleMode: envVars.consoleMode,
|
||||
consoleType: envVars.consoleType,
|
||||
consolePath: envVars.consolePath,
|
||||
serverVersion: envVars.serverVersion,
|
||||
enableTelemetry: envVars.enableTelemetry,
|
||||
isAdminSecretSet: envVars.isAdminSecretSet,
|
||||
};
|
||||
|
||||
case 'pro':
|
||||
return {
|
||||
consoleId: envVars.consoleId,
|
||||
urlPrefix: envVars.urlPrefix,
|
||||
assetsPath: envVars.assetsPath,
|
||||
consoleType: envVars.consoleType,
|
||||
consoleMode: envVars.consoleMode,
|
||||
consolePath: envVars.consolePath,
|
||||
serverVersion: envVars.serverVersion,
|
||||
enableTelemetry: envVars.enableTelemetry,
|
||||
isAdminSecretSet: envVars.isAdminSecretSet,
|
||||
};
|
||||
|
||||
case 'cloud':
|
||||
return {
|
||||
eeMode: envVars.eeMode,
|
||||
tenantID: envVars.tenantID,
|
||||
userRole: envVars.userRole,
|
||||
consoleId: envVars.consoleId,
|
||||
projectID: envVars.projectID,
|
||||
urlPrefix: envVars.urlPrefix,
|
||||
assetsPath: envVars.assetsPath,
|
||||
dataApiUrl: envVars.dataApiUrl,
|
||||
consoleMode: envVars.consoleMode,
|
||||
consoleType: envVars.consoleType,
|
||||
consolePath: envVars.consolePath,
|
||||
luxDataHost: envVars.luxDataHost,
|
||||
serverVersion: envVars.serverVersion,
|
||||
cloudRootDomain: envVars.cloudRootDomain,
|
||||
isAdminSecretSet: envVars.isAdminSecretSet,
|
||||
herokuOAuthClientId: envVars.herokuOAuthClientId,
|
||||
};
|
||||
|
||||
default:
|
||||
console.warn('Unknown Console version');
|
||||
|
||||
return {
|
||||
// This is a fallback it should never happen. If it happens, the above cases should be extended.
|
||||
unknownConsole: true,
|
||||
|
||||
consoleMode: envVars.consoleMode,
|
||||
consoleType: envVars.consoleType,
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
|
||||
export function isSentryAlreadyStarted() {
|
||||
// See https://github.com/getsentry/sentry-go/issues/9#issuecomment-619615289
|
||||
const tracingAlreadyStarted = !!Sentry.getCurrentHub().getClient();
|
||||
|
||||
return tracingAlreadyStarted;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
export function logSentryEnabled(environment: string) {
|
||||
console.group();
|
||||
console.log(
|
||||
'%c Sentry Tracing Enabled ',
|
||||
'background: #A0D7D1; color: black; display: block;'
|
||||
);
|
||||
console.log(
|
||||
`%c Sentry Environment: ${environment} `,
|
||||
'background: #A0D7D1; color: black; display: block;'
|
||||
);
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
export function logSentryDisabled() {
|
||||
// Agree with https://github.com/hasura/graphql-engine-mono/pull/5699#issuecomment-1234205492
|
||||
// we are not going to log anything to the user until we have a user-facing doc that speaks about
|
||||
// Sentry
|
||||
// TODO: log the missing/invalid status
|
||||
return;
|
||||
|
||||
console.group();
|
||||
console.log(
|
||||
'%c Sentry Tracing Disabled ',
|
||||
'background: #A0D7D1; color: black; display: block;'
|
||||
);
|
||||
console.log(
|
||||
'%c Provide HASURA_CONSOLE_SENTRY_DSN env variable to enable it ',
|
||||
'background: #A0D7D1; color: black; display: block;'
|
||||
);
|
||||
console.groupEnd();
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import { parseSentryDsn } from './parseSentryDsn';
|
||||
|
||||
describe('parseSentryDsn', () => {
|
||||
it.each`
|
||||
value | expected
|
||||
${''} | ${{ status: 'missing' }}
|
||||
${null} | ${{ status: 'missing' }}
|
||||
${undefined} | ${{ status: 'missing' }}
|
||||
${0} | ${{ status: 'invalid', value: 0 }}
|
||||
${1} | ${{ status: 'invalid', value: 1 }}
|
||||
${{}} | ${{ status: 'invalid', value: {} }}
|
||||
${[]} | ${{ status: 'invalid', value: [] }}
|
||||
${true} | ${{ status: 'invalid', value: true }}
|
||||
${false} | ${{ status: 'invalid', value: false }}
|
||||
${'https://sentry.io'} | ${{ status: 'invalid', value: 'https://sentry.io' }}
|
||||
${'https://ingest.sentry.io'} | ${{ status: 'invalid', value: 'https://ingest.sentry.io' }}
|
||||
${'https://ingest.sentry.io'} | ${{ status: 'invalid', value: 'https://ingest.sentry.io' }}
|
||||
${'https://foo.ingest.sentry.io'} | ${{ status: 'invalid', value: 'https://foo.ingest.sentry.io' }}
|
||||
${'https://foo.ingest.sentry.io/'} | ${{ status: 'invalid', value: 'https://foo.ingest.sentry.io/' }}
|
||||
${'https://.ingest.sentry.io/bar'} | ${{ status: 'invalid', value: 'https://.ingest.sentry.io/bar' }}
|
||||
${'http://foo.ingest.sentry.io/bar'} | ${{ status: 'invalid', value: 'http://foo.ingest.sentry.io/bar' }}
|
||||
${'https://foo.ingest.sentry.io/bar'} | ${{ status: 'valid', value: 'https://foo.ingest.sentry.io/bar' }}
|
||||
`(
|
||||
`When invoked with '$value', then should return '$expected'`,
|
||||
({ value, expected }) => {
|
||||
expect(parseSentryDsn(value)).toEqual(expected);
|
||||
}
|
||||
);
|
||||
});
|
@ -0,0 +1,38 @@
|
||||
import type { SentryDsn } from '../types';
|
||||
|
||||
type ParseSentryDsnResult =
|
||||
| { status: 'missing' }
|
||||
| { status: 'invalid'; value: unknown }
|
||||
| { status: 'valid'; value: SentryDsn };
|
||||
|
||||
export function parseSentryDsn(value: unknown): ParseSentryDsnResult {
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
return { status: 'missing' };
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
return { status: 'invalid', value };
|
||||
}
|
||||
|
||||
if (!isSentryDsn(value)) {
|
||||
return { status: 'invalid', value };
|
||||
}
|
||||
|
||||
return { status: 'valid', value };
|
||||
}
|
||||
|
||||
function isSentryDsn(url: unknown): url is SentryDsn {
|
||||
if (typeof url !== 'string') return false;
|
||||
|
||||
if (!url.startsWith('https://')) return false;
|
||||
|
||||
if (!url.includes('.ingest.sentry.io/')) return false;
|
||||
|
||||
const missSentryProjectId = url.endsWith('.ingest.sentry.io/');
|
||||
if (missSentryProjectId) return false;
|
||||
|
||||
const missSentryPublicKey = url.includes('https://.ingest.sentry.io');
|
||||
if (missSentryPublicKey) return false;
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
import type { EnvVars } from '@/Globals';
|
||||
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { BrowserTracing } from '@sentry/tracing';
|
||||
|
||||
import globals from '@/Globals';
|
||||
import { getSentryTags } from './getSentryTags';
|
||||
import { getSentryEnvironment } from './getSentryEnvironment';
|
||||
import { isSentryAlreadyStarted } from './isSentryAlreadyStarted';
|
||||
import { logSentryEnabled, logSentryDisabled } from './logSentryInfo';
|
||||
|
||||
type Globals = typeof globals;
|
||||
|
||||
/**
|
||||
* Start Sentry idempotently.
|
||||
*
|
||||
* Please note that Sentry automatically tracks also the React errors, there is no need to manually track them
|
||||
* from the various React error boundaries.
|
||||
*
|
||||
* ATTENTION: This function expects the `window.__envVars` because I think
|
||||
* using the server-driven vars instead of the client-parsed ones (since they could
|
||||
* differ in some details) as tags would be better.
|
||||
*/
|
||||
export function startTracing(globalVars: Globals, envVars: EnvVars) {
|
||||
if (isSentryAlreadyStarted()) return 'enabled';
|
||||
|
||||
const consoleSentryDsn = globalVars.consoleSentryDsn;
|
||||
if (
|
||||
consoleSentryDsn.status === 'missing' ||
|
||||
consoleSentryDsn.status === 'invalid'
|
||||
) {
|
||||
logSentryDisabled();
|
||||
return 'disabled';
|
||||
}
|
||||
|
||||
const tags = getSentryTags(envVars);
|
||||
const environment = getSentryEnvironment(window.location.hostname);
|
||||
|
||||
logSentryEnabled(environment);
|
||||
|
||||
Sentry.init({
|
||||
dsn: consoleSentryDsn.value,
|
||||
tracesSampleRate: 1.0,
|
||||
integrations: [
|
||||
new BrowserTracing(),
|
||||
|
||||
new Sentry.Integrations.Breadcrumbs({
|
||||
// Disable tracking console.logs
|
||||
console: false,
|
||||
|
||||
// Disable tracking clicks
|
||||
dom: false,
|
||||
}),
|
||||
],
|
||||
|
||||
// Allow grouping logs by environment
|
||||
environment,
|
||||
release: tags.serverVersion,
|
||||
initialScope: {
|
||||
tags,
|
||||
},
|
||||
});
|
||||
|
||||
Sentry.setUser({
|
||||
id: globalVars.userId,
|
||||
ip_address: '{{auto}}',
|
||||
});
|
||||
|
||||
return 'enabled';
|
||||
}
|
1
console/src/features/TracingTools/sentry/index.ts
Normal file
1
console/src/features/TracingTools/sentry/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { sentry } from './sentry';
|
10
console/src/features/TracingTools/sentry/sentry.ts
Normal file
10
console/src/features/TracingTools/sentry/sentry.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { startTracing } from './core/startTracing';
|
||||
import { parseSentryDsn } from './core/parseSentryDsn';
|
||||
|
||||
/**
|
||||
* A sentry object that attempts to mirror the actual sentry API.
|
||||
*/
|
||||
export const sentry = {
|
||||
startTracing,
|
||||
parseSentryDsn,
|
||||
};
|
6
console/src/features/TracingTools/sentry/types.ts
Normal file
6
console/src/features/TracingTools/sentry/types.ts
Normal file
@ -0,0 +1,6 @@
|
||||
type SentryPublicKey = string;
|
||||
type SentryProjectId = string;
|
||||
|
||||
// see https://docs.sentry.io/product/sentry-basics/dsn-explainer/
|
||||
export type SentryDsn =
|
||||
`https://${SentryPublicKey}.ingest.sentry.io/${SentryProjectId}`;
|
@ -16,6 +16,7 @@ const serverEnvVars = `
|
||||
projectID: '${process.env.HASURA_CLOUD_PROJECT_ID || ''}',
|
||||
cloudRootDomain: '${process.env.HASURA_CLOUD_ROOT_DOMAIN}',
|
||||
consoleType: '${process.env.HASURA_CONSOLE_TYPE}',
|
||||
consoleSentryDsn: '${process.env.HASURA_CONSOLE_SENTRY_DSN}'
|
||||
`;
|
||||
|
||||
const cliEnvVars = `
|
||||
@ -33,7 +34,8 @@ const cliEnvVars = `
|
||||
herokuOAuthClientId: '${process.env.HEROKU_OAUTH_CLIENT_ID || ''}',
|
||||
tenantID: '${process.env.HASURA_CLOUD_TENANT_ID || ''}',
|
||||
projectID: '${process.env.HASURA_CLOUD_PROJECT_ID || ''}',
|
||||
cloudRootDomain: '${process.env.HASURA_CLOUD_ROOT_DOMAIN}'
|
||||
cloudRootDomain: '${process.env.HASURA_CLOUD_ROOT_DOMAIN}',
|
||||
consoleSentryDsn: '${process.env.HASURA_CONSOLE_SENTRY_DSN}'
|
||||
`;
|
||||
|
||||
const envVars = process.env.CONSOLE_MODE === 'cli' ? cliEnvVars : serverEnvVars;
|
||||
|
@ -1207,7 +1207,8 @@ mkConsoleHTML path authMode enableTelemetry consoleAssetsDir =
|
||||
"enableTelemetry" A..= boolToText enableTelemetry,
|
||||
"cdnAssets" A..= boolToText (isNothing consoleAssetsDir),
|
||||
"assetsVersion" A..= consoleAssetsVersion,
|
||||
"serverVersion" A..= currentVersion
|
||||
"serverVersion" A..= currentVersion,
|
||||
"consoleSentryDsn" A..= ("" :: Text)
|
||||
]
|
||||
where
|
||||
consolePath = case path of
|
||||
|
@ -13,6 +13,7 @@
|
||||
cdnAssets: {{cdnAssets}},
|
||||
serverVersion: "{{serverVersion}}",
|
||||
consoleType: "oss",
|
||||
consoleSentryDsn: "{{consoleSentryDsn}}"
|
||||
};
|
||||
window.__env.versionedAssetsPath = window.__env.assetsPath;
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user