@designofadecade/server 4.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/CHANGELOG.md +62 -0
- package/LICENSE +21 -0
- package/README.md +297 -0
- package/dist/client/ApiClient.d.ts +121 -0
- package/dist/client/ApiClient.d.ts.map +1 -0
- package/dist/client/ApiClient.js +289 -0
- package/dist/client/ApiClient.js.map +1 -0
- package/dist/context/Context.d.ts +71 -0
- package/dist/context/Context.d.ts.map +1 -0
- package/dist/context/Context.js +81 -0
- package/dist/context/Context.js.map +1 -0
- package/dist/docs/OpenApiGenerator.d.ts +135 -0
- package/dist/docs/OpenApiGenerator.d.ts.map +1 -0
- package/dist/docs/OpenApiGenerator.js +165 -0
- package/dist/docs/OpenApiGenerator.js.map +1 -0
- package/dist/events/Events.d.ts +52 -0
- package/dist/events/Events.d.ts.map +1 -0
- package/dist/events/Events.js +70 -0
- package/dist/events/Events.js.map +1 -0
- package/dist/events/EventsManager.d.ts +46 -0
- package/dist/events/EventsManager.d.ts.map +1 -0
- package/dist/events/EventsManager.js +137 -0
- package/dist/events/EventsManager.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/local/Local.d.ts +83 -0
- package/dist/local/Local.d.ts.map +1 -0
- package/dist/local/Local.js +114 -0
- package/dist/local/Local.js.map +1 -0
- package/dist/logger/Logger.d.ts +365 -0
- package/dist/logger/Logger.d.ts.map +1 -0
- package/dist/logger/Logger.js +582 -0
- package/dist/logger/Logger.js.map +1 -0
- package/dist/middleware/RequestLogger.d.ts +62 -0
- package/dist/middleware/RequestLogger.d.ts.map +1 -0
- package/dist/middleware/RequestLogger.js +71 -0
- package/dist/middleware/RequestLogger.js.map +1 -0
- package/dist/notifications/Slack.d.ts +19 -0
- package/dist/notifications/Slack.d.ts.map +1 -0
- package/dist/notifications/Slack.js +55 -0
- package/dist/notifications/Slack.js.map +1 -0
- package/dist/router/RouteError.d.ts +21 -0
- package/dist/router/RouteError.d.ts.map +1 -0
- package/dist/router/RouteError.js +31 -0
- package/dist/router/RouteError.js.map +1 -0
- package/dist/router/Router.d.ts +66 -0
- package/dist/router/Router.d.ts.map +1 -0
- package/dist/router/Router.js +327 -0
- package/dist/router/Router.js.map +1 -0
- package/dist/router/Routes.d.ts +30 -0
- package/dist/router/Routes.d.ts.map +1 -0
- package/dist/router/Routes.js +52 -0
- package/dist/router/Routes.js.map +1 -0
- package/dist/router/StaticFileHandler.d.ts +44 -0
- package/dist/router/StaticFileHandler.d.ts.map +1 -0
- package/dist/router/StaticFileHandler.js +148 -0
- package/dist/router/StaticFileHandler.js.map +1 -0
- package/dist/sanitizer/HtmlSanitizer.d.ts +306 -0
- package/dist/sanitizer/HtmlSanitizer.d.ts.map +1 -0
- package/dist/sanitizer/HtmlSanitizer.js +808 -0
- package/dist/sanitizer/HtmlSanitizer.js.map +1 -0
- package/dist/server/Server.d.ts +28 -0
- package/dist/server/Server.d.ts.map +1 -0
- package/dist/server/Server.js +95 -0
- package/dist/server/Server.js.map +1 -0
- package/dist/state/AppState.d.ts +64 -0
- package/dist/state/AppState.d.ts.map +1 -0
- package/dist/state/AppState.js +89 -0
- package/dist/state/AppState.js.map +1 -0
- package/dist/utils/HtmlRenderer.d.ts +6 -0
- package/dist/utils/HtmlRenderer.d.ts.map +1 -0
- package/dist/utils/HtmlRenderer.js +128 -0
- package/dist/utils/HtmlRenderer.js.map +1 -0
- package/dist/websocket/WebSocketMessageFormatter.d.ts +40 -0
- package/dist/websocket/WebSocketMessageFormatter.d.ts.map +1 -0
- package/dist/websocket/WebSocketMessageFormatter.js +99 -0
- package/dist/websocket/WebSocketMessageFormatter.js.map +1 -0
- package/dist/websocket/WebSocketServer.d.ts +14 -0
- package/dist/websocket/WebSocketServer.d.ts.map +1 -0
- package/dist/websocket/WebSocketServer.js +138 -0
- package/dist/websocket/WebSocketServer.js.map +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Local.d.ts","sourceRoot":"","sources":["../../src/local/Local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAE5D,UAAU,wBAAwB;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,cAAc,EAAE;QACd,IAAI,EAAE;YACJ,MAAM,EAAE,MAAM,CAAC;YACf,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;QACF,UAAU,EAAE,OAAO,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,cAAc;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,MAAM,CAAC,iBAAiB,CACtB,aAAa,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,cAAc,CAAC,EAC9D,OAAO,GAAE,wBAA6B;uBA+D7B,eAAe,OACf,cAAc,mBACH;YACd,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACzC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACjC;;CAkBR"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local development utilities for Lambda handlers
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities to run AWS Lambda handlers locally using a Node.js server.
|
|
5
|
+
* Converts HTTP requests to Lambda event format and responses back to HTTP.
|
|
6
|
+
*
|
|
7
|
+
* @class Local
|
|
8
|
+
* @example
|
|
9
|
+
* // Wrap your Lambda handler for local development
|
|
10
|
+
* import { handler } from './lambda/handler.js';
|
|
11
|
+
* import Local from '@designofadecade/local';
|
|
12
|
+
*
|
|
13
|
+
* const localHandler = Local.LambdaProxyRouter(handler, {
|
|
14
|
+
* requestContext: { stage: 'dev' }
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Use with Node.js http server
|
|
18
|
+
* http.createServer((req, res) => {
|
|
19
|
+
* localHandler.request(req, res);
|
|
20
|
+
* }).listen(3000);
|
|
21
|
+
*/
|
|
22
|
+
import Router from '../router/Router.js';
|
|
23
|
+
import Routes from '../router/Routes.js';
|
|
24
|
+
export default class Local {
|
|
25
|
+
/**
|
|
26
|
+
* Lambda proxy router for local development
|
|
27
|
+
*
|
|
28
|
+
* Creates a router that wraps AWS Lambda handlers and allows them to be
|
|
29
|
+
* run locally with a Node.js HTTP server. Automatically converts between
|
|
30
|
+
* HTTP requests and Lambda event format.
|
|
31
|
+
*
|
|
32
|
+
* @param {Function} LambdaHandler - AWS Lambda handler function
|
|
33
|
+
* @param {Object} options - Configuration options
|
|
34
|
+
* @param {Object} options.requestContext - Additional requestContext fields for Lambda event
|
|
35
|
+
* @param {Object} options.event - Additional event fields for Lambda event
|
|
36
|
+
* @returns {Object} Object with request method for handling HTTP requests
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const handler = Local.LambdaProxyRouter(
|
|
40
|
+
* async (event) => {
|
|
41
|
+
* return {
|
|
42
|
+
* statusCode: 200,
|
|
43
|
+
* body: JSON.stringify({ message: 'Hello!' })
|
|
44
|
+
* };
|
|
45
|
+
* },
|
|
46
|
+
* { requestContext: { stage: 'local' } }
|
|
47
|
+
* );
|
|
48
|
+
*/
|
|
49
|
+
static LambdaProxyRouter(LambdaHandler, options = {}) {
|
|
50
|
+
const router = new Router({
|
|
51
|
+
initRoutes: [
|
|
52
|
+
class LocalRoutes extends Routes {
|
|
53
|
+
constructor(router) {
|
|
54
|
+
super(router);
|
|
55
|
+
this.addRoute('*', ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'], async (request) => {
|
|
56
|
+
const lambdaOptions = request.lambdaOptions || {};
|
|
57
|
+
const LambdaResponse = await LambdaHandler({
|
|
58
|
+
rawPath: request.path,
|
|
59
|
+
headers: request.headers,
|
|
60
|
+
queryStringParameters: request.query,
|
|
61
|
+
cookies: request.cookies,
|
|
62
|
+
requestContext: {
|
|
63
|
+
http: {
|
|
64
|
+
method: request.method,
|
|
65
|
+
path: request.path,
|
|
66
|
+
},
|
|
67
|
+
authorizer: request.authorizer || null,
|
|
68
|
+
...(lambdaOptions.requestContext || {}),
|
|
69
|
+
},
|
|
70
|
+
body: request.body ? JSON.stringify(request.body) : null,
|
|
71
|
+
...(lambdaOptions.event || {}),
|
|
72
|
+
});
|
|
73
|
+
let body = LambdaResponse.body || null;
|
|
74
|
+
if (LambdaResponse.headers?.['content-type']?.includes('application/json') &&
|
|
75
|
+
body) {
|
|
76
|
+
try {
|
|
77
|
+
body = JSON.parse(body);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Silently fail if body is not valid JSON
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Note: Lambda cookies are handled via Set-Cookie headers, not separate cookies property
|
|
84
|
+
return {
|
|
85
|
+
status: LambdaResponse.statusCode,
|
|
86
|
+
headers: LambdaResponse.headers,
|
|
87
|
+
body: body,
|
|
88
|
+
isBase64Encoded: LambdaResponse.isBase64Encoded || false,
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
request: (req, res, requestOptions = {}) => {
|
|
97
|
+
return router.nodeJSRequest(req, res, {
|
|
98
|
+
cors: true,
|
|
99
|
+
lambdaOptions: {
|
|
100
|
+
requestContext: {
|
|
101
|
+
...options.requestContext,
|
|
102
|
+
...requestOptions.requestContext,
|
|
103
|
+
},
|
|
104
|
+
event: {
|
|
105
|
+
...options.event,
|
|
106
|
+
...requestOptions.event,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=Local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Local.js","sourceRoot":"","sources":["../../src/local/Local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,MAAM,MAAM,qBAAqB,CAAC;AACzC,OAAO,MAAM,MAAM,qBAAqB,CAAC;AAkCzC,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,MAAM,CAAC,iBAAiB,CACtB,aAA8D,EAC9D,UAAoC,EAAE;QAEtC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;YACxB,UAAU,EAAE;gBACV,MAAM,WAAY,SAAQ,MAAM;oBAC9B,YAAY,MAAc;wBACxB,KAAK,CAAC,MAAM,CAAC,CAAC;wBAEd,IAAI,CAAC,QAAQ,CACX,GAAG,EACH,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAC5D,KAAK,EAAE,OAAsB,EAA2B,EAAE;4BACxD,MAAM,aAAa,GAChB,OAAO,CAAC,aAGP,IAAI,EAAE,CAAC;4BAEX,MAAM,cAAc,GAAmB,MAAM,aAAa,CAAC;gCACzD,OAAO,EAAE,OAAO,CAAC,IAAI;gCACrB,OAAO,EAAE,OAAO,CAAC,OAAO;gCACxB,qBAAqB,EAAE,OAAO,CAAC,KAAK;gCACpC,OAAO,EAAE,OAAO,CAAC,OAAO;gCACxB,cAAc,EAAE;oCACd,IAAI,EAAE;wCACJ,MAAM,EAAE,OAAO,CAAC,MAAM;wCACtB,IAAI,EAAE,OAAO,CAAC,IAAI;qCACnB;oCACD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI;oCACtC,GAAG,CAAC,aAAa,CAAC,cAAc,IAAI,EAAE,CAAC;iCACxC;gCACD,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;gCACxD,GAAG,CAAC,aAAa,CAAC,KAAK,IAAI,EAAE,CAAC;6BAC/B,CAAC,CAAC;4BAEH,IAAI,IAAI,GAAG,cAAc,CAAC,IAAI,IAAI,IAAI,CAAC;4BACvC,IACE,cAAc,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC;gCACtE,IAAI,EACJ,CAAC;gCACD,IAAI,CAAC;oCACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gCAC1B,CAAC;gCAAC,MAAM,CAAC;oCACP,0CAA0C;gCAC5C,CAAC;4BACH,CAAC;4BAED,yFAAyF;4BACzF,OAAO;gCACL,MAAM,EAAE,cAAc,CAAC,UAAU;gCACjC,OAAO,EAAE,cAAc,CAAC,OAAO;gCAC/B,IAAI,EAAE,IAAI;gCACV,eAAe,EAAE,cAAc,CAAC,eAAe,IAAI,KAAK;6BACzD,CAAC;wBACJ,CAAC,CACF,CAAC;oBACJ,CAAC;iBACF;aACF;SACF,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,CACP,GAAoB,EACpB,GAAmB,EACnB,iBAGI,EAAE,EACN,EAAE;gBACF,OAAO,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE;oBACpC,IAAI,EAAE,IAAI;oBACV,aAAa,EAAE;wBACb,cAAc,EAAE;4BACd,GAAG,OAAO,CAAC,cAAc;4BACzB,GAAG,cAAc,CAAC,cAAc;yBACjC;wBACD,KAAK,EAAE;4BACL,GAAG,OAAO,CAAC,KAAK;4BAChB,GAAG,cAAc,CAAC,KAAK;yBACxB;qBACF;iBACF,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logger for AWS Lambda with CloudWatch Logs
|
|
3
|
+
*
|
|
4
|
+
* @module Logger
|
|
5
|
+
* @description Provides JSON-formatted logging for better CloudWatch Insights queries
|
|
6
|
+
* with configurable log levels and structured context support. Automatically captures
|
|
7
|
+
* AWS Lambda request IDs and properly serializes Error objects.
|
|
8
|
+
*
|
|
9
|
+
* Best Practices for CloudWatch Alarms:
|
|
10
|
+
* - Add a `code` field to log entries (e.g., 'DB_CONNECTION_ERROR') for alarm filtering
|
|
11
|
+
* - Add a `source` field to track where logs originated (e.g., 'UserService.login')
|
|
12
|
+
* - Use consistent error codes across your application
|
|
13
|
+
* - Create CloudWatch metric filters based on specific codes
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* ✅ JSON-formatted logs for CloudWatch Insights
|
|
17
|
+
* ✅ Automatic error serialization (message, name, stack)
|
|
18
|
+
* ✅ AWS Lambda context (request ID, X-Ray trace ID, function name, version)
|
|
19
|
+
* ✅ Environment metadata (stage/environment tracking)
|
|
20
|
+
* ✅ Cold start detection (Lambda performance monitoring)
|
|
21
|
+
* ✅ Sensitive data redaction (passwords, tokens, API keys, etc.)
|
|
22
|
+
* ✅ Performance timing helpers (duration tracking)
|
|
23
|
+
* ✅ Error codes for alarm creation
|
|
24
|
+
* ✅ Source tracking for debugging
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* import { logger } from './Logger';
|
|
28
|
+
*
|
|
29
|
+
* logger.info('User action completed', {
|
|
30
|
+
* source: 'UserController.login',
|
|
31
|
+
* userId: '123',
|
|
32
|
+
* action: 'login'
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Error objects are automatically serialized with message, name, and stack
|
|
36
|
+
* // Use 'code' field for CloudWatch alarms
|
|
37
|
+
* try {
|
|
38
|
+
* await riskyOperation();
|
|
39
|
+
* } catch (err) {
|
|
40
|
+
* logger.error('Operation failed', {
|
|
41
|
+
* code: 'PAYMENT_PROCESSING_ERROR', // For CloudWatch alarm filtering
|
|
42
|
+
* source: 'PaymentService.processPayment', // For debugging
|
|
43
|
+
* error: err
|
|
44
|
+
* });
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* // Performance timing
|
|
48
|
+
* const timer = logger.startTimer();
|
|
49
|
+
* await expensiveOperation();
|
|
50
|
+
* timer.end('expensiveOperation', { source: 'MyService.process' });
|
|
51
|
+
*
|
|
52
|
+
* // Sensitive data is automatically redacted
|
|
53
|
+
* logger.info('User logged in', {
|
|
54
|
+
* username: 'john',
|
|
55
|
+
* password: 'secret123' // Automatically redacted as [REDACTED]
|
|
56
|
+
* });
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* Log level enumeration
|
|
60
|
+
* Lower values indicate higher priority
|
|
61
|
+
*
|
|
62
|
+
* Log Level Guidelines:
|
|
63
|
+
*
|
|
64
|
+
* ERROR (0) - Critical failures requiring immediate attention
|
|
65
|
+
* - Application crashes or unrecoverable errors
|
|
66
|
+
* - Failed database connections or critical service failures
|
|
67
|
+
* - Data corruption or loss scenarios
|
|
68
|
+
* - Security violations or authentication failures
|
|
69
|
+
* - Use when: The application cannot continue normal operation
|
|
70
|
+
*
|
|
71
|
+
* WARN (1) - Potentially harmful situations that don't stop execution
|
|
72
|
+
* - Deprecated API usage or configuration issues
|
|
73
|
+
* - Rate limiting being approached
|
|
74
|
+
* - Retryable failures (e.g., temporary network issues)
|
|
75
|
+
* - Resource constraints (low memory, disk space)
|
|
76
|
+
* - Use when: Something unexpected happened but the app can continue
|
|
77
|
+
*
|
|
78
|
+
* INFO (2) - Informational messages highlighting application progress
|
|
79
|
+
* - Application startup/shutdown events
|
|
80
|
+
* - Successful business operations (user login, order placed)
|
|
81
|
+
* - Configuration loaded successfully
|
|
82
|
+
* - API request/response summaries
|
|
83
|
+
* - Use when: Tracking normal application flow and important milestones
|
|
84
|
+
*
|
|
85
|
+
* DEBUG (3) - Detailed diagnostic information for troubleshooting
|
|
86
|
+
* - Variable values and state changes
|
|
87
|
+
* - Cache hits/misses
|
|
88
|
+
* - Detailed request/response payloads
|
|
89
|
+
* - Function entry/exit points
|
|
90
|
+
* - Use when: Debugging issues in development or production
|
|
91
|
+
*/
|
|
92
|
+
export declare enum LogLevel {
|
|
93
|
+
ERROR = 0,
|
|
94
|
+
WARN = 1,
|
|
95
|
+
INFO = 2,
|
|
96
|
+
DEBUG = 3
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* String representations of log levels
|
|
100
|
+
*/
|
|
101
|
+
export type LogLevelString = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
|
|
102
|
+
/**
|
|
103
|
+
* Context object that can be attached to log entries
|
|
104
|
+
*/
|
|
105
|
+
export type LogContext = Record<string, unknown>;
|
|
106
|
+
/**
|
|
107
|
+
* Structured logger class for AWS Lambda with CloudWatch Logs integration
|
|
108
|
+
*
|
|
109
|
+
* @class Logger
|
|
110
|
+
* @description Outputs JSON-formatted logs for optimal CloudWatch Insights querying.
|
|
111
|
+
* Log level can be configured via LOG_LEVEL environment variable.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* const logger = new Logger();
|
|
115
|
+
* logger.info('Processing started', { requestId: '12345' });
|
|
116
|
+
* logger.error('Failed to process', { error: 'Connection timeout', retries: 3 });
|
|
117
|
+
*/
|
|
118
|
+
export declare class Logger {
|
|
119
|
+
private readonly level;
|
|
120
|
+
private readonly sensitiveKeys;
|
|
121
|
+
private isColdStart;
|
|
122
|
+
private readonly maxLogSize;
|
|
123
|
+
/**
|
|
124
|
+
* Creates a new Logger instance
|
|
125
|
+
* Reads LOG_LEVEL from environment variable (defaults to INFO)
|
|
126
|
+
*/
|
|
127
|
+
constructor();
|
|
128
|
+
/**
|
|
129
|
+
* Determines if a message at the given level should be logged
|
|
130
|
+
*
|
|
131
|
+
* @param level - The log level to check
|
|
132
|
+
* @returns True if the message should be logged
|
|
133
|
+
* @private
|
|
134
|
+
*/
|
|
135
|
+
private shouldLog;
|
|
136
|
+
/**
|
|
137
|
+
* Serializes an Error object for CloudWatch
|
|
138
|
+
* Extracts message, name, and stack trace for better CloudWatch Insights queries
|
|
139
|
+
*
|
|
140
|
+
* @param error - The error to serialize
|
|
141
|
+
* @returns Serialized error object
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
144
|
+
private serializeError;
|
|
145
|
+
/**
|
|
146
|
+
* Redacts sensitive data from log context for security/compliance
|
|
147
|
+
* Handles circular references and prevents infinite recursion
|
|
148
|
+
*
|
|
149
|
+
* @param obj - The object to redact
|
|
150
|
+
* @param seen - WeakSet to track visited objects (prevents circular references)
|
|
151
|
+
* @param depth - Current recursion depth (prevents stack overflow)
|
|
152
|
+
* @returns Redacted object
|
|
153
|
+
* @private
|
|
154
|
+
*/
|
|
155
|
+
private redactSensitiveData;
|
|
156
|
+
/**
|
|
157
|
+
* Processes context to handle special types (Errors) for CloudWatch compatibility
|
|
158
|
+
*
|
|
159
|
+
* @param context - The context object to process
|
|
160
|
+
* @returns Processed context
|
|
161
|
+
* @private
|
|
162
|
+
*/
|
|
163
|
+
private processContext;
|
|
164
|
+
/**
|
|
165
|
+
* Safely stringifies an object, handling BigInt, circular refs, and other edge cases
|
|
166
|
+
*
|
|
167
|
+
* @param obj - The object to stringify
|
|
168
|
+
* @returns JSON string
|
|
169
|
+
* @private
|
|
170
|
+
*/
|
|
171
|
+
private safeStringify;
|
|
172
|
+
/**
|
|
173
|
+
* Outputs a structured log entry to stdout optimized for CloudWatch Logs
|
|
174
|
+
* Handles CloudWatch's 256KB log size limit
|
|
175
|
+
*
|
|
176
|
+
* @param level - The log level string
|
|
177
|
+
* @param message - The log message
|
|
178
|
+
* @param context - Additional context data to include in the log entry
|
|
179
|
+
* @private
|
|
180
|
+
*/
|
|
181
|
+
private log;
|
|
182
|
+
/**
|
|
183
|
+
* Logs an error message
|
|
184
|
+
*
|
|
185
|
+
* @param message - The error message
|
|
186
|
+
* @param context - Additional context data (error details, stack traces, etc.)
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* // Pass Error objects directly - they'll be serialized automatically
|
|
190
|
+
* try {
|
|
191
|
+
* await connectToDatabase();
|
|
192
|
+
* } catch (err) {
|
|
193
|
+
* logger.error('Database connection failed', {
|
|
194
|
+
* code: 'DB_CONNECTION_ERROR', // For CloudWatch alarms
|
|
195
|
+
* source: 'DatabaseService.connect', // Track where error occurred
|
|
196
|
+
* error: err, // Error object is automatically serialized
|
|
197
|
+
* database: 'users',
|
|
198
|
+
* retry: 3
|
|
199
|
+
* });
|
|
200
|
+
* }
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* // CloudWatch Alarm can filter on code field:
|
|
204
|
+
* // fields @timestamp, message, code
|
|
205
|
+
* // | filter code = "DB_CONNECTION_ERROR"
|
|
206
|
+
*/
|
|
207
|
+
error(message: string, context?: LogContext): void;
|
|
208
|
+
/**
|
|
209
|
+
* Logs a warning message
|
|
210
|
+
*
|
|
211
|
+
* @param message - The warning message
|
|
212
|
+
* @param context - Additional context data
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* logger.warn('Rate limit approaching', {
|
|
216
|
+
* code: 'RATE_LIMIT_WARNING',
|
|
217
|
+
* source: 'ApiGateway.checkRateLimit',
|
|
218
|
+
* current: 95,
|
|
219
|
+
* limit: 100,
|
|
220
|
+
* timeWindow: '1m'
|
|
221
|
+
* });
|
|
222
|
+
*/
|
|
223
|
+
warn(message: string, context?: LogContext): void;
|
|
224
|
+
/**
|
|
225
|
+
* Logs an informational message
|
|
226
|
+
*
|
|
227
|
+
* @param message - The info message
|
|
228
|
+
* @param context - Additional context data
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* logger.info('Request processed successfully', {
|
|
232
|
+
* source: 'ApiHandler.processRequest',
|
|
233
|
+
* requestId: 'req-123',
|
|
234
|
+
* duration: 245,
|
|
235
|
+
* statusCode: 200
|
|
236
|
+
* });
|
|
237
|
+
*/
|
|
238
|
+
info(message: string, context?: LogContext): void;
|
|
239
|
+
/**
|
|
240
|
+
* Logs a debug message
|
|
241
|
+
*
|
|
242
|
+
* @param message - The debug message
|
|
243
|
+
* @param context - Additional context data
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* logger.debug('Cache lookup', {
|
|
247
|
+
* key: 'user:123',
|
|
248
|
+
* hit: true,
|
|
249
|
+
* ttl: 3600
|
|
250
|
+
* });
|
|
251
|
+
*/
|
|
252
|
+
debug(message: string, context?: LogContext): void;
|
|
253
|
+
/**
|
|
254
|
+
* Gets the current log level
|
|
255
|
+
*
|
|
256
|
+
* @returns The current log level
|
|
257
|
+
*/
|
|
258
|
+
getLevel(): LogLevel;
|
|
259
|
+
/**
|
|
260
|
+
* Gets the current log level as a string
|
|
261
|
+
*
|
|
262
|
+
* @returns The current log level string
|
|
263
|
+
*/
|
|
264
|
+
getLevelString(): LogLevelString;
|
|
265
|
+
/**
|
|
266
|
+
* Logs operation performance metrics
|
|
267
|
+
* Helper method for tracking duration of operations
|
|
268
|
+
*
|
|
269
|
+
* @param operation - Name of the operation
|
|
270
|
+
* @param durationMs - Duration in milliseconds
|
|
271
|
+
* @param context - Additional context data
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* const start = Date.now();
|
|
275
|
+
* await processPayment();
|
|
276
|
+
* logger.performance('processPayment', Date.now() - start, {
|
|
277
|
+
* source: 'PaymentService.process',
|
|
278
|
+
* paymentId: '12345',
|
|
279
|
+
* amount: 99.99
|
|
280
|
+
* });
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* // CloudWatch Insights - Track slow operations:
|
|
284
|
+
* // fields @timestamp, message, duration, source
|
|
285
|
+
* // | filter duration > 1000
|
|
286
|
+
* // | sort duration desc
|
|
287
|
+
*/
|
|
288
|
+
performance(operation: string, durationMs: number, context?: LogContext): void;
|
|
289
|
+
/**
|
|
290
|
+
* Creates a performance timing wrapper
|
|
291
|
+
* Returns start function that returns end function for measuring duration
|
|
292
|
+
*
|
|
293
|
+
* @returns Object with start method that returns end method
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* const timer = logger.startTimer();
|
|
297
|
+
* await someAsyncOperation();
|
|
298
|
+
* timer.end('someAsyncOperation', { source: 'MyService.method', userId: '123' });
|
|
299
|
+
*/
|
|
300
|
+
startTimer(): {
|
|
301
|
+
/**
|
|
302
|
+
* Ends the timer and logs performance
|
|
303
|
+
* @param operation - Name of the operation
|
|
304
|
+
* @param context - Additional context
|
|
305
|
+
*/
|
|
306
|
+
end: (operation: string, context?: LogContext) => void;
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Singleton logger instance
|
|
311
|
+
* Use this for all logging throughout the application
|
|
312
|
+
*
|
|
313
|
+
* Environment Variables:
|
|
314
|
+
* - LOG_LEVEL: Set log level (ERROR, WARN, INFO, DEBUG) - defaults to INFO
|
|
315
|
+
* - ENVIRONMENT or STAGE: Environment name (dev/staging/prod) - auto-included in logs
|
|
316
|
+
* - AWS_REQUEST_ID: Lambda request ID - auto-captured
|
|
317
|
+
* - _X_AMZN_TRACE_ID: X-Ray trace ID - auto-captured
|
|
318
|
+
* - AWS_LAMBDA_FUNCTION_NAME: Function name - auto-captured
|
|
319
|
+
* - AWS_LAMBDA_FUNCTION_VERSION: Function version - auto-captured
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* import { logger } from './Logger';
|
|
323
|
+
*
|
|
324
|
+
* logger.info('Application started', { source: 'App.main' });
|
|
325
|
+
*
|
|
326
|
+
* logger.error('Failed to load config', {
|
|
327
|
+
* code: 'CONFIG_LOAD_ERROR',
|
|
328
|
+
* source: 'ConfigService.load',
|
|
329
|
+
* error: err
|
|
330
|
+
* });
|
|
331
|
+
*
|
|
332
|
+
* // Performance tracking
|
|
333
|
+
* const timer = logger.startTimer();
|
|
334
|
+
* await processData();
|
|
335
|
+
* timer.end('processData', { source: 'DataProcessor.process', recordCount: 100 });
|
|
336
|
+
*
|
|
337
|
+
* // CloudWatch Insights query examples:
|
|
338
|
+
*
|
|
339
|
+
* // Find specific error codes:
|
|
340
|
+
* // fields @timestamp, message, code, source
|
|
341
|
+
* // | filter code = "DB_CONNECTION_ERROR"
|
|
342
|
+
* // | sort @timestamp desc
|
|
343
|
+
*
|
|
344
|
+
* // Track errors by source:
|
|
345
|
+
* // fields @timestamp, message, source
|
|
346
|
+
* // | filter source like /UserService/
|
|
347
|
+
* // | stats count() by source
|
|
348
|
+
*
|
|
349
|
+
* // Monitor cold starts:
|
|
350
|
+
* // fields @timestamp, message, coldStart, duration
|
|
351
|
+
* // | filter coldStart = true
|
|
352
|
+
* // | stats count() as coldStartCount
|
|
353
|
+
*
|
|
354
|
+
* // Track slow operations:
|
|
355
|
+
* // fields @timestamp, message, duration, source
|
|
356
|
+
* // | filter duration > 1000
|
|
357
|
+
* // | sort duration desc
|
|
358
|
+
* // | limit 20
|
|
359
|
+
*/
|
|
360
|
+
export declare const logger: Logger;
|
|
361
|
+
/**
|
|
362
|
+
* Default export for convenience
|
|
363
|
+
*/
|
|
364
|
+
export default logger;
|
|
365
|
+
//# sourceMappingURL=Logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../../src/logger/Logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,oBAAY,QAAQ;IAClB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACV;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEjE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAoCjD;;;;;;;;;;;GAWG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAW;IAEjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CA0B5B;IACF,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IAErC;;;OAGG;;IAMH;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAIjB;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;;;;;;OASG;IACH,OAAO,CAAC,mBAAmB;IAsD3B;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAkBtB;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAkBrB;;;;;;;;OAQG;IACH,OAAO,CAAC,GAAG;IA+EX;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAMlD;;;;;;;;;;;;;;OAcG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAMjD;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAMjD;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAMlD;;;;OAIG;IACH,QAAQ,IAAI,QAAQ;IAIpB;;;;OAIG;IACH,cAAc,IAAI,cAAc;IAKhC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAO9E;;;;;;;;;;OAUG;IACH,UAAU;QAGN;;;;WAIG;yBACc,MAAM,YAAY,UAAU;;CAKlD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,eAAO,MAAM,MAAM,QAAe,CAAC;AAEnC;;GAEG;AACH,eAAe,MAAM,CAAC"}
|