@leanstacks/lambda-utils 0.1.0-alpha.2 → 0.1.0-alpha.4

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/docs/README.md CHANGED
@@ -2,47 +2,26 @@
2
2
 
3
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
4
 
5
- ## Table of Contents
5
+ ## Overview
6
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)
7
+ Lambda Utilities is a collection of pre-configured tools and helpers designed to reduce boilerplate code when developing AWS Lambda functions. It provides utilities for logging, API responses, configuration validation, and AWS SDK client management—all with full TypeScript support.
12
8
 
13
- ## Quick Start
9
+ ## Documentation
14
10
 
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
- ```
11
+ - **[Logging Guide](./LOGGING.md)** – Implement structured logging in your Lambda functions with Pino and automatic AWS context enrichment
12
+ - **[API Gateway Responses](./API_GATEWAY_RESPONSES.md)** – Format Lambda responses for API Gateway with standard HTTP status codes and headers
13
+ - **[Configuration](./CONFIGURATION.md)** – Validate environment variables and configuration with Zod type safety
14
+ - **[AWS Clients](./CLIENTS.md)** – Pre-configured AWS SDK v3 clients optimized for Lambda
15
+ - **[Getting Started](./GETTING_STARTED.md)** – Quick setup and installation instructions
37
16
 
38
17
  ## Features
39
18
 
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
19
+ - 📝 **Structured Logging** Pino logger pre-configured for Lambda with automatic request context
20
+ - 📤 **API Response Helpers** – Standard response formatting for API Gateway integration
21
+ - ⚙️ **Configuration Validation** – Environment variable validation with Zod schema support
22
+ - 🔌 **AWS Clients** Pre-configured AWS SDK v3 clients for common services
23
+ - 🔒 **Type Safe** Full TypeScript support with comprehensive type definitions
45
24
 
46
25
  ## Support
47
26
 
48
- For issues or questions, please visit the [GitHub repository](https://github.com/leanstacks/lambda-utils).
27
+ For issues or questions, visit the [GitHub repository](https://github.com/leanstacks/lambda-utils).
package/jest.config.ts CHANGED
@@ -3,13 +3,13 @@ import type { Config } from 'jest';
3
3
  const config: Config = {
4
4
  preset: 'ts-jest',
5
5
  testEnvironment: 'node',
6
- rootDir: 'src',
7
- testMatch: ['**/*.test.ts'],
6
+ testMatch: ['<rootDir>/src/**/*.test.ts'],
8
7
  moduleNameMapper: {
9
8
  '^@/(.*)$': '<rootDir>/$1',
10
9
  },
11
- collectCoverageFrom: ['**/*.ts', '!**/*.test.ts'],
12
- coveragePathIgnorePatterns: ['/node_modules/'],
10
+ coverageDirectory: 'coverage',
11
+ collectCoverageFrom: ['src/**/*.ts', '!src/**/*.test.ts', '!src/**/index.ts'],
12
+ coverageReporters: ['json', 'json-summary', 'lcov', 'text', 'clover'],
13
13
  };
14
14
 
15
15
  export default config;
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@leanstacks/lambda-utils",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.4",
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
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "rollup -c",
9
9
  "build:watch": "rollup -c -w",
10
- "clean": "rimraf dist",
11
- "test": "jest",
12
- "test:watch": "jest --watch",
13
- "test:coverage": "jest --coverage",
10
+ "clean": "rimraf coverage dist",
11
+ "format": "prettier --write \"src/**/*.ts\"",
12
+ "format:check": "prettier --check \"src/**/*.ts\"",
14
13
  "lint": "eslint src",
15
14
  "lint:fix": "eslint src --fix",
16
- "format": "prettier --write \"src/**/*.ts\"",
17
- "format:check": "prettier --check \"src/**/*.ts\""
15
+ "test": "jest",
16
+ "test:watch": "jest --watch",
17
+ "test:coverage": "jest --coverage"
18
18
  },
19
19
  "keywords": [
20
20
  "lambda",
@@ -44,7 +44,6 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "pino": "10.1.0",
47
- "pino-lambda": "4.4.1",
48
- "zod": "4.2.1"
47
+ "pino-lambda": "4.4.1"
49
48
  }
50
49
  }
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export { getLogger, initializeLogger, LoggerConfig, withRequestTracking } from './logging/logger';
1
+ export { Logger, LoggerConfig, withRequestTracking } from './logging/logger';
@@ -0,0 +1,400 @@
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
+ });
@@ -7,10 +7,11 @@ import {
7
7
  } from 'pino-lambda';
8
8
 
9
9
  /**
10
- * Middleware to track AWS Lambda requests
10
+ * Logger middleware which adds AWS Lambda attributes to log messages.
11
+ *
11
12
  * @example
12
13
  * ```typescript
