From 17db4ead4007878d26effcdfbe23994eaa361bb6 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson Date: Wed, 13 Dec 2023 08:27:03 -0600 Subject: [PATCH] Add Datadog RUM to client (issue #2067) (#2343) * Conditionally init Datadog RUM in Finder and ARPA * Add RUM options to website runtime config * Update APIGW CORS to allow tracing headers * Configure Datadog RUM inputs for website module * Add environment-specific RUM settings * Add Datadog service manifest --- packages/client/package.json | 1 + packages/client/src/arpa_reporter/main.js | 7 ++++ packages/client/src/main.js | 7 ++++ service.datadog.yaml | 35 +++++++++++++++++++ terraform/main.tf | 12 +++++++ terraform/modules/gost_api/gateway.tf | 5 +++ .../modules/gost_website/runtime_config.tf | 6 ++-- .../modules/gost_website/tpl/deploy-config.js | 4 +++ terraform/modules/gost_website/variables.tf | 31 ++++++++++++++++ terraform/prod.tfvars | 8 +++++ terraform/staging.tfvars | 8 +++++ terraform/variables.tf | 24 +++++++++++++ yarn.lock | 20 +++++++++++ 13 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 service.datadog.yaml diff --git a/packages/client/package.json b/packages/client/package.json index 6efe2d9761..cba07701e7 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "@braid/vue-formulate": "^2.5.3", + "@datadog/browser-rum": "^5.5.0", "bootstrap": "^4.6.1", "bootstrap-vue": "^2.19.0", "core-js": "^3.21.1", diff --git a/packages/client/src/arpa_reporter/main.js b/packages/client/src/arpa_reporter/main.js index 3be16ef447..60b9765a8b 100644 --- a/packages/client/src/arpa_reporter/main.js +++ b/packages/client/src/arpa_reporter/main.js @@ -1,3 +1,10 @@ +/* eslint-disable import/first */ +import { datadogRum } from '@datadog/browser-rum'; + +if (window.APP_CONFIG?.DD_RUM_ENABLED === true) { + datadogRum.init(window.APP_CONFIG.DD_RUM_CONFIG); +} + import Vue from 'vue'; import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'; import App from './App.vue'; diff --git a/packages/client/src/main.js b/packages/client/src/main.js index 71a802dd7b..a219dcf473 100644 --- a/packages/client/src/main.js +++ b/packages/client/src/main.js @@ -1,3 +1,10 @@ +/* eslint-disable import/first */ +import { datadogRum } from '@datadog/browser-rum'; + +if (window.APP_CONFIG?.DD_RUM_ENABLED === true) { + datadogRum.init(window.APP_CONFIG.DD_RUM_CONFIG); +} + import Vue from 'vue'; import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'; import vSelect from 'vue-select'; diff --git a/service.datadog.yaml b/service.datadog.yaml new file mode 100644 index 0000000000..395335af73 --- /dev/null +++ b/service.datadog.yaml @@ -0,0 +1,35 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/DataDog/schema/main/service-catalog/v2.1/schema.json +schema-version: v2.1 +application: GOST +description: > + GOST is a platform that hosts tools to enable state and local government officials to + more easily apply for and report on their federal grants. +dd-service: gost +team: usdr-grants +contacts: + - type: slack + contact: https://usdigitalresponse.slack.com/archives/C0324KDQSCR +links: + - name: Source + type: repo + provider: github + url: https://github.com/usdigitalresponse/usdr-gost + - name: Service Monitoring Dashboard + type: dashboard + url: https://app.datadoghq.com/dashboard/kdw-rtz-5pb/ + - name: ARPA Audit Report Dashboard + type: dashboard + url: https://app.datadoghq.com/dashboard/5gk-g5h-p7t + - name: Project Development Board + type: other + url: https://github.com/orgs/usdigitalresponse/projects/5/views/1 + - name: Grants Program Wiki + type: doc + url: https://www.notion.so/usdr/Grants-Program-Wiki-44d6252c85344eb3b0077a9eb4f0fc5c + - name: Federal Grant Finder product documentation + type: doc + url: https://www.notion.so/usdr/Federal-Grant-Finder-54ffac3935ec478aa3c78c31e98a81ed + - name: ARPA Quarterly Reporter product documentation + type: doc + url: https://www.notion.so/usdr/ARPA-Quarterly-P-E-Reporter-ebd0a1ac2a7f4653b35517819befa9ea diff --git a/terraform/main.tf b/terraform/main.tf index e829a0143b..49e76e07d9 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -69,6 +69,18 @@ module "website" { origin_artifacts_dist_path = coalesce( var.website_origin_artifacts_dist_path, "${path.root}/../packages/client/dist" ) + + datadog_rum_enabled = var.website_datadog_rum_enabled + datadog_rum_config = merge(var.website_datadog_rum_options, { + applicationId = "15db471e-2ccb-4d3c-a6bf-99b750d748f5" + clientToken = "pub50834fcc1999d53e546519b1a0f03934" + site = "datadoghq.com" + service = local.unified_service_tags.service + env = local.unified_service_tags.env + version = local.unified_service_tags.version + defaultPrivacyLevel = "mask" + allowedTracingUrls = ["https://${local.api_domain_name}"] + }) } module "api_to_postgres_security_group" { diff --git a/terraform/modules/gost_api/gateway.tf b/terraform/modules/gost_api/gateway.tf index f61cc4e0fe..aa1d04123f 100644 --- a/terraform/modules/gost_api/gateway.tf +++ b/terraform/modules/gost_api/gateway.tf @@ -54,10 +54,15 @@ module "api_gateway" { allow_headers = [ "authorization", "content-type", + "traceparent", "x-amz-date", "x-amz-security-token", "x-amz-user-agent", "x-api-key", + "x-datadog-trace-id", + "x-datadog-parent-id", + "x-datadog-origin", + "x-datadog-sampling-priority", ] max_age = 86400 // 24 hours, in seconds } diff --git a/terraform/modules/gost_website/runtime_config.tf b/terraform/modules/gost_website/runtime_config.tf index 948596a62b..c18c2c7345 100644 --- a/terraform/modules/gost_website/runtime_config.tf +++ b/terraform/modules/gost_website/runtime_config.tf @@ -2,8 +2,10 @@ locals { deployConfigContents = templatefile( "${path.module}/tpl/deploy-config.js", { - gost_api_domain = var.gost_api_domain, - feature_flags = jsonencode(var.feature_flags), + gost_api_domain = var.gost_api_domain + feature_flags = jsonencode(var.feature_flags) + dd_rum_enabled = var.datadog_rum_enabled + dd_rum_config = jsonencode(var.datadog_rum_config) } ) } diff --git a/terraform/modules/gost_website/tpl/deploy-config.js b/terraform/modules/gost_website/tpl/deploy-config.js index 245fa66425..7b0753baaf 100644 --- a/terraform/modules/gost_website/tpl/deploy-config.js +++ b/terraform/modules/gost_website/tpl/deploy-config.js @@ -1,6 +1,10 @@ window.APP_CONFIG = window.APP_CONFIG || {}; window.APP_CONFIG.apiURLForGOST = 'https://${gost_api_domain}/'; window.apiURLForGOST = window.APP_CONFIG.apiURLForGOST; // Legacy + +window.APP_CONFIG.DD_RUM_ENABLED = ${dd_rum_enabled}; +window.APP_CONFIG.DD_RUM_CONFIG = JSON.parse(${dd_rum_config}); + window.APP_CONFIG.featureFlags = ${feature_flags}; window.APP_CONFIG.overrideFeatureFlag = (flagName, overrideValue) => { diff --git a/terraform/modules/gost_website/variables.tf b/terraform/modules/gost_website/variables.tf index 336661527d..ac0452d2bc 100644 --- a/terraform/modules/gost_website/variables.tf +++ b/terraform/modules/gost_website/variables.tf @@ -35,6 +35,37 @@ variable "gost_api_domain" { type = string } +variable "datadog_rum_enabled" { + description = "Whether to enable Datadog RUM." + type = bool + default = false +} + +variable "datadog_rum_config" { + description = "Runtime configuration options for Datadog RUM." + type = object({ + applicationId = string + clientToken = string + site = string + service = string + env = string + version = string + sessionSampleRate = number + sessionReplaySampleRate = number + trackUserInteractions = bool + trackResources = bool + trackLongTasks = bool + defaultPrivacyLevel = string + allowedTracingUrls = list(string) + }) + default = null + + validation { + condition = can(jsonencode(var.datadog_rum_config)) + error_message = "Value must be JSON-serializable." + } +} + variable "feature_flags" { description = "Feature flags for configuring the website runtime" type = any diff --git a/terraform/prod.tfvars b/terraform/prod.tfvars index 4d78147941..03d00dd8fb 100644 --- a/terraform/prod.tfvars +++ b/terraform/prod.tfvars @@ -38,6 +38,14 @@ website_managed_waf_rules = { metric_visibility = true } } +website_datadog_rum_enabled = true +website_datadog_rum_options = { + sessionSampleRate = 80 + sessionReplaySampleRate = 20 + trackUserInteractions = true + trackResources = true + trackLongTasks = true +} website_feature_flags = { myProfileEnabled = false, newTerminologyEnabled = false diff --git a/terraform/staging.tfvars b/terraform/staging.tfvars index f40cf893e1..116d6fdf72 100644 --- a/terraform/staging.tfvars +++ b/terraform/staging.tfvars @@ -35,6 +35,14 @@ website_managed_waf_rules = { metric_visibility = true } } +website_datadog_rum_enabled = true +website_datadog_rum_options = { + sessionSampleRate = 10 + sessionReplaySampleRate = 1 + trackUserInteractions = true + trackResources = true + trackLongTasks = true +} website_feature_flags = { myProfileEnabled = true, newTerminologyEnabled = true diff --git a/terraform/variables.tf b/terraform/variables.tf index 2982291dcc..b3dc7feee0 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -118,6 +118,30 @@ variable "website_origin_artifacts_dist_path" { default = "" } +variable "website_datadog_rum_enabled" { + description = "Whether to enable Datadog RUM on the website." + type = bool + default = false +} + +variable "website_datadog_rum_options" { + description = "Configuration options for Datadog RUM data collection (if var.website_datadog_rum_enabled is true)." + type = object({ + sessionSampleRate = number + sessionReplaySampleRate = number + trackUserInteractions = bool + trackResources = bool + trackLongTasks = bool + }) + default = { + sessionSampleRate = 100 + sessionReplaySampleRate = 20 + trackUserInteractions = true + trackResources = true + trackLongTasks = true + } +} + variable "website_feature_flags" { description = "Map of website feature flag names and their values." type = any diff --git a/yarn.lock b/yarn.lock index 4c224bb659..571db5a6bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2386,6 +2386,26 @@ debug "^3.1.0" lodash.once "^4.1.1" +"@datadog/browser-core@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@datadog/browser-core/-/browser-core-5.5.0.tgz#9de07fd46fbabbce0a30368394f612512869053c" + integrity sha512-orkbetqiXBrF3r9/WImwJG32tEtNjx2hfP7cyBvPw5qhdjOHkl87IdrKqELaadIAc7Tjgmn38TWccSmcRa1rVw== + +"@datadog/browser-rum-core@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@datadog/browser-rum-core/-/browser-rum-core-5.5.0.tgz#fffb23643cd8be62f12e9781024a3f3fda09e1f9" + integrity sha512-VWI91gwKYTGMycpN5a8kgJ/YCdcnvYAhU2uk6HbTLNg2xj4368FyOdSFOQgQzBvmM323AFS+G0v5u+eQgtNgfQ== + dependencies: + "@datadog/browser-core" "5.5.0" + +"@datadog/browser-rum@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@datadog/browser-rum/-/browser-rum-5.5.0.tgz#b677b5684773db11a24c8b8dec3b0674416f625a" + integrity sha512-nsK9hrD4yuyiSJ2B+R0KVeb61Xj4rwVIIF6mGsNYIaX4sN51Qw/lz5GkOca3YwskS0zMoyicjEWKFZnzq5Q7ew== + dependencies: + "@datadog/browser-core" "5.5.0" + "@datadog/browser-rum-core" "5.5.0" + "@datadog/native-appsec@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-4.0.0.tgz#ee08138b987dec557eac3650a43a972dac85b6a6"