From f70ed94c8c32a3de3beaa7de9aa92d39e996072b Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 15 Jan 2020 23:21:03 +0100 Subject: [PATCH] [api] Add Sentry (#3597) * [api] Add Sentry * Use function name * Add test error * Revert "Add test error" This reverts commit 39cf8a61dad9fcdcb616e418a0deb6ffe9e04ea9. * Revert "Revert "Add test error"" This reverts commit c718f201da9d80743319ac87e0d4560e718fff53. * Add logging * Revert "Add logging" This reverts commit 39cd46c8bbeef9024e71fe70478068480a51545b. * Revert "Revert "Revert "Add test error""" This reverts commit e6f63ee21fabb4ac8fc065b74281dbcdf5811216. * Ignore .env * Use init function for Sentry inline --- .gitignore | 1 + api/_lib/util/assert-env.ts | 9 +++ api/_lib/util/error-handler.ts | 43 +++++++++++ api/_lib/util/with-api-handler.ts | 17 ++++- api/package.json | 1 + api/yarn.lock | 119 ++++++++++++++++++++++++++++++ now.json | 3 +- 7 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 api/_lib/util/assert-env.ts create mode 100644 api/_lib/util/error-handler.ts diff --git a/.gitignore b/.gitignore index 79557d74f..cd28a277a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ packages/now-cli/test/fixtures/integration test/lib/deployment/failed-page.txt .DS_Store .next +.env public diff --git a/api/_lib/util/assert-env.ts b/api/_lib/util/assert-env.ts new file mode 100644 index 000000000..9a5d486fa --- /dev/null +++ b/api/_lib/util/assert-env.ts @@ -0,0 +1,9 @@ +export function assertEnv(name: string) { + const value = process.env[name]; + + if (!value) { + throw new Error(`Missing env "${name}"`); + } + + return value; +} diff --git a/api/_lib/util/error-handler.ts b/api/_lib/util/error-handler.ts new file mode 100644 index 000000000..97f52ef91 --- /dev/null +++ b/api/_lib/util/error-handler.ts @@ -0,0 +1,43 @@ +import { init, captureException, withScope } from '@sentry/node'; +import { assertEnv } from './assert-env'; + +const serviceName = 'api-frameworks'; + +let sentryInitDone = false; + +function initSentry() { + if (sentryInitDone) { + return; + } + + sentryInitDone = true; + + init({ + dsn: assertEnv('SENTRY_DSN'), + environment: process.env.NODE_ENV || 'production', + release: `${serviceName}`, + }); +} + +export function errorHandler(error: Error, extras?: { [key: string]: any }) { + if (!process.env.SENTRY_DSN) { + return; + } + + initSentry(); + + try { + withScope(scope => { + scope.setTag('service', serviceName); + scope.setTag('function_name', assertEnv('AWS_LAMBDA_FUNCTION_NAME')); + + for (const [k, v] of Object.entries(extras)) { + scope.setExtra(k, v); + } + + captureException(error); + }); + } catch (e) { + console.error(`Failed to report error to Sentry: ${e}`); + } +} diff --git a/api/_lib/util/with-api-handler.ts b/api/_lib/util/with-api-handler.ts index 34ffad703..b1361a17b 100644 --- a/api/_lib/util/with-api-handler.ts +++ b/api/_lib/util/with-api-handler.ts @@ -1,4 +1,5 @@ import { NowRequest, NowResponse } from '@now/node'; +import { errorHandler } from './error-handler'; type Handler = (req: NowRequest, res: NowResponse) => Promise; @@ -24,6 +25,20 @@ export function withApiHandler(handler: Handler): Handler { }); } - return handler(req, res); + try { + const result = await handler(req, res); + return result; + } catch (error) { + errorHandler(error, { + url: req.url, + }); + + return res.status(500).json({ + error: { + code: 'unexpected_error', + message: 'An unexpected error occurred.', + }, + }); + } }; } diff --git a/api/package.json b/api/package.json index e0021fa37..eadbc488f 100644 --- a/api/package.json +++ b/api/package.json @@ -8,6 +8,7 @@ "build": "yarn --cwd .. && node ../utils/run.js build all" }, "dependencies": { + "@sentry/node": "5.11.1", "got": "10.2.1", "node-fetch": "2.6.0", "parse-github-url": "1.0.2", diff --git a/api/yarn.lock b/api/yarn.lock index 075b10797..9b57be412 100644 --- a/api/yarn.lock +++ b/api/yarn.lock @@ -9,6 +9,85 @@ dependencies: "@types/node" "*" +"@sentry/apm@5.11.1": + version "5.11.1" + resolved "https://registry.yarnpkg.com/@sentry/apm/-/apm-5.11.1.tgz#cc89fa4150056fbf009f92eca94fccc3980db34e" + integrity sha512-4iZH11p/7w9IMLT9hqNY1+EqLESltiIoF6/YsbpK93sXWGEs8VQ83IuvGuKWxajvHgDmj4ND0TxIliTsYqTqFw== + dependencies: + "@sentry/browser" "5.11.1" + "@sentry/hub" "5.11.1" + "@sentry/minimal" "5.11.1" + "@sentry/types" "5.11.0" + "@sentry/utils" "5.11.1" + tslib "^1.9.3" + +"@sentry/browser@5.11.1": + version "5.11.1" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.11.1.tgz#337ffcb52711b23064c847a07629e966f54a5ebb" + integrity sha512-oqOX/otmuP92DEGRyZeBuQokXdeT9HQRxH73oqIURXXNLMP3PWJALSb4HtT4AftEt/2ROGobZLuA4TaID6My/Q== + dependencies: + "@sentry/core" "5.11.1" + "@sentry/types" "5.11.0" + "@sentry/utils" "5.11.1" + tslib "^1.9.3" + +"@sentry/core@5.11.1": + version "5.11.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.11.1.tgz#9e2da485e196ae32971545c1c49ee6fe719930e2" + integrity sha512-BpvPosVNT20Xso4gAV54Lu3KqDmD20vO63HYwbNdST5LUi8oYV4JhvOkoBraPEM2cbBwQvwVcFdeEYKk4tin9A== + dependencies: + "@sentry/hub" "5.11.1" + "@sentry/minimal" "5.11.1" + "@sentry/types" "5.11.0" + "@sentry/utils" "5.11.1" + tslib "^1.9.3" + +"@sentry/hub@5.11.1": + version "5.11.1" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.11.1.tgz#ddcb865563fae53852d405885c46b4c6de68a91b" + integrity sha512-ucKprYCbGGLLjVz4hWUqHN9KH0WKUkGf5ZYfD8LUhksuobRkYVyig0ZGbshECZxW5jcDTzip4Q9Qimq/PkkXBg== + dependencies: + "@sentry/types" "5.11.0" + "@sentry/utils" "5.11.1" + tslib "^1.9.3" + +"@sentry/minimal@5.11.1": + version "5.11.1" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.11.1.tgz#0e705d01a567282d8fbbda2aed848b4974cc3cec" + integrity sha512-HK8zs7Pgdq7DsbZQTThrhQPrJsVWzz7MaluAbQA0rTIAJ3TvHKQpsVRu17xDpjZXypqWcKCRsthDrC4LxDM1Bg== + dependencies: + "@sentry/hub" "5.11.1" + "@sentry/types" "5.11.0" + tslib "^1.9.3" + +"@sentry/node@5.11.1": + version "5.11.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.11.1.tgz#2a9c18cd1209cfdf7a69b9d91303413149d2c910" + integrity sha512-FbJs0blJ36gEzE0rc2yBfA/KE+kXOLl8MUfFTcyJCBdCGF8XMETDCmgINnJ4TyBUJviwKoPw2TCk9TL2pa/A1w== + dependencies: + "@sentry/apm" "5.11.1" + "@sentry/core" "5.11.1" + "@sentry/hub" "5.11.1" + "@sentry/types" "5.11.0" + "@sentry/utils" "5.11.1" + cookie "^0.3.1" + https-proxy-agent "^4.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/types@5.11.0": + version "5.11.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.11.0.tgz#40f0f3174362928e033ddd9725d55e7c5cb7c5b6" + integrity sha512-1Uhycpmeo1ZK2GLvrtwZhTwIodJHcyIS6bn+t4IMkN9MFoo6ktbAfhvexBDW/IDtdLlCGJbfm8nIZerxy0QUpg== + +"@sentry/utils@5.11.1": + version "5.11.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.11.1.tgz#aa19fcc234cf632257b2281261651d2fac967607" + integrity sha512-O0Zl4R2JJh8cTkQ8ZL2cDqGCmQdpA5VeXpuBbEl1v78LQPkBDISi35wH4mKmLwMsLBtTVpx2UeUHBj0KO5aLlA== + dependencies: + "@sentry/types" "5.11.0" + tslib "^1.9.3" + "@sindresorhus/is@^1.0.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-1.2.0.tgz#63ce3638cb85231f3704164c90a18ef816da3fb7" @@ -62,6 +141,11 @@ dependencies: "@types/node" "*" +agent-base@5: + version "5.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" + integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== + binary@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" @@ -121,6 +205,18 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +cookie@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +debug@4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + decompress-response@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f" @@ -182,6 +278,14 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5" integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew== +https-proxy-agent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" + integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== + dependencies: + agent-base "5" + debug "4" + inherits@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" @@ -204,6 +308,11 @@ lowercase-keys@^2.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +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= + mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -226,6 +335,11 @@ mkdirp@^0.5.1: dependencies: minimist "0.0.8" +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + node-fetch@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" @@ -320,6 +434,11 @@ to-readable-stream@^2.0.0: resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= +tslib@^1.9.3: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + type-fest@^0.8.0: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" diff --git a/now.json b/now.json index 3a217bb36..b9df48861 100644 --- a/now.json +++ b/now.json @@ -7,7 +7,8 @@ } ], "env": { - "GITHUB_ACCESS_TOKEN": "@now-api-examples-github-token" + "GITHUB_ACCESS_TOKEN": "@now-api-examples-github-token", + "SENTRY_DSN": "@sentry-product-dsn" }, "headers": [ {