serverless-event-logger 1.0.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/README.md +262 -0
- package/dist/constants.d.ts +23 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +33 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +67 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +148 -0
- package/dist/logger.js.map +1 -0
- package/dist/types.d.ts +131 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/extract-context.d.ts +14 -0
- package/dist/utils/extract-context.d.ts.map +1 -0
- package/dist/utils/extract-context.js +44 -0
- package/dist/utils/extract-context.js.map +1 -0
- package/dist/utils/format.d.ts +18 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +39 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/redact.d.ts +10 -0
- package/dist/utils/redact.d.ts.map +1 -0
- package/dist/utils/redact.js +40 -0
- package/dist/utils/redact.js.map +1 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# serverless-event-logger
|
|
2
|
+
|
|
3
|
+
🚀 Lightweight, zero-dependency structured JSON logger for AWS Lambda. Optimized for observability with automatic context extraction from serverless events.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/serverless-event-logger)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Zero dependencies** - Minimal bundle size (< 5KB minified)
|
|
11
|
+
- **Structured JSON output** - Perfect for CloudWatch Insights queries
|
|
12
|
+
- **Automatic context extraction** - Captures requestId, userId, segment from events
|
|
13
|
+
- **Log level filtering** - debug, info, warn, error
|
|
14
|
+
- **Sensitive data redaction** - Automatically redact passwords, tokens, etc.
|
|
15
|
+
- **Timer utility** - Measure operation duration
|
|
16
|
+
- **Child loggers** - Add module-specific context
|
|
17
|
+
- **TypeScript first** - Full type definitions included
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install serverless-event-logger
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { createLogger } from 'serverless-event-logger';
|
|
29
|
+
|
|
30
|
+
// Create a logger instance
|
|
31
|
+
const logger = createLogger({
|
|
32
|
+
service: 'my-lambda',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Basic logging
|
|
36
|
+
logger.info('User created', { userId: '123' });
|
|
37
|
+
// Output: {"timestamp":"2024-01-15T10:30:00.000Z","level":"info","message":"User created","service":"my-lambda","userId":"123"}
|
|
38
|
+
|
|
39
|
+
logger.error('Database connection failed', { error: err.message });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage with Lambda Events
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { createLogger } from 'serverless-event-logger';
|
|
46
|
+
import { NormalizedEvent } from 'serverless-event-orchestrator';
|
|
47
|
+
|
|
48
|
+
const logger = createLogger({
|
|
49
|
+
service: 'ml-properties-lambda',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
async function handler(event: NormalizedEvent) {
|
|
53
|
+
// Create logger with request context
|
|
54
|
+
const log = logger.withContext(event);
|
|
55
|
+
|
|
56
|
+
log.info('Handler started');
|
|
57
|
+
// Output includes: requestId, userId, segment, path, method
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const result = await processRequest(event);
|
|
61
|
+
log.info('Request processed', { resultId: result.id });
|
|
62
|
+
return result;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
log.error('Request failed', { error: error.message, stack: error.stack });
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API Reference
|
|
71
|
+
|
|
72
|
+
### `createLogger(config)`
|
|
73
|
+
|
|
74
|
+
Creates a new logger instance.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
interface LoggerConfig {
|
|
78
|
+
service: string; // REQUIRED: Name of your lambda/service
|
|
79
|
+
defaultLevel?: LogLevel; // Default: 'info'
|
|
80
|
+
silent?: boolean; // Default: false (set true for tests)
|
|
81
|
+
redactPaths?: string[]; // Fields to redact (e.g., ['password', 'token'])
|
|
82
|
+
timestampFormat?: 'iso' | 'epoch'; // Default: 'iso'
|
|
83
|
+
pretty?: boolean; // Default: false (formatted output for local dev)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Logging Methods
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
logger.debug(message: string, data?: object): void
|
|
93
|
+
logger.info(message: string, data?: object): void
|
|
94
|
+
logger.warn(message: string, data?: object): void
|
|
95
|
+
logger.error(message: string, data?: object): void
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `logger.withContext(event)`
|
|
99
|
+
|
|
100
|
+
Creates a new logger with context extracted from a `NormalizedEvent`:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const log = logger.withContext(event);
|
|
104
|
+
// Extracts: requestId, userId, segment, path, method, userAgent
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### `logger.child(fields)`
|
|
108
|
+
|
|
109
|
+
Creates a child logger with additional fixed fields:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const dbLogger = logger.child({ module: 'dynamodb' });
|
|
113
|
+
dbLogger.info('Query executed', { table: 'Users' });
|
|
114
|
+
// Output includes module: 'dynamodb'
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `logger.startTimer(label)`
|
|
118
|
+
|
|
119
|
+
Measures operation duration:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const timer = log.startTimer('database-query');
|
|
123
|
+
await db.query(...);
|
|
124
|
+
timer.done({ recordsFound: 150 });
|
|
125
|
+
// Output: {"message":"database-query completed","duration":234,"recordsFound":150,...}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Configuration
|
|
129
|
+
|
|
130
|
+
### Environment Variables
|
|
131
|
+
|
|
132
|
+
| Variable | Description | Default |
|
|
133
|
+
|----------|-------------|---------|
|
|
134
|
+
| `LOG_LEVEL` | Minimum log level | `info` |
|
|
135
|
+
| `LOG_SILENT` | Disable all logs | `false` |
|
|
136
|
+
| `LOG_PRETTY` | Formatted output | `false` |
|
|
137
|
+
|
|
138
|
+
### Sensitive Data Redaction
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const logger = createLogger({
|
|
142
|
+
service: 'auth-lambda',
|
|
143
|
+
redactPaths: ['password', 'token', 'authorization', 'apiKey'],
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
logger.info('Login attempt', {
|
|
147
|
+
username: 'john',
|
|
148
|
+
password: 'secret123'
|
|
149
|
+
});
|
|
150
|
+
// Output: {..., "username": "john", "password": "[REDACTED]"}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Log Output Structure
|
|
154
|
+
|
|
155
|
+
### Base Fields (always present)
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"timestamp": "2024-01-15T10:30:00.000Z",
|
|
160
|
+
"level": "info",
|
|
161
|
+
"message": "Your log message",
|
|
162
|
+
"service": "your-service-name"
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Context Fields (with `withContext`)
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"requestId": "abc-123-def-456",
|
|
171
|
+
"userId": "user_abc123",
|
|
172
|
+
"segment": "private",
|
|
173
|
+
"path": "/api/users",
|
|
174
|
+
"method": "POST",
|
|
175
|
+
"userAgent": "Mozilla/5.0..."
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## CloudWatch Insights Queries
|
|
180
|
+
|
|
181
|
+
### Find errors by endpoint
|
|
182
|
+
|
|
183
|
+
```sql
|
|
184
|
+
fields @timestamp, message, path, method, error, userId
|
|
185
|
+
| filter level = "error"
|
|
186
|
+
| filter service = "my-lambda"
|
|
187
|
+
| sort @timestamp desc
|
|
188
|
+
| limit 100
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Latency analysis
|
|
192
|
+
|
|
193
|
+
```sql
|
|
194
|
+
fields @timestamp, path, method, duration
|
|
195
|
+
| filter message like /completed/
|
|
196
|
+
| stats avg(duration) as avg_ms, max(duration) as max_ms by path, method
|
|
197
|
+
| sort avg_ms desc
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### User activity trace
|
|
201
|
+
|
|
202
|
+
```sql
|
|
203
|
+
fields @timestamp, level, message, path
|
|
204
|
+
| filter userId = "user_abc123"
|
|
205
|
+
| sort @timestamp desc
|
|
206
|
+
| limit 50
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## TypeScript Support
|
|
210
|
+
|
|
211
|
+
Full TypeScript definitions are included:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import {
|
|
215
|
+
createLogger,
|
|
216
|
+
Logger,
|
|
217
|
+
LoggerConfig,
|
|
218
|
+
LogLevel,
|
|
219
|
+
Timer,
|
|
220
|
+
NormalizedEventLike
|
|
221
|
+
} from 'serverless-event-logger';
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Best Practices
|
|
225
|
+
|
|
226
|
+
1. **Create one logger per service** - Initialize at module level
|
|
227
|
+
2. **Use `withContext` in handlers** - Captures request-specific info
|
|
228
|
+
3. **Use `child` for modules** - Adds component context
|
|
229
|
+
4. **Redact sensitive data** - Configure `redactPaths`
|
|
230
|
+
5. **Use timers for slow operations** - Helps identify bottlenecks
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// src/logging.ts
|
|
234
|
+
export const logger = createLogger({
|
|
235
|
+
service: process.env.LAMBDA_NAME || 'unknown-lambda',
|
|
236
|
+
redactPaths: ['password', 'token', 'authorization'],
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// src/handlers/user.ts
|
|
240
|
+
import { logger } from '../logging';
|
|
241
|
+
|
|
242
|
+
export async function createUser(event: NormalizedEvent) {
|
|
243
|
+
const log = logger.withContext(event);
|
|
244
|
+
log.info('Creating user', { email: event.payload.body.email });
|
|
245
|
+
// ...
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/repositories/user-repository.ts
|
|
249
|
+
import { logger } from '../logging';
|
|
250
|
+
|
|
251
|
+
const log = logger.child({ module: 'UserRepository' });
|
|
252
|
+
|
|
253
|
+
export async function save(user: User) {
|
|
254
|
+
const timer = log.startTimer('dynamodb-put');
|
|
255
|
+
await db.put(user);
|
|
256
|
+
timer.done({ userId: user.id });
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
MIT © MLHolding
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { LogLevel, ResolvedLoggerConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Log level priority mapping.
|
|
4
|
+
* Lower number = more verbose (will log more)
|
|
5
|
+
*/
|
|
6
|
+
export declare const LOG_LEVELS: Record<LogLevel, number>;
|
|
7
|
+
/**
|
|
8
|
+
* Default configuration values
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_CONFIG: Omit<ResolvedLoggerConfig, 'service'>;
|
|
11
|
+
/**
|
|
12
|
+
* Environment variable names
|
|
13
|
+
*/
|
|
14
|
+
export declare const ENV_VARS: {
|
|
15
|
+
readonly LOG_LEVEL: "LOG_LEVEL";
|
|
16
|
+
readonly LOG_SILENT: "LOG_SILENT";
|
|
17
|
+
readonly LOG_PRETTY: "LOG_PRETTY";
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Redaction placeholder
|
|
21
|
+
*/
|
|
22
|
+
export declare const REDACTED_VALUE = "[REDACTED]";
|
|
23
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAMtC,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAMvD,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;CAIX,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log level priority mapping.
|
|
3
|
+
* Lower number = more verbose (will log more)
|
|
4
|
+
*/
|
|
5
|
+
export const LOG_LEVELS = {
|
|
6
|
+
debug: 0,
|
|
7
|
+
info: 1,
|
|
8
|
+
warn: 2,
|
|
9
|
+
error: 3,
|
|
10
|
+
silent: 4,
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Default configuration values
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_CONFIG = {
|
|
16
|
+
defaultLevel: 'info',
|
|
17
|
+
silent: false,
|
|
18
|
+
redactPaths: [],
|
|
19
|
+
timestampFormat: 'iso',
|
|
20
|
+
pretty: false,
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Environment variable names
|
|
24
|
+
*/
|
|
25
|
+
export const ENV_VARS = {
|
|
26
|
+
LOG_LEVEL: 'LOG_LEVEL',
|
|
27
|
+
LOG_SILENT: 'LOG_SILENT',
|
|
28
|
+
LOG_PRETTY: 'LOG_PRETTY',
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Redaction placeholder
|
|
32
|
+
*/
|
|
33
|
+
export const REDACTED_VALUE = '[REDACTED]';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACU,QAAA,UAAU,GAA6B;IAClD,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;CACD,CAAC;AAEX;;GAEG;AACU,QAAA,cAAc,GAA0C;IACnE,YAAY,EAAE,MAAM;IACpB,MAAM,EAAE,KAAK;IACb,WAAW,EAAE,EAAE;IACf,eAAe,EAAE,KAAK;IACtB,MAAM,EAAE,KAAK;CACL,CAAC;AAEX;;GAEG;AACU,QAAA,QAAQ,GAAG;IACtB,SAAS,EAAE,WAAW;IACtB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;CAChB,CAAC;AAEX;;GAEG;AACU,QAAA,cAAc,GAAG,YAAY,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* serverless-event-logger
|
|
3
|
+
*
|
|
4
|
+
* Lightweight, zero-dependency structured JSON logger for AWS Lambda.
|
|
5
|
+
* Optimized for observability with automatic context extraction from serverless events.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export { Logger, createLogger } from './logger';
|
|
10
|
+
export type { LogLevel, LoggerConfig, Timer, ILogger, LogEntry, ContextFields, AdditionalFields, LogOutput, NormalizedEventLike, TimestampFormat, } from './types';
|
|
11
|
+
export { LOG_LEVELS, REDACTED_VALUE } from './constants';
|
|
12
|
+
export { extractContext, generateRequestId } from './utils/extract-context';
|
|
13
|
+
export { serializeError } from './utils/format';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEhD,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,OAAO,EACP,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,mBAAmB,EACnB,eAAe,GAChB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* serverless-event-logger
|
|
3
|
+
*
|
|
4
|
+
* Lightweight, zero-dependency structured JSON logger for AWS Lambda.
|
|
5
|
+
* Optimized for observability with automatic context extraction from serverless events.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export { Logger, createLogger } from './logger';
|
|
10
|
+
export { LOG_LEVELS, REDACTED_VALUE } from './constants';
|
|
11
|
+
export { extractContext, generateRequestId } from './utils/extract-context';
|
|
12
|
+
export { serializeError } from './utils/format';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,mCAAgD;AAAvC,gGAAA,MAAM,OAAA;AAAE,sGAAA,YAAY,OAAA;AAe7B,yCAAyD;AAAhD,uGAAA,UAAU,OAAA;AAAE,2GAAA,cAAc,OAAA;AAEnC,2DAA4E;AAAnE,iHAAA,cAAc,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAC1C,yCAAgD;AAAvC,wGAAA,cAAc,OAAA"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { LoggerConfig, Timer, ILogger, NormalizedEventLike } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Logger class for structured JSON logging.
|
|
4
|
+
* Optimized for AWS Lambda and CloudWatch Insights.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Logger implements ILogger {
|
|
7
|
+
private readonly config;
|
|
8
|
+
private readonly contextData;
|
|
9
|
+
constructor(config: LoggerConfig, context?: Record<string, unknown>);
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new Logger instance with context extracted from a NormalizedEvent.
|
|
12
|
+
* The new logger includes requestId, userId, segment, path, method from the event.
|
|
13
|
+
*/
|
|
14
|
+
withContext(event: NormalizedEventLike): Logger;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a child logger with additional fixed fields.
|
|
17
|
+
* Useful for adding module-specific context.
|
|
18
|
+
*/
|
|
19
|
+
child(fields: Record<string, unknown>): Logger;
|
|
20
|
+
/**
|
|
21
|
+
* Log a debug message. Only outputs if LOG_LEVEL is 'debug'.
|
|
22
|
+
*/
|
|
23
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
24
|
+
/**
|
|
25
|
+
* Log an info message.
|
|
26
|
+
*/
|
|
27
|
+
info(message: string, data?: Record<string, unknown>): void;
|
|
28
|
+
/**
|
|
29
|
+
* Log a warning message.
|
|
30
|
+
*/
|
|
31
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
32
|
+
/**
|
|
33
|
+
* Log an error message.
|
|
34
|
+
*/
|
|
35
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
36
|
+
/**
|
|
37
|
+
* Starts a timer for measuring operation duration.
|
|
38
|
+
* Call timer.done() when the operation completes.
|
|
39
|
+
*
|
|
40
|
+
* @param label - Description of the operation being timed
|
|
41
|
+
* @returns Timer object with done() method
|
|
42
|
+
*/
|
|
43
|
+
startTimer(label: string): Timer;
|
|
44
|
+
/**
|
|
45
|
+
* Internal method to output a log entry
|
|
46
|
+
*/
|
|
47
|
+
private log;
|
|
48
|
+
/**
|
|
49
|
+
* Redacts sensitive fields from data
|
|
50
|
+
*/
|
|
51
|
+
private redact;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Factory function to create a new Logger instance.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const logger = createLogger({
|
|
59
|
+
* service: 'my-lambda',
|
|
60
|
+
* defaultLevel: 'info',
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* logger.info('Hello world', { userId: '123' });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function createLogger(config: LoggerConfig): Logger;
|
|
67
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAIZ,KAAK,EACL,OAAO,EACP,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAsBjB;;;GAGG;AACH,qBAAa,MAAO,YAAW,OAAO;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA0B;gBAE1C,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAKvE;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM;IAQ/C;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAO9C;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D;;;;;;OAMG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK;IAUhC;;OAEG;IACH,OAAO,CAAC,GAAG;IA4CX;;OAEG;IACH,OAAO,CAAC,MAAM;CAMf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEzD"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { LOG_LEVELS, DEFAULT_CONFIG, ENV_VARS } from './constants';
|
|
2
|
+
import { redactFields, getTimestamp, formatLogEntry, extractContext } from './utils';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves configuration by merging provided config with defaults and environment variables
|
|
5
|
+
*/
|
|
6
|
+
function resolveConfig(config) {
|
|
7
|
+
const envLevel = process.env[ENV_VARS.LOG_LEVEL];
|
|
8
|
+
const envSilent = process.env[ENV_VARS.LOG_SILENT] === 'true';
|
|
9
|
+
const envPretty = process.env[ENV_VARS.LOG_PRETTY] === 'true';
|
|
10
|
+
return {
|
|
11
|
+
service: config.service,
|
|
12
|
+
defaultLevel: config.defaultLevel ?? envLevel ?? DEFAULT_CONFIG.defaultLevel,
|
|
13
|
+
silent: config.silent ?? envSilent ?? DEFAULT_CONFIG.silent,
|
|
14
|
+
redactPaths: config.redactPaths ?? DEFAULT_CONFIG.redactPaths,
|
|
15
|
+
timestampFormat: config.timestampFormat ?? DEFAULT_CONFIG.timestampFormat,
|
|
16
|
+
pretty: config.pretty ?? envPretty ?? DEFAULT_CONFIG.pretty,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Logger class for structured JSON logging.
|
|
21
|
+
* Optimized for AWS Lambda and CloudWatch Insights.
|
|
22
|
+
*/
|
|
23
|
+
export class Logger {
|
|
24
|
+
constructor(config, context = {}) {
|
|
25
|
+
this.config = resolveConfig(config);
|
|
26
|
+
this.contextData = context;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new Logger instance with context extracted from a NormalizedEvent.
|
|
30
|
+
* The new logger includes requestId, userId, segment, path, method from the event.
|
|
31
|
+
*/
|
|
32
|
+
withContext(event) {
|
|
33
|
+
const eventContext = extractContext(event);
|
|
34
|
+
return new Logger(this.config, { ...this.contextData, ...eventContext });
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates a child logger with additional fixed fields.
|
|
38
|
+
* Useful for adding module-specific context.
|
|
39
|
+
*/
|
|
40
|
+
child(fields) {
|
|
41
|
+
return new Logger(this.config, { ...this.contextData, ...fields });
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Log a debug message. Only outputs if LOG_LEVEL is 'debug'.
|
|
45
|
+
*/
|
|
46
|
+
debug(message, data) {
|
|
47
|
+
this.log('debug', message, data);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Log an info message.
|
|
51
|
+
*/
|
|
52
|
+
info(message, data) {
|
|
53
|
+
this.log('info', message, data);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Log a warning message.
|
|
57
|
+
*/
|
|
58
|
+
warn(message, data) {
|
|
59
|
+
this.log('warn', message, data);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Log an error message.
|
|
63
|
+
*/
|
|
64
|
+
error(message, data) {
|
|
65
|
+
this.log('error', message, data);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Starts a timer for measuring operation duration.
|
|
69
|
+
* Call timer.done() when the operation completes.
|
|
70
|
+
*
|
|
71
|
+
* @param label - Description of the operation being timed
|
|
72
|
+
* @returns Timer object with done() method
|
|
73
|
+
*/
|
|
74
|
+
startTimer(label) {
|
|
75
|
+
const start = Date.now();
|
|
76
|
+
return {
|
|
77
|
+
done: (data) => {
|
|
78
|
+
const duration = Date.now() - start;
|
|
79
|
+
this.info(`${label} completed`, { duration, ...data });
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Internal method to output a log entry
|
|
85
|
+
*/
|
|
86
|
+
log(level, message, data) {
|
|
87
|
+
// Check if logging is disabled
|
|
88
|
+
if (this.config.silent) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Check log level threshold
|
|
92
|
+
const currentLevelPriority = LOG_LEVELS[level];
|
|
93
|
+
const configuredLevelPriority = LOG_LEVELS[this.config.defaultLevel];
|
|
94
|
+
if (currentLevelPriority === undefined || configuredLevelPriority === undefined) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (currentLevelPriority < configuredLevelPriority) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Build log entry
|
|
101
|
+
const entry = {
|
|
102
|
+
timestamp: getTimestamp(this.config.timestampFormat),
|
|
103
|
+
level,
|
|
104
|
+
message,
|
|
105
|
+
service: this.config.service,
|
|
106
|
+
...this.contextData,
|
|
107
|
+
...this.redact(data),
|
|
108
|
+
};
|
|
109
|
+
// Format output
|
|
110
|
+
const output = formatLogEntry(entry, this.config.pretty);
|
|
111
|
+
// Output to appropriate console method for CloudWatch categorization
|
|
112
|
+
switch (level) {
|
|
113
|
+
case 'error':
|
|
114
|
+
console.error(output);
|
|
115
|
+
break;
|
|
116
|
+
case 'warn':
|
|
117
|
+
console.warn(output);
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
console.log(output);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Redacts sensitive fields from data
|
|
125
|
+
*/
|
|
126
|
+
redact(data) {
|
|
127
|
+
if (!data || this.config.redactPaths.length === 0) {
|
|
128
|
+
return data ?? {};
|
|
129
|
+
}
|
|
130
|
+
return redactFields(data, this.config.redactPaths);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Factory function to create a new Logger instance.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const logger = createLogger({
|
|
139
|
+
* service: 'my-lambda',
|
|
140
|
+
* defaultLevel: 'info',
|
|
141
|
+
* });
|
|
142
|
+
*
|
|
143
|
+
* logger.info('Hello world', { userId: '123' });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export function createLogger(config) {
|
|
147
|
+
return new Logger(config);
|
|
148
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log levels supported by the logger
|
|
3
|
+
*/
|
|
4
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
5
|
+
/**
|
|
6
|
+
* Timestamp format options
|
|
7
|
+
*/
|
|
8
|
+
export type TimestampFormat = 'iso' | 'epoch';
|
|
9
|
+
/**
|
|
10
|
+
* Configuration options for creating a logger instance
|
|
11
|
+
*/
|
|
12
|
+
export interface LoggerConfig {
|
|
13
|
+
/** REQUIRED: Name of the lambda/service */
|
|
14
|
+
service: string;
|
|
15
|
+
/** Minimum log level to output. Default: 'info' */
|
|
16
|
+
defaultLevel?: LogLevel;
|
|
17
|
+
/** If true, disables all log output (useful for tests). Default: false */
|
|
18
|
+
silent?: boolean;
|
|
19
|
+
/** Array of field names to redact from logs (e.g., ['password', 'token']) */
|
|
20
|
+
redactPaths?: string[];
|
|
21
|
+
/** Timestamp format. Default: 'iso' */
|
|
22
|
+
timestampFormat?: TimestampFormat;
|
|
23
|
+
/** If true, outputs formatted JSON (useful for local development). Default: false */
|
|
24
|
+
pretty?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Internal resolved configuration (all fields required)
|
|
28
|
+
*/
|
|
29
|
+
export interface ResolvedLoggerConfig {
|
|
30
|
+
service: string;
|
|
31
|
+
defaultLevel: LogLevel;
|
|
32
|
+
silent: boolean;
|
|
33
|
+
redactPaths: string[];
|
|
34
|
+
timestampFormat: TimestampFormat;
|
|
35
|
+
pretty: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Base fields always present in log output
|
|
39
|
+
*/
|
|
40
|
+
export interface LogEntry {
|
|
41
|
+
timestamp: string | number;
|
|
42
|
+
level: LogLevel;
|
|
43
|
+
message: string;
|
|
44
|
+
service: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Context fields extracted from NormalizedEvent
|
|
48
|
+
*/
|
|
49
|
+
export interface ContextFields {
|
|
50
|
+
requestId?: string;
|
|
51
|
+
userId?: string;
|
|
52
|
+
segment?: string;
|
|
53
|
+
path?: string;
|
|
54
|
+
method?: string;
|
|
55
|
+
userAgent?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Additional fields that can be added to log entries
|
|
59
|
+
*/
|
|
60
|
+
export interface AdditionalFields {
|
|
61
|
+
[key: string]: unknown;
|
|
62
|
+
error?: string;
|
|
63
|
+
stack?: string;
|
|
64
|
+
duration?: number;
|
|
65
|
+
module?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Complete log output structure
|
|
69
|
+
*/
|
|
70
|
+
export type LogOutput = LogEntry & ContextFields & AdditionalFields;
|
|
71
|
+
/**
|
|
72
|
+
* Timer interface returned by startTimer()
|
|
73
|
+
*/
|
|
74
|
+
export interface Timer {
|
|
75
|
+
/** Call when the operation is complete */
|
|
76
|
+
done: (data?: Record<string, unknown>) => void;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Identity information from NormalizedEvent
|
|
80
|
+
*/
|
|
81
|
+
export interface EventIdentity {
|
|
82
|
+
userId?: string;
|
|
83
|
+
[key: string]: unknown;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Context from NormalizedEvent
|
|
87
|
+
*/
|
|
88
|
+
export interface EventContext {
|
|
89
|
+
requestId?: string;
|
|
90
|
+
identity?: EventIdentity;
|
|
91
|
+
segment?: string;
|
|
92
|
+
[key: string]: unknown;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Payload from NormalizedEvent
|
|
96
|
+
*/
|
|
97
|
+
export interface EventPayload {
|
|
98
|
+
httpMethod?: string;
|
|
99
|
+
path?: string;
|
|
100
|
+
headers?: Record<string, string | undefined>;
|
|
101
|
+
[key: string]: unknown;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Minimal NormalizedEvent interface for context extraction.
|
|
105
|
+
* Compatible with serverless-event-orchestrator's NormalizedEvent.
|
|
106
|
+
*/
|
|
107
|
+
export interface NormalizedEventLike {
|
|
108
|
+
context?: EventContext;
|
|
109
|
+
payload?: EventPayload;
|
|
110
|
+
[key: string]: unknown;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Logger interface defining the public API
|
|
114
|
+
*/
|
|
115
|
+
export interface ILogger {
|
|
116
|
+
/** Log a debug message */
|
|
117
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
118
|
+
/** Log an info message */
|
|
119
|
+
info(message: string, data?: Record<string, unknown>): void;
|
|
120
|
+
/** Log a warning message */
|
|
121
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
122
|
+
/** Log an error message */
|
|
123
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
124
|
+
/** Create a new logger with context extracted from a NormalizedEvent */
|
|
125
|
+
withContext(event: NormalizedEventLike): ILogger;
|
|
126
|
+
/** Create a child logger with additional fixed fields */
|
|
127
|
+
child(fields: Record<string, unknown>): ILogger;
|
|
128
|
+
/** Start a timer for measuring operation duration */
|
|
129
|
+
startTimer(label: string): Timer;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ContextFields, NormalizedEventLike } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Generates a unique request ID
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateRequestId(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Extracts logging context from a NormalizedEvent.
|
|
8
|
+
* Compatible with serverless-event-orchestrator's NormalizedEvent structure.
|
|
9
|
+
*
|
|
10
|
+
* @param event - The NormalizedEvent or similar event object
|
|
11
|
+
* @returns Context fields for logging
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractContext(event: NormalizedEventLike): ContextFields;
|
|
14
|
+
//# sourceMappingURL=extract-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-context.d.ts","sourceRoot":"","sources":["../../src/utils/extract-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEnE;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAI1C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,aAAa,CAsCxE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a unique request ID
|
|
3
|
+
*/
|
|
4
|
+
export function generateRequestId() {
|
|
5
|
+
const timestamp = Date.now().toString(36);
|
|
6
|
+
const random = Math.random().toString(36).substring(2, 11);
|
|
7
|
+
return `req_${timestamp}_${random}`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Extracts logging context from a NormalizedEvent.
|
|
11
|
+
* Compatible with serverless-event-orchestrator's NormalizedEvent structure.
|
|
12
|
+
*
|
|
13
|
+
* @param event - The NormalizedEvent or similar event object
|
|
14
|
+
* @returns Context fields for logging
|
|
15
|
+
*/
|
|
16
|
+
export function extractContext(event) {
|
|
17
|
+
const context = {};
|
|
18
|
+
// Extract requestId
|
|
19
|
+
context.requestId = event.context?.requestId || generateRequestId();
|
|
20
|
+
// Extract userId from identity
|
|
21
|
+
if (event.context?.identity?.userId) {
|
|
22
|
+
context.userId = event.context.identity.userId;
|
|
23
|
+
}
|
|
24
|
+
// Extract segment
|
|
25
|
+
if (event.context?.segment) {
|
|
26
|
+
context.segment = event.context.segment;
|
|
27
|
+
}
|
|
28
|
+
// Extract HTTP method
|
|
29
|
+
if (event.payload?.httpMethod) {
|
|
30
|
+
context.method = event.payload.httpMethod;
|
|
31
|
+
}
|
|
32
|
+
// Extract path
|
|
33
|
+
if (event.payload?.path) {
|
|
34
|
+
context.path = event.payload.path;
|
|
35
|
+
}
|
|
36
|
+
// Extract User-Agent (optional)
|
|
37
|
+
const userAgent = event.payload?.headers?.['user-agent'] ||
|
|
38
|
+
event.payload?.headers?.['User-Agent'];
|
|
39
|
+
if (userAgent) {
|
|
40
|
+
context.userAgent = userAgent;
|
|
41
|
+
}
|
|
42
|
+
// Remove undefined values
|
|
43
|
+
return Object.fromEntries(Object.entries(context).filter(([, value]) => value !== undefined));
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-context.js","sourceRoot":"","sources":["../../src/utils/extract-context.ts"],"names":[],"mappings":";;AAKA,8CAIC;AASD,wCAsCC;AAtDD;;GAEG;AACH,SAAgB,iBAAiB;IAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3D,OAAO,OAAO,SAAS,IAAI,MAAM,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,KAA0B;IACvD,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,oBAAoB;IACpB,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC,OAAO,EAAE,SAAS,IAAI,iBAAiB,EAAE,CAAC;IAEpE,+BAA+B;IAC/B,IAAI,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACpC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACjD,CAAC;IAED,kBAAkB;IAClB,IAAI,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;QAC3B,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;IAC1C,CAAC;IAED,sBAAsB;IACtB,IAAI,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC;QAC9B,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;IAC5C,CAAC;IAED,eAAe;IACf,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;IACpC,CAAC;IAED,gCAAgC;IAChC,MAAM,SAAS,GACb,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,YAAY,CAAC;QACtC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAChC,CAAC;IAED,0BAA0B;IAC1B,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAClD,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LogOutput, TimestampFormat } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Get current timestamp in the specified format
|
|
4
|
+
*/
|
|
5
|
+
export declare function getTimestamp(format: TimestampFormat): string | number;
|
|
6
|
+
/**
|
|
7
|
+
* Format a log entry as JSON string
|
|
8
|
+
*
|
|
9
|
+
* @param entry - The log entry to format
|
|
10
|
+
* @param pretty - If true, formats with indentation for readability
|
|
11
|
+
* @returns JSON string representation of the log entry
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatLogEntry(entry: LogOutput, pretty: boolean): string;
|
|
14
|
+
/**
|
|
15
|
+
* Safely serialize error objects for logging
|
|
16
|
+
*/
|
|
17
|
+
export declare function serializeError(error: unknown): Record<string, unknown>;
|
|
18
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3D;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,CAGrE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAKxE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBtE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get current timestamp in the specified format
|
|
3
|
+
*/
|
|
4
|
+
export function getTimestamp(format) {
|
|
5
|
+
const now = new Date();
|
|
6
|
+
return format === 'epoch' ? now.getTime() : now.toISOString();
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Format a log entry as JSON string
|
|
10
|
+
*
|
|
11
|
+
* @param entry - The log entry to format
|
|
12
|
+
* @param pretty - If true, formats with indentation for readability
|
|
13
|
+
* @returns JSON string representation of the log entry
|
|
14
|
+
*/
|
|
15
|
+
export function formatLogEntry(entry, pretty) {
|
|
16
|
+
if (pretty) {
|
|
17
|
+
return JSON.stringify(entry, null, 2);
|
|
18
|
+
}
|
|
19
|
+
return JSON.stringify(entry);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Safely serialize error objects for logging
|
|
23
|
+
*/
|
|
24
|
+
export function serializeError(error) {
|
|
25
|
+
if (error instanceof Error) {
|
|
26
|
+
return {
|
|
27
|
+
error: error.message,
|
|
28
|
+
stack: error.stack,
|
|
29
|
+
name: error.name,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (typeof error === 'string') {
|
|
33
|
+
return { error };
|
|
34
|
+
}
|
|
35
|
+
if (typeof error === 'object' && error !== null) {
|
|
36
|
+
return error;
|
|
37
|
+
}
|
|
38
|
+
return { error: String(error) };
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":";;AAKA,oCAGC;AASD,wCAKC;AAKD,wCAkBC;AA3CD;;GAEG;AACH,SAAgB,YAAY,CAAC,MAAuB;IAClD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,OAAO,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,KAAgB,EAAE,MAAe;IAC9D,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO;YACL,KAAK,EAAE,KAAK,CAAC,OAAO;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,KAAgC,CAAC;IAC1C,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;AAAA,mCAAwC;AAA/B,sGAAA,YAAY,OAAA;AACrB,mCAAwE;AAA/D,sGAAA,YAAY,OAAA;AAAE,wGAAA,cAAc,OAAA;AAAE,wGAAA,cAAc,OAAA;AACrD,qDAAsE;AAA7D,iHAAA,cAAc,OAAA;AAAE,oHAAA,iBAAiB,OAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively redacts sensitive fields from an object.
|
|
3
|
+
* Creates a new object without mutating the original.
|
|
4
|
+
*
|
|
5
|
+
* @param data - The object to redact
|
|
6
|
+
* @param paths - Array of field names to redact (case-insensitive matching)
|
|
7
|
+
* @returns A new object with sensitive fields replaced by '[REDACTED]'
|
|
8
|
+
*/
|
|
9
|
+
export declare function redactFields(data: Record<string, unknown>, paths: string[]): Record<string, unknown>;
|
|
10
|
+
//# sourceMappingURL=redact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/utils/redact.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,MAAM,EAAE,GACd,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { REDACTED_VALUE } from '../constants';
|
|
2
|
+
/**
|
|
3
|
+
* Recursively redacts sensitive fields from an object.
|
|
4
|
+
* Creates a new object without mutating the original.
|
|
5
|
+
*
|
|
6
|
+
* @param data - The object to redact
|
|
7
|
+
* @param paths - Array of field names to redact (case-insensitive matching)
|
|
8
|
+
* @returns A new object with sensitive fields replaced by '[REDACTED]'
|
|
9
|
+
*/
|
|
10
|
+
export function redactFields(data, paths) {
|
|
11
|
+
if (!data || typeof data !== 'object' || paths.length === 0) {
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
const lowerPaths = paths.map((p) => p.toLowerCase());
|
|
15
|
+
return redactRecursive(data, lowerPaths);
|
|
16
|
+
}
|
|
17
|
+
function redactRecursive(obj, lowerPaths) {
|
|
18
|
+
if (obj === null || obj === undefined) {
|
|
19
|
+
return obj;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(obj)) {
|
|
22
|
+
return obj.map((item) => redactRecursive(item, lowerPaths));
|
|
23
|
+
}
|
|
24
|
+
if (typeof obj !== 'object') {
|
|
25
|
+
return obj;
|
|
26
|
+
}
|
|
27
|
+
const result = {};
|
|
28
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
29
|
+
if (lowerPaths.includes(key.toLowerCase())) {
|
|
30
|
+
result[key] = REDACTED_VALUE;
|
|
31
|
+
}
|
|
32
|
+
else if (value !== null && typeof value === 'object') {
|
|
33
|
+
result[key] = redactRecursive(value, lowerPaths);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
result[key] = value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/utils/redact.ts"],"names":[],"mappings":";;AAUA,oCAWC;AArBD,4CAA8C;AAE9C;;;;;;;GAOG;AACH,SAAgB,YAAY,CAC1B,IAA6B,EAC7B,KAAe;IAEf,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAErD,OAAO,eAAe,CAAC,IAAI,EAAE,UAAU,CAA4B,CAAC;AACtE,CAAC;AAED,SAAS,eAAe,CACtB,GAAY,EACZ,UAAoB;IAEpB,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IAED,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC,EAAE,CAAC;QAC1E,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAC3C,MAAM,CAAC,GAAG,CAAC,GAAG,0BAAc,CAAC;QAC/B,CAAC;aAAM,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "serverless-event-logger",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "🚀 Lightweight, zero-dependency structured JSON logger for AWS Lambda. Optimized for observability with automatic context extraction from serverless events.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc && npm run build:esm",
|
|
20
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
21
|
+
"test": "jest",
|
|
22
|
+
"test:coverage": "jest --coverage",
|
|
23
|
+
"prepublishOnly": "npm run build && npm test",
|
|
24
|
+
"lint": "eslint src --ext .ts",
|
|
25
|
+
"clean": "rm -rf dist"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"logging",
|
|
29
|
+
"logger",
|
|
30
|
+
"lambda",
|
|
31
|
+
"aws",
|
|
32
|
+
"cloudwatch",
|
|
33
|
+
"json",
|
|
34
|
+
"structured-logging",
|
|
35
|
+
"serverless",
|
|
36
|
+
"observability"
|
|
37
|
+
],
|
|
38
|
+
"author": "MLHolding",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/mlholding/serverless-event-logger.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/mlholding/serverless-event-logger/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/mlholding/serverless-event-logger#readme",
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18.0.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/jest": "^29.5.12",
|
|
53
|
+
"@types/node": "^20.11.0",
|
|
54
|
+
"jest": "^29.7.0",
|
|
55
|
+
"ts-jest": "^29.1.2",
|
|
56
|
+
"typescript": "^5.3.3"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"serverless-event-orchestrator": "^1.2.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"serverless-event-orchestrator": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|