Add initial sentry setup
Related to #343 but will probably need a few more changes
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@redwoodjs/api": "^0.33.0",
|
"@redwoodjs/api": "^0.33.0",
|
||||||
"@redwoodjs/api-server": "^0.33.0",
|
"@redwoodjs/api-server": "^0.33.0",
|
||||||
|
"@sentry/node": "^6.5.1",
|
||||||
"cloudinary": "^1.23.0"
|
"cloudinary": "^1.23.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
makeMergedSchema,
|
makeMergedSchema,
|
||||||
makeServices,
|
makeServices,
|
||||||
} from '@redwoodjs/api'
|
} from '@redwoodjs/api'
|
||||||
|
import { createSentryApolloPlugin } from 'src/lib/sentry'
|
||||||
|
|
||||||
import schemas from 'src/graphql/**/*.{js,ts}'
|
import schemas from 'src/graphql/**/*.{js,ts}'
|
||||||
import services from 'src/services/**/*.{js,ts}'
|
import services from 'src/services/**/*.{js,ts}'
|
||||||
@@ -16,6 +17,9 @@ export const handler = createGraphQLHandler({
|
|||||||
schemas,
|
schemas,
|
||||||
services: makeServices({ services }),
|
services: makeServices({ services }),
|
||||||
}),
|
}),
|
||||||
|
plugins: [
|
||||||
|
createSentryApolloPlugin(),
|
||||||
|
],
|
||||||
onException: () => {
|
onException: () => {
|
||||||
// Disconnect from your database with an unhandled exception.
|
// Disconnect from your database with an unhandled exception.
|
||||||
db.$disconnect()
|
db.$disconnect()
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { createUserInsecure } from 'src/services/users/users.js'
|
import { createUserInsecure } from 'src/services/users/users.js'
|
||||||
import { db } from 'src/lib/db'
|
import { db } from 'src/lib/db'
|
||||||
|
import { sentryWrapper } from 'src/lib/sentry'
|
||||||
import { enforceAlphaNumeric, generateUniqueString } from 'src/services/helpers'
|
import { enforceAlphaNumeric, generateUniqueString } from 'src/services/helpers'
|
||||||
|
|
||||||
export const handler = async (req, _context) => {
|
const unWrappedHandler = async (req, _context) => {
|
||||||
const body = JSON.parse(req.body)
|
const body = JSON.parse(req.body)
|
||||||
console.log(body)
|
console.log(body)
|
||||||
console.log(_context)
|
console.log(_context)
|
||||||
@@ -82,3 +83,5 @@ export const handler = async (req, _context) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const handler = sentryWrapper(unWrappedHandler)
|
||||||
|
|||||||
106
app/api/src/lib/sentry.ts
Normal file
106
app/api/src/lib/sentry.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import * as Sentry from '@sentry/node'
|
||||||
|
import { context, Config, ApolloError } from '@redwoodjs/api'
|
||||||
|
|
||||||
|
let sentryInitialized = false
|
||||||
|
if (process.env.SENTRY_DSN && !sentryInitialized) {
|
||||||
|
Sentry.init({
|
||||||
|
dsn: process.env.SENTRY_DSN,
|
||||||
|
environment: process.env.CONTEXT,
|
||||||
|
release: process.env.COMMIT_REF,
|
||||||
|
})
|
||||||
|
sentryInitialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function reportError(error) {
|
||||||
|
if (!sentryInitialized) return
|
||||||
|
// If you do have authentication set up, we can add
|
||||||
|
// some user data to help debug issues
|
||||||
|
// if (context.currentUser) {
|
||||||
|
// Sentry.configureScope((scope) => {
|
||||||
|
// scope.setUser({
|
||||||
|
// id: context?.currentUser?.id,
|
||||||
|
// email: context?.currentUser?.email,
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
if (typeof error === 'string') {
|
||||||
|
Sentry.captureMessage(error)
|
||||||
|
} else {
|
||||||
|
Sentry.captureException(error)
|
||||||
|
}
|
||||||
|
await Sentry.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sentryWrapper = (handler) => async (event, lambdaContext) => {
|
||||||
|
lambdaContext.callbackWaitsForEmptyEventLoop = false
|
||||||
|
try {
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
const callback = (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
resolve(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resp = handler(event, lambdaContext, callback)
|
||||||
|
if (resp?.then) {
|
||||||
|
resp.then(resolve, reject)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
// This catches both sync errors & promise
|
||||||
|
// rejections, because we 'await' on the handler
|
||||||
|
await reportError(e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createSentryApolloPlugin: Config['plugins'][number] = () => ({
|
||||||
|
requestDidStart: () => {
|
||||||
|
return {
|
||||||
|
didEncounterErrors(ctx) {
|
||||||
|
// If we couldn't parse the operation, don't
|
||||||
|
// do anything here
|
||||||
|
if (!ctx.operation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const err of ctx.errors) {
|
||||||
|
// Only report internal server errors,
|
||||||
|
// all errors extending ApolloError should be user-facing
|
||||||
|
if (err instanceof ApolloError) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add scoped report details and send to Sentry
|
||||||
|
Sentry.withScope(scope => {
|
||||||
|
// Annotate whether failing operation was query/mutation/subscription
|
||||||
|
scope.setTag("kind", ctx.operation.operation);
|
||||||
|
|
||||||
|
// Log query and variables as extras (make sure to strip out sensitive data!)
|
||||||
|
scope.setExtra("query", ctx.request.query);
|
||||||
|
scope.setExtra("variables", ctx.request.variables);
|
||||||
|
|
||||||
|
if (err.path) {
|
||||||
|
// We can also add the path as breadcrumb
|
||||||
|
scope.addBreadcrumb({
|
||||||
|
category: "query-path",
|
||||||
|
message: err.path.join(" > "),
|
||||||
|
level: Sentry.Severity.Debug
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const transactionId = ctx.request.http.headers.get(
|
||||||
|
"x-transaction-id"
|
||||||
|
);
|
||||||
|
if (transactionId) {
|
||||||
|
scope.setTransaction(transactionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sentry.captureException(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -8,7 +8,16 @@
|
|||||||
[web]
|
[web]
|
||||||
port = 8910
|
port = 8910
|
||||||
apiProxyPath = "/.netlify/functions"
|
apiProxyPath = "/.netlify/functions"
|
||||||
includeEnvironmentVariables = ['GOOGLE_ANALYTICS_ID', 'CLOUDINARY_API_KEY', 'CLOUDINARY_API_SECRET', 'CAD_LAMBDA_BASE_URL']
|
includeEnvironmentVariables = [
|
||||||
|
'GOOGLE_ANALYTICS_ID',
|
||||||
|
'CLOUDINARY_API_KEY',
|
||||||
|
'CLOUDINARY_API_SECRET',
|
||||||
|
'CAD_LAMBDA_BASE_URL',
|
||||||
|
'SENTRY_DSN',
|
||||||
|
'SENTRY_AUTH_TOKEN',
|
||||||
|
'SENTRY_ORG',
|
||||||
|
'SENTRY_PROJECT'
|
||||||
|
]
|
||||||
# experimentalFastRefresh = true # this seems to break cascadeStudio
|
# experimentalFastRefresh = true # this seems to break cascadeStudio
|
||||||
[api]
|
[api]
|
||||||
port = 8911
|
port = 8911
|
||||||
@@ -18,3 +27,10 @@
|
|||||||
|
|
||||||
[experimental]
|
[experimental]
|
||||||
esbuild = false
|
esbuild = false
|
||||||
|
|
||||||
|
[[plugins]]
|
||||||
|
package = "@sentry/netlify-build-plugin"
|
||||||
|
|
||||||
|
[plugins.inputs]
|
||||||
|
sentryOrg = "cadhub-org"
|
||||||
|
sentryProject = "cadhub"
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"@redwoodjs/forms": "^0.33.0",
|
"@redwoodjs/forms": "^0.33.0",
|
||||||
"@redwoodjs/router": "^0.33.0",
|
"@redwoodjs/router": "^0.33.0",
|
||||||
"@redwoodjs/web": "^0.33.0",
|
"@redwoodjs/web": "^0.33.0",
|
||||||
|
"@sentry/browser": "^6.5.1",
|
||||||
"browser-fs-access": "^0.17.2",
|
"browser-fs-access": "^0.17.2",
|
||||||
"cloudinary-react": "^1.6.7",
|
"cloudinary-react": "^1.6.7",
|
||||||
"controlkit": "^0.1.9",
|
"controlkit": "^0.1.9",
|
||||||
@@ -56,4 +57,4 @@
|
|||||||
"tailwindcss": "^2.1.2",
|
"tailwindcss": "^2.1.2",
|
||||||
"worker-loader": "^3.0.7"
|
"worker-loader": "^3.0.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { FatalErrorBoundary as FatalErrorBoundaryBase } from '@redwoodjs/web'
|
||||||
|
import * as Sentry from '@sentry/browser'
|
||||||
|
|
||||||
|
class FatalErrorBoundary extends FatalErrorBoundaryBase {
|
||||||
|
componentDidCatch(error, errorInfo) {
|
||||||
|
Sentry.withScope((scope) => {
|
||||||
|
scope.setExtras(errorInfo)
|
||||||
|
Sentry.captureException(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default FatalErrorBoundary
|
||||||
@@ -2985,6 +2985,84 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
any-observable "^0.3.0"
|
any-observable "^0.3.0"
|
||||||
|
|
||||||
|
"@sentry/browser@^6.5.1":
|
||||||
|
version "6.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.5.1.tgz#9a6ed5607b3b0f4e83f38720e3e202906f8c5bdb"
|
||||||
|
integrity sha512-iVLCdEFwsoWAzE/hNknexPQjjDpMQV7mmaq9Z1P63bD6MfhwVTx4hG4pHn8HEvC38VvCVf1wv0v/LxtoODAYXg==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/core" "6.5.1"
|
||||||
|
"@sentry/types" "6.5.1"
|
||||||
|
"@sentry/utils" "6.5.1"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@sentry/core@6.5.1":
|
||||||
|
version "6.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.5.1.tgz#c8b6c3ed86ed07b193c95d599c1b9a4a161e500e"
|
||||||
|
integrity sha512-Mh3sl/iUOT1myHmM6RlDy2ARzkUClx/g4DAt1rJ/IpQBOlDYQraplXSIW80i/hzRgQDfwhwgf4wUa5DicKBjKw==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/hub" "6.5.1"
|
||||||
|
"@sentry/minimal" "6.5.1"
|
||||||
|
"@sentry/types" "6.5.1"
|
||||||
|
"@sentry/utils" "6.5.1"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@sentry/hub@6.5.1":
|
||||||
|
version "6.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.5.1.tgz#135ef09d07d32e87a53f664c0ae8fcc4f5963519"
|
||||||
|
integrity sha512-lBRMBVMYP8B4PfRiM70murbtJAXiIAao/asDEMIRNGMP6pI2ArqXfJCBYDkStukhikYD0Kqb4trXq+JYF07Hbg==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/types" "6.5.1"
|
||||||
|
"@sentry/utils" "6.5.1"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@sentry/minimal@6.5.1":
|
||||||
|
version "6.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.5.1.tgz#b8c1b382c2ea788eec3d32d203e5081b00eb6838"
|
||||||
|
integrity sha512-q9Do/oreu1RP695CXCLowVDuQyk7ilE6FGdz2QLpTXAfx8247qOwk6+zy9Kea/Djk93+BoSDVQUSneNiVwl0nQ==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/hub" "6.5.1"
|
||||||
|
"@sentry/types" "6.5.1"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@sentry/node@^6.5.1":
|
||||||
|
version "6.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.5.1.tgz#a572b380858de5aeaf98eade6d8d3afcba13d364"
|
||||||
|
integrity sha512-Yh8J/QJ5e8gRBVL9VLCDpUvmiaxsxVZm0CInPHw3V/smgMkrzSKEiqxSeMq8ImPlaJrCFECqdpv4gnvYKI+mQQ==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/core" "6.5.1"
|
||||||
|
"@sentry/hub" "6.5.1"
|
||||||
|
"@sentry/tracing" "6.5.1"
|
||||||
|
"@sentry/types" "6.5.1"
|
||||||
|
"@sentry/utils" "6.5.1"
|
||||||
|
cookie "^0.4.1"
|
||||||
|
https-proxy-agent "^5.0.0"
|
||||||
|
lru_map "^0.3.3"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@sentry/tracing@6.5.1":
|
||||||
|
version "6.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.5.1.tgz#a5f3e497d4f1f319f36475df050e135cf65af750"
|
||||||
|
integrity sha512-y1W/xFC2hAuKqSuuaovkElHY4pbli3XoXrreesg8PtO7ilX6ZbatOQbHsEsHQyoUv0F6aVA+MABOxWH2jt7tfw==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/hub" "6.5.1"
|
||||||
|
"@sentry/minimal" "6.5.1"
|
||||||
|
"@sentry/types" "6.5.1"
|
||||||
|
"@sentry/utils" "6.5.1"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@sentry/types@6.5.1":
|
||||||
|
version "6.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.5.1.tgz#0a34ecfd1ae9275a416a105640eb4bed45a46a1d"
|
||||||
|
integrity sha512-b/7a6CMoytaeFPx4IBjfxPw3nPvsQh7ui1C8Vw0LxNNDgBwVhPLzUOWeLWbo5YZCVbGEMIWwtCUQYWxneceZSA==
|
||||||
|
|
||||||
|
"@sentry/utils@6.5.1":
|
||||||
|
version "6.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.5.1.tgz#046baf7d1a6564d6d555437ad3674dba9bc0806a"
|
||||||
|
integrity sha512-Wv86JYGQH+ZJ5XGFQX7h6ijl32667ikenoL9EyXMn8UoOYX/MLwZoQZin1P60wmKkYR9ifTNVmpaI9OoTaH+UQ==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/types" "6.5.1"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
"@sindresorhus/is@^0.14.0":
|
"@sindresorhus/is@^0.14.0":
|
||||||
version "0.14.0"
|
version "0.14.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
||||||
@@ -12660,6 +12738,11 @@ lru-memoizer@^2.1.2:
|
|||||||
lodash.clonedeep "^4.5.0"
|
lodash.clonedeep "^4.5.0"
|
||||||
lru-cache "~4.0.0"
|
lru-cache "~4.0.0"
|
||||||
|
|
||||||
|
lru_map@^0.3.3:
|
||||||
|
version "0.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
|
||||||
|
integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=
|
||||||
|
|
||||||
lz-string@^1.4.4:
|
lz-string@^1.4.4:
|
||||||
version "1.4.4"
|
version "1.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
|
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
|
||||||
|
|||||||
Reference in New Issue
Block a user