13
- * import { withRequestTracking } from '@utils/logging/logger';
14
+ * import { withRequestTracking } from '@leanstacks/lambda-utils';
14
15
  *
15
16
  * export const handler = async (event, context) => {
16
17
  * withRequestTracking(event, context);
@@ -22,7 +23,7 @@ import {
22
23
  export const withRequestTracking = lambdaRequestTracker();
23
24
 
24
25
  /**
25
- * Configuration options for the Pino Lambda logger
26
+ * Configuration options for the Logger
26
27
  */
27
28
  export interface LoggerConfig {
28
29
  /** Whether logging is enabled */
@@ -34,82 +35,70 @@ export interface LoggerConfig {
34
35
  }
35
36
 
36
37
  /**
37
- * Module-level state to store logger configuration
38
- */
39
- let _loggerConfig: LoggerConfig = {
40
- enabled: true,
41
- level: 'info',
42
- format: 'json',
43
- };
44
-
45
- /**
46
- * Module-level cache for the logger instance
47
- */
48
- let _loggerInstance: pino.Logger | null = null;
49
-
50
- /**
51
- * Create and return the Pino Lambda logger instance
52
- * Uses the configuration set by initializeLogger
53
- * Logger instance is cached after first creation
54
- */
55
- const _createLogger = (): pino.Logger => {
56
- const formatter = _loggerConfig.format === 'json' ? new StructuredLogFormatter() : new CloudwatchLogFormatter();
57
-
58
- const lambdaDestination = pinoLambdaDestination({
59
- formatter,
60
- });
61
-
62
- return pino(
63
- {
64
- enabled: _loggerConfig.enabled,
65
- level: _loggerConfig.level,
66
- },
67
- lambdaDestination,
68
- );
69
- };
70
-
71
- /**
72
- * Initialize the logger with configuration
73
- * Should be called once at Lambda handler entry point
74
- * Invalidates the cached logger instance so a new one is created with the updated config
75
- *
76
- * @param config Logger configuration options
77
- * @returns void
38
+ * Logger class which provides a Pino logger instance with AWS Lambda attributes.
78
39
  *
79
40
  * @example
80
41
  * ```typescript
81
- * import { initializeLogger } from '@utils/logging/logger';
42
+ * import { Logger } from '@leanstacks/lambda-utils';
43
+ * const logger = new Logger().instance;
82
44
  *
83
- * initializeLogger({
84
- * enabled: true,
85
- * level: 'debug',
86
- * format: 'json',
87
- * });
45
+ * logger.info('Hello, world!');
88
46
  * ```
89
47
  */
90
- export const initializeLogger = (config: LoggerConfig): void => {
91
- _loggerConfig = {
92
- enabled: config.enabled ?? true,
93
- level: config.level ?? 'info',
94
- format: config.format ?? 'json',
48
+ export class Logger {
49
+ private _loggerConfig: LoggerConfig = {
50
+ enabled: true,
51
+ level: 'info',
52
+ format: 'json',
95
53
  };
96
- // Invalidate the cached logger instance so a new one is created with updated config
97
- _loggerInstance = null;
98
- };
99
54
 
100
- /**
101
- * Get the logger instance
102
- *
103
- * @example
104
- * ```typescript
105
- * import { logger } from '@utils/logging/logger';
106
- *
107
- * logger.info('Hello, world!');
108
- * ```
109
- */
110
- export const getLogger = (): pino.Logger => {
111
- if (_loggerInstance === null) {
112
- _loggerInstance = _createLogger();
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
+ }
113
65
  }
114
- return _loggerInstance;
115
- };
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/dist/index.d.ts DELETED
@@ -1 +0,0 @@
1
- export { getLogger, initializeLogger, LoggerConfig, withRequestTracking } from './logging/logger';