unnbound-logger-sdk 2.0.4 → 2.0.6

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 CHANGED
@@ -48,12 +48,14 @@ All logs follow a standardized format:
48
48
 
49
49
  ```typescript
50
50
  interface Log<T extends LogType = 'general'> {
51
+ logId: string; // Unique identifier for each log entry
51
52
  level: LogLevel; // "info" | "debug" | "error" | "warn"
52
53
  type: T; // "general" | "httpRequest" | "httpResponse" | "sftpTransaction" | "dbQueryTransaction"
53
54
  message: string;
55
+ workflowId: string; // Workflow tracking (empty string if not set)
54
56
  traceId: string;
55
57
  requestId: string;
56
- deploymentId: string; // Automatically populated from DEPLOYMENT_ID environment variable
58
+ deploymentId: string; // Automatically populated from UNNBOUND_DEPLOYMENT_ID
57
59
  error?: SerializableError; // Only present for Error objects
58
60
  }
59
61
 
@@ -62,24 +64,44 @@ interface LogTransaction<T extends LogType> extends Log<T> {
62
64
  }
63
65
  ```
64
66
 
65
- ## Deployment Tracking
67
+ ## Workflow and Deployment Tracking
66
68
 
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.
69
+ ### Workflow Tracking
70
+
71
+ The logger includes a `workflowId` field in all log entries for tracking operations across services:
72
+
73
+ ```bash
74
+ # Set the workflow ID in your environment
75
+ export UNNBOUND_WORKFLOW_ID="order-processing-12345"
76
+
77
+ # Or in your deployment configuration
78
+ UNNBOUND_WORKFLOW_ID=order-processing-12345
79
+ ```
80
+
81
+ ```typescript
82
+ // Create a logger - workflowId is automatically set from environment
83
+ const logger = new UnnboundLogger();
84
+ // All logs will include the workflowId from UNNBOUND_WORKFLOW_ID environment variable
85
+ ```
86
+
87
+ ### Deployment Tracking
88
+
89
+ The logger automatically includes a `deploymentId` field in all log entries. This field is populated from the `UNNBOUND_DEPLOYMENT_ID` environment variable, allowing you to track logs per deployment.
68
90
 
69
91
  ```bash
70
92
  # Set the deployment ID in your environment
71
- export DEPLOYMENT_ID="v1.2.3-prod-20231201"
93
+ export UNNBOUND_DEPLOYMENT_ID="v1.2.3-prod-20231201"
72
94
 
73
95
  # Or in your deployment configuration
74
- DEPLOYMENT_ID=v1.2.3-prod-20231201
96
+ UNNBOUND_DEPLOYMENT_ID=v1.2.3-prod-20231201
75
97
  ```
76
98
 
77
- If the `DEPLOYMENT_ID` environment variable is not set, the `deploymentId` field will be an empty string. This field helps with:
99
+ If the environment variables are not set, the fields will be empty strings. These fields help with:
78
100
 
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
101
+ - **Workflow ID**: Unique identifier for the workflow
102
+ - **Deployment ID**: Tracking logs across different application deployments
103
+ - **Correlating issues**: Link problems to specific workflows and releases
104
+ - **Monitoring**: Track health and performance across workflows and deployments
83
105
 
84
106
  ## HTTP Request/Response Logging
85
107
 
@@ -326,14 +348,21 @@ The main logger class that provides all logging functionality using Pino.
326
348
  new UnnboundLogger(options?: LoggerOptions)
