Skip to content

Commit eea36fc

Browse files
committed
feat: add logging format configuration and integrate pino logger
- Added `CDK_APP_LOGGING_FORMAT` to configuration schema with options for 'text' and 'json'. - Integrated pino as the logging library for structured logging. - Updated logger utility to support both text and JSON formats based on configuration. - Modified logging statements across the application to include contextual information. - Enhanced tests to validate logging behavior for both formats.
1 parent df3db62 commit eea36fc

21 files changed

Lines changed: 503 additions & 107 deletions

docs/InfrastructureGuide.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ All configuration is managed through environment variables prefixed with `CDK_`:
324324
| `CDK_OWNER` | No | Resource owner | `unknown` |
325325
| `CDK_APP_ENABLE_LOGGING` | No | Enable application logging | `true` |
326326
| `CDK_APP_LOGGING_LEVEL` | No | Application logging level | `info` |
327+
| `CDK_APP_LOGGING_FORMAT` | No | Application logging format | `json` |
327328

328329
### Configuration Validation
329330

@@ -342,6 +343,7 @@ const configSchema = z.object({
342343
.transform((val) => val === 'true')
343344
.default('true'),
344345
CDK_APP_LOGGING_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
346+
CDK_APP_LOGGING_FORMAT: z.enum(['text', 'json']).default('json'),
345347
});
346348
```
347349

@@ -432,6 +434,7 @@ const tableName = process.env.TASK_TABLE_NAME;
432434
- `TASKS_TABLE`: DynamoDB table name
433435
- `ENABLE_LOGGING`: Logging enabled flag (from `CDK_APP_ENABLE_LOGGING`)
434436
- `LOG_LEVEL`: Minimum log level (from `CDK_APP_LOGGING_LEVEL`)
437+
- `LOG_FORMAT`: Log output format (from `CDK_APP_LOGGING_FORMAT`)
435438

436439
**CloudWatch Logs**:
437440

@@ -486,16 +489,24 @@ The Lambda stack uses environment variables to configure application behavior:
486489
- Passed to Lambda as `LOG_LEVEL` environment variable
487490
- Controls verbosity of application logging
488491

492+
- **CDK_APP_LOGGING_FORMAT**: Sets the log output format
493+
- Valid values: `text`, `json` (default)
494+
- Passed to Lambda as `LOG_FORMAT` environment variable
495+
- `json`: Structured JSON logs ideal for CloudWatch Logs Insights and log aggregation
496+
- `text`: Human-readable text format with stringified context
497+
489498
**Example Usage**:
490499

491500
```bash
492-
# Development with debug logging
501+
# Development with debug logging in text format
493502
CDK_APP_ENABLE_LOGGING=true
494503
CDK_APP_LOGGING_LEVEL=debug
504+
CDK_APP_LOGGING_FORMAT=text
495505

496-
# Production with info logging
506+
# Production with info logging in JSON format
497507
CDK_APP_ENABLE_LOGGING=true
498508
CDK_APP_LOGGING_LEVEL=info
509+
CDK_APP_LOGGING_FORMAT=json
499510

500511
# Disable logging (not recommended)
501512
CDK_APP_ENABLE_LOGGING=false

infrastructure/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ CDK_ENV=dev
2525
# CDK_APP_ENABLE_LOGGING=true
2626
## Application logging level: debug, info, warn, error (default: info)
2727
# CDK_APP_LOGGING_LEVEL=info
28+
## Application logging format: text, json (default: json)
29+
# CDK_APP_LOGGING_FORMAT=json

