Chore: Application monitoring support with sentry (#702)

* setup sentry for server

* setup sentry for client

* update docs for sentry dns

* explicitly specify apm vendor

* add module for sentry

* revise directory struct and make sentry debuggable

* setup csp and trace headers for sentry

* whitelist csp for all sentry urls

* change senrty error sample rate to 50%

* make sentry send all errors from backend
This commit is contained in:
Akshay 2021-09-09 22:14:34 +05:30 committed by GitHub
parent 6bd08608ad
commit f4af291b6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 784 additions and 36 deletions

View file

@ -27,3 +27,8 @@ SMTP_ADDRESS=
# DISABLE USER SIGNUPS (true or false). Default: true
DISABLE_SIGNUPS=
# OBSERVABILITY
APM_VENDOR=
SENTRY_DNS=
SENTRY_DEBUG=

View file

@ -86,14 +86,6 @@ If your ToolJet installation needs access to datasources such as Google sheets,
| GOOGLE_CLIENT_ID | client id |
| GOOGLE_CLIENT_SECRET | client secret |
## ToolJet client
#### Server URL ( optional )
| variable | description |
| ----------- | ----------- |
| TOOLJET_SERVER_URL | the URL of ToolJet server ( eg: https://server.tooljet.io ) |
#### Google maps configuration ( optional )
If your ToolJet installation requires `Maps` widget, you need to create an API key for Google Maps API.
@ -101,3 +93,40 @@ If your ToolJet installation requires `Maps` widget, you need to create an API k
| variable | description |
| ----------- | ----------- |
| GOOGLE_MAPS_API_KEY | Google maps API key |
#### APM VENDOR ( optional )
Specify application monitoring vendor. Currently supported values - `sentry`.
| variable | description |
| ----------- | ----------- |
| APM VENDOR | Application performance monitoring vendor |
#### SENTRY DNS ( optional )
DSN tells a Sentry SDK where to send events so the events are associated with the correct project
#### SENTRY DEBUG ( optional )
Prints logs for sentry. Supported values: `true` | `false`
Default value is `false`
#### Server URL ( optional)
This is used to set up for CSP headers and put trace info to be used with APM vendors.
| variable | description |
| ----------- | ----------- |
| TOOLJET_SERVER_URL | the URL of ToolJet server ( eg: https://server.tooljet.io ) |
#### RELEASE VERSION ( optional)
Once set any APM provider that supports segregation with releases will track it.
## ToolJet client
#### Server URL ( optionally required )
This is required when client is built separately.
| variable | description |
| ----------- | ----------- |
| TOOLJET_SERVER_URL | the URL of ToolJet server ( eg: https://server.tooljet.io ) |

View file

@ -5,7 +5,6 @@
"requires": true,
"packages": {
"": {
"name": "frontend",
"version": "0.1.0",
"dependencies": {
"@babel/core": "^7.4.3",
@ -13,6 +12,8 @@
"@babel/preset-env": "^7.4.3",
"@babel/preset-react": "^7.0.0",
"@react-google-maps/api": "^2.1.1",
"@sentry/react": "^6.12.0",
"@sentry/tracing": "^6.12.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
@ -62,6 +63,7 @@
"rxjs": "^6.3.3",
"semver": "^5.7.1",
"tinycolor2": "^1.4.2",
"uuid": "8.3.2",
"webpack-cli": "^3.3.0",
"yup": "^0.27.0"
},
@ -1746,6 +1748,16 @@
"node": ">= 6"
}
},
"node_modules/@cypress/request/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"dev": true,
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/@cypress/webpack-dev-server": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@cypress/webpack-dev-server/-/webpack-dev-server-1.3.1.tgz",
@ -2460,6 +2472,115 @@
}
}
},
"node_modules/@sentry/browser": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.12.0.tgz",
"integrity": "sha512-wsJi1NLOmfwtPNYxEC50dpDcVY7sdYckzwfqz1/zHrede1mtxpqSw+7iP4bHADOJXuF+ObYYTHND0v38GSXznQ==",
"dependencies": {
"@sentry/core": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/core": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.12.0.tgz",
"integrity": "sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ==",
"dependencies": {
"@sentry/hub": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/hub": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.12.0.tgz",
"integrity": "sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg==",
"dependencies": {
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/minimal": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.12.0.tgz",
"integrity": "sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw==",
"dependencies": {
"@sentry/hub": "6.12.0",
"@sentry/types": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/react": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-6.12.0.tgz",
"integrity": "sha512-E8Nw9PPzP/EyMy64ksr9xcyYYlBmUA5ROnkPQp7o5wF0xf5/J+nMS1tQdyPnLQe2KUgHlN4kVs2HHft1m7mSYQ==",
"dependencies": {
"@sentry/browser": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"hoist-non-react-statics": "^3.3.2",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
},
"peerDependencies": {
"react": "15.x || 16.x || 17.x"
}
},
"node_modules/@sentry/tracing": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.12.0.tgz",
"integrity": "sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA==",
"dependencies": {
"@sentry/hub": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/types": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.12.0.tgz",
"integrity": "sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA==",
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/utils": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.12.0.tgz",
"integrity": "sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA==",
"dependencies": {
"@sentry/types": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sheerun/mutationobserver-shim": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz",
@ -17790,6 +17911,15 @@
"object.getownpropertydescriptors": "^2.0.3"
}
},
"node_modules/react-scripts/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/react-scripts/node_modules/webpack-dev-server": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz",
@ -18395,6 +18525,15 @@
"request": "^2.34"
}
},
"node_modules/request/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@ -19395,6 +19534,16 @@
"ms": "^2.1.1"
}
},
"node_modules/sockjs/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"dev": true,
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/sort-keys": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
@ -20951,12 +21100,11 @@
}
},
"node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "bin/uuid"
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache": {
@ -21533,6 +21681,15 @@
"node": ">= 6"
}
},
"node_modules/webpack-log/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/webpack-manifest-plugin": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz",
@ -23511,6 +23668,14 @@
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"dev": true
}
}
},
"@cypress/webpack-dev-server": {
@ -24090,6 +24255,88 @@
"any-observable": "^0.3.0"
}
},
"@sentry/browser": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.12.0.tgz",
"integrity": "sha512-wsJi1NLOmfwtPNYxEC50dpDcVY7sdYckzwfqz1/zHrede1mtxpqSw+7iP4bHADOJXuF+ObYYTHND0v38GSXznQ==",
"requires": {
"@sentry/core": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
}
},
"@sentry/core": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.12.0.tgz",
"integrity": "sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ==",
"requires": {
"@sentry/hub": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
}
},
"@sentry/hub": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.12.0.tgz",
"integrity": "sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg==",
"requires": {
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
}
},
"@sentry/minimal": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.12.0.tgz",
"integrity": "sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw==",
"requires": {
"@sentry/hub": "6.12.0",
"@sentry/types": "6.12.0",
"tslib": "^1.9.3"
}
},
"@sentry/react": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-6.12.0.tgz",
"integrity": "sha512-E8Nw9PPzP/EyMy64ksr9xcyYYlBmUA5ROnkPQp7o5wF0xf5/J+nMS1tQdyPnLQe2KUgHlN4kVs2HHft1m7mSYQ==",
"requires": {
"@sentry/browser": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"hoist-non-react-statics": "^3.3.2",
"tslib": "^1.9.3"
}
},
"@sentry/tracing": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.12.0.tgz",
"integrity": "sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA==",
"requires": {
"@sentry/hub": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
}
},
"@sentry/types": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.12.0.tgz",
"integrity": "sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA=="
},
"@sentry/utils": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.12.0.tgz",
"integrity": "sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA==",
"requires": {
"@sentry/types": "6.12.0",
"tslib": "^1.9.3"
}
},
"@sheerun/mutationobserver-shim": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz",
@ -36218,6 +36465,11 @@
"object.getownpropertydescriptors": "^2.0.3"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"webpack-dev-server": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz",
@ -36653,6 +36905,13 @@
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"request-progress": {
@ -37469,6 +37728,14 @@
"faye-websocket": "^0.11.3",
"uuid": "^3.4.0",
"websocket-driver": "^0.7.4"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"dev": true
}
}
},
"sockjs-client": {
@ -38707,9 +38974,9 @@
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"v8-compile-cache": {
"version": "2.3.0",
@ -39254,6 +39521,13 @@
"requires": {
"ansi-colors": "^3.0.0",
"uuid": "^3.3.2"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"webpack-manifest-plugin": {

View file

@ -8,6 +8,8 @@
"@babel/preset-env": "^7.4.3",
"@babel/preset-react": "^7.0.0",
"@react-google-maps/api": "^2.1.1",
"@sentry/react": "^6.12.0",
"@sentry/tracing": "^6.12.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",

View file

@ -11,15 +11,25 @@ appService.getConfig().then((config) => {
if (window.public_config.APM_VENDOR == 'sentry') {
const history = createBrowserHistory();
const tooljetServerUrl = window.public_config.TOOLJET_SERVER_URL;
const tracingOrigins = ['localhost', /^\//];
const releaseVersion = window.public_config.RELEASE_VERSION
? `tooljet-${window.public_config.RELEASE_VERSION}`
: 'toojet';
if (!!tooljetServerUrl) tracingOrigins.push(tooljetServerUrl);
Sentry.init({
dsn: window.public_config.SENTRY_DNS,
debug: !!window.public_config.SENTRY_DEBUG,
release: releaseVersion,
integrations: [
new Integrations.BrowserTracing({
routingInstrumentation: Sentry.reactRouterV5Instrumentation(history),
tracingOrigins: tracingOrigins,
}),
],
tracesSampleRate: 0.25
tracesSampleRate: 0.50,
});
}
});

266
server/package-lock.json generated
View file

@ -19,6 +19,8 @@
"@nestjs/platform-express": "^8.0.0",
"@nestjs/serve-static": "^2.2.2",
"@nestjs/typeorm": "^8.0.0",
"@sentry/node": "^6.12.0",
"@sentry/tracing": "^6.12.0",
"@types/got": "^9.6.12",
"@types/humps": "^2.0.1",
"@types/nodemailer": "^6.4.4",
@ -2463,6 +2465,139 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
},
"node_modules/@sentry/core": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.12.0.tgz",
"integrity": "sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ==",
"dependencies": {
"@sentry/hub": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"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": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.12.0.tgz",
"integrity": "sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg==",
"dependencies": {
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"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/minimal": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.12.0.tgz",
"integrity": "sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw==",
"dependencies": {
"@sentry/hub": "6.12.0",
"@sentry/types": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/minimal/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/node": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.12.0.tgz",
"integrity": "sha512-hfAU3cX5sNWgqyDQBCOIQOZj21l0w1z2dG4MjmrMMHKrQ18pfMaaOtEwRXMCdjTUlwsK+L3TOoUB23lbezmu1A==",
"dependencies": {
"@sentry/core": "6.12.0",
"@sentry/hub": "6.12.0",
"@sentry/tracing": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"cookie": "^0.4.1",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/node/node_modules/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/@sentry/node/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": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.12.0.tgz",
"integrity": "sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA==",
"dependencies": {
"@sentry/hub": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"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": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.12.0.tgz",
"integrity": "sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA==",
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/utils": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.12.0.tgz",
"integrity": "sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA==",
"dependencies": {
"@sentry/types": "6.12.0",
"tslib": "^1.9.3"
},
"engines": {
"node": ">=6"
}
},
"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/@sideway/address": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz",
@ -9812,6 +9947,11 @@
"node": ">=8"
}
},
"node_modules/lru_map": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz",
"integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0="
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@ -15885,6 +16025,127 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
},
"@sentry/core": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.12.0.tgz",
"integrity": "sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ==",
"requires": {
"@sentry/hub": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"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": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.12.0.tgz",
"integrity": "sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg==",
"requires": {
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"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/minimal": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.12.0.tgz",
"integrity": "sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw==",
"requires": {
"@sentry/hub": "6.12.0",
"@sentry/types": "6.12.0",
"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/node": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.12.0.tgz",
"integrity": "sha512-hfAU3cX5sNWgqyDQBCOIQOZj21l0w1z2dG4MjmrMMHKrQ18pfMaaOtEwRXMCdjTUlwsK+L3TOoUB23lbezmu1A==",
"requires": {
"@sentry/core": "6.12.0",
"@sentry/hub": "6.12.0",
"@sentry/tracing": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"cookie": "^0.4.1",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
"tslib": "^1.9.3"
},
"dependencies": {
"cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/tracing": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.12.0.tgz",
"integrity": "sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA==",
"requires": {
"@sentry/hub": "6.12.0",
"@sentry/minimal": "6.12.0",
"@sentry/types": "6.12.0",
"@sentry/utils": "6.12.0",
"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": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.12.0.tgz",
"integrity": "sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA=="
},
"@sentry/utils": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.12.0.tgz",
"integrity": "sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA==",
"requires": {
"@sentry/types": "6.12.0",
"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=="
}
}
},
"@sideway/address": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz",
@ -21722,6 +21983,11 @@
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="
},
"lru_map": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz",
"integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0="
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",

View file

@ -38,6 +38,8 @@
"@nestjs/platform-express": "^8.0.0",
"@nestjs/serve-static": "^2.2.2",
"@nestjs/typeorm": "^8.0.0",
"@sentry/node": "^6.12.0",
"@sentry/tracing": "^6.12.0",
"@types/got": "^9.6.12",
"@types/humps": "^2.0.1",
"@types/nodemailer": "^6.4.4",

View file

@ -1,12 +1,30 @@
import { Module, OnApplicationBootstrap, OnModuleInit } from '@nestjs/common';
import {
Module,
OnApplicationBootstrap,
OnModuleInit,
RequestMethod,
MiddlewareConsumer,
} from '@nestjs/common';
import { Connection } from 'typeorm';
import { TypeOrmModule } from '@nestjs/typeorm';
import ormconfig from '../ormconfig';
import { SeedsModule } from './modules/seeds/seeds.module';
import { SeedsService } from '@services/seeds.service';
import { LoggerModule } from 'nestjs-pino';
import { SentryModule } from './modules/observability/sentry/sentry.module';
import * as Sentry from '@sentry/node';
import { ConfigModule } from '@nestjs/config';
import { ServeStaticModule } from '@nestjs/serve-static';
import { CaslModule } from './modules/casl/casl.module';
import { EmailService } from '@services/email.service';
import { MetaModule } from './modules/meta/meta.module';
import { AppController } from './controllers/app.controller';
import { AppService } from './services/app.service';
import { AuthModule } from './modules/auth/auth.module';
import { UsersModule } from './modules/users/users.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { SeedsModule } from './modules/seeds/seeds.module';
import { SeedsService } from '@services/seeds.service';
import { AppConfigModule } from './modules/app_config/app_config.module'
import { AppsModule } from './modules/apps/apps.module';
import { FoldersModule } from './modules/folders/folders.module';
@ -14,14 +32,7 @@ import { FolderAppsModule } from './modules/folder_apps/folder_apps.module';
import { DataQueriesModule } from './modules/data_queries/data_queries.module';
import { DataSourcesModule } from './modules/data_sources/data_sources.module';
import { OrganizationsModule } from './modules/organizations/organizations.module';
import { ConfigModule } from '@nestjs/config';
import ormconfig from '../ormconfig';
import { CaslModule } from './modules/casl/casl.module';
import { EmailService } from '@services/email.service';
import { MetaModule } from './modules/meta/meta.module';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
import { LoggerModule } from 'nestjs-pino';
const imports = [
ConfigModule.forRoot({
@ -60,12 +71,23 @@ const imports = [
MetaModule,
];
if (process.env.SERVE_CLIENT !== 'false')
if (process.env.SERVE_CLIENT !== 'false') {
imports.unshift(
ServeStaticModule.forRoot({
rootPath: join(__dirname, '../../../', 'frontend/build'),
}),
);
}
if (process.env.APM_VENDOR == 'sentry') {
imports.unshift(
SentryModule.forRoot({
dsn: process.env.SENTRY_DNS,
tracesSampleRate: 1.0,
debug: !!process.env.SENTRY_DEBUG,
}),
);
}
@Module({
imports,
@ -75,6 +97,13 @@ if (process.env.SERVE_CLIENT !== 'false')
export class AppModule implements OnModuleInit, OnApplicationBootstrap {
constructor(private connection: Connection) {}
configure(consumer: MiddlewareConsumer): void {
consumer.apply(Sentry.Handlers.requestHandler()).forRoutes({
path: '*',
method: RequestMethod.ALL,
});
}
onModuleInit() {
console.log(`Initializing ToolJet server modules 📡 `);
}

View file

@ -0,0 +1,40 @@
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
Scope,
} from '@nestjs/common';
import { catchError, finalize, Observable, throwError } from 'rxjs';
import { SentryService } from '../services/sentry.service';
import * as Sentry from '@sentry/node';
/**
* We must be in Request scope as we inject SentryService
*/
@Injectable({ scope: Scope.REQUEST })
export class SentryInterceptor implements NestInterceptor {
constructor(private sentryService: SentryService) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// start a child span for performance tracing
const span = this.sentryService.startChild({ op: `route handler` });
return next.handle().pipe(
catchError((error) => {
// capture the error, you can filter out some errors here
Sentry.captureException(
error,
this.sentryService.span.getTraceContext(),
);
// throw again the error
return throwError(() => error);
}),
finalize(() => {
span.finish();
this.sentryService.span.finish();
}),
);
}
}

View file

@ -24,7 +24,7 @@ async function bootstrap() {
useDefaults: true,
directives: {
'script-src': ["'self'", "'unsafe-inline'", "'unsafe-eval'", 'blob:'],
'default-src': ["'self'", 'blob:'],
'default-src': ["*.sentry.io", "'self'", 'blob:'],
},
}),
);

View file

@ -0,0 +1,32 @@
import { Module } from '@nestjs/common';
import * as Sentry from '@sentry/node';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { SentryService } from '../../../services/sentry.service';
import { SentryInterceptor } from '../../../interceptors/sentry.interceptor';
export const SENTRY_OPTIONS = 'SENTRY_OPTIONS';
@Module({
providers: [SentryService],
})
export class SentryModule {
static forRoot(options: Sentry.NodeOptions) {
// initialization of Sentry, this is where Sentry will create a Hub
Sentry.init(options);
return {
module: SentryModule,
providers: [
{
provide: SENTRY_OPTIONS,
useValue: options,
},
SentryService,
{
provide: APP_INTERCEPTOR,
useClass: SentryInterceptor,
},
],
exports: [SentryService],
};
}
}

View file

@ -9,20 +9,24 @@ export class AppConfigService {
? this.fetchAllowedConfigFromEnv()
: this.fetchDefaultConfig();
const mapEntries = await Promise.all(whitelistedConfigVars.map(
(envVar) => [envVar, process.env[envVar]] as [string, string],
));
const mapEntries = await Promise.all(
whitelistedConfigVars.map(
(envVar) => [envVar, process.env[envVar]] as [string, string],
),
);
return Object.fromEntries(mapEntries);
}
fetchDefaultConfig() {
return [
'TOOLJET_SERVER_URL',
'RELEASE_VERSION',
'GOOGLE_MAPS_API_KEY',
'APM_VENDOR',
'SENTRY_DNS',
'SENTRY_DEBUG',
]
];
}
fetchAllowedConfigFromEnv() {

View file

@ -0,0 +1,55 @@
import { Request } from 'express';
import { Scope } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import * as Sentry from '@sentry/node';
import { Span, SpanContext } from '@sentry/types';
/**
* Because we inject REQUEST we need to set the service as request scoped
*/
@Injectable({ scope: Scope.REQUEST })
export class SentryService {
/**
* Return the current span defined in the current Hub and Scope
*/
get span(): Span {
return Sentry.getCurrentHub().getScope().getSpan();
}
/**
* When injecting the service it will create the main transaction
*
* @param request
*/
constructor(@Inject(REQUEST) private request: Request) {
const { method, headers, url } = this.request;
// recreate transaction based from HTTP request
const transaction = Sentry.startTransaction({
name: `Route: ${method} ${url}`,
op: 'transaction',
});
// setup context of newly created transaction
Sentry.getCurrentHub().configureScope((scope) => {
scope.setSpan(transaction);
// customize your context here
scope.setContext('http', {
method,
url,
headers,
});
});
}
/**
* This will simply start a new child span in the current span
*
* @param spanContext
*/
startChild(spanContext: SpanContext) {
return this.span.startChild(spanContext);
}
}