From d58dae136257b97777c85e3945f37b647c8c7a30 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Tue, 2 Dec 2025 13:04:25 -0500 Subject: [PATCH 1/3] Standardize logging configuration variables and update related documentation --- infrastructure/.env.example | 2 +- infrastructure/README.md | 28 ++++----- infrastructure/app.ts | 3 +- infrastructure/stacks/lambda-stack.test.ts | 18 +++--- infrastructure/stacks/lambda-stack.ts | 44 ++++++++------ infrastructure/utils/config.test.ts | 33 +++++++---- infrastructure/utils/config.ts | 3 +- src/handlers/create-task.test.ts | 2 +- src/handlers/delete-task.test.ts | 2 +- src/handlers/get-task.test.ts | 2 +- src/handlers/list-tasks.test.ts | 2 +- src/handlers/update-task.test.ts | 2 +- src/utils/config.test.ts | 68 +++++++++++----------- src/utils/config.ts | 8 +-- src/utils/dynamodb-client.test.ts | 4 +- src/utils/logger.test.ts | 42 ++++++------- src/utils/logger.ts | 8 +-- 17 files changed, 149 insertions(+), 122 deletions(-) diff --git a/infrastructure/.env.example b/infrastructure/.env.example index 6899bad..da4ed28 100644 --- a/infrastructure/.env.example +++ b/infrastructure/.env.example @@ -22,7 +22,7 @@ CDK_ENV=dev ### Logging Configuration ### ## Enable application logging (default: true) -# CDK_APP_ENABLE_LOGGING=true +# CDK_APP_LOGGING_ENABLED=true ## Application logging level: debug, info, warn, error (default: info) # CDK_APP_LOGGING_LEVEL=info ## Application logging format: text, json (default: json) diff --git a/infrastructure/README.md b/infrastructure/README.md index 0773396..cdce4da 100644 --- a/infrastructure/README.md +++ b/infrastructure/README.md @@ -170,17 +170,17 @@ npm run deploy All CDK configuration is managed through environment variables prefixed with `CDK_` to avoid conflicts with application code. -| Variable | Required | Description | Valid Values | Default | -| ------------------------ | -------- | ------------------------------------------ | -------------------------------- | ---------------------------------- | -| `CDK_APP_NAME` | No | Application name for stack naming and tags | Any string | `lambda-starter` | -| `CDK_ENV` | Yes | Infrastructure environment | `dev`, `qat`, `prd` | - | -| `CDK_ACCOUNT` | No | Override AWS account ID | 12-digit account ID | `CDK_DEFAULT_ACCOUNT` from AWS CLI | -| `CDK_REGION` | No | Override AWS region | Valid AWS region | `CDK_DEFAULT_REGION` from AWS CLI | -| `CDK_OU` | No | Organizational unit | Any string | `leanstacks` | -| `CDK_OWNER` | No | Team or owner name | Any string | `unknown` | -| `CDK_APP_ENABLE_LOGGING` | No | Enable application logging | `true`, `false` | `true` | -| `CDK_APP_LOGGING_LEVEL` | No | Application logging level | `debug`, `info`, `warn`, `error` | `info` | -| `CDK_APP_LOGGING_FORMAT` | No | Application logging format | `text`, `json` | `json` | +| Variable | Required | Description | Valid Values | Default | +| ------------------------- | -------- | ------------------------------------------ | -------------------------------- | ---------------------------------- | +| `CDK_APP_NAME` | No | Application name for stack naming and tags | Any string | `lambda-starter` | +| `CDK_ENV` | Yes | Infrastructure environment | `dev`, `qat`, `prd` | - | +| `CDK_ACCOUNT` | No | Override AWS account ID | 12-digit account ID | `CDK_DEFAULT_ACCOUNT` from AWS CLI | +| `CDK_REGION` | No | Override AWS region | Valid AWS region | `CDK_DEFAULT_REGION` from AWS CLI | +| `CDK_OU` | No | Organizational unit | Any string | `leanstacks` | +| `CDK_OWNER` | No | Team or owner name | Any string | `unknown` | +| `CDK_APP_LOGGING_ENABLED` | No | Enable application logging | `true`, `false` | `true` | +| `CDK_APP_LOGGING_LEVEL` | No | Application logging level | `debug`, `info`, `warn`, `error` | `info` | +| `CDK_APP_LOGGING_FORMAT` | No | Application logging format | `text`, `json` | `json` | ### AWS Account and Region Resolution @@ -338,13 +338,13 @@ npm run cdk destroy --all **Logging Configuration:** -The Lambda stack uses the `CDK_APP_ENABLE_LOGGING`, `CDK_APP_LOGGING_LEVEL`, and `CDK_APP_LOGGING_FORMAT` environment variables to configure application logging: +The Lambda stack uses the `CDK_APP_LOGGING_ENABLED`, `CDK_APP_LOGGING_LEVEL`, and `CDK_APP_LOGGING_FORMAT` environment variables to configure application logging: -- **CDK_APP_ENABLE_LOGGING**: Controls whether logging is enabled in the Lambda functions +- **CDK_APP_LOGGING_ENABLED**: Controls whether logging is enabled in the Lambda functions - **CDK_APP_LOGGING_LEVEL**: Sets the minimum log level (`debug`, `info`, `warn`, `error`) - **CDK_APP_LOGGING_FORMAT**: Sets the log output format (`text` or `json`) -These values are passed to the Lambda functions as environment variables (`ENABLE_LOGGING`, `LOG_LEVEL`, and `LOG_FORMAT`) and control both CloudWatch log output and application-level logging behavior. +These values are passed to the Lambda functions as environment variables (`LOGGING_ENABLED`, `LOGGING_LEVEL`, and `LOGGING_FORMAT`) and control both CloudWatch log output and application-level logging behavior. **Log Format Options:** diff --git a/infrastructure/app.ts b/infrastructure/app.ts index d1917f9..c2f5e2d 100644 --- a/infrastructure/app.ts +++ b/infrastructure/app.ts @@ -34,9 +34,10 @@ new LambdaStack(app, `${config.CDK_APP_NAME}-lambda-stack-${config.CDK_ENV}`, { stackName: `${config.CDK_APP_NAME}-lambda-${config.CDK_ENV}`, description: `Lambda functions and API Gateway for ${config.CDK_APP_NAME} (${config.CDK_ENV})`, taskTable: dataStack.taskTable, - enableLogging: config.CDK_APP_ENABLE_LOGGING, + loggingEnabled: config.CDK_APP_LOGGING_ENABLED, loggingLevel: config.CDK_APP_LOGGING_LEVEL, loggingFormat: config.CDK_APP_LOGGING_FORMAT, + corsAllowOrigin: config.CDK_CORS_ALLOW_ORIGIN, ...(environmentConfig && { env: environmentConfig }), }); diff --git a/infrastructure/stacks/lambda-stack.test.ts b/infrastructure/stacks/lambda-stack.test.ts index 709c371..8cb8e00 100644 --- a/infrastructure/stacks/lambda-stack.test.ts +++ b/infrastructure/stacks/lambda-stack.test.ts @@ -40,9 +40,10 @@ describe('LambdaStack', () => { appName: 'lambda-starter', envName: 'dev', taskTable: testMockTable, - enableLogging: true, + loggingEnabled: true, loggingLevel: 'debug', loggingFormat: 'json', + corsAllowOrigin: '*', }); template = Template.fromStack(stack); }); @@ -102,9 +103,10 @@ describe('LambdaStack', () => { Environment: { Variables: { TASKS_TABLE: Match.anyValue(), - ENABLE_LOGGING: 'true', - LOG_LEVEL: 'debug', - LOG_FORMAT: 'json', + LOGGING_ENABLED: 'true', + LOGGING_LEVEL: 'debug', + LOGGING_FORMAT: 'json', + CORS_ALLOW_ORIGIN: '*', }, }, }); @@ -314,9 +316,10 @@ describe('LambdaStack', () => { appName: 'lambda-starter', envName: 'prd', taskTable: testMockTable, - enableLogging: true, + loggingEnabled: true, loggingLevel: 'info', loggingFormat: 'json', + corsAllowOrigin: '*', }); template = Template.fromStack(stack); }); @@ -331,7 +334,7 @@ describe('LambdaStack', () => { template.hasResourceProperties('AWS::Lambda::Function', { Environment: { Variables: { - LOG_LEVEL: 'info', + LOGGING_LEVEL: 'info', }, }, }); @@ -369,9 +372,10 @@ describe('LambdaStack', () => { appName: 'lambda-starter', envName: 'dev', taskTable: testMockTable, - enableLogging: true, + loggingEnabled: true, loggingLevel: 'debug', loggingFormat: 'json', + corsAllowOrigin: '*', }); template = Template.fromStack(stack); }); diff --git a/infrastructure/stacks/lambda-stack.ts b/infrastructure/stacks/lambda-stack.ts index 9c46772..71d7eeb 100644 --- a/infrastructure/stacks/lambda-stack.ts +++ b/infrastructure/stacks/lambda-stack.ts @@ -29,7 +29,7 @@ export interface LambdaStackProps extends cdk.StackProps { /** * Whether to enable application logging. */ - enableLogging: boolean; + loggingEnabled: boolean; /** * Application logging level. @@ -40,6 +40,11 @@ export interface LambdaStackProps extends cdk.StackProps { * Application logging format (text or json). */ loggingFormat: string; + + /** + * CORS allow origin value. + */ + corsAllowOrigin: string; } /** @@ -87,9 +92,10 @@ export class LambdaStack extends cdk.Stack { entry: path.join(__dirname, '../../src/handlers/list-tasks.ts'), environment: { TASKS_TABLE: props.taskTable.tableName, - ENABLE_LOGGING: props.enableLogging.toString(), - LOG_LEVEL: props.loggingLevel, - LOG_FORMAT: props.loggingFormat, + LOGGING_ENABLED: props.loggingEnabled.toString(), + LOGGING_LEVEL: props.loggingLevel, + LOGGING_FORMAT: props.loggingFormat, + CORS_ALLOW_ORIGIN: props.corsAllowOrigin, }, timeout: cdk.Duration.seconds(10), memorySize: 256, @@ -118,9 +124,10 @@ export class LambdaStack extends cdk.Stack { entry: path.join(__dirname, '../../src/handlers/get-task.ts'), environment: { TASKS_TABLE: props.taskTable.tableName, - ENABLE_LOGGING: props.enableLogging.toString(), - LOG_LEVEL: props.loggingLevel, - LOG_FORMAT: props.loggingFormat, + LOGGING_ENABLED: props.loggingEnabled.toString(), + LOGGING_LEVEL: props.loggingLevel, + LOGGING_FORMAT: props.loggingFormat, + CORS_ALLOW_ORIGIN: props.corsAllowOrigin, }, timeout: cdk.Duration.seconds(10), memorySize: 256, @@ -149,9 +156,10 @@ export class LambdaStack extends cdk.Stack { entry: path.join(__dirname, '../../src/handlers/create-task.ts'), environment: { TASKS_TABLE: props.taskTable.tableName, - ENABLE_LOGGING: props.enableLogging.toString(), - LOG_LEVEL: props.loggingLevel, - LOG_FORMAT: props.loggingFormat, + LOGGING_ENABLED: props.loggingEnabled.toString(), + LOGGING_LEVEL: props.loggingLevel, + LOGGING_FORMAT: props.loggingFormat, + CORS_ALLOW_ORIGIN: props.corsAllowOrigin, }, timeout: cdk.Duration.seconds(10), memorySize: 256, @@ -180,9 +188,10 @@ export class LambdaStack extends cdk.Stack { entry: path.join(__dirname, '../../src/handlers/update-task.ts'), environment: { TASKS_TABLE: props.taskTable.tableName, - ENABLE_LOGGING: props.enableLogging.toString(), - LOG_LEVEL: props.loggingLevel, - LOG_FORMAT: props.loggingFormat, + LOGGING_ENABLED: props.loggingEnabled.toString(), + LOGGING_LEVEL: props.loggingLevel, + LOGGING_FORMAT: props.loggingFormat, + CORS_ALLOW_ORIGIN: props.corsAllowOrigin, }, timeout: cdk.Duration.seconds(10), memorySize: 256, @@ -211,9 +220,10 @@ export class LambdaStack extends cdk.Stack { entry: path.join(__dirname, '../../src/handlers/delete-task.ts'), environment: { TASKS_TABLE: props.taskTable.tableName, - ENABLE_LOGGING: props.enableLogging.toString(), - LOG_LEVEL: props.loggingLevel, - LOG_FORMAT: props.loggingFormat, + LOGGING_ENABLED: props.loggingEnabled.toString(), + LOGGING_LEVEL: props.loggingLevel, + LOGGING_FORMAT: props.loggingFormat, + CORS_ALLOW_ORIGIN: props.corsAllowOrigin, }, timeout: cdk.Duration.seconds(10), memorySize: 256, @@ -244,7 +254,7 @@ export class LambdaStack extends cdk.Stack { throttlingBurstLimit: 200, }, defaultCorsPreflightOptions: { - allowOrigins: apigateway.Cors.ALL_ORIGINS, + allowOrigins: [props.corsAllowOrigin], allowMethods: apigateway.Cors.ALL_METHODS, allowHeaders: ['Content-Type', 'Authorization'], }, diff --git a/infrastructure/utils/config.test.ts b/infrastructure/utils/config.test.ts index ce21cf7..aa604a3 100644 --- a/infrastructure/utils/config.test.ts +++ b/infrastructure/utils/config.test.ts @@ -30,7 +30,8 @@ describe('config', () => { process.env.CDK_REGION = 'us-east-1'; process.env.CDK_OU = 'leanstacks'; process.env.CDK_OWNER = 'platform-team'; - process.env.CDK_APP_ENABLE_LOGGING = 'false'; + process.env.CDK_CORS_ALLOW_ORIGIN = 'https://example.com'; + process.env.CDK_APP_LOGGING_ENABLED = 'false'; process.env.CDK_APP_LOGGING_LEVEL = 'warn'; process.env.CDK_APP_LOGGING_FORMAT = 'text'; @@ -43,7 +44,8 @@ describe('config', () => { CDK_REGION: 'us-east-1', CDK_OU: 'leanstacks', CDK_OWNER: 'platform-team', - CDK_APP_ENABLE_LOGGING: false, + CDK_CORS_ALLOW_ORIGIN: 'https://example.com', + CDK_APP_LOGGING_ENABLED: false, CDK_APP_LOGGING_LEVEL: 'warn', CDK_APP_LOGGING_FORMAT: 'text', }); @@ -89,7 +91,8 @@ describe('config', () => { CDK_ENV: 'dev', CDK_OU: 'leanstacks', CDK_OWNER: 'platform-team', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; @@ -108,7 +111,8 @@ describe('config', () => { const config: Config = { CDK_APP_NAME: 'lambda-starter', CDK_ENV: 'qat', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; @@ -127,7 +131,8 @@ describe('config', () => { const config: Config = { CDK_APP_NAME: 'my-custom-app', CDK_ENV: 'dev', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; @@ -153,7 +158,8 @@ describe('config', () => { CDK_ENV: 'dev', CDK_ACCOUNT: '123456789012', CDK_REGION: 'us-west-2', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; @@ -175,7 +181,8 @@ describe('config', () => { const config: Config = { CDK_APP_NAME: 'lambda-starter', CDK_ENV: 'dev', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; @@ -197,7 +204,8 @@ describe('config', () => { CDK_ENV: 'prd', CDK_ACCOUNT: '999999999999', CDK_REGION: 'ap-southeast-2', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; @@ -219,7 +227,8 @@ describe('config', () => { const config: Config = { CDK_APP_NAME: 'lambda-starter', CDK_ENV: 'dev', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; @@ -236,7 +245,8 @@ describe('config', () => { const config: Config = { CDK_APP_NAME: 'lambda-starter', CDK_ENV: 'dev', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; @@ -253,7 +263,8 @@ describe('config', () => { const config: Config = { CDK_APP_NAME: 'lambda-starter', CDK_ENV: 'dev', - CDK_APP_ENABLE_LOGGING: true, + CDK_CORS_ALLOW_ORIGIN: '*', + CDK_APP_LOGGING_ENABLED: true, CDK_APP_LOGGING_LEVEL: 'info', CDK_APP_LOGGING_FORMAT: 'json', }; diff --git a/infrastructure/utils/config.ts b/infrastructure/utils/config.ts index 2d43e65..26e8421 100644 --- a/infrastructure/utils/config.ts +++ b/infrastructure/utils/config.ts @@ -11,7 +11,8 @@ const configSchema = z.object({ CDK_REGION: z.string().optional(), CDK_OU: z.string().optional(), CDK_OWNER: z.string().optional(), - CDK_APP_ENABLE_LOGGING: z + CDK_CORS_ALLOW_ORIGIN: z.string().default('*'), + CDK_APP_LOGGING_ENABLED: z .enum(['true', 'false'] as const) .default('true') .transform((val) => val === 'true'), diff --git a/src/handlers/create-task.test.ts b/src/handlers/create-task.test.ts index 601663a..1cdaaa9 100644 --- a/src/handlers/create-task.test.ts +++ b/src/handlers/create-task.test.ts @@ -13,7 +13,7 @@ jest.mock('../utils/config', () => ({ TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', ENABLE_LOGGING: true, - LOG_LEVEL: 'info', + LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, })); diff --git a/src/handlers/delete-task.test.ts b/src/handlers/delete-task.test.ts index 3048023..695db1e 100644 --- a/src/handlers/delete-task.test.ts +++ b/src/handlers/delete-task.test.ts @@ -11,7 +11,7 @@ jest.mock('../utils/config', () => ({ TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', ENABLE_LOGGING: true, - LOG_LEVEL: 'info', + LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, })); diff --git a/src/handlers/get-task.test.ts b/src/handlers/get-task.test.ts index ebc3061..cf2966f 100644 --- a/src/handlers/get-task.test.ts +++ b/src/handlers/get-task.test.ts @@ -13,7 +13,7 @@ jest.mock('../utils/config', () => ({ TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', ENABLE_LOGGING: true, - LOG_LEVEL: 'info', + LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, })); diff --git a/src/handlers/list-tasks.test.ts b/src/handlers/list-tasks.test.ts index 132e3cf..80b2b22 100644 --- a/src/handlers/list-tasks.test.ts +++ b/src/handlers/list-tasks.test.ts @@ -12,7 +12,7 @@ jest.mock('../utils/config', () => ({ TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', ENABLE_LOGGING: true, - LOG_LEVEL: 'info', + LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, })); diff --git a/src/handlers/update-task.test.ts b/src/handlers/update-task.test.ts index a31f923..92061f2 100644 --- a/src/handlers/update-task.test.ts +++ b/src/handlers/update-task.test.ts @@ -13,7 +13,7 @@ jest.mock('../utils/config', () => ({ TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', ENABLE_LOGGING: true, - LOG_LEVEL: 'info', + LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, })); diff --git a/src/utils/config.test.ts b/src/utils/config.test.ts index d32d6a7..a1dda74 100644 --- a/src/utils/config.test.ts +++ b/src/utils/config.test.ts @@ -49,9 +49,9 @@ describe('config', () => { // Assert expect(config.AWS_REGION).toBe('us-east-1'); - expect(config.ENABLE_LOGGING).toBe(true); - expect(config.LOG_LEVEL).toBe('debug'); - expect(config.LOG_FORMAT).toBe('json'); + expect(config.LOGGING_ENABLED).toBe(true); + expect(config.LOGGING_LEVEL).toBe('debug'); + expect(config.LOGGING_FORMAT).toBe('json'); expect(config.CORS_ALLOW_ORIGIN).toBe('*'); }); @@ -59,9 +59,9 @@ describe('config', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; process.env.AWS_REGION = 'us-west-2'; - process.env.ENABLE_LOGGING = 'false'; - process.env.LOG_LEVEL = 'error'; - process.env.LOG_FORMAT = 'text'; + process.env.LOGGING_ENABLED = 'false'; + process.env.LOGGING_LEVEL = 'error'; + process.env.LOGGING_FORMAT = 'text'; process.env.CORS_ALLOW_ORIGIN = 'https://example.com'; // Act @@ -69,9 +69,9 @@ describe('config', () => { // Assert expect(config.AWS_REGION).toBe('us-west-2'); - expect(config.ENABLE_LOGGING).toBe(false); - expect(config.LOG_LEVEL).toBe('error'); - expect(config.LOG_FORMAT).toBe('text'); + expect(config.LOGGING_ENABLED).toBe(false); + expect(config.LOGGING_LEVEL).toBe('error'); + expect(config.LOGGING_FORMAT).toBe('text'); expect(config.CORS_ALLOW_ORIGIN).toBe('https://example.com'); }); @@ -105,33 +105,33 @@ describe('config', () => { }).toThrow('TASKS_TABLE'); }); - it('should transform ENABLE_LOGGING string to boolean true', () => { + it('should transform LOGGING_ENABLED string to boolean true', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; - process.env.ENABLE_LOGGING = 'true'; + process.env.LOGGING_ENABLED = 'true'; // Act config = require('./config').config; // Assert - expect(config.ENABLE_LOGGING).toBe(true); - expect(typeof config.ENABLE_LOGGING).toBe('boolean'); + expect(config.LOGGING_ENABLED).toBe(true); + expect(typeof config.LOGGING_ENABLED).toBe('boolean'); }); - it('should transform ENABLE_LOGGING string to boolean false', () => { + it('should transform LOGGING_ENABLED string to boolean false', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; - process.env.ENABLE_LOGGING = 'false'; + process.env.LOGGING_ENABLED = 'false'; // Act config = require('./config').config; // Assert - expect(config.ENABLE_LOGGING).toBe(false); - expect(typeof config.ENABLE_LOGGING).toBe('boolean'); + expect(config.LOGGING_ENABLED).toBe(false); + expect(typeof config.LOGGING_ENABLED).toBe('boolean'); }); - it('should validate LOG_LEVEL enum values', () => { + it('should validate LOGGING_LEVEL enum values', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; @@ -139,16 +139,16 @@ describe('config', () => { const validLogLevels = ['debug', 'info', 'warn', 'error']; validLogLevels.forEach((level) => { jest.resetModules(); - process.env.LOG_LEVEL = level; + process.env.LOGGING_LEVEL = level; config = require('./config').config; - expect(config.LOG_LEVEL).toBe(level); + expect(config.LOGGING_LEVEL).toBe(level); }); }); - it('should throw error for invalid LOG_LEVEL', () => { + it('should throw error for invalid LOGGING_LEVEL', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; - process.env.LOG_LEVEL = 'invalid'; + process.env.LOGGING_LEVEL = 'invalid'; // Act & Assert expect(() => { @@ -157,10 +157,10 @@ describe('config', () => { }).toThrow('Configuration validation failed'); }); - it('should throw error for invalid ENABLE_LOGGING value', () => { + it('should throw error for invalid LOGGING_ENABLED value', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; - process.env.ENABLE_LOGGING = 'yes'; + process.env.LOGGING_ENABLED = 'yes'; // Act & Assert expect(() => { @@ -169,7 +169,7 @@ describe('config', () => { }).toThrow('Configuration validation failed'); }); - it('should validate LOG_FORMAT enum values', () => { + it('should validate LOGGING_FORMAT enum values', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; @@ -177,16 +177,16 @@ describe('config', () => { const validLogFormats = ['text', 'json']; validLogFormats.forEach((format) => { jest.resetModules(); - process.env.LOG_FORMAT = format; + process.env.LOGGING_FORMAT = format; config = require('./config').config; - expect(config.LOG_FORMAT).toBe(format); + expect(config.LOGGING_FORMAT).toBe(format); }); }); - it('should throw error for invalid LOG_FORMAT', () => { + it('should throw error for invalid LOGGING_FORMAT', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; - process.env.LOG_FORMAT = 'xml'; + process.env.LOGGING_FORMAT = 'xml'; // Act & Assert expect(() => { @@ -289,7 +289,7 @@ describe('config', () => { it('should provide detailed error message for multiple validation failures', () => { // Arrange delete process.env.TASKS_TABLE; - process.env.LOG_LEVEL = 'invalid'; + process.env.LOGGING_LEVEL = 'invalid'; // Act & Assert expect(() => { @@ -321,8 +321,8 @@ describe('config', () => { // Arrange process.env.TASKS_TABLE = 'my-tasks-table'; process.env.AWS_REGION = 'us-east-1'; - process.env.ENABLE_LOGGING = 'true'; - process.env.LOG_LEVEL = 'info'; + process.env.LOGGING_ENABLED = 'true'; + process.env.LOGGING_LEVEL = 'info'; process.env.CORS_ALLOW_ORIGIN = 'https://example.com'; // Act @@ -331,8 +331,8 @@ describe('config', () => { // Assert - verify all expected properties exist and have correct types expect(typeof config.TASKS_TABLE).toBe('string'); expect(typeof config.AWS_REGION).toBe('string'); - expect(typeof config.ENABLE_LOGGING).toBe('boolean'); - expect(['debug', 'info', 'warn', 'error']).toContain(config.LOG_LEVEL); + expect(typeof config.LOGGING_ENABLED).toBe('boolean'); + expect(['debug', 'info', 'warn', 'error']).toContain(config.LOGGING_LEVEL); expect(typeof config.CORS_ALLOW_ORIGIN).toBe('string'); }); }); diff --git a/src/utils/config.ts b/src/utils/config.ts index a4837d3..f7bfb39 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -10,13 +10,13 @@ const envSchema = z.object({ // Optional variables with defaults AWS_REGION: z.string().default('us-east-1'), - // Feature flags (optional) - ENABLE_LOGGING: z + // Logging configuration + LOGGING_ENABLED: z .enum(['true', 'false'] as const) .default('true') .transform((val) => val === 'true'), - LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error'] as const).default('debug'), - LOG_FORMAT: z.enum(['text', 'json'] as const).default('json'), + LOGGING_LEVEL: z.enum(['debug', 'info', 'warn', 'error'] as const).default('debug'), + LOGGING_FORMAT: z.enum(['text', 'json'] as const).default('json'), // CORS configuration CORS_ALLOW_ORIGIN: z.string().default('*'), diff --git a/src/utils/dynamodb-client.test.ts b/src/utils/dynamodb-client.test.ts index 4840922..b9e3f6f 100644 --- a/src/utils/dynamodb-client.test.ts +++ b/src/utils/dynamodb-client.test.ts @@ -13,7 +13,7 @@ describe('dynamodb-client', () => { AWS_REGION: 'us-east-1', TASKS_TABLE: 'test-table', ENABLE_LOGGING: true, - LOG_LEVEL: 'info', + LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, })); @@ -115,7 +115,7 @@ describe('dynamodb-client', () => { AWS_REGION: 'eu-west-1', TASKS_TABLE: 'test-table', ENABLE_LOGGING: true, - LOG_LEVEL: 'info', + LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, })); diff --git a/src/utils/logger.test.ts b/src/utils/logger.test.ts index 6a91dc1..d6b8a1f 100644 --- a/src/utils/logger.test.ts +++ b/src/utils/logger.test.ts @@ -6,13 +6,13 @@ describe('logger', () => { let mockError: jest.SpyInstance; // Helper to mock config before importing logger - function setConfig(overrides: Partial<{ ENABLE_LOGGING: boolean; LOG_LEVEL: string; LOG_FORMAT: string }>) { + function setConfig(overrides: Partial<{ LOGGING_ENABLED: boolean; LOGGING_LEVEL: string; LOGGING_FORMAT: string }>) { jest.resetModules(); jest.doMock('./config', () => ({ config: { - ENABLE_LOGGING: true, - LOG_LEVEL: 'debug', - LOG_FORMAT: 'json', + LOGGING_ENABLED: true, + LOGGING_LEVEL: 'debug', + LOGGING_FORMAT: 'json', ...overrides, }, })); @@ -38,7 +38,7 @@ describe('logger', () => { it('logs debug when enabled and level is debug', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'debug', LOG_FORMAT: 'text' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'debug', LOGGING_FORMAT: 'text' }); // Act logger.debug('debug message', { foo: 'bar' }); @@ -49,7 +49,7 @@ describe('logger', () => { it('does not log debug if level is info', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'info' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'info' }); // Act logger.debug('should not log'); @@ -60,7 +60,7 @@ describe('logger', () => { it('logs info when enabled and level is info', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'info', LOG_FORMAT: 'text' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', LOGGING_FORMAT: 'text' }); // Act logger.info('info message'); @@ -71,7 +71,7 @@ describe('logger', () => { it('does not log info if level is warn', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'warn' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'warn' }); // Act logger.info('should not log'); @@ -82,7 +82,7 @@ describe('logger', () => { it('logs warn when enabled and level is warn', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'warn', LOG_FORMAT: 'text' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'warn', LOGGING_FORMAT: 'text' }); // Act logger.warn('warn message', { a: 1 }); @@ -93,7 +93,7 @@ describe('logger', () => { it('logs error with error object', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'error', LOG_FORMAT: 'text' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'error', LOGGING_FORMAT: 'text' }); const error = new Error('fail'); // Act @@ -109,7 +109,7 @@ describe('logger', () => { it('logs error without error object', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'error', LOG_FORMAT: 'text' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'error', LOGGING_FORMAT: 'text' }); // Act logger.error('error message'); @@ -118,9 +118,9 @@ describe('logger', () => { expect(mockError).toHaveBeenCalledWith('error message', undefined); }); - it('does not log if ENABLE_LOGGING is false', () => { + it('does not log if LOGGING_ENABLED is false', () => { // Arrange - setConfig({ ENABLE_LOGGING: false, LOG_LEVEL: 'debug' }); + setConfig({ LOGGING_ENABLED: false, LOGGING_LEVEL: 'debug' }); // Act logger.debug('should not log'); @@ -146,9 +146,9 @@ describe('logger', () => { stdoutSpy.mockRestore(); }); - it('logs as JSON when LOG_FORMAT is json', () => { + it('logs as JSON when LOGGING_FORMAT is json', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'info', LOG_FORMAT: 'json' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', LOGGING_FORMAT: 'json' }); // Act logger.info('test message', { userId: 123 }); @@ -163,7 +163,7 @@ describe('logger', () => { it('logs context as separate fields in JSON format', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'debug', LOG_FORMAT: 'json' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'debug', LOGGING_FORMAT: 'json' }); // Act logger.debug('processing request', { requestId: 'abc-123', duration: 250 }); @@ -179,7 +179,7 @@ describe('logger', () => { it('logs error details in JSON format', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'error', LOG_FORMAT: 'json' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'error', LOGGING_FORMAT: 'json' }); const error = new Error('test error'); // Act @@ -196,9 +196,9 @@ describe('logger', () => { }); describe('text format', () => { - it('logs as text when LOG_FORMAT is text', () => { + it('logs as text when LOGGING_FORMAT is text', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'info', LOG_FORMAT: 'text' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', LOGGING_FORMAT: 'text' }); // Act logger.info('test message', { userId: 123 }); @@ -213,7 +213,7 @@ describe('logger', () => { it('logs with context as stringified object in text format', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'warn', LOG_FORMAT: 'text' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'warn', LOGGING_FORMAT: 'text' }); // Act logger.warn('warning message', { code: 'WARN_001' }); @@ -228,7 +228,7 @@ describe('logger', () => { it('logs error with error details in text format', () => { // Arrange - setConfig({ ENABLE_LOGGING: true, LOG_LEVEL: 'error', LOG_FORMAT: 'text' }); + setConfig({ LOGGING_ENABLED: true, LOGGING_LEVEL: 'error', LOGGING_FORMAT: 'text' }); const error = new Error('test error'); // Act diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 1f5929b..98ca54b 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -14,7 +14,7 @@ const _lambdaDestination = pinoLambdaDestination(); */ const _logger = pino( { - level: config.LOG_LEVEL, + level: config.LOGGING_LEVEL, formatters: { level: (label) => { return { level: label }; @@ -41,9 +41,9 @@ type LogLevel = keyof typeof LOG_LEVELS; * Check if a given log level should be logged based on configured level */ const _shouldLog = (level: LogLevel): boolean => { - if (!config.ENABLE_LOGGING) return false; + if (!config.LOGGING_ENABLED) return false; - const configuredLevel = LOG_LEVELS[config.LOG_LEVEL as LogLevel]; + const configuredLevel = LOG_LEVELS[config.LOGGING_LEVEL as LogLevel]; const requestedLevel = LOG_LEVELS[level]; return requestedLevel >= configuredLevel; @@ -95,7 +95,7 @@ const _logJson = (level: LogLevel, message: string, context?: Record): void => { if (!_shouldLog(level)) return; - if (config.LOG_FORMAT === 'json') { + if (config.LOGGING_FORMAT === 'json') { _logJson(level, message, context); } else { _logText(level, message, context); From c0cb9b92d8cacf84aa4cc4de969afcf81aea9d2b Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Tue, 2 Dec 2025 13:04:35 -0500 Subject: [PATCH 2/3] Add comprehensive configuration guide and update README for clarity --- docs/ConfigurationGuide.md | 196 ++++++++++++++++++++++++++++++++++++ docs/InfrastructureGuide.md | 24 ++--- docs/README.md | 23 +++-- 3 files changed, 225 insertions(+), 18 deletions(-) create mode 100644 docs/ConfigurationGuide.md diff --git a/docs/ConfigurationGuide.md b/docs/ConfigurationGuide.md new file mode 100644 index 0000000..2a2cd1d --- /dev/null +++ b/docs/ConfigurationGuide.md @@ -0,0 +1,196 @@ +# Configuration Guide + +This guide provides comprehensive information about configuring the Lambda Starter application and its infrastructure. + +## Application Configuration + +The application configuration is managed through environment variables. These variables are validated using Zod schemas at runtime to ensure proper configuration. + +### Environment Variables + +The following environment variables are available for configuring the application: + +| Variable | Type | Description | Default | Required | +| ------------------- | ------- | ------------------------------------------------ | ----------- | -------- | +| `TASKS_TABLE` | string | The name of the DynamoDB table for storing tasks | - | Yes | +| `AWS_REGION` | string | The AWS region where resources are deployed | `us-east-1` | No | +| `LOGGING_ENABLED` | boolean | Enable or disable application logging | `true` | No | +| `LOGGING_LEVEL` | enum | Logging level: `debug`, `info`, `warn`, `error` | `debug` | No | +| `LOGGING_FORMAT` | enum | Logging format: `text`, `json` | `json` | No | +| `CORS_ALLOW_ORIGIN` | string | CORS allow origin header value | `*` | No | + +### Usage + +Application configuration is accessed through the `config` object exported from `src/utils/config.ts`: + +```typescript +import { config } from './utils/config'; + +console.log(`Tasks table: ${config.TASKS_TABLE}`); +console.log(`Logging enabled: ${config.LOGGING_ENABLED}`); +``` + +### Configuration Validation + +The application uses Zod to validate environment variables at startup. If validation fails, the application will throw an error with details about the validation issues. + +--- + +## Infrastructure Configuration + +The infrastructure configuration is managed through environment variables prefixed with `CDK_`. These variables control how AWS resources are provisioned using the AWS CDK. + +### Environment Variables + +The following environment variables are available for configuring the infrastructure: + +| Variable | Type | Description | Default | Required | +| ------------------------- | ------- | ------------------------------------------------------ | ---------------- | -------- | +| `CDK_APP_NAME` | string | The application name used in resource naming | `lambda-starter` | No | +| `CDK_ENV` | enum | Environment: `dev`, `qat`, `prd` | - | Yes | +| `CDK_ACCOUNT` | string | AWS account ID for deployment | - | No | +| `CDK_REGION` | string | AWS region for deployment | - | No | +| `CDK_OU` | string | Organizational Unit for resource tagging | `leanstacks` | No | +| `CDK_OWNER` | string | Owner tag for resource tracking | `unknown` | No | +| `CDK_CORS_ALLOW_ORIGIN` | string | CORS allow origin for API Gateway and Lambda functions | `*` | No | +| `CDK_APP_LOGGING_ENABLED` | boolean | Enable logging in Lambda functions | `true` | No | +| `CDK_APP_LOGGING_LEVEL` | enum | Logging level: `debug`, `info`, `warn`, `error` | `info` | No | +| `CDK_APP_LOGGING_FORMAT` | enum | Logging format: `text`, `json` | `json` | No | + +### Usage + +Infrastructure configuration is managed through the `getConfig()` function in `infrastructure/utils/config.ts`: + +```typescript +import { getConfig } from './utils/config'; + +const config = getConfig(); +console.log(`Environment: ${config.CDK_ENV}`); +console.log(`App name: ${config.CDK_APP_NAME}`); +``` + +### Configuration Files + +Infrastructure configuration can be provided through: + +1. **Environment variables** - Set directly in your shell or CI/CD pipeline +2. **.env file** - Create a `.env` file in the `infrastructure/` directory for local development + +Example `.env` file: + +```bash +CDK_ENV=dev +CDK_ACCOUNT=123456789012 +CDK_REGION=us-east-1 +CDK_OU=leanstacks +CDK_OWNER=platform-team +CDK_CORS_ALLOW_ORIGIN=https://example.com +CDK_APP_LOGGING_ENABLED=true +CDK_APP_LOGGING_LEVEL=debug +CDK_APP_LOGGING_FORMAT=json +``` + +**Important:** Never commit `.env` files containing sensitive information to source control. + +### Resource Tagging + +All AWS resources created by the CDK are automatically tagged with the following tags: + +| Tag | Description | Source | +| ------- | ------------------------------ | -------------- | +| `App` | Application name | `CDK_APP_NAME` | +| `Env` | Environment (dev, qat, prd) | `CDK_ENV` | +| `OU` | Organizational Unit | `CDK_OU` | +| `Owner` | Team or individual responsible | `CDK_OWNER` | + +These tags are used for cost allocation, resource management, and identifying resources in AWS. + +### Environment-Specific Settings + +Different environments may require different configuration values. Consider these recommendations: + +#### Development (dev) + +- `CDK_APP_LOGGING_LEVEL=debug` - Verbose logging for development +- `CDK_CORS_ALLOW_ORIGIN=*` - Allow all origins for easier testing +- Use minimal resource sizes to reduce costs + +#### QA Testing (qat) + +- `CDK_APP_LOGGING_LEVEL=info` - Balanced logging +- `CDK_CORS_ALLOW_ORIGIN=https://qat.example.com` - Restrict to QA environment +- Use production-like resource sizes + +#### Production (prd) + +- `CDK_APP_LOGGING_LEVEL=warn` or `error` - Minimal logging for performance +- `CDK_CORS_ALLOW_ORIGIN=https://example.com` - Restrict to production domain +- Use appropriate resource sizes and retention policies +- Enable additional monitoring and alerting + +--- + +## Configuration Flow + +The configuration flow from infrastructure to application is as follows: + +1. **Infrastructure Deployment** + - CDK reads `CDK_*` environment variables + - CDK provisions AWS resources with configured values + - Lambda functions receive environment variables from CDK configuration + +2. **Application Runtime** + - Lambda functions read their environment variables + - Application config validates variables using Zod schemas + - Application uses validated configuration for runtime behavior + +### Mapping: Infrastructure → Application + +Infrastructure configuration variables are passed to Lambda functions with modified names: + +| Infrastructure Variable | Lambda Environment Variable | +| ------------------------- | --------------------------- | +| `CDK_APP_LOGGING_ENABLED` | `LOGGING_ENABLED` | +| `CDK_APP_LOGGING_LEVEL` | `LOGGING_LEVEL` | +| `CDK_APP_LOGGING_FORMAT` | `LOGGING_FORMAT` | +| `CDK_CORS_ALLOW_ORIGIN` | `CORS_ALLOW_ORIGIN` | +| (DynamoDB table name) | `TASKS_TABLE` | +| (AWS Region) | `AWS_REGION` | + +--- + +## Troubleshooting + +### Configuration Validation Errors + +If you encounter configuration validation errors: + +1. **Check required variables** - Ensure all required variables are set +2. **Verify enum values** - Check that enum values match allowed options +3. **Review error messages** - Validation errors include the field name and specific issue + +Example error: + +``` +Configuration validation failed: +LOGGING_LEVEL: Invalid enum value. Expected 'debug' | 'info' | 'warn' | 'error', received 'verbose' +``` + +### Environment Variable Precedence + +Environment variables can be set in multiple places. The precedence order is: + +1. System environment variables (highest priority) +2. `.env` file (infrastructure only) +3. Default values in schema (lowest priority) + +--- + +## Best Practices + +1. **Never commit secrets** - Use AWS Secrets Manager or Parameter Store for sensitive data +2. **Use .env for local development** - Keep local configuration separate from code +3. **Document custom variables** - Update this guide when adding new configuration options +4. **Validate early** - Use Zod schemas to catch configuration errors at startup +5. **Use environment-specific values** - Configure resources appropriately for each environment +6. **Tag all resources** - Ensure proper tagging for cost allocation and management diff --git a/docs/InfrastructureGuide.md b/docs/InfrastructureGuide.md index 97afe4d..42b0b9d 100644 --- a/docs/InfrastructureGuide.md +++ b/docs/InfrastructureGuide.md @@ -407,8 +407,8 @@ const tableName = process.env.TASK_TABLE_NAME; - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) - - `LOG_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - - `LOG_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) + - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) + - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) **CloudWatch Logs**: @@ -441,8 +441,8 @@ const tableName = process.env.TASK_TABLE_NAME; - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) - - `LOG_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - - `LOG_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) + - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) + - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) **CloudWatch Logs**: @@ -475,8 +475,8 @@ const tableName = process.env.TASK_TABLE_NAME; - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) - - `LOG_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - - `LOG_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) + - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) + - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) **CloudWatch Logs**: @@ -509,8 +509,8 @@ const tableName = process.env.TASK_TABLE_NAME; - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) - - `LOG_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - - `LOG_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) + - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) + - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) **CloudWatch Logs**: @@ -543,8 +543,8 @@ const tableName = process.env.TASK_TABLE_NAME; - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) - - `LOG_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - - `LOG_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) + - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) + - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) **CloudWatch Logs**: @@ -650,12 +650,12 @@ The Lambda stack uses environment variables to configure application behavior: - **CDK_APP_LOGGING_LEVEL**: Sets the minimum log level for application logs - Valid values: `debug`, `info` (default), `warn`, `error` - - Passed to Lambda as `LOG_LEVEL` environment variable + - Passed to Lambda as `LOGGING_LEVEL` environment variable - Controls verbosity of application logging - **CDK_APP_LOGGING_FORMAT**: Sets the log output format - Valid values: `text`, `json` (default) - - Passed to Lambda as `LOG_FORMAT` environment variable + - Passed to Lambda as `LOGGING_FORMAT` environment variable - `json`: Structured JSON logs ideal for CloudWatch Logs Insights and log aggregation - `text`: Human-readable text format with stringified context diff --git a/docs/README.md b/docs/README.md index afb7a95..6f0ed78 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,6 +4,16 @@ Welcome to the lambda-starter project documentation. This directory contains com ## Table of Contents +### Configuration + +- **[Configuration Guide](ConfigurationGuide.md)** - Complete guide to application and infrastructure configuration + - Application environment variables and validation + - Infrastructure CDK configuration variables + - Resource tagging standards + - Environment-specific configuration recommendations + - Configuration flow from infrastructure to application + - Troubleshooting and best practices + ### Infrastructure - **[Infrastructure Guide](InfrastructureGuide.md)** - Complete guide to AWS CDK infrastructure implementation @@ -23,9 +33,9 @@ Welcome to the lambda-starter project documentation. This directory contains com New to the project? Start here: 1. Review the [main README](../README.md) for project overview -2. Read the [Infrastructure Guide](InfrastructureGuide.md) to understand the AWS CDK setup -3. Follow the [Getting Started](InfrastructureGuide.md#getting-started) section to deploy infrastructure -4. Check the [Configuration](InfrastructureGuide.md#configuration) section for environment setup +2. Read the [Configuration Guide](ConfigurationGuide.md) to understand environment variables +3. Read the [Infrastructure Guide](InfrastructureGuide.md) to understand the AWS CDK setup +4. Follow the [Getting Started](InfrastructureGuide.md#getting-started) section to deploy infrastructure --- @@ -53,9 +63,10 @@ When adding new documentation: ## Document Index -| Document | Description | Last Updated | -| ---------------------------------------------- | ------------------------------------ | ------------ | -| [Infrastructure Guide](InfrastructureGuide.md) | AWS CDK infrastructure documentation | 2025-11-30 | +| Document | Description | Last Updated | +| ---------------------------------------------- | -------------------------------------------- | ------------ | +| [Configuration Guide](ConfigurationGuide.md) | Application and infrastructure configuration | 2025-12-02 | +| [Infrastructure Guide](InfrastructureGuide.md) | AWS CDK infrastructure documentation | 2025-11-30 | --- From b142a6454879fc3c6fba9f77a92f51490625e22f Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Tue, 2 Dec 2025 13:55:42 -0500 Subject: [PATCH 3/3] Standardize logging configuration variable names across documentation and test files --- docs/InfrastructureGuide.md | 48 +++++++++++++++---------------- src/handlers/create-task.test.ts | 2 +- src/handlers/delete-task.test.ts | 2 +- src/handlers/get-task.test.ts | 2 +- src/handlers/list-tasks.test.ts | 2 +- src/handlers/update-task.test.ts | 2 +- src/utils/dynamodb-client.test.ts | 4 +-- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/InfrastructureGuide.md b/docs/InfrastructureGuide.md index 42b0b9d..204a2d8 100644 --- a/docs/InfrastructureGuide.md +++ b/docs/InfrastructureGuide.md @@ -307,17 +307,17 @@ The lambda-starter infrastructure uses a modular, environment-aware design: All configuration is managed through environment variables prefixed with `CDK_`: -| Variable | Required | Description | Default | -| ------------------------ | -------- | -------------------------- | ---------------- | -| `CDK_APP_NAME` | No | Application name | `lambda-starter` | -| `CDK_ENV` | Yes | Environment | - | -| `CDK_ACCOUNT` | No | AWS account ID override | From AWS CLI | -| `CDK_REGION` | No | AWS region override | From AWS CLI | -| `CDK_OU` | No | Organizational unit | `leanstacks` | -| `CDK_OWNER` | No | Resource owner | `unknown` | -| `CDK_APP_ENABLE_LOGGING` | No | Enable application logging | `true` | -| `CDK_APP_LOGGING_LEVEL` | No | Application logging level | `info` | -| `CDK_APP_LOGGING_FORMAT` | No | Application logging format | `json` | +| Variable | Required | Description | Default | +| ------------------------- | -------- | -------------------------- | ---------------- | +| `CDK_APP_NAME` | No | Application name | `lambda-starter` | +| `CDK_ENV` | Yes | Environment | - | +| `CDK_ACCOUNT` | No | AWS account ID override | From AWS CLI | +| `CDK_REGION` | No | AWS region override | From AWS CLI | +| `CDK_OU` | No | Organizational unit | `leanstacks` | +| `CDK_OWNER` | No | Resource owner | `unknown` | +| `CDK_APP_LOGGING_ENABLED` | No | Enable application logging | `true` | +| `CDK_APP_LOGGING_LEVEL` | No | Application logging level | `info` | +| `CDK_APP_LOGGING_FORMAT` | No | Application logging format | `json` | ### Configuration Validation @@ -406,7 +406,7 @@ const tableName = process.env.TASK_TABLE_NAME; - **Bundling**: Automatic TypeScript compilation with esbuild - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) + - `LOGGING_ENABLED`: Logging enabled flag (from `CDK_APP_LOGGING_ENABLED`) - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) @@ -440,7 +440,7 @@ const tableName = process.env.TASK_TABLE_NAME; - **Bundling**: Automatic TypeScript compilation with esbuild - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) + - `LOGGING_ENABLED`: Logging enabled flag (from `CDK_APP_LOGGING_ENABLED`) - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) @@ -474,7 +474,7 @@ const tableName = process.env.TASK_TABLE_NAME; - **Bundling**: Automatic TypeScript compilation with esbuild - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) + - `LOGGING_ENABLED`: Logging enabled flag (from `CDK_APP_LOGGING_ENABLED`) - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) @@ -508,7 +508,7 @@ const tableName = process.env.TASK_TABLE_NAME; - **Bundling**: Automatic TypeScript compilation with esbuild - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) + - `LOGGING_ENABLED`: Logging enabled flag (from `CDK_APP_LOGGING_ENABLED`) - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) @@ -542,7 +542,7 @@ const tableName = process.env.TASK_TABLE_NAME; - **Bundling**: Automatic TypeScript compilation with esbuild - **Environment Variables**: - `TASKS_TABLE`: DynamoDB table name - - `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`) + - `LOGGING_ENABLED`: Logging enabled flag (from `CDK_APP_LOGGING_ENABLED`) - `LOGGING_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`) - `LOGGING_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`) @@ -643,9 +643,9 @@ const tableName = process.env.TASK_TABLE_NAME; The Lambda stack uses environment variables to configure application behavior: -- **CDK_APP_ENABLE_LOGGING**: Controls whether logging is enabled in Lambda functions +- **CDK_APP_LOGGING_ENABLED**: Controls whether logging is enabled in Lambda functions - Set to `true` (default) or `false` - - Passed to Lambda as `ENABLE_LOGGING` environment variable + - Passed to Lambda as `LOGGING_ENABLED` environment variable - When disabled, Lambda functions produce minimal log output - **CDK_APP_LOGGING_LEVEL**: Sets the minimum log level for application logs @@ -663,17 +663,17 @@ The Lambda stack uses environment variables to configure application behavior: ```bash # Development with debug logging in text format -CDK_APP_ENABLE_LOGGING=true +CDK_APP_LOGGING_ENABLED=true CDK_APP_LOGGING_LEVEL=debug CDK_APP_LOGGING_FORMAT=text # Production with info logging in JSON format -CDK_APP_ENABLE_LOGGING=true +CDK_APP_LOGGING_ENABLED=true CDK_APP_LOGGING_LEVEL=info CDK_APP_LOGGING_FORMAT=json # Disable logging (not recommended) -CDK_APP_ENABLE_LOGGING=false +CDK_APP_LOGGING_ENABLED=false ``` ### Resource Tagging @@ -819,7 +819,7 @@ npm run cdk watch # 1. Configure for dev cat > .env << EOF CDK_ENV=dev -CDK_APP_ENABLE_LOGGING=true +CDK_APP_LOGGING_ENABLED=true CDK_APP_LOGGING_LEVEL=debug EOF @@ -841,7 +841,7 @@ CDK_ACCOUNT=123456789012 CDK_REGION=us-east-1 CDK_OU=leanstacks CDK_OWNER=platform-team -CDK_APP_ENABLE_LOGGING=true +CDK_APP_LOGGING_ENABLED=true CDK_APP_LOGGING_LEVEL=info EOF @@ -859,7 +859,7 @@ npm run deploy export CDK_ENV=prd export CDK_ACCOUNT=123456789012 export CDK_REGION=us-east-1 -export CDK_APP_ENABLE_LOGGING=true +export CDK_APP_LOGGING_ENABLED=true export CDK_APP_LOGGING_LEVEL=info # Deploy without prompts diff --git a/src/handlers/create-task.test.ts b/src/handlers/create-task.test.ts index 1cdaaa9..d588ea8 100644 --- a/src/handlers/create-task.test.ts +++ b/src/handlers/create-task.test.ts @@ -12,7 +12,7 @@ jest.mock('../utils/config', () => ({ config: { TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', - ENABLE_LOGGING: true, + LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, diff --git a/src/handlers/delete-task.test.ts b/src/handlers/delete-task.test.ts index 695db1e..cdd7f5b 100644 --- a/src/handlers/delete-task.test.ts +++ b/src/handlers/delete-task.test.ts @@ -10,7 +10,7 @@ jest.mock('../utils/config', () => ({ config: { TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', - ENABLE_LOGGING: true, + LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, diff --git a/src/handlers/get-task.test.ts b/src/handlers/get-task.test.ts index cf2966f..f36eb52 100644 --- a/src/handlers/get-task.test.ts +++ b/src/handlers/get-task.test.ts @@ -12,7 +12,7 @@ jest.mock('../utils/config', () => ({ config: { TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', - ENABLE_LOGGING: true, + LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, diff --git a/src/handlers/list-tasks.test.ts b/src/handlers/list-tasks.test.ts index 80b2b22..c458bfb 100644 --- a/src/handlers/list-tasks.test.ts +++ b/src/handlers/list-tasks.test.ts @@ -11,7 +11,7 @@ jest.mock('../utils/config', () => ({ config: { TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', - ENABLE_LOGGING: true, + LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, diff --git a/src/handlers/update-task.test.ts b/src/handlers/update-task.test.ts index 92061f2..ef9cfb5 100644 --- a/src/handlers/update-task.test.ts +++ b/src/handlers/update-task.test.ts @@ -12,7 +12,7 @@ jest.mock('../utils/config', () => ({ config: { TASKS_TABLE: 'test-tasks-table', AWS_REGION: 'us-east-1', - ENABLE_LOGGING: true, + LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, diff --git a/src/utils/dynamodb-client.test.ts b/src/utils/dynamodb-client.test.ts index b9e3f6f..16e7bee 100644 --- a/src/utils/dynamodb-client.test.ts +++ b/src/utils/dynamodb-client.test.ts @@ -12,7 +12,7 @@ describe('dynamodb-client', () => { config: { AWS_REGION: 'us-east-1', TASKS_TABLE: 'test-table', - ENABLE_LOGGING: true, + LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', }, @@ -114,7 +114,7 @@ describe('dynamodb-client', () => { config: { AWS_REGION: 'eu-west-1', TASKS_TABLE: 'test-table', - ENABLE_LOGGING: true, + LOGGING_ENABLED: true, LOGGING_LEVEL: 'info', CORS_ALLOW_ORIGIN: '*', },