From a52df2214fa2de5595e79f183562b9e13bc1d654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Comeau?= Date: Thu, 16 Nov 2023 14:41:37 -0400 Subject: [PATCH] Fix logger level baking issue --- frontend/.env.example | 19 +++++------ frontend/__mocks__/next/config.ts | 2 +- frontend/next.config.js | 10 +++--- .../components/BreadcrumbStructuredData.tsx | 2 +- frontend/src/components/Header.tsx | 2 +- frontend/src/components/pages/HomePage.tsx | 4 +-- .../src/lib/hooks/usePublicRuntimeConfig.ts | 23 +++++++------ .../schemas/public-runtime-config-schema.ts | 32 +++++++++++++------ frontend/src/logging/log-level.ts | 13 ++++++-- frontend/src/logging/log-util.ts | 15 ++++----- frontend/src/pages/_app.tsx | 8 ++--- frontend/src/pages/_document.tsx | 4 +-- frontend/src/pages/api/readyz.ts | 1 - .../environments/dev/deployments.patch.yaml | 4 +-- gitops/environments/dev/kustomization.yaml | 2 +- .../production/deployments.patch.yaml | 29 ++++++++++++++--- .../production/kustomization.yaml | 8 ++--- .../staging/deployments.patch.yaml | 29 ++++++++++++++--- .../environments/staging/kustomization.yaml | 8 ++--- .../environments/test/deployments.patch.yaml | 8 ++++- gitops/environments/test/kustomization.yaml | 2 +- 21 files changed, 144 insertions(+), 81 deletions(-) diff --git a/frontend/.env.example b/frontend/.env.example index 21f6757d..2866fc12 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1,16 +1,21 @@ -LOGGING_LEVEL=debug +# Content-Security-Policy response header settings +# These settings have default values within the application, so should only be changed if the Adobe Analytics scripts change +ADOBE_ANALYTICS_CSP_DOMAINS=["*.demdex.net", "assets.adobedtm.com", "cm.everesttech.net", "code.jquery.com"] # Adobe Analytics Script Source -NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC=https://assets.adobedtm.com/be5dfd287373/1e84b99f81fb/launch-ffa1e01dbeab-staging.min.js +ADOBE_ANALYTICS_SCRIPT_SRC=https://assets.adobedtm.com/be5dfd287373/1e84b99f81fb/launch-ffa1e01dbeab-staging.min.js # Analytics beacon execution delay in milliseconds (Default: 250) -NEXT_PUBLIC_ANALYTICS_BEACON_DELAY=250 +ANALYTICS_BEACON_DELAY=250 # [REQUIRED] Base URI for the Application -NEXT_PUBLIC_APP_BASE_URI=https://example.com +APP_BASE_URI=https://example.com # Variable to specify what environment app is currently deployed to (dev, staging, test, prod, etc.) -NEXT_PUBLIC_ENVIRONMENT=dev +ENVIRONMENT=dev + +# Logging level (Default: info) +LOGGING_LEVEL=debug # OpenTelemetry/Dynatrace settings # Note: to disable metrics and/or tracing exporting, leave the respective endpoint undefined @@ -20,7 +25,3 @@ OTEL_METRICS_ENDPOINT=https://example.com/e/00000000-0000-0000-0000-000000000000 OTEL_METRICS_EXPORT_INTERVAL_MILLIS=30000 # optional -- default: 60000 OTEL_METRICS_EXPORT_TIMEOUT_MILLIS=5000 # optional -- default: 30000 OTEL_TRACES_ENDPOINT=https://example.com/e/00000000-0000-0000-0000-000000000000/api/v2/otlp/v1/traces - -# Content-Security-Policy response header settings -# These settings have default values within the application, so should only be changed if the Adobe Analytics scripts change -ADOBE_ANALYTICS_CSP_DOMAINS=["*.demdex.net", "assets.adobedtm.com", "cm.everesttech.net", "code.jquery.com"] diff --git a/frontend/__mocks__/next/config.ts b/frontend/__mocks__/next/config.ts index 21dcf80e..5f29a5d9 100644 --- a/frontend/__mocks__/next/config.ts +++ b/frontend/__mocks__/next/config.ts @@ -1,6 +1,6 @@ const getConfigMock = () => ({ publicRuntimeConfig: { - NEXT_PUBLIC_APP_BASE_URI: 'https://example.com', + APP_BASE_URI: 'https://example.com', }, }) diff --git a/frontend/next.config.js b/frontend/next.config.js index 5e2c39d4..8fb07b67 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -22,7 +22,6 @@ const nextConfig = { NEXT_PUBLIC_BUILD_REVISION: process.env.BUILD_REVISION ?? '00000000', NEXT_PUBLIC_BUILD_TIMESTAMP: new Date(process.env.BUILD_DATE ?? statSync('package.json').mtime).toISOString(), NEXT_PUBLIC_BUILD_VERSION: process.env.BUILD_VERSION ?? '00000000-0000-00000000', - LOGGING_LEVEL: process.env.LOGGING_LEVEL ?? 'info', }, experimental: { instrumentationHook: true @@ -32,10 +31,11 @@ const nextConfig = { i18n: { ...i18n, localeDetection: false }, poweredByHeader: false, publicRuntimeConfig: { - NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC: process.env.NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC, - NEXT_PUBLIC_ANALYTICS_BEACON_DELAY: process.env.NEXT_PUBLIC_ANALYTICS_BEACON_DELAY, - NEXT_PUBLIC_APP_BASE_URI: process.env.NEXT_PUBLIC_APP_BASE_URI, - NEXT_PUBLIC_ENVIRONMENT: process.env.NEXT_PUBLIC_ENVIRONMENT, + ADOBE_ANALYTICS_SCRIPT_SRC: process.env.ADOBE_ANALYTICS_SCRIPT_SRC, + ANALYTICS_BEACON_DELAY: process.env.ANALYTICS_BEACON_DELAY, + APP_BASE_URI: process.env.APP_BASE_URI, + ENVIRONMENT: process.env.ENVIRONMENT, + LOGGING_LEVEL: process.env.LOGGING_LEVEL ?? 'info', }, reactStrictMode: true, } diff --git a/frontend/src/components/BreadcrumbStructuredData.tsx b/frontend/src/components/BreadcrumbStructuredData.tsx index 6083392c..bf594053 100644 --- a/frontend/src/components/BreadcrumbStructuredData.tsx +++ b/frontend/src/components/BreadcrumbStructuredData.tsx @@ -29,7 +29,7 @@ const BreadcrumbStructuredData = ({ items }: BreadcrumbProps) => { '@type': 'ListItem', 'position': index + 2, 'name': text, - 'item': urlcat(publicRuntimeConfig.NEXT_PUBLIC_APP_BASE_URI, `/${locale ?? 'en'}${link}`), + 'item': urlcat(publicRuntimeConfig.APP_BASE_URI, `/${locale ?? 'en'}${link}`), })) ?? []), ] diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index d7a88428..bf4bd2b2 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -28,7 +28,7 @@ const Header = ({ gocLink, skipToMainText, breadcrumbItems, hideChecklist, class const langSelectorLocale = locale === 'en' ? 'fr' : 'en' const langSelectorAbbreviation = langSelectorLocale === 'fr' ? 'FR' : 'EN' const langSelectorText = langSelectorLocale === 'fr' ? 'Français' : 'English' - const showBanner = publicRuntimeConfig.NEXT_PUBLIC_ENVIRONMENT !== 'prod' + const showBanner = publicRuntimeConfig.ENVIRONMENT !== 'prod' return ( <> diff --git a/frontend/src/components/pages/HomePage.tsx b/frontend/src/components/pages/HomePage.tsx index 6c210f7b..194eb18c 100644 --- a/frontend/src/components/pages/HomePage.tsx +++ b/frontend/src/components/pages/HomePage.tsx @@ -61,10 +61,10 @@ export const HomePage = () => { '@context': 'https://schema.org', '@type': 'WebSite', 'name': t('common:application-name'), - 'url': urlcat(publicRuntimeConfig.NEXT_PUBLIC_APP_BASE_URI, `/${locale ?? 'en'}`), + 'url': urlcat(publicRuntimeConfig.APP_BASE_URI, `/${locale ?? 'en'}`), }), }), - [publicRuntimeConfig.NEXT_PUBLIC_APP_BASE_URI, locale, t], + [publicRuntimeConfig.APP_BASE_URI, locale, t], ) return ( diff --git a/frontend/src/lib/hooks/usePublicRuntimeConfig.ts b/frontend/src/lib/hooks/usePublicRuntimeConfig.ts index 881c4411..1cbaef56 100644 --- a/frontend/src/lib/hooks/usePublicRuntimeConfig.ts +++ b/frontend/src/lib/hooks/usePublicRuntimeConfig.ts @@ -1,25 +1,24 @@ import { useMemo } from 'react' -import { NextConfig } from 'next' import getConfig from 'next/config' import { publicRuntimeConfigSchema } from '../schemas/public-runtime-config-schema' export const usePublicRuntimeConfig = () => { - const config = getConfig() as NextConfig + const config = getConfig() + + const { ADOBE_ANALYTICS_SCRIPT_SRC, ANALYTICS_BEACON_DELAY, APP_BASE_URI, ENVIRONMENT, LOGGING_LEVEL } = + config?.publicRuntimeConfig ?? {} + return useMemo( () => publicRuntimeConfigSchema.validateSync({ - NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC: config.publicRuntimeConfig?.NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC, - NEXT_PUBLIC_ANALYTICS_BEACON_DELAY: config.publicRuntimeConfig?.NEXT_PUBLIC_ANALYTICS_BEACON_DELAY, - NEXT_PUBLIC_APP_BASE_URI: config.publicRuntimeConfig?.NEXT_PUBLIC_APP_BASE_URI, - NEXT_PUBLIC_ENVIRONMENT: config.publicRuntimeConfig?.NEXT_PUBLIC_ENVIRONMENT, + ADOBE_ANALYTICS_SCRIPT_SRC, + ANALYTICS_BEACON_DELAY, + APP_BASE_URI, + ENVIRONMENT, + LOGGING_LEVEL, }), - [ - config.publicRuntimeConfig?.NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC, - config.publicRuntimeConfig?.NEXT_PUBLIC_ANALYTICS_BEACON_DELAY, - config.publicRuntimeConfig?.NEXT_PUBLIC_APP_BASE_URI, - config.publicRuntimeConfig?.NEXT_PUBLIC_ENVIRONMENT, - ] + [ADOBE_ANALYTICS_SCRIPT_SRC, ANALYTICS_BEACON_DELAY, APP_BASE_URI, ENVIRONMENT, LOGGING_LEVEL], ) } diff --git a/frontend/src/lib/schemas/public-runtime-config-schema.ts b/frontend/src/lib/schemas/public-runtime-config-schema.ts index eecc4fa5..8c05299c 100644 --- a/frontend/src/lib/schemas/public-runtime-config-schema.ts +++ b/frontend/src/lib/schemas/public-runtime-config-schema.ts @@ -1,17 +1,29 @@ +import { LevelWithSilent } from 'pino' import * as yup from 'yup' +export const levelsWithSilent: ReadonlyArray = [ + 'debug', + 'error', + 'fatal', + 'info', + 'silent', + 'trace', + 'warn', +] + export const publicRuntimeConfigSchema = yup.object({ - NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC: yup - .string() - .url('Environment variable NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC must be a valid URL'), - NEXT_PUBLIC_ANALYTICS_BEACON_DELAY: yup + ADOBE_ANALYTICS_SCRIPT_SRC: yup.string().url('Env. variable ${path} must be a valid URL'), + ANALYTICS_BEACON_DELAY: yup .number() - .integer('Environment variable NEXT_PUBLIC_ANALYTICS_BEACON_DELAY must be an integer') - .min(0, 'Environment variable NEXT_PUBLIC_ANALYTICS_BEACON_DELAY must be greater than or equal to 0') + .integer('Env. variable ${path} must be an integer') + .min(0, 'Env. variable ${path} must be greater than or equal to ${min}') .default(() => 250), - NEXT_PUBLIC_APP_BASE_URI: yup + APP_BASE_URI: yup + .string() + .required('Env. variable ${path} is required') + .url('Env. variable ${path} must be a valid URL'), + ENVIRONMENT: yup.string(), + LOGGING_LEVEL: yup .string() - .required('Environment variable NEXT_PUBLIC_APP_BASE_URI is required') - .url('Environment variable NEXT_PUBLIC_APP_BASE_URI must be a valid URL'), - NEXT_PUBLIC_ENVIRONMENT: yup.string(), + .oneOf(levelsWithSilent, 'Env. variable ${path} must be one of the following values: ${values}'), }) diff --git a/frontend/src/logging/log-level.ts b/frontend/src/logging/log-level.ts index df36cee5..7c195b07 100644 --- a/frontend/src/logging/log-level.ts +++ b/frontend/src/logging/log-level.ts @@ -1,7 +1,14 @@ -const logLevelData = { - '*': process.env.LOGGING_LEVEL, +import getConfig from 'next/config' + +export const getLoggingLevelConfig = (): string | undefined => { + // middleware can only read from process.env + if (process.env.LOGGING_LEVEL) return process.env.LOGGING_LEVEL + return getConfig()?.publicRuntimeConfig?.LOGGING_LEVEL +} + +export const logLevelData = { + '*': getLoggingLevelConfig(), // 'middleware': '' // 'home': 'info', // 'app': 'debug', } -export default logLevelData diff --git a/frontend/src/logging/log-util.ts b/frontend/src/logging/log-util.ts index 2b37a6c5..ecd6e719 100644 --- a/frontend/src/logging/log-util.ts +++ b/frontend/src/logging/log-util.ts @@ -1,16 +1,13 @@ -import pino, { Logger, stdTimeFunctions } from 'pino' +import pino, { stdTimeFunctions } from 'pino' -import logLevelData from './log-level' +import { logLevelData } from './log-level' -const logLevels = new Map( - Object.entries(logLevelData) -) - -export function getLogLevel(logger: string): string { - return logLevels.get(logger) || logLevels.get('*') || 'info' +export const getLogLevel = (logger: string) => { + const logLevels = new Map(Object.entries(logLevelData)) + return logLevels.get(logger) ?? logLevels.get('*') ?? 'info' } -export function getLogger(name: string): Logger { +export const getLogger = (name: string) => { return pino({ name, level: getLogLevel(name), diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx index 4504f6b8..f0546573 100644 --- a/frontend/src/pages/_app.tsx +++ b/frontend/src/pages/_app.tsx @@ -40,7 +40,7 @@ export interface MyAppProps extends AppProps { const MyApp = ({ Component, emotionCache = clientSideEmotionCache, pageProps, router }: MyAppProps) => { const publicRuntimeConfig = usePublicRuntimeConfig() - const nextSEOConfig = getNextSEOConfig(publicRuntimeConfig.NEXT_PUBLIC_APP_BASE_URI, router) + const nextSEOConfig = getNextSEOConfig(publicRuntimeConfig.APP_BASE_URI, router) // XXX :: GjB :: this is just a sample metric! requestCounter.add(1) @@ -63,14 +63,14 @@ const MyApp = ({ Component, emotionCache = clientSideEmotionCache, pageProps, ro logger.debug( { appPreviousLocationPathname, - beaconDelay: publicRuntimeConfig.NEXT_PUBLIC_ANALYTICS_BEACON_DELAY, + beaconDelay: publicRuntimeConfig.ANALYTICS_BEACON_DELAY, documentTitle: document.title, windowLocationPathname: window.location.pathname, }, 'Analytics beacon execution', ) ;(window as AppWindow).adobeDataLayer?.push?.({ event: 'pageLoad' }) - }, publicRuntimeConfig.NEXT_PUBLIC_ANALYTICS_BEACON_DELAY) + }, publicRuntimeConfig.ANALYTICS_BEACON_DELAY) } } @@ -82,7 +82,7 @@ const MyApp = ({ Component, emotionCache = clientSideEmotionCache, pageProps, ro router.events.off('routeChangeComplete', handleRouteChange) router.events.off('hashChangeComplete', handleRouteChange) } - }, [publicRuntimeConfig.NEXT_PUBLIC_ANALYTICS_BEACON_DELAY, router.events]) + }, [publicRuntimeConfig.ANALYTICS_BEACON_DELAY, router.events]) return ( diff --git a/frontend/src/pages/_document.tsx b/frontend/src/pages/_document.tsx index 5ad8b77b..509c6248 100644 --- a/frontend/src/pages/_document.tsx +++ b/frontend/src/pages/_document.tsx @@ -13,7 +13,7 @@ import { MyAppProps } from './_app' const log = getLogger('_document.tsx') -const adobeAnalyticsConfigured = process.env.NEXT_PUBLIC_ADOBE_ANALYTICS_SCRIPT_SRC !== undefined +const adobeAnalyticsConfigured = process.env.ADOBE_ANALYTICS_SCRIPT_SRC !== undefined const devmodeEnabled = process.env.NODE_ENV !== 'production' // see https://experienceleague.adobe.com/docs/id-service/using/reference/csp.html @@ -125,7 +125,7 @@ export default function MyDocument({ emotionStyleTags, locale, nonce }: MyDocume