@leanstacks/lambda-utils 0.1.0-alpha.4 → 0.1.0
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/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/logger.d.ts +59 -0
- package/package.json +29 -10
- package/.editorconfig +0 -12
- package/.github/ISSUE_TEMPLATE/bug.md +0 -47
- package/.github/ISSUE_TEMPLATE/story.md +0 -25
- package/.github/ISSUE_TEMPLATE/task.md +0 -15
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -39
- package/.github/copilot-instructions.md +0 -101
- package/.nvmrc +0 -1
- package/.prettierrc +0 -8
- package/eslint.config.mjs +0 -44
- package/jest.config.ts +0 -15
- package/jest.setup.ts +0 -9
- package/rollup.config.js +0 -18
- package/src/logging/logger.test.ts +0 -400
- package/src/logging/logger.ts +0 -104
- package/tsconfig.json +0 -22
- /package/{src/index.ts → dist/index.d.ts} +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"pino";import{lambdaRequestTracker as n,StructuredLogFormatter as t,CloudwatchLogFormatter as o,pinoLambdaDestination as i}from"pino-lambda";const l=n();class r{constructor(n){this._loggerConfig={enabled:!0,level:"info",format:"json"},this._instance=null,this._createLogger=()=>{const n="json"===this._loggerConfig.format?new t:new o,l=i({formatter:n});return e({enabled:this._loggerConfig.enabled,level:this._loggerConfig.level},l)},n&&(this._loggerConfig={enabled:n.enabled??!0,level:n.level??"info",format:n.format??"json"})}get instance(){return null===this._instance&&(this._instance=this._createLogger()),this._instance}}export{r as Logger,l as withRequestTracking};
|
|
2
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var e=require("pino"),t=require("pino-lambda");const n=t.lambdaRequestTracker();exports.Logger=class{constructor(n){this._loggerConfig={enabled:!0,level:"info",format:"json"},this._instance=null,this._createLogger=()=>{const n="json"===this._loggerConfig.format?new t.StructuredLogFormatter:new t.CloudwatchLogFormatter,r=t.pinoLambdaDestination({formatter:n});return e({enabled:this._loggerConfig.enabled,level:this._loggerConfig.level},r)},n&&(this._loggerConfig={enabled:n.enabled??!0,level:n.level??"info",format:n.format??"json"})}get instance(){return null===this._instance&&(this._instance=this._createLogger()),this._instance}},exports.withRequestTracking=n;
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
/**
|
|
3
|
+
* Logger middleware which adds AWS Lambda attributes to log messages.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { withRequestTracking } from '@leanstacks/lambda-utils';
|
|
8
|
+
*
|
|
9
|
+
* export const handler = async (event, context) => {
|
|
10
|
+
* withRequestTracking(event, context);
|
|
11
|
+
*
|
|
12
|
+
* // Your Lambda handler logic here
|
|
13
|
+
* };
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare const withRequestTracking: (event: import("pino-lambda").LambdaEvent, context: import("pino-lambda").LambdaContext) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Configuration options for the Logger
|
|
19
|
+
*/
|
|
20
|
+
export interface LoggerConfig {
|
|
21
|
+
/** Whether logging is enabled */
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
/** Minimum log level (e.g., 'debug', 'info', 'warn', 'error') */
|
|
24
|
+
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
25
|
+
/** Output format: 'json' for StructuredLogFormatter, 'text' for CloudwatchLogFormatter */
|
|
26
|
+
format?: 'json' | 'text';
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Logger class which provides a Pino logger instance with AWS Lambda attributes.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { Logger } from '@leanstacks/lambda-utils';
|
|
34
|
+
* const logger = new Logger().instance;
|
|
35
|
+
*
|
|
36
|
+
* logger.info('Hello, world!');
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class Logger {
|
|
40
|
+
private _loggerConfig;
|
|
41
|
+
private _instance;
|
|
42
|
+
constructor(config?: LoggerConfig);
|
|
43
|
+
/**
|
|
44
|
+
* Creates a new, fully configured Pino logger instance.
|
|
45
|
+
*/
|
|
46
|
+
private _createLogger;
|
|
47
|
+
/**
|
|
48
|
+
* Get the logger instance.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* import { Logger } from '@leanstacks/lambda-utils';
|
|
53
|
+
* const logger = new Logger().instance;
|
|
54
|
+
*
|
|
55
|
+
* logger.info('Hello, world!');
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
get instance(): pino.Logger;
|
|
59
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leanstacks/lambda-utils",
|
|
3
|
-
"version": "0.1.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "A collection of utilities and helper functions designed to streamline the development of AWS Lambda functions using TypeScript.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"docs"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"lambda",
|
|
14
|
+
"aws",
|
|
15
|
+
"utilities",
|
|
16
|
+
"nodejs",
|
|
17
|
+
"typescript"
|
|
18
|
+
],
|
|
19
|
+
"author": "Matthew Warman <leanstacker@gmail.com> (https://leanstacks.com)",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/leanstacks/lambda-utils.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/leanstacks/lambda-utils#readme",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/leanstacks/lambda-utils/issues"
|
|
28
|
+
},
|
|
7
29
|
"scripts": {
|
|
8
30
|
"build": "rollup -c",
|
|
9
31
|
"build:watch": "rollup -c -w",
|
|
@@ -12,31 +34,28 @@
|
|
|
12
34
|
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
13
35
|
"lint": "eslint src",
|
|
14
36
|
"lint:fix": "eslint src --fix",
|
|
37
|
+
"prepare": "husky",
|
|
15
38
|
"test": "jest",
|
|
16
39
|
"test:watch": "jest --watch",
|
|
17
40
|
"test:coverage": "jest --coverage"
|
|
18
41
|
},
|
|
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
42
|
"devDependencies": {
|
|
29
43
|
"@eslint/js": "9.39.2",
|
|
44
|
+
"@rollup/plugin-commonjs": "29.0.0",
|
|
45
|
+
"@rollup/plugin-node-resolve": "16.0.3",
|
|
46
|
+
"@rollup/plugin-terser": "0.4.4",
|
|
30
47
|
"@types/aws-lambda": "8.10.159",
|
|
31
48
|
"@types/jest": "30.0.0",
|
|
32
49
|
"@types/node": "25.0.3",
|
|
33
50
|
"@typescript-eslint/eslint-plugin": "8.50.0",
|
|
34
51
|
"@typescript-eslint/parser": "8.50.0",
|
|
35
52
|
"eslint": "9.39.2",
|
|
53
|
+
"husky": "9.1.7",
|
|
36
54
|
"jest": "30.2.0",
|
|
37
55
|
"prettier": "3.7.4",
|
|
38
56
|
"rimraf": "6.1.2",
|
|
39
57
|
"rollup": "4.53.5",
|
|
58
|
+
"rollup-plugin-peer-deps-external": "2.2.4",
|
|
40
59
|
"rollup-plugin-typescript2": "0.36.0",
|
|
41
60
|
"ts-jest": "29.4.6",
|
|
42
61
|
"ts-node": "10.9.2",
|
package/.editorconfig
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
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
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Bug report
|
|
3
|
-
about: Create a report to help us improve
|
|
4
|
-
title: ''
|
|
5
|
-
labels: bug
|
|
6
|
-
assignees: ''
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Describe the bug
|
|
10
|
-
|
|
11
|
-
_Provide a clear and concise description of what the bug is._
|
|
12
|
-
|
|
13
|
-
## Steps to reproduce
|
|
14
|
-
|
|
15
|
-
Steps to reproduce the behavior:
|
|
16
|
-
|
|
17
|
-
1. Go to '...'
|
|
18
|
-
2. Click on '....'
|
|
19
|
-
3. Scroll down to '....'
|
|
20
|
-
4. See error
|
|
21
|
-
|
|
22
|
-
## Expected behavior
|
|
23
|
-
|
|
24
|
-
_Provide a clear and concise description of what you expected to happen._
|
|
25
|
-
|
|
26
|
-
## Screenshots
|
|
27
|
-
|
|
28
|
-
_If applicable, add screenshots to help explain your problem._
|
|
29
|
-
|
|
30
|
-
## Environment
|
|
31
|
-
|
|
32
|
-
**Desktop (please complete the following information):**
|
|
33
|
-
|
|
34
|
-
- OS: [e.g. iOS]
|
|
35
|
-
- Browser [e.g. chrome, safari]
|
|
36
|
-
- Version [e.g. 22]
|
|
37
|
-
|
|
38
|
-
**Smartphone (please complete the following information):**
|
|
39
|
-
|
|
40
|
-
- Device: [e.g. iPhone6]
|
|
41
|
-
- OS: [e.g. iOS8.1]
|
|
42
|
-
- Browser [e.g. stock browser, safari]
|
|
43
|
-
- Version [e.g. 22]
|
|
44
|
-
|
|
45
|
-
## Additional context
|
|
46
|
-
|
|
47
|
-
_Add any other context about the problem here._
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Story
|
|
3
|
-
about: New feature or improvement request
|
|
4
|
-
title: ''
|
|
5
|
-
labels: enhancement
|
|
6
|
-
assignees: ''
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Describe the story
|
|
10
|
-
|
|
11
|
-
_Provide a clear description of the new feature or improvement to existing functionality._
|
|
12
|
-
|
|
13
|
-
## Acceptance criteria
|
|
14
|
-
|
|
15
|
-
_Provide clear acceptance criteria to validate the story is complete._
|
|
16
|
-
|
|
17
|
-
[Gherkin syntax](https://cucumber.io/docs/gherkin/reference) example:
|
|
18
|
-
|
|
19
|
-
> Given the 'PERSONA' has 'DONE SOMETHING'
|
|
20
|
-
> When the 'PERSONA' does 'ONE THING'
|
|
21
|
-
> Then the 'PERSONA' must do 'ANOTHER THING'
|
|
22
|
-
|
|
23
|
-
## Additional context
|
|
24
|
-
|
|
25
|
-
_Add any other context about the story here._
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Task
|
|
3
|
-
about: A chore unrelated to features or problems
|
|
4
|
-
title: ''
|
|
5
|
-
labels: task
|
|
6
|
-
assignees: ''
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Describe the task
|
|
10
|
-
|
|
11
|
-
_Provide a clear description of the task._
|
|
12
|
-
|
|
13
|
-
## Additional context
|
|
14
|
-
|
|
15
|
-
_Add any other context about the task here._
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
:loudspeaker: **Instructions**
|
|
2
|
-
|
|
3
|
-
- Begin with a **DRAFT** pull request.
|
|
4
|
-
- Follow _italicized instructions_ to add detail to assist the reviewers.
|
|
5
|
-
- After completing all checklist items, change the pull request to **READY**.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
### :wrench: Change Summary
|
|
10
|
-
|
|
11
|
-
_Describe the changes included in this pull request. Link to the associated [GitHub](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) or Jira issue(s)._
|
|
12
|
-
|
|
13
|
-
- see #1234
|
|
14
|
-
- Added the [...]
|
|
15
|
-
- Updated the [...]
|
|
16
|
-
- Fixed the [...]
|
|
17
|
-
|
|
18
|
-
### :memo: Checklist
|
|
19
|
-
|
|
20
|
-
_Pull request authors must complete the following tasks before marking the PR as ready to review._
|
|
21
|
-
|
|
22
|
-
- [ ] Complete a self-review of changes
|
|
23
|
-
- [ ] Unit tests have been created or updated
|
|
24
|
-
- [ ] The code is free of [new] lint errors and warnings
|
|
25
|
-
- [ ] Update project documentation as needed: README, /docs, JSDoc, etc.
|
|
26
|
-
|
|
27
|
-
### :test_tube: Steps to Test
|
|
28
|
-
|
|
29
|
-
_Describe the process to test the changes in this pull request._
|
|
30
|
-
|
|
31
|
-
1. Go to [...]
|
|
32
|
-
2. Click on [...]
|
|
33
|
-
3. Verify that [...]
|
|
34
|
-
|
|
35
|
-
### :link: Additional Information
|
|
36
|
-
|
|
37
|
-
_Optionally, provide additional details, screenshots, or URLs that may assist the reviewer._
|
|
38
|
-
|
|
39
|
-
- [...]
|
|
@@ -1,101 +0,0 @@
|
|
|
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
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
24.11.1
|
package/.prettierrc
DELETED
package/eslint.config.mjs
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Config } from 'jest';
|
|
2
|
-
|
|
3
|
-
const config: Config = {
|
|
4
|
-
preset: 'ts-jest',
|
|
5
|
-
testEnvironment: 'node',
|
|
6
|
-
testMatch: ['<rootDir>/src/**/*.test.ts'],
|
|
7
|
-
moduleNameMapper: {
|
|
8
|
-
'^@/(.*)$': '<rootDir>/$1',
|
|
9
|
-
},
|
|
10
|
-
coverageDirectory: 'coverage',
|
|
11
|
-
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.test.ts', '!src/**/index.ts'],
|
|
12
|
-
coverageReporters: ['json', 'json-summary', 'lcov', 'text', 'clover'],
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export default config;
|
package/jest.setup.ts
DELETED
package/rollup.config.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,400 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import pino from 'pino';
|
|
3
|
-
import { CloudwatchLogFormatter, pinoLambdaDestination, StructuredLogFormatter } from 'pino-lambda';
|
|
4
|
-
import { Logger, withRequestTracking } from './logger';
|
|
5
|
-
|
|
6
|
-
// Mock pino-lambda module
|
|
7
|
-
jest.mock('pino-lambda');
|
|
8
|
-
|
|
9
|
-
// Mock pino module
|
|
10
|
-
jest.mock('pino');
|
|
11
|
-
|
|
12
|
-
describe('Logger', () => {
|
|
13
|
-
// Setup and cleanup
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
jest.clearAllMocks();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
jest.clearAllMocks();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
describe('withRequestTracking', () => {
|
|
23
|
-
it('should be exported from logger module', () => {
|
|
24
|
-
// Arrange
|
|
25
|
-
// withRequestTracking is exported from logger.ts and is the result of calling lambdaRequestTracker()
|
|
26
|
-
// from pino-lambda. Jest mocks mean it will be the mocked value.
|
|
27
|
-
|
|
28
|
-
// Act & Assert
|
|
29
|
-
// We just verify that it was exported (defined by the import statement at the top)
|
|
30
|
-
// The actual functionality of lambdaRequestTracker is tested in pino-lambda
|
|
31
|
-
expect(typeof withRequestTracking === 'function' || withRequestTracking === undefined).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('constructor', () => {
|
|
36
|
-
it('should create Logger with default configuration', () => {
|
|
37
|
-
// Arrange
|
|
38
|
-
const mockLogger = { info: jest.fn() };
|
|
39
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
40
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
41
|
-
|
|
42
|
-
// Act
|
|
43
|
-
const logger = new Logger();
|
|
44
|
-
|
|
45
|
-
// Assert
|
|
46
|
-
expect(logger).toBeDefined();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should create Logger with custom enabled configuration', () => {
|
|
50
|
-
// Arrange
|
|
51
|
-
const mockLogger = { info: jest.fn() };
|
|
52
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
53
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
54
|
-
|
|
55
|
-
// Act
|
|
56
|
-
const logger = new Logger({ enabled: false });
|
|
57
|
-
const _instance = logger.instance;
|
|
58
|
-
|
|
59
|
-
// Assert
|
|
60
|
-
expect(pino).toHaveBeenCalledWith(
|
|
61
|
-
expect.objectContaining({
|
|
62
|
-
enabled: false,
|
|
63
|
-
}),
|
|
64
|
-
expect.anything(),
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should create Logger with custom log level configuration', () => {
|
|
69
|
-
// Arrange
|
|
70
|
-
const mockLogger = { info: jest.fn() };
|
|
71
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
72
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
73
|
-
|
|
74
|
-
// Act
|
|
75
|
-
const logger = new Logger({ level: 'debug' });
|
|
76
|
-
const _instance = logger.instance;
|
|
77
|
-
|
|
78
|
-
// Assert
|
|
79
|
-
expect(pino).toHaveBeenCalledWith(
|
|
80
|
-
expect.objectContaining({
|
|
81
|
-
level: 'debug',
|
|
82
|
-
}),
|
|
83
|
-
expect.anything(),
|
|
84
|
-
);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should create Logger with custom format configuration (json)', () => {
|
|
88
|
-
// Arrange
|
|
89
|
-
const mockLogger = { info: jest.fn() };
|
|
90
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
91
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
92
|
-
|
|
93
|
-
// Act
|
|
94
|
-
const logger = new Logger({ format: 'json' });
|
|
95
|
-
const _instance = logger.instance;
|
|
96
|
-
|
|
97
|
-
// Assert
|
|
98
|
-
expect(StructuredLogFormatter).toHaveBeenCalled();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should create Logger with custom format configuration (text)', () => {
|
|
102
|
-
// Arrange
|
|
103
|
-
const mockLogger = { info: jest.fn() };
|
|
104
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
105
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
106
|
-
|
|
107
|
-
// Act
|
|
108
|
-
const logger = new Logger({ format: 'text' });
|
|
109
|
-
const _instance = logger.instance;
|
|
110
|
-
|
|
111
|
-
// Assert
|
|
112
|
-
expect(CloudwatchLogFormatter).toHaveBeenCalled();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('should merge provided config with defaults', () => {
|
|
116
|
-
// Arrange
|
|
117
|
-
const mockLogger = { info: jest.fn() };
|
|
118
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
119
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
120
|
-
|
|
121
|
-
// Act
|
|
122
|
-
const logger = new Logger({ level: 'error' });
|
|
123
|
-
const _instance = logger.instance;
|
|
124
|
-
|
|
125
|
-
// Assert
|
|
126
|
-
expect(pino).toHaveBeenCalledWith(
|
|
127
|
-
expect.objectContaining({
|
|
128
|
-
enabled: true,
|
|
129
|
-
level: 'error',
|
|
130
|
-
}),
|
|
131
|
-
expect.anything(),
|
|
132
|
-
);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
describe('instance getter', () => {
|
|
137
|
-
it('should return a Pino logger instance', () => {
|
|
138
|
-
// Arrange
|
|
139
|
-
const mockLogger = { info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn() };
|
|
140
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
141
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
142
|
-
const logger = new Logger();
|
|
143
|
-
|
|
144
|
-
// Act
|
|
145
|
-
const instance = logger.instance;
|
|
146
|
-
|
|
147
|
-
// Assert
|
|
148
|
-
expect(instance).toBe(mockLogger);
|
|
149
|
-
expect(instance).toHaveProperty('info');
|
|
150
|
-
expect(instance).toHaveProperty('warn');
|
|
151
|
-
expect(instance).toHaveProperty('error');
|
|
152
|
-
expect(instance).toHaveProperty('debug');
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('should create logger instance only once (lazy initialization)', () => {
|
|
156
|
-
// Arrange
|
|
157
|
-
const mockLogger = { info: jest.fn() };
|
|
158
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
159
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
160
|
-
const logger = new Logger();
|
|
161
|
-
|
|
162
|
-
// Act
|
|
163
|
-
const instance1 = logger.instance;
|
|
164
|
-
const instance2 = logger.instance;
|
|
165
|
-
|
|
166
|
-
// Assert
|
|
167
|
-
expect(instance1).toBe(instance2);
|
|
168
|
-
expect(pino).toHaveBeenCalledTimes(1);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it('should configure pino with enabled flag', () => {
|
|
172
|
-
// Arrange
|
|
173
|
-
const mockLogger = { info: jest.fn() };
|
|
174
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
175
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
176
|
-
|
|
177
|
-
// Act
|
|
178
|
-
const logger = new Logger({ enabled: false });
|
|
179
|
-
const _instance = logger.instance;
|
|
180
|
-
|
|
181
|
-
// Assert
|
|
182
|
-
expect(pino).toHaveBeenCalledWith(
|
|
183
|
-
expect.objectContaining({
|
|
184
|
-
enabled: false,
|
|
185
|
-
}),
|
|
186
|
-
expect.anything(),
|
|
187
|
-
);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it('should configure pino with log level', () => {
|
|
191
|
-
// Arrange
|
|
192
|
-
const mockLogger = { info: jest.fn() };
|
|
193
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
194
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
195
|
-
|
|
196
|
-
// Act
|
|
197
|
-
const logger = new Logger({ level: 'warn' });
|
|
198
|
-
const _instance = logger.instance;
|
|
199
|
-
|
|
200
|
-
// Assert
|
|
201
|
-
expect(pino).toHaveBeenCalledWith(
|
|
202
|
-
expect.objectContaining({
|
|
203
|
-
level: 'warn',
|
|
204
|
-
}),
|
|
205
|
-
expect.anything(),
|
|
206
|
-
);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('should call pinoLambdaDestination with selected formatter', () => {
|
|
210
|
-
// Arrange
|
|
211
|
-
const mockLogger = { info: jest.fn() };
|
|
212
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
213
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
214
|
-
|
|
215
|
-
// Act
|
|
216
|
-
const logger = new Logger({ format: 'json' });
|
|
217
|
-
const _instance = logger.instance;
|
|
218
|
-
|
|
219
|
-
// Assert
|
|
220
|
-
expect(pinoLambdaDestination).toHaveBeenCalledWith(
|
|
221
|
-
expect.objectContaining({
|
|
222
|
-
formatter: expect.any(StructuredLogFormatter),
|
|
223
|
-
}),
|
|
224
|
-
);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('should use StructuredLogFormatter when format is json', () => {
|
|
228
|
-
// Arrange
|
|
229
|
-
const mockLogger = { info: jest.fn() };
|
|
230
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
231
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
232
|
-
|
|
233
|
-
// Act
|
|
234
|
-
const logger = new Logger({ format: 'json' });
|
|
235
|
-
const _instance = logger.instance;
|
|
236
|
-
|
|
237
|
-
// Assert
|
|
238
|
-
expect(StructuredLogFormatter).toHaveBeenCalled();
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it('should use CloudwatchLogFormatter when format is text', () => {
|
|
242
|
-
// Arrange
|
|
243
|
-
const mockLogger = { info: jest.fn() };
|
|
244
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
245
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
246
|
-
|
|
247
|
-
// Act
|
|
248
|
-
const logger = new Logger({ format: 'text' });
|
|
249
|
-
const _instance = logger.instance;
|
|
250
|
-
|
|
251
|
-
// Assert
|
|
252
|
-
expect(CloudwatchLogFormatter).toHaveBeenCalled();
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
describe('Logger configurations', () => {
|
|
257
|
-
it('should support all log levels', () => {
|
|
258
|
-
// Arrange
|
|
259
|
-
const mockLogger = { info: jest.fn() };
|
|
260
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
261
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
262
|
-
const levels: Array<'debug' | 'info' | 'warn' | 'error'> = ['debug', 'info', 'warn', 'error'];
|
|
263
|
-
|
|
264
|
-
// Act & Assert
|
|
265
|
-
levels.forEach((level) => {
|
|
266
|
-
jest.clearAllMocks();
|
|
267
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
268
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
269
|
-
|
|
270
|
-
const logger = new Logger({ level });
|
|
271
|
-
const _instance = logger.instance;
|
|
272
|
-
|
|
273
|
-
expect(pino).toHaveBeenCalledWith(
|
|
274
|
-
expect.objectContaining({
|
|
275
|
-
level,
|
|
276
|
-
}),
|
|
277
|
-
expect.anything(),
|
|
278
|
-
);
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it('should support both json and text formats', () => {
|
|
283
|
-
// Arrange
|
|
284
|
-
const mockLogger = { info: jest.fn() };
|
|
285
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
286
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
287
|
-
|
|
288
|
-
// Act
|
|
289
|
-
const jsonLogger = new Logger({ format: 'json' });
|
|
290
|
-
const _jsonInstance = jsonLogger.instance;
|
|
291
|
-
const structuredFormatterCallCount = (StructuredLogFormatter as jest.Mock).mock.calls.length;
|
|
292
|
-
|
|
293
|
-
jest.clearAllMocks();
|
|
294
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
295
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
296
|
-
|
|
297
|
-
const textLogger = new Logger({ format: 'text' });
|
|
298
|
-
const _textInstance = textLogger.instance;
|
|
299
|
-
|
|
300
|
-
// Assert
|
|
301
|
-
expect(structuredFormatterCallCount).toBeGreaterThan(0);
|
|
302
|
-
expect(CloudwatchLogFormatter).toHaveBeenCalled();
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
it('should support enabled and disabled logging', () => {
|
|
306
|
-
// Arrange
|
|
307
|
-
const mockLogger = { info: jest.fn() };
|
|
308
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
309
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
310
|
-
|
|
311
|
-
// Act
|
|
312
|
-
const enabledLogger = new Logger({ enabled: true });
|
|
313
|
-
const _enabledInstance = enabledLogger.instance;
|
|
314
|
-
const firstCallArgs = jest.mocked(pino).mock.calls[0];
|
|
315
|
-
|
|
316
|
-
jest.clearAllMocks();
|
|
317
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
318
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
319
|
-
|
|
320
|
-
const disabledLogger = new Logger({ enabled: false });
|
|
321
|
-
const _disabledInstance = disabledLogger.instance;
|
|
322
|
-
const secondCallArgs = jest.mocked(pino).mock.calls[0];
|
|
323
|
-
|
|
324
|
-
// Assert
|
|
325
|
-
expect(firstCallArgs[0]).toEqual(expect.objectContaining({ enabled: true }));
|
|
326
|
-
expect(secondCallArgs[0]).toEqual(expect.objectContaining({ enabled: false }));
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
describe('integration scenarios', () => {
|
|
331
|
-
it('should create multiple logger instances with different configurations', () => {
|
|
332
|
-
// Arrange
|
|
333
|
-
const mockLogger1 = { info: jest.fn(), level: 'debug' };
|
|
334
|
-
const mockLogger2 = { info: jest.fn(), level: 'error' };
|
|
335
|
-
jest
|
|
336
|
-
.mocked(pino)
|
|
337
|
-
.mockReturnValueOnce(mockLogger1 as unknown as any)
|
|
338
|
-
.mockReturnValueOnce(mockLogger2 as unknown as any);
|
|
339
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
340
|
-
|
|
341
|
-
// Act
|
|
342
|
-
const debugLogger = new Logger({ level: 'debug', format: 'json' });
|
|
343
|
-
const errorLogger = new Logger({ level: 'error', format: 'text' });
|
|
344
|
-
|
|
345
|
-
const instance1 = debugLogger.instance;
|
|
346
|
-
const instance2 = errorLogger.instance;
|
|
347
|
-
|
|
348
|
-
// Assert
|
|
349
|
-
expect(instance1).toBe(mockLogger1);
|
|
350
|
-
expect(instance2).toBe(mockLogger2);
|
|
351
|
-
expect(pino).toHaveBeenCalledTimes(2);
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
it('should handle partial configuration overrides', () => {
|
|
355
|
-
// Arrange
|
|
356
|
-
const mockLogger = { info: jest.fn() };
|
|
357
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
358
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
359
|
-
|
|
360
|
-
// Act
|
|
361
|
-
const logger = new Logger({ level: 'warn' });
|
|
362
|
-
const _instance = logger.instance;
|
|
363
|
-
|
|
364
|
-
// Assert - should have custom level but default enabled and format
|
|
365
|
-
expect(pino).toHaveBeenCalledWith(
|
|
366
|
-
expect.objectContaining({
|
|
367
|
-
enabled: true,
|
|
368
|
-
level: 'warn',
|
|
369
|
-
}),
|
|
370
|
-
expect.anything(),
|
|
371
|
-
);
|
|
372
|
-
expect(StructuredLogFormatter).toHaveBeenCalled();
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
it('should handle full configuration override', () => {
|
|
376
|
-
// Arrange
|
|
377
|
-
const mockLogger = { info: jest.fn() };
|
|
378
|
-
jest.mocked(pino).mockReturnValue(mockLogger as unknown as any);
|
|
379
|
-
(pinoLambdaDestination as jest.Mock).mockReturnValue({});
|
|
380
|
-
|
|
381
|
-
// Act
|
|
382
|
-
const logger = new Logger({
|
|
383
|
-
enabled: false,
|
|
384
|
-
level: 'error',
|
|
385
|
-
format: 'text',
|
|
386
|
-
});
|
|
387
|
-
const _instance = logger.instance;
|
|
388
|
-
|
|
389
|
-
// Assert
|
|
390
|
-
expect(pino).toHaveBeenCalledWith(
|
|
391
|
-
expect.objectContaining({
|
|
392
|
-
enabled: false,
|
|
393
|
-
level: 'error',
|
|
394
|
-
}),
|
|
395
|
-
expect.anything(),
|
|
396
|
-
);
|
|
397
|
-
expect(CloudwatchLogFormatter).toHaveBeenCalled();
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
});
|
package/src/logging/logger.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import pino from 'pino';
|
|
2
|
-
import {
|
|
3
|
-
CloudwatchLogFormatter,
|
|
4
|
-
lambdaRequestTracker,
|
|
5
|
-
pinoLambdaDestination,
|
|
6
|
-
StructuredLogFormatter,
|
|
7
|
-
} from 'pino-lambda';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Logger middleware which adds AWS Lambda attributes to log messages.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```typescript
|
|
14
|
-
* import { withRequestTracking } from '@leanstacks/lambda-utils';
|
|
15
|
-
*
|
|
16
|
-
* export const handler = async (event, context) => {
|
|
17
|
-
* withRequestTracking(event, context);
|
|
18
|
-
*
|
|
19
|
-
* // Your Lambda handler logic here
|
|
20
|
-
* };
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export const withRequestTracking = lambdaRequestTracker();
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Configuration options for the Logger
|
|
27
|
-
*/
|
|
28
|
-
export interface LoggerConfig {
|
|
29
|
-
/** Whether logging is enabled */
|
|
30
|
-
enabled?: boolean;
|
|
31
|
-
/** Minimum log level (e.g., 'debug', 'info', 'warn', 'error') */
|
|
32
|
-
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
33
|
-
/** Output format: 'json' for StructuredLogFormatter, 'text' for CloudwatchLogFormatter */
|
|
34
|
-
format?: 'json' | 'text';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Logger class which provides a Pino logger instance with AWS Lambda attributes.
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* ```typescript
|
|
42
|
-
* import { Logger } from '@leanstacks/lambda-utils';
|
|
43
|
-
* const logger = new Logger().instance;
|
|
44
|
-
*
|
|
45
|
-
* logger.info('Hello, world!');
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
export class Logger {
|
|
49
|
-
private _loggerConfig: LoggerConfig = {
|
|
50
|
-
enabled: true,
|
|
51
|
-
level: 'info',
|
|
52
|
-
format: 'json',
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
private _instance: pino.Logger | null = null;
|
|
56
|
-
|
|
57
|
-
constructor(config?: LoggerConfig) {
|
|
58
|
-
if (config) {
|
|
59
|
-
this._loggerConfig = {
|
|
60
|
-
enabled: config.enabled ?? true,
|
|
61
|
-
level: config.level ?? 'info',
|
|
62
|
-
format: config.format ?? 'json',
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Creates a new, fully configured Pino logger instance.
|
|
69
|
-
*/
|
|
70
|
-
private _createLogger = (): pino.Logger => {
|
|
71
|
-
const formatter =
|
|
72
|
-
this._loggerConfig.format === 'json' ? new StructuredLogFormatter() : new CloudwatchLogFormatter();
|
|
73
|
-
|
|
74
|
-
const lambdaDestination = pinoLambdaDestination({
|
|
75
|
-
formatter,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
return pino(
|
|
79
|
-
{
|
|
80
|
-
enabled: this._loggerConfig.enabled,
|
|
81
|
-
level: this._loggerConfig.level,
|
|
82
|
-
},
|
|
83
|
-
lambdaDestination,
|
|
84
|
-
);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Get the logger instance.
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```typescript
|
|
92
|
-
* import { Logger } from '@leanstacks/lambda-utils';
|
|
93
|
-
* const logger = new Logger().instance;
|
|
94
|
-
*
|
|
95
|
-
* logger.info('Hello, world!');
|
|
96
|
-
* ```
|
|
97
|
-
*/
|
|
98
|
-
get instance(): pino.Logger {
|
|
99
|
-
if (this._instance === null) {
|
|
100
|
-
this._instance = this._createLogger();
|
|
101
|
-
}
|
|
102
|
-
return this._instance;
|
|
103
|
-
}
|
|
104
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
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
|
-
}
|
|
File without changes
|