diff --git a/copilot/fsd-form-runner-adapter/manifest.yml b/copilot/fsd-form-runner-adapter/manifest.yml index 7046856d..761005c0 100644 --- a/copilot/fsd-form-runner-adapter/manifest.yml +++ b/copilot/fsd-form-runner-adapter/manifest.yml @@ -51,7 +51,10 @@ network: # # Pass environment variables as key value pairs. variables: + SENTRY_DSN: "https://6724d8df633d3f4599fbd4cf9c537e3c@o1432034.ingest.us.sentry.io/4508573162864640" + SENTRY_TRACES_SAMPLE_RATE: 1.0 ACCESSIBILITY_STATEMENT_URL: "https://frontend.${COPILOT_ENVIRONMENT_NAME}.access-funding.test.levellingup.gov.uk/accessibility_statement" + SENTRY_ENV: ${COPILOT_ENVIRONMENT_NAME} AWS_BUCKET_NAME: from_cfn: ${COPILOT_APPLICATION_NAME}-${COPILOT_ENVIRONMENT_NAME}-FormUploadsBucket BASIC_AUTH_ON: false @@ -118,6 +121,7 @@ environments: PRIVACY_POLICY_URL: "https://frontend.access-funding.levellingup.gov.uk/privacy" SERVICE_START_PAGE: "https://frontend.access-funding.levellingup.gov.uk/account" ELIGIBILITY_RESULT_URL: "https://frontend.access-funding.levellingup.gov.uk/eligibility-result" + SENTRY_TRACES_SAMPLE_RATE: 0.02 count: range: 2-4 cooldown: diff --git a/runner/config/custom-environment-variables.json b/runner/config/custom-environment-variables.json index 94c57b7d..254dcf77 100644 --- a/runner/config/custom-environment-variables.json +++ b/runner/config/custom-environment-variables.json @@ -67,5 +67,8 @@ "__name": "MIGRATION_BANNER_ENABLED", "__format": "boolean" }, - "ignoreSectionsFromSummary": "IGNORE_SECTIONS_FROM_SUMMARY_PAGE" + "ignoreSectionsFromSummary": "IGNORE_SECTIONS_FROM_SUMMARY_PAGE", + "sentryDsn": "SENTRY_DSN", + "sentryTracesSampleRate": "SENTRY_TRACES_SAMPLE_RATE", + "sentryEnv": "SENTRY_ENV" } diff --git a/runner/config/default.js b/runner/config/default.js index 90fb4c48..256b5047 100644 --- a/runner/config/default.js +++ b/runner/config/default.js @@ -109,4 +109,9 @@ module.exports = { migrationBannerEnabled: false, eligibilityResultUrl: "", ignoreSectionsFromSummary: ["FabDefault"], + + /*sentry configurations*/ + sentryDsn: "", + sentryTracesSampleRate: "", + sentryEnv: "" }; diff --git a/runner/package.json b/runner/package.json index 37ecedfa..a92ef6f3 100644 --- a/runner/package.json +++ b/runner/package.json @@ -26,6 +26,7 @@ "@aws-sdk/client-s3": "3.633.0", "@aws-sdk/lib-storage": "3.633.0", "@aws-sdk/s3-request-presigner": "3.633.0", + "@sentry/node": "^8.47.0", "dropzone": "5.9.3", "hapi-i18n": "3.0.1", "joi": "17.13.3", diff --git a/runner/src/index.ts b/runner/src/index.ts index b63f1b32..d1ad14aa 100644 --- a/runner/src/index.ts +++ b/runner/src/index.ts @@ -1,9 +1,10 @@ import createServer from "./server"; createServer({}) - .then((server) => server.start()) - .then(() => process.send && process.send("online")) - .catch((err) => { - console.error(err); - process.exit(1); - }); + .then((server) => server.start()) + .then(() => process.send && process.send("online")) + .then(() => console.log("*** SERVER STARTED ***")) + .catch((err) => { + console.error(err); + process.exit(1); + }); diff --git a/runner/src/instrument.ts b/runner/src/instrument.ts new file mode 100644 index 00000000..0ca88423 --- /dev/null +++ b/runner/src/instrument.ts @@ -0,0 +1,16 @@ +import {config} from "./server/plugins/utils/AdapterConfigurationSchema"; +import * as Sentry from "@sentry/node"; +import {NodeOptions} from "@sentry/node"; + +if (config.sentryDsn) { + const sentryConfig: NodeOptions = { + dsn: config.sentryDsn, // Replace with your Sentry DSN + environment: config.sentryEnv || "development" // Use the provided environment or default to "development" + }; + // Include tracesSampleRate only if it's available + if (config.sentryTracesSampleRate) { + sentryConfig.tracesSampleRate = Number(config.sentryTracesSampleRate); + } + console.log(`[SENTRY MONITORING ENABLED] Environment: ${sentryConfig.environment} Sample Rate: ${sentryConfig.tracesSampleRate} DSN Available`); + Sentry.init(sentryConfig); +} diff --git a/runner/src/server/index.ts b/runner/src/server/index.ts index 16cd4cb6..8656777e 100644 --- a/runner/src/server/index.ts +++ b/runner/src/server/index.ts @@ -1,5 +1,6 @@ // @ts-ignore import fs from "fs"; +import "../instrument"; // @ts-ignore import hapi, {ServerOptions} from "@hapi/hapi"; @@ -40,6 +41,8 @@ import {TranslationLoaderService} from "./services/TranslationLoaderService"; import {WebhookService} from "./services/WebhookService"; import {pluginLog} from "./plugins/logging"; +const Sentry = require('@sentry/node'); + const serverOptions = async (): Promise => { const hasCertificate = config.sslKey && config.sslCert; @@ -109,11 +112,10 @@ function determineLocal(request: any) { } async function createServer(routeConfig: RouteConfig) { - console.log("SERVER CREATING") + console.log("*** SERVER CREATING WITH PLUGINS ***") const server = hapi.server(await serverOptions()); // @ts-ignore const {formFileName, formFilePath, options} = routeConfig; - if (config.rateLimit) { await server.register(configureRateLimitPlugin(routeConfig)); } @@ -147,7 +149,10 @@ async function createServer(routeConfig: RouteConfig) { (request: HapiRequest, h: HapiResponseToolkit) => { const {response} = request; - if ("isBoom" in response && response.isBoom) { + if ("isBoom" in response && response.isBoom + && response?.output?.statusCode >= 500 + && response?.output?.statusCode < 600) { + Sentry.captureException(response); return h.continue; } @@ -207,6 +212,9 @@ async function createServer(routeConfig: RouteConfig) { server.state("cookies_policy", { encoding: "base64json", }); + + // Sentry error monitoring + await Sentry.setupHapiErrorHandler(server); return server; }