327
349
  ```
328
350
 
351
+ **LoggerOptions:**
352
+ - `traceHeaderKey?: string` - Custom trace header name (default: 'unnbound-trace-id')
353
+ - `ignoreTraceRoutes?: string[]` - Routes to ignore in Express middleware
354
+ - `ignoreAxiosTraceRoutes?: string[]` - Routes to ignore in Axios middleware
355
+
356
+ **Note:** `workflowId` and `deploymentId` are configured via environment variables (`UNNBOUND_WORKFLOW_ID`, `UNNBOUND_DEPLOYMENT_ID`).
357
+
329
358
  #### Methods
330
359
 
331
- - `log(level: LogLevel, message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void`
332
- - `error(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void`
333
- - `warn(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void`
334
- - `info(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void`
335
- - `debug(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void`
336
- - `httpRequest(req: Request, options?: HttpRequestLogOptions): string`
337
- - `httpResponse(res: Response, req: Request, options: HttpResponseLogOptions): void`
338
- - `sftpTransaction(operation: SftpOperation, options?: SftpTransactionLogOptions): void`
339
- - `dbQueryTransaction(query: DbQuery, options?: DbQueryTransactionLogOptions): void`
360
+ - `log(level: LogLevel, message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log`
361
+ - `error(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log`
362
+ - `warn(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log`
363
+ - `info(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log`
364
+ - `debug(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log`
365
+ - `httpRequest(req: Request, options?: HttpRequestLogOptions): HttpRequestLog`
366
+ - `httpResponse(res: Response, req: Request, options: HttpResponseLogOptions): HttpResponseLog`
367
+ - `sftpTransaction(operation: SftpOperation, options?: SftpTransactionLogOptions): SftpTransactionLog`
368
+ - `dbQueryTransaction(query: DbQuery, options?: DbQueryTransactionLogOptions): DbQueryTransactionLog`
package/dist/types.d.ts CHANGED
@@ -19,10 +19,12 @@ export interface SerializableError {
19
19
  stack?: string;
20
20
  }
21
21
  export interface Log<T extends LogType = 'general'> {
22
+ logId: string;
22
23
  level: LogLevel;
23
24
  type: T;
24
25
  message: string;
25
26
  deploymentId: string;
27
+ workflowId: string;
26
28
  traceId: string;
27
29
  requestId: string;
28
30
  error?: SerializableError;
@@ -75,12 +77,6 @@ export interface DbQueryTransactionLog extends LogTransaction<'dbQueryTransactio
75
77
  * Configuration options for the logger
76
78
  */
77
79
  export interface LoggerOptions {
78
- /** Default log level */
79
- defaultLevel?: LogLevel;
80
- /** Optional service name to include in logs */
81
- serviceName?: string;
82
- /** Optional environment name to include in logs */
83
- environment?: string;
84
80
  /** Optional trace header key */
85
81
  traceHeaderKey?: string;
86
82
  /** Routes to ignore in trace middleware (supports glob patterns) */
@@ -1,4 +1,4 @@
1
- import { LogLevel, LoggerOptions, GeneralLogOptions, HttpRequestLogOptions, HttpResponseLogOptions, SftpTransactionLogOptions, DbQueryTransactionLogOptions } from './types';
1
+ import { LogLevel, LoggerOptions, GeneralLogOptions, HttpRequestLogOptions, HttpResponseLogOptions, SftpTransactionLogOptions, DbQueryTransactionLogOptions, Log, HttpRequestLog, HttpResponseLog, SftpTransactionLog, DbQueryTransactionLog } from './types';
2
2
  import { Request, Response, NextFunction } from 'express';
3
3
  import { InternalAxiosRequestConfig } from 'axios';
4
4
  declare module 'axios' {
@@ -14,9 +14,7 @@ declare module 'axios' {
14
14
  */
15
15
  export declare class UnnboundLogger {
16
16
  private logger;
17
- private defaultLevel;
18
- private serviceName?;
19
- private environment?;
17
+ private workflowId;
20
18
  private deploymentId;
21
19
  private traceHeaderKey;
22
20
  private ignoreTraceRoutes;
@@ -39,31 +37,31 @@ export declare class UnnboundLogger {
39
37
  * @param message - Log message
40
38
  * @param options - Additional logging options
41
39
  */
42
- log(level: LogLevel, message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
40
+ log(level: LogLevel, message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log;
43
41
  /**
44
42
  * Logs an error message
45
43
  * @param message - Error message or object
46
44
  * @param options - Additional logging options
47
45
  */
48
- error(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
46
+ error(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log;
49
47
  /**
50
48
  * Logs a warning message
51
49
  * @param message - Warning message
52
50
  * @param options - Additional logging options
53
51
  */
54
- warn(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
52
+ warn(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log;
55
53
  /**
56
54
  * Logs an info message
57
55
  * @param message - Info message
58
56
  * @param options - Additional logging options
59
57
  */
60
- info(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
58
+ info(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log;
61
59
  /**
62
60
  * Logs a debug message
63
61
  * @param message - Debug message
64
62
  * @param options - Additional logging options
65
63
  */
66
- debug(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
64
+ debug(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): Log;
67
65
  /**
68
66
  * Constructs the full URL from request information
69
67
  * @param req - Express request object
@@ -76,14 +74,14 @@ export declare class UnnboundLogger {
76
74
  * @param options - Additional logging options
77
75
  * @returns The request ID for correlating with the response
78
76
  */
79
- httpRequest(req: Request, options?: HttpRequestLogOptions): string;
77
+ httpRequest(req: Request, options?: HttpRequestLogOptions): HttpRequestLog;
80
78
  /**
81
79
  * Logs an HTTP response
82
80
  * @param res - Express response object
83
81
  * @param req - Express request object
84
82
  * @param options - Additional logging options
85
83
  */
86
- httpResponse(res: Response, req: Request, options?: HttpResponseLogOptions): void;
84
+ httpResponse(res: Response, req: Request, options?: HttpResponseLogOptions): HttpResponseLog;
87
85
  /**
88
86
  * Logs an SFTP transaction
89
87
  * @param operation - SFTP operation details
@@ -98,7 +96,7 @@ export declare class UnnboundLogger {
98
96
  bytesTransferred?: number;
99
97
  filesListed?: number;
100
98
  sourcePath?: string;
101
- }, options?: SftpTransactionLogOptions): void;
99
+ }, options?: SftpTransactionLogOptions): SftpTransactionLog;
102
100
  /**
103
101
  * Logs a database query transaction
104
102
  * @param query - Database query details
@@ -111,7 +109,7 @@ export declare class UnnboundLogger {
111
109
  status: 'success' | 'failure';
112
110
  rowsReturned?: number;
113
111
  rowsAffected?: number;
114
- }, options?: DbQueryTransactionLogOptions): void;
112
+ }, options?: DbQueryTransactionLogOptions): DbQueryTransactionLog;
115
113
  traceMiddleware: (req: Request, res: Response, next: NextFunction) => void;
116
114
  axiosTraceMiddleware: {
117
115
  onFulfilled: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
@@ -32,7 +32,7 @@ class UnnboundLogger {
32
32
  res.setHeader(this.traceHeaderKey, traceId);
33
33
  trace_context_1.traceContext.run(traceId, () => {
34
34
  // Log the incoming request
35
- const requestId = this.httpRequest(req, { traceId });
35
+ const reqLog = this.httpRequest(req, { traceId });
36
36
  // Capture response body for logging
37
37
  const originalSend = res.send;
38
38
  res.send = function (body) {
@@ -41,7 +41,7 @@ class UnnboundLogger {
41
41
  };
42
42
  // Log the response when it finishes
43
43
  res.on('finish', () => {
44
- this.httpResponse(res, req, { requestId, traceId });
44
+ this.httpResponse(res, req, { requestId: reqLog.requestId, traceId });
45
45
  });
46
46
  next();
47
47
  });
@@ -168,20 +168,15 @@ class UnnboundLogger {
168
168
  return Promise.reject(error);
169
169
  }
170
170
  };
171
- this.defaultLevel = options.defaultLevel || 'info';
172
- this.serviceName = options.serviceName;
173
- this.environment = options.environment;
174
- this.deploymentId = process.env.DEPLOYMENT_ID || '';
171
+ this.workflowId = process.env.UNNBOUND_WORKFLOW_ID || '';
172
+ this.deploymentId = process.env.UNNBOUND_DEPLOYMENT_ID || '';
175
173
  this.traceHeaderKey = options.traceHeaderKey || 'unnbound-trace-id';
176
174
  this.ignoreTraceRoutes = options.ignoreTraceRoutes || [];
177
175
  this.ignoreAxiosTraceRoutes = options.ignoreAxiosTraceRoutes || [];
178
176
  // Create Pino logger
179
177
  this.logger = (0, pino_1.default)({
180
- level: this.defaultLevel,
181
- base: {
182
- ...(this.serviceName && { service: this.serviceName }),
183
- ...(this.environment && { environment: this.environment }),
184
- },
178
+ level: 'info',
179
+ base: {}, // Disable all default base fields (pid, hostname)
185
180
  timestamp: false, // Let CloudWatch handle timestamps
186
181
  formatters: {
187
182
  level: (label) => {
@@ -214,10 +209,19 @@ class UnnboundLogger {
214
209
  * @param options - Additional logging options
215
210
  */
216
211
  log(level, message, options = {}) {
212
+ const logId = (0, uuid_1.v4)();
217
213
  const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
218
214
  const requestId = options.requestId || (0, uuid_1.v4)();
219
215
  let logEntry;
220
- const { traceId: optionTraceId, requestId: optionRequestId, ...restOptions } = options;
216
+ const { traceId: optionTraceId, requestId: optionRequestId, level: optionLevel, ...restOptions } = options;
217
+ const baseEntry = {
218
+ logId,
219
+ type: 'general',
220
+ workflowId: this.workflowId,
221
+ traceId,
222
+ requestId,
223
+ deploymentId: this.deploymentId,
224
+ };
221
225
  if (message instanceof Error) {
222
226
  const error = {
223
227
  name: message.name,
@@ -225,10 +229,7 @@ class UnnboundLogger {
225
229
  stack: message.stack,
226
230
  };
227
231
  logEntry = {
228
- type: 'general',
229
- traceId,
230
- requestId,
231
- deploymentId: this.deploymentId,
232
+ ...baseEntry,
232
233
  message: message.name,
233
234
  error,
234
235
  ...restOptions,
@@ -236,10 +237,7 @@ class UnnboundLogger {
236
237
  }
237
238
  else if (typeof message === 'string') {
238
239
  logEntry = {
239
- type: 'general',
240
- traceId,
241
- requestId,
242
- deploymentId: this.deploymentId,
240
+ ...baseEntry,
243
241
  message,
244
242
  ...restOptions,
245
243
  };
@@ -247,16 +245,16 @@ class UnnboundLogger {
247
245
  else {
248
246
  // If message is an object, it's part of the log entry
249
247
  logEntry = {
250
- type: 'general',
251
- traceId,
252
- requestId,
253
- deploymentId: this.deploymentId,
248
+ ...baseEntry,
254
249
  ...message,
255
250
  message: message.message || 'Structured log data',
256
251
  ...restOptions,
257
252
  };
258
253
  }
259
- this.logger[level](logEntry);
254
+ // Separate the message from the log data and explicitly exclude any level field
255
+ const { message: logMessage, level: excludedLevel, ...logData } = logEntry;
256
+ this.logger[level](logData, logMessage);
257
+ return logEntry;
260
258
  }
261
259
  /**
262
260
  * Logs an error message
@@ -264,7 +262,7 @@ class UnnboundLogger {
264
262
  * @param options - Additional logging options
265
263
  */
266
264
  error(message, options = {}) {
267
- this.log('error', message, options);
265
+ return this.log('error', message, options);
268
266
  }
269
267
  /**
270
268
  * Logs a warning message
@@ -272,7 +270,7 @@ class UnnboundLogger {
272
270
  * @param options - Additional logging options
273
271
  */
274
272
  warn(message, options = {}) {
275
- this.log('warn', message, options);
273
+ return this.log('warn', message, options);
276
274
  }
277
275
  /**
278
276
  * Logs an info message
@@ -280,7 +278,7 @@ class UnnboundLogger {
280
278
  * @param options - Additional logging options
281
279
  */
282
280
  info(message, options = {}) {
283
- this.log('info', message, options);
281
+ return this.log('info', message, options);
284
282
  }
285
283
  /**
286
284
  * Logs a debug message
@@ -288,7 +286,7 @@ class UnnboundLogger {
288
286
  * @param options - Additional logging options
289
287
  */
290
288
  debug(message, options = {}) {
291
- this.log('debug', message, options);
289
+ return this.log('debug', message, options);
292
290
  }
293
291
  /**
294
292
  * Constructs the full URL from request information
@@ -319,6 +317,7 @@ class UnnboundLogger {
319
317
  * @returns The request ID for correlating with the response
320
318
  */
321
319
  httpRequest(req, options = {}) {
320
+ const logId = (0, uuid_1.v4)();
322
321
  const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
323
322
  const requestId = options.requestId || (0, uuid_1.v4)();
324
323
  const startTime = options.startTime || Date.now();
@@ -327,10 +326,13 @@ class UnnboundLogger {
327
326
  req.res.locals.requestId = requestId;
328
327
  req.res.locals.startTime = startTime;
329
328
  req.res.locals.traceId = traceId;
329
+ req.res.locals.workflowId = this.workflowId;
330
330
  }
331
331
  const logEntry = {
332
+ logId,
332
333
  type: 'httpRequest',
333
334
  message: req.ip === 'outgoing' ? 'Outgoing HTTP Request' : 'Incoming HTTP Request',
335
+ workflowId: this.workflowId,
334
336
  traceId,
335
337
  requestId,
336
338
  deploymentId: this.deploymentId,
@@ -343,8 +345,8 @@ class UnnboundLogger {
343
345
  body: (0, logger_utils_1.safeJsonParse)(req.body),
344
346
  },
345
347
  };
346
- this.log(options.level || 'info', logEntry);
347
- return requestId;
348
+ const result = this.log(options.level || 'info', logEntry);
349
+ return result;
348
350
  }
349
351
  /**
350
352
  * Logs an HTTP response
@@ -353,12 +355,14 @@ class UnnboundLogger {
353
355
  * @param options - Additional logging options
354
356
  */
355
357
  httpResponse(res, req, options = {}) {
358
+ const logId = (0, uuid_1.v4)();
356
359
  const requestId = res.locals.requestId || options.requestId || (0, uuid_1.v4)();
357
360
  const startTime = res.locals.startTime || options.startTime || Date.now();
361
+ const workflowId = res.locals.workflowId || this.workflowId;
358
362
  const traceId = res.locals.traceId || options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
359
363
  const duration = options.duration || (Date.now() - startTime);
360
364
  // Determine log level based on status code
361
- let level = options.level || this.defaultLevel;
365
+ let level = options.level || 'info';
362
366
  if (!options.level) {
363
367
  if (res.statusCode >= 400) {
364
368
  level = 'error';
@@ -368,8 +372,10 @@ class UnnboundLogger {
368
372
  }
369
373
  }
370
374
  const logEntry = {
375
+ logId,
371
376
  type: 'httpResponse',
372
377
  message: (0, http_status_messages_1.getStatusMessage)(res.statusCode),
378
+ workflowId: workflowId || '',
373
379
  traceId,
374
380
  requestId,
375
381
  deploymentId: this.deploymentId,
@@ -383,7 +389,8 @@ class UnnboundLogger {
383
389
  body: (0, logger_utils_1.safeJsonParse)(res.locals.body),
384
390
  },
385
391
  };
386
- this.log(level, logEntry);
392
+ const result = this.log(level, logEntry);
393
+ return result;
387
394
  }
388
395
  /**
389
396
  * Logs an SFTP transaction
@@ -391,20 +398,24 @@ class UnnboundLogger {
391
398
  * @param options - Additional logging options
392
399
  */
393
400
  sftpTransaction(operation, options = {}) {
401
+ const logId = (0, uuid_1.v4)();
394
402
  const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
395
403
  const requestId = options.requestId || (0, uuid_1.v4)();
396
404
  const duration = options.duration || (options.startTime ? Date.now() - options.startTime : 0);
397
405
  const level = operation.status === 'success' ? 'info' : 'error';
398
406
  const logEntry = {
407
+ logId,
399
408
  type: 'sftpTransaction',
400
409
  message: `SFTP ${operation.operation} ${operation.status} - ${operation.path}`,
410
+ workflowId: this.workflowId,
401
411
  traceId,
402
412
  requestId,
403
413
  deploymentId: this.deploymentId,
404
414
  duration,
405
415
  sftp: operation,
406
416
  };
407
- this.log(level, logEntry);
417
+ const result = this.log(level, logEntry);
418
+ return result;
408
419
  }
409
420
  /**
410
421
  * Logs a database query transaction
@@ -412,20 +423,24 @@ class UnnboundLogger {
412
423
  * @param options - Additional logging options
413
424
  */
414
425
  dbQueryTransaction(query, options = {}) {
426
+ const logId = (0, uuid_1.v4)();
415
427
  const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
416
428
  const requestId = options.requestId || (0, uuid_1.v4)();
417
429
  const duration = options.duration || (options.startTime ? Date.now() - options.startTime : 0);
418
430
  const level = query.status === 'success' ? 'info' : 'error';
419
431
  const logEntry = {
432
+ logId,
420
433
  type: 'dbQueryTransaction',
421
434
  message: `DB Query ${query.status} - ${query.vendor}`,
435
+ workflowId: this.workflowId,
422
436
  traceId,
423
437
  requestId,
424
438
  deploymentId: this.deploymentId,
425
439
  duration,
426
440
  db: query,
427
441
  };
428
- this.log(level, logEntry);
442
+ const result = this.log(level, logEntry);
443
+ return result;
429
444
  }
430
445
  }
431
446
  exports.UnnboundLogger = UnnboundLogger;
@@ -49,7 +49,7 @@ exports.httpStatusDetails = {
49
49
  function getStatusMessage(statusCode) {
50
50
  const status = exports.httpStatusDetails[statusCode];
51
51
  if (status) {
52
- return `${status.message} - ${status.description}`;
52
+ return `${statusCode} ${status.message} - ${status.description}`;
53
53
  }
54
- return 'Unknown Status';
54
+ return `${statusCode} Unknown Status`;
55
55
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unnbound-logger-sdk",
3
- "version": "2.0.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.",
3
+ "version": "2.0.6",
4
+ "description": "A structured logging library with TypeScript support using Pino. Provides consistent, well-typed logging with automatic logId, workflowId, traceId, and deploymentId tracking across operational contexts.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {