unnbound-logger-sdk 1.1.5 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/index.d.ts +2 -30
- package/dist/index.js +3 -19
- package/dist/types.d.ts +1 -0
- package/dist/unnbound-logger.d.ts +8 -0
- package/dist/unnbound-logger.js +91 -33
- package/dist/utils/http-status-messages.d.ts +9 -0
- package/dist/utils/http-status-messages.js +55 -0
- package/dist/utils/logger-utils.d.ts +14 -1
- package/dist/utils/logger-utils.js +36 -3
- package/dist/utils/with-trace.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,6 +53,7 @@ interface Log<T extends LogType = 'general'> {
|
|
|
53
53
|
message: string;
|
|
54
54
|
traceId: string;
|
|
55
55
|
requestId: string;
|
|
56
|
+
deploymentId: string; // Automatically populated from DEPLOYMENT_ID environment variable
|
|
56
57
|
error?: SerializableError; // Only present for Error objects
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -61,6 +62,25 @@ interface LogTransaction<T extends LogType> extends Log<T> {
|
|
|
61
62
|
}
|
|
62
63
|
```
|
|
63
64
|
|
|
65
|
+
## Deployment Tracking
|
|
66
|
+
|
|
67
|
+
The logger automatically includes a `deploymentId` field in all log entries. This field is populated from the `DEPLOYMENT_ID` environment variable, allowing you to track logs across different deployments of your application.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Set the deployment ID in your environment
|
|
71
|
+
export DEPLOYMENT_ID="v1.2.3-prod-20231201"
|
|
72
|
+
|
|
73
|
+
# Or in your deployment configuration
|
|
74
|
+
DEPLOYMENT_ID=v1.2.3-prod-20231201
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If the `DEPLOYMENT_ID` environment variable is not set, the `deploymentId` field will be an empty string. This field helps with:
|
|
78
|
+
|
|
79
|
+
- Tracking logs across different application deployments
|
|
80
|
+
- Correlating issues with specific releases
|
|
81
|
+
- Monitoring deployment health and performance
|
|
82
|
+
- Debugging problems in specific deployment versions
|
|
83
|
+
|
|
64
84
|
## HTTP Request/Response Logging
|
|
65
85
|
|
|
66
86
|
```typescript
|
package/dist/index.d.ts
CHANGED
|
@@ -6,33 +6,5 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { UnnboundLogger } from './unnbound-logger';
|
|
8
8
|
import { LogLevel, LogType, HttpMethod, LoggerOptions, GeneralLogOptions, HttpRequestLogOptions, HttpResponseLogOptions, SftpTransactionLogOptions, DbQueryTransactionLogOptions, Log, LogTransaction, HttpRequestLog, HttpResponseLog, SftpTransactionLog, DbQueryTransactionLog, SerializableError } from './types';
|
|
9
|
-
import {
|
|
10
|
-
export { UnnboundLogger, LogLevel, LogType, HttpMethod, LoggerOptions, GeneralLogOptions, HttpRequestLogOptions, HttpResponseLogOptions, SftpTransactionLogOptions, DbQueryTransactionLogOptions, Log, LogTransaction, HttpRequestLog, HttpResponseLog, SftpTransactionLog, DbQueryTransactionLog, SerializableError,
|
|
11
|
-
declare const defaultLogger: UnnboundLogger;
|
|
12
|
-
export { defaultLogger };
|
|
13
|
-
export declare const log: (level: LogLevel, message: string | Error | Record<string, unknown>, options?: GeneralLogOptions) => void;
|
|
14
|
-
export declare const error: (message: string | Error | Record<string, unknown>, options?: GeneralLogOptions) => void;
|
|
15
|
-
export declare const warn: (message: string | Error | Record<string, unknown>, options?: GeneralLogOptions) => void;
|
|
16
|
-
export declare const info: (message: string | Error | Record<string, unknown>, options?: GeneralLogOptions) => void;
|
|
17
|
-
export declare const debug: (message: string | Error | Record<string, unknown>, options?: GeneralLogOptions) => void;
|
|
18
|
-
export declare const httpRequest: (req: import("express").Request, options?: HttpRequestLogOptions) => string;
|
|
19
|
-
export declare const httpResponse: (res: import("express").Response, req: import("express").Request, options?: HttpResponseLogOptions) => void;
|
|
20
|
-
export declare const sftpTransaction: (operation: {
|
|
21
|
-
host: string;
|
|
22
|
-
username: string;
|
|
23
|
-
operation: "upload" | "download" | "list" | "delete" | "rename" | "stat";
|
|
24
|
-
path: string;
|
|
25
|
-
status: "success" | "failure";
|
|
26
|
-
bytesTransferred?: number;
|
|
27
|
-
filesListed?: number;
|
|
28
|
-
sourcePath?: string;
|
|
29
|
-
}, options?: SftpTransactionLogOptions) => void;
|
|
30
|
-
export declare const dbQueryTransaction: (query: {
|
|
31
|
-
instance: string;
|
|
32
|
-
vendor: "postgres" | "mysql" | "mssql" | "mongodb";
|
|
33
|
-
query?: string;
|
|
34
|
-
status: "success" | "failure";
|
|
35
|
-
rowsReturned?: number;
|
|
36
|
-
rowsAffected?: number;
|
|
37
|
-
}, options?: DbQueryTransactionLogOptions) => void;
|
|
38
|
-
export default UnnboundLogger;
|
|
9
|
+
import { clearTraceId } from './utils/logger-utils';
|
|
10
|
+
export { UnnboundLogger, LogLevel, LogType, HttpMethod, LoggerOptions, GeneralLogOptions, HttpRequestLogOptions, HttpResponseLogOptions, SftpTransactionLogOptions, DbQueryTransactionLogOptions, Log, LogTransaction, HttpRequestLog, HttpResponseLog, SftpTransactionLog, DbQueryTransactionLog, SerializableError, clearTraceId, };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.clearTraceId = exports.UnnboundLogger = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* unnbound-logger
|
|
6
6
|
*
|
|
@@ -9,21 +9,5 @@ exports.dbQueryTransaction = exports.sftpTransaction = exports.httpResponse = ex
|
|
|
9
9
|
*/
|
|
10
10
|
const unnbound_logger_1 = require("./unnbound-logger");
|
|
11
11
|
Object.defineProperty(exports, "UnnboundLogger", { enumerable: true, get: function () { return unnbound_logger_1.UnnboundLogger; } });
|
|
12
|
-
const
|
|
13
|
-
Object.defineProperty(exports, "
|
|
14
|
-
Object.defineProperty(exports, "clearTraceId", { enumerable: true, get: function () { return id_generator_1.clearTraceId; } });
|
|
15
|
-
// Create a default logger instance
|
|
16
|
-
const defaultLogger = new unnbound_logger_1.UnnboundLogger();
|
|
17
|
-
exports.defaultLogger = defaultLogger;
|
|
18
|
-
// Export default logger functions for convenience
|
|
19
|
-
exports.log = defaultLogger.log.bind(defaultLogger);
|
|
20
|
-
exports.error = defaultLogger.error.bind(defaultLogger);
|
|
21
|
-
exports.warn = defaultLogger.warn.bind(defaultLogger);
|
|
22
|
-
exports.info = defaultLogger.info.bind(defaultLogger);
|
|
23
|
-
exports.debug = defaultLogger.debug.bind(defaultLogger);
|
|
24
|
-
exports.httpRequest = defaultLogger.httpRequest.bind(defaultLogger);
|
|
25
|
-
exports.httpResponse = defaultLogger.httpResponse.bind(defaultLogger);
|
|
26
|
-
exports.sftpTransaction = defaultLogger.sftpTransaction.bind(defaultLogger);
|
|
27
|
-
exports.dbQueryTransaction = defaultLogger.dbQueryTransaction.bind(defaultLogger);
|
|
28
|
-
// Default export is the UnnboundLogger class
|
|
29
|
-
exports.default = unnbound_logger_1.UnnboundLogger;
|
|
12
|
+
const logger_utils_1 = require("./utils/logger-utils");
|
|
13
|
+
Object.defineProperty(exports, "clearTraceId", { enumerable: true, get: function () { return logger_utils_1.clearTraceId; } });
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ declare module 'axios' {
|
|
|
5
5
|
interface InternalAxiosRequestConfig {
|
|
6
6
|
metadata?: {
|
|
7
7
|
startTime: number;
|
|
8
|
+
requestId?: string;
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
11
|
}
|
|
@@ -16,6 +17,7 @@ export declare class UnnboundLogger {
|
|
|
16
17
|
private defaultLevel;
|
|
17
18
|
private serviceName?;
|
|
18
19
|
private environment?;
|
|
20
|
+
private deploymentId;
|
|
19
21
|
private traceHeaderKey;
|
|
20
22
|
private ignoreTraceRoutes;
|
|
21
23
|
private ignoreAxiosTraceRoutes;
|
|
@@ -62,6 +64,12 @@ export declare class UnnboundLogger {
|
|
|
62
64
|
* @param options - Additional logging options
|
|
63
65
|
*/
|
|
64
66
|
debug(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
|
|
67
|
+
/**
|
|
68
|
+
* Constructs the full URL from request information
|
|
69
|
+
* @param req - Express request object
|
|
70
|
+
* @returns Full URL string
|
|
71
|
+
*/
|
|
72
|
+
private constructFullUrl;
|
|
65
73
|
/**
|
|
66
74
|
* Logs an HTTP request
|
|
67
75
|
* @param req - Express request object
|
package/dist/unnbound-logger.js
CHANGED
|
@@ -8,11 +8,11 @@ exports.UnnboundLogger = void 0;
|
|
|
8
8
|
* Core logger implementation
|
|
9
9
|
*/
|
|
10
10
|
const pino_1 = __importDefault(require("pino"));
|
|
11
|
-
const id_generator_1 = require("./utils/id-generator");
|
|
12
11
|
const logger_utils_1 = require("./utils/logger-utils");
|
|
13
12
|
const uuid_1 = require("uuid");
|
|
14
13
|
const trace_context_1 = require("./utils/trace-context");
|
|
15
14
|
const axios_1 = require("axios");
|
|
15
|
+
const http_status_messages_1 = require("./utils/http-status-messages");
|
|
16
16
|
/**
|
|
17
17
|
* UnnboundLogger provides typed, structured logging using Pino
|
|
18
18
|
*/
|
|
@@ -59,8 +59,10 @@ class UnnboundLogger {
|
|
|
59
59
|
headers.set(this.traceHeaderKey, traceId);
|
|
60
60
|
config.headers = headers;
|
|
61
61
|
}
|
|
62
|
-
// Store request start time for duration calculation
|
|
63
|
-
|
|
62
|
+
// Store request start time and generate requestId for duration calculation and correlation
|
|
63
|
+
const startTime = Date.now();
|
|
64
|
+
const requestId = (0, uuid_1.v4)();
|
|
65
|
+
config.metadata = { startTime, requestId };
|
|
64
66
|
// Log the outgoing request using proper httpRequest method
|
|
65
67
|
const mockReq = {
|
|
66
68
|
method: config.method?.toUpperCase() || 'UNKNOWN',
|
|
@@ -68,11 +70,15 @@ class UnnboundLogger {
|
|
|
68
70
|
originalUrl: `${config.baseURL || ''}${config.url}`,
|
|
69
71
|
headers: config.headers || {},
|
|
70
72
|
body: config.data,
|
|
71
|
-
ip: 'outgoing' // Mark as outgoing request
|
|
73
|
+
ip: 'outgoing', // Mark as outgoing request
|
|
74
|
+
protocol: 'https', // Default for outgoing
|
|
75
|
+
secure: true,
|
|
76
|
+
get: () => undefined // Mock get method for constructFullUrl
|
|
72
77
|
};
|
|
73
78
|
this.httpRequest(mockReq, {
|
|
74
79
|
traceId,
|
|
75
|
-
|
|
80
|
+
requestId,
|
|
81
|
+
startTime
|
|
76
82
|
});
|
|
77
83
|
return config;
|
|
78
84
|
},
|
|
@@ -85,24 +91,30 @@ class UnnboundLogger {
|
|
|
85
91
|
onFulfilled: (response) => {
|
|
86
92
|
// Calculate duration
|
|
87
93
|
const startTime = response.config.metadata?.startTime || Date.now();
|
|
94
|
+
const requestId = response.config.metadata?.requestId;
|
|
88
95
|
const duration = Date.now() - startTime;
|
|
89
96
|
// Log the successful response using proper httpResponse method
|
|
90
97
|
const mockReq = {
|
|
91
98
|
method: response.config.method?.toUpperCase() || 'UNKNOWN',
|
|
92
99
|
url: `${response.config.baseURL || ''}${response.config.url}`,
|
|
93
100
|
originalUrl: `${response.config.baseURL || ''}${response.config.url}`,
|
|
94
|
-
ip: 'outgoing' // Mark as outgoing request
|
|
101
|
+
ip: 'outgoing', // Mark as outgoing request
|
|
102
|
+
protocol: 'https', // Default for outgoing
|
|
103
|
+
secure: true,
|
|
104
|
+
get: () => undefined // Mock get method for constructFullUrl
|
|
95
105
|
};
|
|
96
106
|
const mockRes = {
|
|
97
107
|
statusCode: response.status,
|
|
98
108
|
locals: {
|
|
99
109
|
body: response.data,
|
|
100
110
|
startTime: startTime,
|
|
101
|
-
traceId: trace_context_1.traceContext.getTraceId()
|
|
111
|
+
traceId: trace_context_1.traceContext.getTraceId(),
|
|
112
|
+
requestId: requestId
|
|
102
113
|
},
|
|
103
114
|
getHeaders: () => response.headers || {}
|
|
104
115
|
};
|
|
105
116
|
this.httpResponse(mockRes, mockReq, {
|
|
117
|
+
requestId,
|
|
106
118
|
duration,
|
|
107
119
|
traceId: trace_context_1.traceContext.getTraceId()
|
|
108
120
|
});
|
|
@@ -111,6 +123,7 @@ class UnnboundLogger {
|
|
|
111
123
|
onRejected: (error) => {
|
|
112
124
|
// Calculate duration for error responses
|
|
113
125
|
const startTime = error.config?.metadata?.startTime || Date.now();
|
|
126
|
+
const requestId = error.config?.metadata?.requestId;
|
|
114
127
|
const duration = Date.now() - startTime;
|
|
115
128
|
// Log the error response using proper httpResponse method
|
|
116
129
|
if (error.response) {
|
|
@@ -118,27 +131,38 @@ class UnnboundLogger {
|
|
|
118
131
|
method: error.config?.method?.toUpperCase() || 'UNKNOWN',
|
|
119
132
|
url: `${error.config?.baseURL || ''}${error.config?.url}`,
|
|
120
133
|
originalUrl: `${error.config?.baseURL || ''}${error.config?.url}`,
|
|
121
|
-
ip: 'outgoing' // Mark as outgoing request
|
|
134
|
+
ip: 'outgoing', // Mark as outgoing request
|
|
135
|
+
protocol: 'https', // Default for outgoing
|
|
136
|
+
secure: true,
|
|
137
|
+
get: () => undefined // Mock get method for constructFullUrl
|
|
122
138
|
};
|
|
123
139
|
const mockRes = {
|
|
124
140
|
statusCode: error.response.status,
|
|
125
141
|
locals: {
|
|
126
142
|
body: error.response.data,
|
|
127
143
|
startTime: startTime,
|
|
128
|
-
traceId: trace_context_1.traceContext.getTraceId()
|
|
144
|
+
traceId: trace_context_1.traceContext.getTraceId(),
|
|
145
|
+
requestId: requestId
|
|
129
146
|
},
|
|
130
147
|
getHeaders: () => error.response.headers || {}
|
|
131
148
|
};
|
|
132
149
|
this.httpResponse(mockRes, mockReq, {
|
|
150
|
+
requestId,
|
|
133
151
|
duration,
|
|
134
152
|
traceId: trace_context_1.traceContext.getTraceId()
|
|
135
153
|
});
|
|
136
154
|
}
|
|
137
155
|
else {
|
|
138
156
|
// For network errors without response, log as general error
|
|
139
|
-
this.error(
|
|
140
|
-
context:
|
|
141
|
-
|
|
157
|
+
this.error('HTTP Request Failed', {
|
|
158
|
+
context: {
|
|
159
|
+
reason: 'No response received',
|
|
160
|
+
method: error.config?.method?.toUpperCase() || 'UNKNOWN',
|
|
161
|
+
url: `${error.config?.baseURL || ''}${error.config?.url}`,
|
|
162
|
+
},
|
|
163
|
+
error: error.message,
|
|
164
|
+
requestId,
|
|
165
|
+
traceId: trace_context_1.traceContext.getTraceId()
|
|
142
166
|
});
|
|
143
167
|
}
|
|
144
168
|
return Promise.reject(error);
|
|
@@ -147,6 +171,7 @@ class UnnboundLogger {
|
|
|
147
171
|
this.defaultLevel = options.defaultLevel || 'info';
|
|
148
172
|
this.serviceName = options.serviceName;
|
|
149
173
|
this.environment = options.environment;
|
|
174
|
+
this.deploymentId = process.env.DEPLOYMENT_ID || '';
|
|
150
175
|
this.traceHeaderKey = options.traceHeaderKey || 'unnbound-trace-id';
|
|
151
176
|
this.ignoreTraceRoutes = options.ignoreTraceRoutes || [];
|
|
152
177
|
this.ignoreAxiosTraceRoutes = options.ignoreAxiosTraceRoutes || [];
|
|
@@ -157,7 +182,7 @@ class UnnboundLogger {
|
|
|
157
182
|
...(this.serviceName && { service: this.serviceName }),
|
|
158
183
|
...(this.environment && { environment: this.environment }),
|
|
159
184
|
},
|
|
160
|
-
timestamp:
|
|
185
|
+
timestamp: false, // Let CloudWatch handle timestamps
|
|
161
186
|
formatters: {
|
|
162
187
|
level: (label) => {
|
|
163
188
|
return { level: label };
|
|
@@ -189,39 +214,46 @@ class UnnboundLogger {
|
|
|
189
214
|
* @param options - Additional logging options
|
|
190
215
|
*/
|
|
191
216
|
log(level, message, options = {}) {
|
|
192
|
-
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0,
|
|
193
|
-
const requestId = options.requestId || (0,
|
|
217
|
+
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
|
|
218
|
+
const requestId = options.requestId || (0, uuid_1.v4)();
|
|
194
219
|
let logEntry;
|
|
195
|
-
|
|
220
|
+
const { traceId: optionTraceId, requestId: optionRequestId, ...restOptions } = options;
|
|
196
221
|
if (message instanceof Error) {
|
|
197
|
-
error = {
|
|
222
|
+
const error = {
|
|
198
223
|
name: message.name,
|
|
199
224
|
message: message.message,
|
|
200
225
|
stack: message.stack,
|
|
201
226
|
};
|
|
202
227
|
logEntry = {
|
|
203
228
|
type: 'general',
|
|
204
|
-
message: message.message,
|
|
205
229
|
traceId,
|
|
206
230
|
requestId,
|
|
231
|
+
deploymentId: this.deploymentId,
|
|
232
|
+
message: message.name,
|
|
207
233
|
error,
|
|
234
|
+
...restOptions,
|
|
208
235
|
};
|
|
209
236
|
}
|
|
210
237
|
else if (typeof message === 'string') {
|
|
211
238
|
logEntry = {
|
|
212
239
|
type: 'general',
|
|
213
|
-
message,
|
|
214
240
|
traceId,
|
|
215
241
|
requestId,
|
|
242
|
+
deploymentId: this.deploymentId,
|
|
243
|
+
message,
|
|
244
|
+
...restOptions,
|
|
216
245
|
};
|
|
217
246
|
}
|
|
218
247
|
else {
|
|
219
|
-
// If message is an object,
|
|
248
|
+
// If message is an object, it's part of the log entry
|
|
220
249
|
logEntry = {
|
|
221
250
|
type: 'general',
|
|
222
|
-
message: JSON.stringify(message),
|
|
223
251
|
traceId,
|
|
224
252
|
requestId,
|
|
253
|
+
deploymentId: this.deploymentId,
|
|
254
|
+
...message,
|
|
255
|
+
message: message.message || 'Structured log data',
|
|
256
|
+
...restOptions,
|
|
225
257
|
};
|
|
226
258
|
}
|
|
227
259
|
this.logger[level](logEntry);
|
|
@@ -258,6 +290,28 @@ class UnnboundLogger {
|
|
|
258
290
|
debug(message, options = {}) {
|
|
259
291
|
this.log('debug', message, options);
|
|
260
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* Constructs the full URL from request information
|
|
295
|
+
* @param req - Express request object
|
|
296
|
+
* @returns Full URL string
|
|
297
|
+
*/
|
|
298
|
+
constructFullUrl(req) {
|
|
299
|
+
// If the URL is already absolute, return it directly
|
|
300
|
+
const reqUrl = req.originalUrl || req.url;
|
|
301
|
+
if (reqUrl?.startsWith('http://') || reqUrl?.startsWith('https://')) {
|
|
302
|
+
return reqUrl;
|
|
303
|
+
}
|
|
304
|
+
// Check if we have a base URL configured via environment variable
|
|
305
|
+
const serviceBaseUrl = process.env.SERVICE_BASE_URL;
|
|
306
|
+
if (serviceBaseUrl) {
|
|
307
|
+
// Use configured base URL (useful for ECS when you know your service URL)
|
|
308
|
+
return `${serviceBaseUrl.replace(/\/$/, '')}${reqUrl}`;
|
|
309
|
+
}
|
|
310
|
+
// Fallback to constructing from request info for incoming requests
|
|
311
|
+
const protocol = req.protocol || (req.secure ? 'https' : 'http');
|
|
312
|
+
const host = req.get('host') || req.get('x-forwarded-host') || 'localhost';
|
|
313
|
+
return `${protocol}://${host}${reqUrl}`;
|
|
314
|
+
}
|
|
261
315
|
/**
|
|
262
316
|
* Logs an HTTP request
|
|
263
317
|
* @param req - Express request object
|
|
@@ -265,8 +319,8 @@ class UnnboundLogger {
|
|
|
265
319
|
* @returns The request ID for correlating with the response
|
|
266
320
|
*/
|
|
267
321
|
httpRequest(req, options = {}) {
|
|
268
|
-
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0,
|
|
269
|
-
const requestId = options.requestId || (0,
|
|
322
|
+
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
|
|
323
|
+
const requestId = options.requestId || (0, uuid_1.v4)();
|
|
270
324
|
const startTime = options.startTime || Date.now();
|
|
271
325
|
// Store request metadata in res.locals for later use
|
|
272
326
|
if (req.res) {
|
|
@@ -276,12 +330,13 @@ class UnnboundLogger {
|
|
|
276
330
|
}
|
|
277
331
|
const logEntry = {
|
|
278
332
|
type: 'httpRequest',
|
|
279
|
-
message:
|
|
333
|
+
message: req.ip === 'outgoing' ? 'Outgoing HTTP Request' : 'Incoming HTTP Request',
|
|
280
334
|
traceId,
|
|
281
335
|
requestId,
|
|
336
|
+
deploymentId: this.deploymentId,
|
|
282
337
|
duration: 0, // Will be updated in response
|
|
283
338
|
httpRequest: {
|
|
284
|
-
url:
|
|
339
|
+
url: this.constructFullUrl(req),
|
|
285
340
|
method: req.method,
|
|
286
341
|
headers: (0, logger_utils_1.filterHeaders)(req.headers),
|
|
287
342
|
ip: (0, logger_utils_1.normalizeIp)(req.ip),
|
|
@@ -298,9 +353,9 @@ class UnnboundLogger {
|
|
|
298
353
|
* @param options - Additional logging options
|
|
299
354
|
*/
|
|
300
355
|
httpResponse(res, req, options = {}) {
|
|
301
|
-
const requestId = res.locals.requestId || options.requestId || (0,
|
|
356
|
+
const requestId = res.locals.requestId || options.requestId || (0, uuid_1.v4)();
|
|
302
357
|
const startTime = res.locals.startTime || options.startTime || Date.now();
|
|
303
|
-
const traceId = res.locals.traceId || options.traceId || trace_context_1.traceContext.getTraceId() || (0,
|
|
358
|
+
const traceId = res.locals.traceId || options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
|
|
304
359
|
const duration = options.duration || (Date.now() - startTime);
|
|
305
360
|
// Determine log level based on status code
|
|
306
361
|
let level = options.level || this.defaultLevel;
|
|
@@ -317,12 +372,13 @@ class UnnboundLogger {
|
|
|
317
372
|
}
|
|
318
373
|
const logEntry = {
|
|
319
374
|
type: 'httpResponse',
|
|
320
|
-
message:
|
|
375
|
+
message: (0, http_status_messages_1.getStatusMessage)(res.statusCode),
|
|
321
376
|
traceId,
|
|
322
377
|
requestId,
|
|
378
|
+
deploymentId: this.deploymentId,
|
|
323
379
|
duration,
|
|
324
380
|
httpResponse: {
|
|
325
|
-
url:
|
|
381
|
+
url: this.constructFullUrl(req),
|
|
326
382
|
method: req.method,
|
|
327
383
|
headers: (0, logger_utils_1.filterHeaders)(res.getHeaders()),
|
|
328
384
|
ip: (0, logger_utils_1.normalizeIp)(req.ip),
|
|
@@ -338,8 +394,8 @@ class UnnboundLogger {
|
|
|
338
394
|
* @param options - Additional logging options
|
|
339
395
|
*/
|
|
340
396
|
sftpTransaction(operation, options = {}) {
|
|
341
|
-
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0,
|
|
342
|
-
const requestId = options.requestId || (0,
|
|
397
|
+
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
|
|
398
|
+
const requestId = options.requestId || (0, uuid_1.v4)();
|
|
343
399
|
const duration = options.duration || (options.startTime ? Date.now() - options.startTime : 0);
|
|
344
400
|
const level = operation.status === 'success' ? 'info' : 'error';
|
|
345
401
|
const logEntry = {
|
|
@@ -347,6 +403,7 @@ class UnnboundLogger {
|
|
|
347
403
|
message: `SFTP ${operation.operation} ${operation.status} - ${operation.path}`,
|
|
348
404
|
traceId,
|
|
349
405
|
requestId,
|
|
406
|
+
deploymentId: this.deploymentId,
|
|
350
407
|
duration,
|
|
351
408
|
sftp: operation,
|
|
352
409
|
};
|
|
@@ -358,8 +415,8 @@ class UnnboundLogger {
|
|
|
358
415
|
* @param options - Additional logging options
|
|
359
416
|
*/
|
|
360
417
|
dbQueryTransaction(query, options = {}) {
|
|
361
|
-
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0,
|
|
362
|
-
const requestId = options.requestId || (0,
|
|
418
|
+
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
|
|
419
|
+
const requestId = options.requestId || (0, uuid_1.v4)();
|
|
363
420
|
const duration = options.duration || (options.startTime ? Date.now() - options.startTime : 0);
|
|
364
421
|
const level = query.status === 'success' ? 'info' : 'error';
|
|
365
422
|
const logEntry = {
|
|
@@ -367,6 +424,7 @@ class UnnboundLogger {
|
|
|
367
424
|
message: `DB Query ${query.status} - ${query.vendor}`,
|
|
368
425
|
traceId,
|
|
369
426
|
requestId,
|
|
427
|
+
deploymentId: this.deploymentId,
|
|
370
428
|
duration,
|
|
371
429
|
db: query,
|
|
372
430
|
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.httpStatusDetails = void 0;
|
|
4
|
+
exports.getStatusMessage = getStatusMessage;
|
|
5
|
+
exports.httpStatusDetails = {
|
|
6
|
+
100: { message: 'Continue', description: 'The server has received the request headers, and the client should proceed to send the request body' },
|
|
7
|
+
101: { message: 'Switching Protocols', description: 'The requester has asked the server to switch protocols' },
|
|
8
|
+
103: { message: 'Early Hints', description: 'Used with the Link header to allow the browser to start preloading resources while the server prepares a response' },
|
|
9
|
+
200: { message: 'OK', description: 'The request is OK' },
|
|
10
|
+
201: { message: 'Created', description: 'The request has been fulfilled, and a new resource is created' },
|
|
11
|
+
202: { message: 'Accepted', description: 'The request has been accepted for processing, but the processing has not been completed' },
|
|
12
|
+
203: { message: 'Non-Authoritative Information', description: 'The request has been successfully processed, but is returning information that may be from another source' },
|
|
13
|
+
204: { message: 'No Content', description: 'The request has been successfully processed, but is not returning any content' },
|
|
14
|
+
205: { message: 'Reset Content', description: 'The request has been successfully processed, but is not returning any content, and requires that the requester reset the document view' },
|
|
15
|
+
206: { message: 'Partial Content', description: 'The server is delivering only part of the resource due to a range header sent by the client' },
|
|
16
|
+
300: { message: 'Multiple Choices', description: 'A link list. The user can select a link and go to that location. Maximum five addresses' },
|
|
17
|
+
301: { message: 'Moved Permanently', description: 'The requested page has moved to a new URL' },
|
|
18
|
+
302: { message: 'Found', description: 'The requested page has moved temporarily to a new URL' },
|
|
19
|
+
303: { message: 'See Other', description: 'The requested page can be found under a different URL' },
|
|
20
|
+
304: { message: 'Not Modified', description: 'Indicates the requested page has not been modified since last requested' },
|
|
21
|
+
307: { message: 'Temporary Redirect', description: 'The requested page has moved temporarily to a new URL' },
|
|
22
|
+
308: { message: 'Permanent Redirect', description: 'The requested page has moved permanently to a new URL' },
|
|
23
|
+
400: { message: 'Bad Request', description: 'The request cannot be fulfilled due to bad syntax' },
|
|
24
|
+
401: { message: 'Unauthorized', description: 'The request was a legal request, but the server is refusing to respond to it. For use when authentication is possible but has failed or not yet been provided' },
|
|
25
|
+
402: { message: 'Payment Required', description: 'Reserved for future use' },
|
|
26
|
+
403: { message: 'Forbidden', description: 'The request was a legal request, but the server is refusing to respond to it' },
|
|
27
|
+
404: { message: 'Not Found', description: 'The requested page could not be found but may be available again in the future' },
|
|
28
|
+
405: { message: 'Method Not Allowed', description: 'A request was made of a page using a request method not supported by that page' },
|
|
29
|
+
406: { message: 'Not Acceptable', description: 'The server can only generate a response that is not accepted by the client' },
|
|
30
|
+
407: { message: 'Proxy Authentication Required', description: 'The client must first authenticate itself with the proxy' },
|
|
31
|
+
408: { message: 'Request Timeout', description: 'The server timed out waiting for the request' },
|
|
32
|
+
409: { message: 'Conflict', description: 'The request could not be completed because of a conflict in the request' },
|
|
33
|
+
410: { message: 'Gone', description: 'The requested page is no longer available' },
|
|
34
|
+
411: { message: 'Length Required', description: 'The "Content-Length" is not defined. The server will not accept the request without it' },
|
|
35
|
+
412: { message: 'Precondition Failed', description: 'The precondition given in the request evaluated to false by the server' },
|
|
36
|
+
413: { message: 'Request Too Large', description: 'The server will not accept the request, because the request entity is too large' },
|
|
37
|
+
414: { message: 'Request-URI Too Long', description: 'The server will not accept the request, because the URI is too long. Occurs when you convert a POST request to a GET request with a long query information' },
|
|
38
|
+
415: { message: 'Unsupported Media Type', description: 'The server will not accept the request, because the media type is not supported' },
|
|
39
|
+
416: { message: 'Range Not Satisfiable', description: 'The client has asked for a portion of the file, but the server cannot supply that portion' },
|
|
40
|
+
417: { message: 'Expectation Failed', description: 'The server cannot meet the requirements of the Expect request-header field' },
|
|
41
|
+
500: { message: 'Internal Server Error', description: 'A generic error message, given when no more specific message is suitable' },
|
|
42
|
+
501: { message: 'Not Implemented', description: 'The server either does not recognize the request method, or it lacks the ability to fulfill the request' },
|
|
43
|
+
502: { message: 'Bad Gateway', description: 'The server was acting as a gateway or proxy and received an invalid response from the upstream server' },
|
|
44
|
+
503: { message: 'Service Unavailable', description: 'The server is currently unavailable (overloaded or down)' },
|
|
45
|
+
504: { message: 'Gateway Timeout', description: 'The server was acting as a gateway or proxy and did not receive a timely response from the upstream server' },
|
|
46
|
+
505: { message: 'HTTP Version Not Supported', description: 'The server does not support the HTTP protocol version used in the request' },
|
|
47
|
+
511: { message: 'Network Authentication Required', description: 'The client needs to authenticate to gain network access' },
|
|
48
|
+
};
|
|
49
|
+
function getStatusMessage(statusCode) {
|
|
50
|
+
const status = exports.httpStatusDetails[statusCode];
|
|
51
|
+
if (status) {
|
|
52
|
+
return `${status.message} - ${status.description}`;
|
|
53
|
+
}
|
|
54
|
+
return 'Unknown Status';
|
|
55
|
+
}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Generates the current timestamp in ISO format
|
|
3
|
+
* @returns ISO timestamp string
|
|
3
4
|
*/
|
|
5
|
+
export declare function generateTimestamp(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Gets or creates a trace ID for a workflow
|
|
8
|
+
* @param workflowId - The workflow ID to get a trace ID for
|
|
9
|
+
* @returns A trace ID associated with the workflow
|
|
10
|
+
*/
|
|
11
|
+
export declare function getTraceId(workflowId: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Clears a trace ID from the map
|
|
14
|
+
* @param workflowId - The workflow ID to clear
|
|
15
|
+
*/
|
|
16
|
+
export declare function clearTraceId(workflowId: string): void;
|
|
4
17
|
/**
|
|
5
18
|
* Filters an object of headers, returning a new object with only the allowed headers.
|
|
6
19
|
* @param headers The original headers object.
|
|
@@ -1,11 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Utility functions for logging
|
|
4
|
-
*/
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateTimestamp = generateTimestamp;
|
|
4
|
+
exports.getTraceId = getTraceId;
|
|
5
|
+
exports.clearTraceId = clearTraceId;
|
|
6
6
|
exports.filterHeaders = filterHeaders;
|
|
7
7
|
exports.safeJsonParse = safeJsonParse;
|
|
8
8
|
exports.normalizeIp = normalizeIp;
|
|
9
|
+
/**
|
|
10
|
+
* Utility functions for logging
|
|
11
|
+
*/
|
|
12
|
+
const uuid_1 = require("uuid");
|
|
13
|
+
/**
|
|
14
|
+
* Generates the current timestamp in ISO format
|
|
15
|
+
* @returns ISO timestamp string
|
|
16
|
+
*/
|
|
17
|
+
function generateTimestamp() {
|
|
18
|
+
return new Date().toISOString();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Stores trace IDs by workflow ID for consistent tracking
|
|
22
|
+
*/
|
|
23
|
+
const traceIdMap = new Map();
|
|
24
|
+
/**
|
|
25
|
+
* Gets or creates a trace ID for a workflow
|
|
26
|
+
* @param workflowId - The workflow ID to get a trace ID for
|
|
27
|
+
* @returns A trace ID associated with the workflow
|
|
28
|
+
*/
|
|
29
|
+
function getTraceId(workflowId) {
|
|
30
|
+
if (!traceIdMap.has(workflowId)) {
|
|
31
|
+
traceIdMap.set(workflowId, (0, uuid_1.v4)());
|
|
32
|
+
}
|
|
33
|
+
return traceIdMap.get(workflowId);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Clears a trace ID from the map
|
|
37
|
+
* @param workflowId - The workflow ID to clear
|
|
38
|
+
*/
|
|
39
|
+
function clearTraceId(workflowId) {
|
|
40
|
+
traceIdMap.delete(workflowId);
|
|
41
|
+
}
|
|
9
42
|
// --- Header Allow-Listing ---
|
|
10
43
|
const ALLOWED_HEADERS = new Set([
|
|
11
44
|
'content-type',
|
package/dist/utils/with-trace.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.withTrace = withTrace;
|
|
4
|
+
/**
|
|
5
|
+
* Utility function to wrap a function with trace context
|
|
6
|
+
*/
|
|
4
7
|
const uuid_1 = require("uuid");
|
|
5
8
|
const trace_context_1 = require("./trace-context");
|
|
6
9
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unnbound-logger-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A structured logging library with TypeScript support using Pino. Provides consistent, well-typed logging across different operational contexts with automatic trace ID propagation.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|