@leanstacks/lambda-utils 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +12 -0
- package/.github/copilot-instructions.md +101 -0
- package/.nvmrc +1 -0
- package/.prettierrc +8 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +75 -0
- package/dist/logging/logger.d.ts +38 -0
- package/docs/README.md +48 -0
- package/eslint.config.mjs +44 -0
- package/jest.config.ts +15 -0
- package/jest.setup.ts +9 -0
- package/package.json +50 -0
- package/rollup.config.js +18 -0
- package/src/index.ts +1 -0
- package/src/logging/logger.ts +95 -0
- package/tsconfig.json +22 -0
package/.editorconfig
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# This file is used to define coding styles and formatting rules for the project.
|
|
2
|
+
# For more information, see https://editorconfig.org/
|
|
3
|
+
root=true
|
|
4
|
+
|
|
5
|
+
[*]
|
|
6
|
+
charset=utf-8
|
|
7
|
+
end_of_line=lf
|
|
8
|
+
indent_style=space
|
|
9
|
+
indent_size=2
|
|
10
|
+
insert_final_newline=true
|
|
11
|
+
max_line_length=120
|
|
12
|
+
trim_trailing_whitespace=true
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Lambda Utilities Project Instructions
|
|
2
|
+
|
|
3
|
+
This project contains a set of utilities and helper functions designed to streamline the development of AWS Lambda functions using TypeScript. The utilities cover common tasks such as input validation, response formatting, error handling, and logging. The project is packaged and published as an npm package for easy integration into other Lambda projects.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Technology Stack
|
|
8
|
+
|
|
9
|
+
Each pattern project uses the following technology stack:
|
|
10
|
+
|
|
11
|
+
- **Language:** TypeScript
|
|
12
|
+
- **Platform:** AWS Lambda
|
|
13
|
+
- **Runtime:** Node.js 24.x
|
|
14
|
+
- **AWS SDK:** v3 (modular packages)
|
|
15
|
+
- **Testing:** Jest
|
|
16
|
+
- **Linting/Formatting:** ESLint + Prettier
|
|
17
|
+
- **Validation:** Zod
|
|
18
|
+
- **Logging:** Pino + Pino-Lambda
|
|
19
|
+
- **Package Manager:** npm
|
|
20
|
+
- **Package Bundler:** rollup
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Pattern Project Structure
|
|
25
|
+
|
|
26
|
+
Each pattern project follows a consistent directory and file structure to promote maintainability and scalability. Below is an example structure:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
/docs # Project documentation
|
|
30
|
+
README.md # Documentation table of contents
|
|
31
|
+
|
|
32
|
+
/src
|
|
33
|
+
/logging
|
|
34
|
+
logger.ts # Logger utility using Pino
|
|
35
|
+
logger.test.ts # Unit tests for logger
|
|
36
|
+
/clients
|
|
37
|
+
dynamodb-client.ts # AWS SDK client for DynamoDB
|
|
38
|
+
dynamodb-client.test.ts # Unit tests for DynamoDB client
|
|
39
|
+
lambda-client.ts # AWS SDK client for Lambda
|
|
40
|
+
lambda-client.test.ts # Unit tests for Lambda client
|
|
41
|
+
/validation
|
|
42
|
+
config.ts # Configuration validation with Zod
|
|
43
|
+
config.test.ts # Unit tests for config
|
|
44
|
+
validator.ts # Generic validator helpers
|
|
45
|
+
validator.test.ts # Unit tests for validator
|
|
46
|
+
/responses
|
|
47
|
+
apigateway-response.ts # Standard API response helpers
|
|
48
|
+
apigateway-response.test.ts # Unit tests for API response helpers
|
|
49
|
+
.editorconfig # Editor config
|
|
50
|
+
.gitignore # Git ignore rules
|
|
51
|
+
.nvmrc # Node version manager config
|
|
52
|
+
.prettierrc # Prettier config
|
|
53
|
+
eslint.config.mjs # ESLint config
|
|
54
|
+
jest.config.ts # App Jest config
|
|
55
|
+
jest.setup.ts # App Jest setup
|
|
56
|
+
package.json # App NPM package config
|
|
57
|
+
README.md # Project README
|
|
58
|
+
tsconfig.json # Project TypeScript config
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Source Code Guidelines
|
|
64
|
+
|
|
65
|
+
Each pattern project follows best practices for source code organization, naming conventions, and coding standards. Below are the key guidelines:
|
|
66
|
+
|
|
67
|
+
- Use **TypeScript** for all source and infrastructure code.
|
|
68
|
+
- Use arrow functions for defining functions.
|
|
69
|
+
- Use path aliases for cleaner imports (e.g., `@utils`, `@models`).
|
|
70
|
+
- Organize import statements: external packages first, then internal modules.
|
|
71
|
+
- Use async/await for asynchronous operations.
|
|
72
|
+
- Document functions and modules with JSDoc comments.
|
|
73
|
+
|
|
74
|
+
### Source Code Commands & Scripts
|
|
75
|
+
|
|
76
|
+
- Use `npm run build` to compile TypeScript.
|
|
77
|
+
- Use `npm run test` to run tests.
|
|
78
|
+
- Use `npm run test:coverage` to run tests with coverage report.
|
|
79
|
+
- Use `npm run lint` to run ESLint.
|
|
80
|
+
- Use `npm run lint:fix` to fix ESLint issues.
|
|
81
|
+
- Use `npm run format` to run Prettier to format code.
|
|
82
|
+
- Use `npm run format:check` to check code formatting with Prettier.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Unit Testing Guidelines
|
|
87
|
+
|
|
88
|
+
Each pattern project includes comprehensive unit tests for both application and infrastructure code. Below are the key guidelines for writing unit tests:
|
|
89
|
+
|
|
90
|
+
- Use the **Jest** testing framework.
|
|
91
|
+
- Place test files next to the source file, with `.test.ts` suffix.
|
|
92
|
+
- Use `describe` and `it` blocks for organization.
|
|
93
|
+
- Use `beforeEach` for setup and `afterEach` for cleanup.
|
|
94
|
+
- Use `expect` assertions for results.
|
|
95
|
+
- Mock dependencies to isolate the component under test.
|
|
96
|
+
- Mock external calls (e.g., AWS SDK, databases).
|
|
97
|
+
- Structure your tests using the Arrange-Act-Assert pattern:
|
|
98
|
+
- **Arrange:** Set up the test environment, including any necessary mocks and test data.
|
|
99
|
+
- **Act:** Execute the function or service being tested.
|
|
100
|
+
- **Assert:** Verify that the results are as expected.
|
|
101
|
+
- Add comments to separate these sections for clarity.
|
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
24.11.1
|
package/.prettierrc
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LeanStacks
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { initializeLogger, logger, LoggerConfig } from './logging/logger';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import { StructuredLogFormatter, pinoLambdaDestination, CloudwatchLogFormatter } from 'pino-lambda';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Module-level state to store logger configuration
|
|
6
|
+
*/
|
|
7
|
+
let _loggerConfig = {
|
|
8
|
+
enabled: true,
|
|
9
|
+
level: 'info',
|
|
10
|
+
format: 'json',
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Module-level cache for the logger instance
|
|
14
|
+
*/
|
|
15
|
+
let _loggerInstance = null;
|
|
16
|
+
/**
|
|
17
|
+
* Create and return the Pino Lambda logger instance
|
|
18
|
+
* Uses the configuration set by initializeLogger
|
|
19
|
+
* Logger instance is cached after first creation
|
|
20
|
+
*/
|
|
21
|
+
const _createLogger = () => {
|
|
22
|
+
const formatter = _loggerConfig.format === 'json' ? new StructuredLogFormatter() : new CloudwatchLogFormatter();
|
|
23
|
+
const lambdaDestination = pinoLambdaDestination({
|
|
24
|
+
formatter,
|
|
25
|
+
});
|
|
26
|
+
return pino({
|
|
27
|
+
enabled: _loggerConfig.enabled,
|
|
28
|
+
level: _loggerConfig.level,
|
|
29
|
+
}, lambdaDestination);
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Get the cached logger instance, creating it if necessary
|
|
33
|
+
*/
|
|
34
|
+
const _getLogger = () => {
|
|
35
|
+
if (_loggerInstance === null) {
|
|
36
|
+
_loggerInstance = _createLogger();
|
|
37
|
+
}
|
|
38
|
+
return _loggerInstance;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Initialize the logger with configuration
|
|
42
|
+
* Should be called once at Lambda handler entry point
|
|
43
|
+
* Invalidates the cached logger instance so a new one is created with the updated config
|
|
44
|
+
*
|
|
45
|
+
* @param config Logger configuration options
|
|
46
|
+
* @returns void
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* import { initializeLogger } from '@utils/logging/logger';
|
|
51
|
+
*
|
|
52
|
+
* initializeLogger({
|
|
53
|
+
* enabled: true,
|
|
54
|
+
* level: 'debug',
|
|
55
|
+
* format: 'json',
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
const initializeLogger = (config) => {
|
|
60
|
+
_loggerConfig = {
|
|
61
|
+
enabled: config.enabled ?? true,
|
|
62
|
+
level: config.level ?? 'info',
|
|
63
|
+
format: config.format ?? 'json',
|
|
64
|
+
};
|
|
65
|
+
// Invalidate the cached logger instance so a new one is created with updated config
|
|
66
|
+
_loggerInstance = null;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Pino logger instance
|
|
70
|
+
* Configuration is supplied via initializeLogger() and persists across imports
|
|
71
|
+
* Logger instance is cached after first creation for reuse
|
|
72
|
+
*/
|
|
73
|
+
const logger = _getLogger();
|
|
74
|
+
|
|
75
|
+
export { initializeLogger, logger };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration options for the Pino Lambda logger
|
|
4
|
+
*/
|
|
5
|
+
export interface LoggerConfig {
|
|
6
|
+
/** Whether logging is enabled */
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
/** Minimum log level (e.g., 'debug', 'info', 'warn', 'error') */
|
|
9
|
+
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
10
|
+
/** Output format: 'json' for StructuredLogFormatter, 'text' for CloudwatchLogFormatter */
|
|
11
|
+
format?: 'json' | 'text';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Initialize the logger with configuration
|
|
15
|
+
* Should be called once at Lambda handler entry point
|
|
16
|
+
* Invalidates the cached logger instance so a new one is created with the updated config
|
|
17
|
+
*
|
|
18
|
+
* @param config Logger configuration options
|
|
19
|
+
* @returns void
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { initializeLogger } from '@utils/logging/logger';
|
|
24
|
+
*
|
|
25
|
+
* initializeLogger({
|
|
26
|
+
* enabled: true,
|
|
27
|
+
* level: 'debug',
|
|
28
|
+
* format: 'json',
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare const initializeLogger: (config: LoggerConfig) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Pino logger instance
|
|
35
|
+
* Configuration is supplied via initializeLogger() and persists across imports
|
|
36
|
+
* Logger instance is cached after first creation for reuse
|
|
37
|
+
*/
|
|
38
|
+
export declare const logger: pino.Logger<never, boolean>;
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Lambda Utilities - Documentation
|
|
2
|
+
|
|
3
|
+
Welcome to the Lambda Utilities documentation. This library provides a comprehensive set of utilities and helper functions to streamline the development of AWS Lambda functions using TypeScript.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Getting Started](./GETTING_STARTED.md)
|
|
8
|
+
- [Logging](./LOGGING.md)
|
|
9
|
+
- [API Gateway Responses](./API_GATEWAY_RESPONSES.md)
|
|
10
|
+
- [Configuration](./CONFIGURATION.md)
|
|
11
|
+
- [Clients](./CLIENTS.md)
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
Install the package:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @leanstacks/lambda-utils
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Use a utility in your Lambda function:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { getLogger } from '@leanstacks/lambda-utils';
|
|
25
|
+
import { success } from '@leanstacks/lambda-utils';
|
|
26
|
+
|
|
27
|
+
const logger = getLogger();
|
|
28
|
+
|
|
29
|
+
export const handler = async (event: any) => {
|
|
30
|
+
logger.info({ message: 'Processing event', event });
|
|
31
|
+
|
|
32
|
+
// Your handler logic here
|
|
33
|
+
|
|
34
|
+
return success({ message: 'Success' });
|
|
35
|
+
};
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- **Logging:** Structured logging with Pino configured for Lambda
|
|
41
|
+
- **API Responses:** Standard response formatting for API Gateway
|
|
42
|
+
- **Configuration:** Environment variable validation with Zod
|
|
43
|
+
- **AWS Clients:** Pre-configured AWS SDK v3 clients
|
|
44
|
+
- **Type Safe:** Full TypeScript support with comprehensive types
|
|
45
|
+
|
|
46
|
+
## Support
|
|
47
|
+
|
|
48
|
+
For issues or questions, please visit the [GitHub repository](https://github.com/leanstacks/lambda-utils).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import tsPlugin from '@typescript-eslint/eslint-plugin';
|
|
3
|
+
import tsParser from '@typescript-eslint/parser';
|
|
4
|
+
|
|
5
|
+
export default [
|
|
6
|
+
{
|
|
7
|
+
ignores: ['dist', 'node_modules'],
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
files: ['src/**/*.ts'],
|
|
11
|
+
languageOptions: {
|
|
12
|
+
parser: tsParser,
|
|
13
|
+
parserOptions: {
|
|
14
|
+
ecmaVersion: 2020,
|
|
15
|
+
sourceType: 'module',
|
|
16
|
+
},
|
|
17
|
+
globals: {
|
|
18
|
+
console: 'readonly',
|
|
19
|
+
process: 'readonly',
|
|
20
|
+
describe: 'readonly',
|
|
21
|
+
it: 'readonly',
|
|
22
|
+
expect: 'readonly',
|
|
23
|
+
beforeEach: 'readonly',
|
|
24
|
+
afterEach: 'readonly',
|
|
25
|
+
jest: 'readonly',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
plugins: {
|
|
29
|
+
'@typescript-eslint': tsPlugin,
|
|
30
|
+
},
|
|
31
|
+
rules: {
|
|
32
|
+
...js.configs.recommended.rules,
|
|
33
|
+
...tsPlugin.configs.recommended.rules,
|
|
34
|
+
'@typescript-eslint/no-unused-vars': [
|
|
35
|
+
'error',
|
|
36
|
+
{
|
|
37
|
+
argsIgnorePattern: '^_',
|
|
38
|
+
varsIgnorePattern: '^_',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
];
|
package/jest.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Config } from 'jest';
|
|
2
|
+
|
|
3
|
+
const config: Config = {
|
|
4
|
+
preset: 'ts-jest',
|
|
5
|
+
testEnvironment: 'node',
|
|
6
|
+
rootDir: 'src',
|
|
7
|
+
testMatch: ['**/*.test.ts'],
|
|
8
|
+
moduleNameMapper: {
|
|
9
|
+
'^@/(.*)$': '<rootDir>/$1',
|
|
10
|
+
},
|
|
11
|
+
collectCoverageFrom: ['**/*.ts', '!**/*.test.ts'],
|
|
12
|
+
coveragePathIgnorePatterns: ['/node_modules/'],
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default config;
|
package/jest.setup.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@leanstacks/lambda-utils",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "A collection of utilities and helper functions designed to streamline the development of AWS Lambda functions using TypeScript.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "rollup -c",
|
|
9
|
+
"build:watch": "rollup -c -w",
|
|
10
|
+
"clean": "rimraf dist",
|
|
11
|
+
"test": "jest",
|
|
12
|
+
"test:watch": "jest --watch",
|
|
13
|
+
"test:coverage": "jest --coverage",
|
|
14
|
+
"lint": "eslint src",
|
|
15
|
+
"lint:fix": "eslint src --fix",
|
|
16
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
17
|
+
"format:check": "prettier --check \"src/**/*.ts\""
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"lambda",
|
|
21
|
+
"aws",
|
|
22
|
+
"utilities",
|
|
23
|
+
"nodejs",
|
|
24
|
+
"typescript"
|
|
25
|
+
],
|
|
26
|
+
"author": "Matthew Warman <leanstacker@gmail.com> (https://leanstacks.com)",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@eslint/js": "9.39.2",
|
|
30
|
+
"@types/aws-lambda": "8.10.159",
|
|
31
|
+
"@types/jest": "30.0.0",
|
|
32
|
+
"@types/node": "25.0.3",
|
|
33
|
+
"@typescript-eslint/eslint-plugin": "8.50.0",
|
|
34
|
+
"@typescript-eslint/parser": "8.50.0",
|
|
35
|
+
"eslint": "9.39.2",
|
|
36
|
+
"jest": "30.2.0",
|
|
37
|
+
"prettier": "3.7.4",
|
|
38
|
+
"rimraf": "6.1.2",
|
|
39
|
+
"rollup": "4.53.5",
|
|
40
|
+
"rollup-plugin-typescript2": "0.36.0",
|
|
41
|
+
"ts-jest": "29.4.6",
|
|
42
|
+
"ts-node": "10.9.2",
|
|
43
|
+
"typescript": "5.9.3"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"pino": "10.1.0",
|
|
47
|
+
"pino-lambda": "4.4.1",
|
|
48
|
+
"zod": "4.2.1"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import typescript from 'rollup-plugin-typescript2';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
input: 'src/index.ts',
|
|
5
|
+
output: [
|
|
6
|
+
{
|
|
7
|
+
file: 'dist/index.js',
|
|
8
|
+
format: 'esm',
|
|
9
|
+
},
|
|
10
|
+
],
|
|
11
|
+
external: ['pino', 'pino-lambda', 'zod', '@aws-sdk/client-dynamodb', '@aws-sdk/client-lambda'],
|
|
12
|
+
plugins: [
|
|
13
|
+
typescript({
|
|
14
|
+
tsconfig: 'tsconfig.json',
|
|
15
|
+
clean: true,
|
|
16
|
+
}),
|
|
17
|
+
],
|
|
18
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { initializeLogger, logger, LoggerConfig } from './logging/logger';
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import { CloudwatchLogFormatter, pinoLambdaDestination, StructuredLogFormatter } from 'pino-lambda';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for the Pino Lambda logger
|
|
6
|
+
*/
|
|
7
|
+
export interface LoggerConfig {
|
|
8
|
+
/** Whether logging is enabled */
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
/** Minimum log level (e.g., 'debug', 'info', 'warn', 'error') */
|
|
11
|
+
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
12
|
+
/** Output format: 'json' for StructuredLogFormatter, 'text' for CloudwatchLogFormatter */
|
|
13
|
+
format?: 'json' | 'text';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Module-level state to store logger configuration
|
|
18
|
+
*/
|
|
19
|
+
let _loggerConfig: LoggerConfig = {
|
|
20
|
+
enabled: true,
|
|
21
|
+
level: 'info',
|
|
22
|
+
format: 'json',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Module-level cache for the logger instance
|
|
27
|
+
*/
|
|
28
|
+
let _loggerInstance: pino.Logger | null = null;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create and return the Pino Lambda logger instance
|
|
32
|
+
* Uses the configuration set by initializeLogger
|
|
33
|
+
* Logger instance is cached after first creation
|
|
34
|
+
*/
|
|
35
|
+
const _createLogger = (): pino.Logger => {
|
|
36
|
+
const formatter = _loggerConfig.format === 'json' ? new StructuredLogFormatter() : new CloudwatchLogFormatter();
|
|
37
|
+
|
|
38
|
+
const lambdaDestination = pinoLambdaDestination({
|
|
39
|
+
formatter,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return pino(
|
|
43
|
+
{
|
|
44
|
+
enabled: _loggerConfig.enabled,
|
|
45
|
+
level: _loggerConfig.level,
|
|
46
|
+
},
|
|
47
|
+
lambdaDestination,
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get the cached logger instance, creating it if necessary
|
|
53
|
+
*/
|
|
54
|
+
const _getLogger = (): pino.Logger => {
|
|
55
|
+
if (_loggerInstance === null) {
|
|
56
|
+
_loggerInstance = _createLogger();
|
|
57
|
+
}
|
|
58
|
+
return _loggerInstance;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Initialize the logger with configuration
|
|
63
|
+
* Should be called once at Lambda handler entry point
|
|
64
|
+
* Invalidates the cached logger instance so a new one is created with the updated config
|
|
65
|
+
*
|
|
66
|
+
* @param config Logger configuration options
|
|
67
|
+
* @returns void
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* import { initializeLogger } from '@utils/logging/logger';
|
|
72
|
+
*
|
|
73
|
+
* initializeLogger({
|
|
74
|
+
* enabled: true,
|
|
75
|
+
* level: 'debug',
|
|
76
|
+
* format: 'json',
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export const initializeLogger = (config: LoggerConfig): void => {
|
|
81
|
+
_loggerConfig = {
|
|
82
|
+
enabled: config.enabled ?? true,
|
|
83
|
+
level: config.level ?? 'info',
|
|
84
|
+
format: config.format ?? 'json',
|
|
85
|
+
};
|
|
86
|
+
// Invalidate the cached logger instance so a new one is created with updated config
|
|
87
|
+
_loggerInstance = null;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Pino logger instance
|
|
92
|
+
* Configuration is supplied via initializeLogger() and persists across imports
|
|
93
|
+
* Logger instance is cached after first creation for reuse
|
|
94
|
+
*/
|
|
95
|
+
export const logger = _getLogger();
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"moduleResolution": "node",
|
|
15
|
+
"baseUrl": "./src",
|
|
16
|
+
"paths": {
|
|
17
|
+
"@/*": ["./*"]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*"],
|
|
21
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
22
|
+
}
|