infrastructure/README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ All CDK configuration is managed through environment variables prefixed with `CD
180180
| `CDK_OWNER` | No | Team or owner name | Any string | `unknown` |
181181
| `CDK_APP_ENABLE_LOGGING` | No | Enable application logging | `true`, `false` | `true` |
182182
| `CDK_APP_LOGGING_LEVEL` | No | Application logging level | `debug`, `info`, `warn`, `error` | `info` |
183+
| `CDK_APP_LOGGING_FORMAT` | No | Application logging format | `text`, `json` | `json` |
183184

184185
### AWS Account and Region Resolution
185186

@@ -294,12 +295,18 @@ npm run cdk destroy --all
294295

295296
**Logging Configuration:**
296297

297-
The Lambda stack uses the `CDK_APP_ENABLE_LOGGING` and `CDK_APP_LOGGING_LEVEL` environment variables to configure application logging:
298+
The Lambda stack uses the `CDK_APP_ENABLE_LOGGING`, `CDK_APP_LOGGING_LEVEL`, and `CDK_APP_LOGGING_FORMAT` environment variables to configure application logging:
298299

299300
- **CDK_APP_ENABLE_LOGGING**: Controls whether logging is enabled in the Lambda functions
300301
- **CDK_APP_LOGGING_LEVEL**: Sets the minimum log level (`debug`, `info`, `warn`, `error`)
302+
- **CDK_APP_LOGGING_FORMAT**: Sets the log output format (`text` or `json`)
301303

302-
These values are passed to the Lambda functions as environment variables (`ENABLE_LOGGING` and `LOG_LEVEL`) and control both CloudWatch log output and application-level logging behavior.
304+
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.
305+
306+
**Log Format Options:**
307+
308+
- **json** (default): Structured JSON logs ideal for CloudWatch Logs Insights and log aggregation tools. Each log entry is a JSON object with fields like `timestamp`, `level`, `message`, and any additional context fields.
309+
- **text**: Human-readable text format with timestamp, level, and message. Context is stringified and appended to the message.
303310

304311
## Resource Tagging
305312

infrastructure/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ new LambdaStack(app, `${config.CDK_APP_NAME}-lambda-stack-${config.CDK_ENV}`, {
3636
taskTable: dataStack.taskTable,
3737
enableLogging: config.CDK_APP_ENABLE_LOGGING,
3838
loggingLevel: config.CDK_APP_LOGGING_LEVEL,
39+
loggingFormat: config.CDK_APP_LOGGING_FORMAT,
3940
...(environmentConfig && { env: environmentConfig }),
4041
});
4142

infrastructure/stacks/data-stack.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ describe('DataStack', () => {
2121
BillingMode: 'PAY_PER_REQUEST',
2222
KeySchema: [
2323
{
24-
AttributeName: 'id',
24+
AttributeName: 'pk',
2525
KeyType: 'HASH',
2626
},
2727
],
2828
AttributeDefinitions: [
2929
{
30-
AttributeName: 'id',
30+
AttributeName: 'pk',
3131
AttributeType: 'S',
3232
},
3333
],

infrastructure/stacks/lambda-stack.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ describe('LambdaStack', () => {
4242
taskTable: testMockTable,
4343
enableLogging: true,
4444
loggingLevel: 'debug',
45+
loggingFormat: 'json',
4546
});
4647
template = Template.fromStack(stack);
4748
});
@@ -63,6 +64,7 @@ describe('LambdaStack', () => {
6364
TASKS_TABLE: Match.anyValue(),
6465
ENABLE_LOGGING: 'true',
6566
LOG_LEVEL: 'debug',
67+
LOG_FORMAT: 'json',
6668
},
6769
},
6870
});
@@ -179,6 +181,7 @@ describe('LambdaStack', () => {
179181
taskTable: testMockTable,
180182
enableLogging: true,
181183
loggingLevel: 'info',
184+
loggingFormat: 'json',
182185
});
183186
template = Template.fromStack(stack);
184187
});
@@ -233,6 +236,7 @@ describe('LambdaStack', () => {
233236
taskTable: testMockTable,
234237
enableLogging: true,
235238
loggingLevel: 'debug',
239+
loggingFormat: 'json',
236240
});
237241
template = Template.fromStack(stack);
238242
});

infrastructure/stacks/lambda-stack.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ export interface LambdaStackProps extends cdk.StackProps {
3535
* Application logging level.
3636
*/
3737
loggingLevel: string;
38+
39+
/**
40+
* Application logging format (text or json).
41+
*/
42+
loggingFormat: string;
3843
}
3944

4045
/**
@@ -64,6 +69,7 @@ export class LambdaStack extends cdk.Stack {
6469
TASKS_TABLE: props.taskTable.tableName,
6570
ENABLE_LOGGING: props.enableLogging.toString(),
6671
LOG_LEVEL: props.loggingLevel,
72+
LOG_FORMAT: props.loggingFormat,
6773
},
6874
timeout: cdk.Duration.seconds(10),
6975
memorySize: 256,

infrastructure/utils/config.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ describe('config', () => {
3232
process.env.CDK_OWNER = 'platform-team';
3333
process.env.CDK_APP_ENABLE_LOGGING = 'false';
3434
process.env.CDK_APP_LOGGING_LEVEL = 'warn';
35+
process.env.CDK_APP_LOGGING_FORMAT = 'text';
3536

3637
const config = getConfig();
3738

@@ -44,6 +45,7 @@ describe('config', () => {
4445
CDK_OWNER: 'platform-team',
4546
CDK_APP_ENABLE_LOGGING: false,
4647
CDK_APP_LOGGING_LEVEL: 'warn',
48+
CDK_APP_LOGGING_FORMAT: 'text',
4749
});
4850
});
4951

@@ -58,6 +60,26 @@ describe('config', () => {
5860

5961
expect(() => getConfig()).toThrow('CDK_ENV must be one of: dev, qat, prd');
6062
});
63+
64+
it('should validate CDK_APP_LOGGING_FORMAT enum values', () => {
65+
process.env.CDK_ENV = 'dev';
66+
67+
// Valid values
68+
const validFormats = ['text', 'json'];
69+
validFormats.forEach((format) => {
70+
jest.resetModules();
71+
process.env.CDK_APP_LOGGING_FORMAT = format;
72+
const config = getConfig();
73+
expect(config.CDK_APP_LOGGING_FORMAT).toBe(format);
74+
});
75+
});
76+
77+
it('should throw error when CDK_APP_LOGGING_FORMAT is invalid', () => {
78+
process.env.CDK_ENV = 'dev';
79+
process.env.CDK_APP_LOGGING_FORMAT = 'xml';
80+
81+
expect(() => getConfig()).toThrow('CDK configuration validation failed');
82+
});
6183
});
6284

6385
describe('getTags', () => {
@@ -69,6 +91,7 @@ describe('config', () => {
6991
CDK_OWNER: 'platform-team',
7092
CDK_APP_ENABLE_LOGGING: true,
7193
CDK_APP_LOGGING_LEVEL: 'info',
94+
CDK_APP_LOGGING_FORMAT: 'json',
7295
};
7396

7497
const tags = getTags(config);
@@ -87,6 +110,7 @@ describe('config', () => {
87110
CDK_ENV: 'qat',
88111
CDK_APP_ENABLE_LOGGING: true,
89112
CDK_APP_LOGGING_LEVEL: 'info',
113+
CDK_APP_LOGGING_FORMAT: 'json',
90114
};
91115

92116
const tags = getTags(config);
@@ -105,6 +129,7 @@ describe('config', () => {
105129
CDK_ENV: 'dev',
106130
CDK_APP_ENABLE_LOGGING: true,
107131
CDK_APP_LOGGING_LEVEL: 'info',
132+
CDK_APP_LOGGING_FORMAT: 'json',
108133
};
109134

110135
const tags = getTags(config);
@@ -130,6 +155,7 @@ describe('config', () => {
130155
CDK_REGION: 'us-west-2',
131156
CDK_APP_ENABLE_LOGGING: true,
132157
CDK_APP_LOGGING_LEVEL: 'info',
158+
CDK_APP_LOGGING_FORMAT: 'json',
133159
};
134160

135161
const envConfig = getEnvironmentConfig(config);
@@ -151,6 +177,7 @@ describe('config', () => {
151177
CDK_ENV: 'dev',
152178
CDK_APP_ENABLE_LOGGING: true,
153179
CDK_APP_LOGGING_LEVEL: 'info',
180+
CDK_APP_LOGGING_FORMAT: 'json',
154181
};
155182

156183
const envConfig = getEnvironmentConfig(config);
@@ -172,6 +199,7 @@ describe('config', () => {
172199
CDK_REGION: 'ap-southeast-2',
173200
CDK_APP_ENABLE_LOGGING: true,
174201
CDK_APP_LOGGING_LEVEL: 'info',
202+
CDK_APP_LOGGING_FORMAT: 'json',
175203
};
176204

177205
const envConfig = getEnvironmentConfig(config);
@@ -193,6 +221,7 @@ describe('config', () => {
193221
CDK_ENV: 'dev',
194222
CDK_APP_ENABLE_LOGGING: true,
195223
CDK_APP_LOGGING_LEVEL: 'info',
224+
CDK_APP_LOGGING_FORMAT: 'json',
196225
};
197226

198227
const envConfig = getEnvironmentConfig(config);
@@ -209,6 +238,7 @@ describe('config', () => {
209238
CDK_ENV: 'dev',
210239
CDK_APP_ENABLE_LOGGING: true,
211240
CDK_APP_LOGGING_LEVEL: 'info',
241+
CDK_APP_LOGGING_FORMAT: 'json',
212242
};
213243

214244
const envConfig = getEnvironmentConfig(config);
@@ -225,6 +255,7 @@ describe('config', () => {
225255
CDK_ENV: 'dev',
226256
CDK_APP_ENABLE_LOGGING: true,
227257
CDK_APP_LOGGING_LEVEL: 'info',
258+
CDK_APP_LOGGING_FORMAT: 'json',
228259
};
229260

230261
const envConfig = getEnvironmentConfig(config);

infrastructure/utils/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const configSchema = z.object({
1616
.default('true')
1717
.transform((val) => val === 'true'),
1818
CDK_APP_LOGGING_LEVEL: z.enum(['debug', 'info', 'warn', 'error'] as const).default('info'),
19+
CDK_APP_LOGGING_FORMAT: z.enum(['text', 'json'] as const).default('json'),
1920
});
2021

2122
/**

0 commit comments

Comments
 (0)