unnbound-logger-sdk 2.0.7 → 2.0.9

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
@@ -52,7 +52,8 @@ interface Log<T extends LogType = 'general'> {
52
52
  level: LogLevel; // "info" | "debug" | "error" | "warn"
53
53
  type: T; // "general" | "httpRequest" | "httpResponse" | "sftpTransaction" | "dbQueryTransaction"
54
54
  message: string;
55
- workflowId: string; // Workflow tracking (empty string if not set)
55
+ workflowId: string;
56
+ serviceId: string;
56
57
  traceId: string;
57
58
  requestId: string;
58
59
  deploymentId: string; // Automatically populated from UNNBOUND_DEPLOYMENT_ID
@@ -73,15 +74,18 @@ The logger includes a `workflowId` field in all log entries for tracking operati
73
74
  ```bash
74
75
  # Set the workflow ID in your environment
75
76
  export UNNBOUND_WORKFLOW_ID="order-processing-12345"
77
+ export UNNBOUND_WORKFLOW_URL="https://workflows.example.com/order-processing-12345"
78
+ export UNNBOUND_SERVICE_ID="order-service"
76
79
 
77
80
  # Or in your deployment configuration
78
81
  UNNBOUND_WORKFLOW_ID=order-processing-12345
82
+ UNNBOUND_WORKFLOW_URL=https://workflows.example.com/order-processing-12345
83
+ UNNBOUND_SERVICE_ID=order-service
79
84
  ```
80
85
 
81
86
  ```typescript
82
- // Create a logger - workflowId is automatically set from environment
87
+ // Create a logger - workflowId and serviceId are automatically set from environment
83
88
  const logger = new UnnboundLogger();
84
- // All logs will include the workflowId from UNNBOUND_WORKFLOW_ID environment variable
85
89
  ```
86
90
 
87
91
  ### Deployment Tracking
@@ -98,8 +102,10 @@ UNNBOUND_DEPLOYMENT_ID=v1.2.3-prod-20231201
98
102
 
99
103
  If the environment variables are not set, the fields will be empty strings. These fields help with:
100
104
 
101
- - **Workflow ID**: Unique identifier for the workflow
102
- - **Deployment ID**: Tracking logs across different application deployments
105
+ - **Workflow ID**: Unique identifier for the workflow (logged in each entry)
106
+ - **Workflow URL**: Used internally for URL construction in webhook endpoints (not logged as a field)
107
+ - **Service ID**: Identifier for the specific service/component (logged in each entry)
108
+ - **Deployment ID**: Tracking logs across different application deployments (logged in each entry)
103
109
  - **Correlating issues**: Link problems to specific workflows and releases
104
110
  - **Monitoring**: Track health and performance across workflows and deployments
105
111
 
@@ -146,6 +152,46 @@ The logger automatically captures:
146
152
  - Request duration
147
153
  - Trace ID and request ID for correlation
148
154
 
155
+ ### Full URL Logging for Webhook Endpoints
156
+
157
+ When webhook endpoints receive incoming requests, the logger automatically constructs and logs the full URL using a smart fallback strategy:
158
+
159
+ 1. **Preferred: Uses `UNNBOUND_WORKFLOW_URL`** - If set, this becomes the base URL for all logged requests
160
+ 2. **Fallback: Constructs from request headers** - Uses protocol, host, and forwarded headers from the incoming request
161
+
162
+ ```bash
163
+ # Set your workflow URL to ensure full URLs in logs
164
+ export UNNBOUND_WORKFLOW_URL="https://api.yourservice.com"
165
+
166
+ # Example webhook endpoints will be logged as:
167
+ # POST https://api.yourservice.com/webhooks/stripe
168
+ # POST https://api.yourservice.com/webhooks/github
169
+ ```
170
+
171
+ ```typescript
172
+ import express from 'express';
173
+ import { UnnboundLogger } from 'unnbound-logger';
174
+
175
+ const app = express();
176
+ const logger = new UnnboundLogger();
177
+
178
+ // Apply trace middleware for automatic logging
179
+ app.use(logger.traceMiddleware);
180
+
181
+ // Webhook endpoints - URLs automatically logged with full domain
182
+ app.post('/webhooks/stripe', (req, res) => {
183
+ // Request logged as: https://api.yourservice.com/webhooks/stripe
184
+ res.status(200).send('OK');
185
+ });
186
+
187
+ app.post('/webhooks/github', (req, res) => {
188
+ // Request logged as: https://api.yourservice.com/webhooks/github
189
+ res.status(200).send('OK');
190
+ });
191
+ ```
192
+
193
+ This ensures webhook logs contain the complete URL for easy debugging and monitoring.
194
+
149
195
  ## SFTP Transaction Logging
150
196
 
151
197
  For logging SFTP operations:
@@ -353,7 +399,7 @@ new UnnboundLogger(options?: LoggerOptions)
353
399
  - `ignoreTraceRoutes?: string[]` - Routes to ignore in Express middleware
354
400
  - `ignoreAxiosTraceRoutes?: string[]` - Routes to ignore in Axios middleware
355
401
 
356
- **Note:** `workflowId` and `deploymentId` are configured via environment variables (`UNNBOUND_WORKFLOW_ID`, `UNNBOUND_DEPLOYMENT_ID`).
402
+ **Note:** `workflowId`, `serviceId`, and `deploymentId` are configured via environment variables (`UNNBOUND_WORKFLOW_ID`, `UNNBOUND_SERVICE_ID`, `UNNBOUND_DEPLOYMENT_ID`). The `UNNBOUND_WORKFLOW_URL` is used for URL construction in webhook endpoints.
357
403
 
358
404
  #### Methods
359
405
 
package/dist/types.d.ts CHANGED
@@ -23,6 +23,7 @@ export interface Log<T extends LogType = 'general'> {
23
23
  level: LogLevel;
24
24
  type: T;
25
25
  message: string;
26
+ serviceId: string;
26
27
  deploymentId: string;
27
28
  workflowId: string;
28
29
  traceId: string;
@@ -15,6 +15,8 @@ declare module 'axios' {
15
15
  export declare class UnnboundLogger {
16
16
  private logger;
17
17
  private workflowId;
18
+ private workflowUrl;
19
+ private serviceId;
18
20
  private deploymentId;
19
21
  private traceHeaderKey;
20
22
  private ignoreTraceRoutes;
@@ -89,6 +89,11 @@ class UnnboundLogger {
89
89
  // Axios response interceptor (should be used separately)
90
90
  this.axiosResponseInterceptor = {
91
91
  onFulfilled: (response) => {
92
+ // Check if the URL should be ignored
93
+ const url = `${response.config?.baseURL || ''}${response.config?.url}`;
94
+ if (url && this.shouldIgnorePath(url, this.ignoreAxiosTraceRoutes)) {
95
+ return response;
96
+ }
92
97
  // Calculate duration
93
98
  const startTime = response.config.metadata?.startTime || Date.now();
94
99
  const requestId = response.config.metadata?.requestId;
@@ -121,6 +126,11 @@ class UnnboundLogger {
121
126
  return response;
122
127
  },
123
128
  onRejected: (error) => {
129
+ // Check if the URL should be ignored
130
+ const url = `${error.config?.baseURL || ''}${error.config?.url}`;
131
+ if (url && this.shouldIgnorePath(url, this.ignoreAxiosTraceRoutes)) {
132
+ return Promise.reject(error);
133
+ }
124
134
  // Calculate duration for error responses
125
135
  const startTime = error.config?.metadata?.startTime || Date.now();
126
136
  const requestId = error.config?.metadata?.requestId;
@@ -169,6 +179,8 @@ class UnnboundLogger {
169
179
  }
170
180
  };
171
181
  this.workflowId = process.env.UNNBOUND_WORKFLOW_ID || '';
182
+ this.workflowUrl = process.env.UNNBOUND_WORKFLOW_URL || '';
183
+ this.serviceId = process.env.UNNBOUND_SERVICE_ID || '';
172
184
  this.deploymentId = process.env.UNNBOUND_DEPLOYMENT_ID || '';
173
185
  this.traceHeaderKey = options.traceHeaderKey || 'unnbound-trace-id';
174
186
  this.ignoreTraceRoutes = options.ignoreTraceRoutes || [];
@@ -219,6 +231,7 @@ class UnnboundLogger {
219
231
  logId,
220
232
  type: 'general',
221
233
  workflowId: this.workflowId,
234
+ serviceId: this.serviceId,
222
235
  traceId,
223
236
  requestId,
224
237
  deploymentId: this.deploymentId,
@@ -300,11 +313,10 @@ class UnnboundLogger {
300
313
  if (reqUrl?.startsWith('http://') || reqUrl?.startsWith('https://')) {
301
314
  return reqUrl;
302
315
  }
303
- // Check if we have a base URL configured via environment variable
304
- const serviceBaseUrl = process.env.SERVICE_BASE_URL;
305
- if (serviceBaseUrl) {
306
- // Use configured base URL (useful for ECS when you know your service URL)
307
- return `${serviceBaseUrl.replace(/\/$/, '')}${reqUrl}`;
316
+ // Check if we have a workflow URL configured (preferred method)
317
+ if (this.workflowUrl) {
318
+ // Use workflow URL as the base URL
319
+ return `${this.workflowUrl.replace(/\/$/, '')}${reqUrl}`;
308
320
  }
309
321
  // Fallback to constructing from request info for incoming requests
310
322
  const protocol = req.protocol || (req.secure ? 'https' : 'http');
@@ -328,12 +340,15 @@ class UnnboundLogger {
328
340
  req.res.locals.startTime = startTime;
329
341
  req.res.locals.traceId = traceId;
330
342
  req.res.locals.workflowId = this.workflowId;
343
+ req.res.locals.workflowUrl = this.workflowUrl;
344
+ req.res.locals.serviceId = this.serviceId;
331
345
  }
332
346
  const logEntry = {
333
347
  logId,
334
348
  type: 'httpRequest',
335
349
  message: req.ip === 'outgoing' ? 'Outgoing HTTP Request' : 'Incoming HTTP Request',
336
350
  workflowId: this.workflowId,
351
+ serviceId: this.serviceId,
337
352
  traceId,
338
353
  requestId,
339
354
  deploymentId: this.deploymentId,
@@ -346,8 +361,9 @@ class UnnboundLogger {
346
361
  body: (0, logger_utils_1.safeJsonParse)(req.body),
347
362
  },
348
363
  };
349
- const result = this.log(options.level || 'info', logEntry);
350
- return result;
364
+ const { message: logMessage, ...logData } = logEntry;
365
+ this.logger[options.level || 'info'](logData, logMessage);
366
+ return logEntry;
351
367
  }
352
368
  /**
353
369
  * Logs an HTTP response
@@ -360,6 +376,7 @@ class UnnboundLogger {
360
376
  const requestId = res.locals.requestId || options.requestId || (0, uuid_1.v4)();
361
377
  const startTime = res.locals.startTime || options.startTime || Date.now();
362
378
  const workflowId = res.locals.workflowId || this.workflowId;
379
+ const serviceId = res.locals.serviceId || this.serviceId;
363
380
  const traceId = res.locals.traceId || options.traceId || trace_context_1.traceContext.getTraceId() || (0, uuid_1.v4)();
364
381
  const duration = options.duration || (Date.now() - startTime);
365
382
  // Determine log level based on status code
@@ -377,6 +394,7 @@ class UnnboundLogger {
377
394
  type: 'httpResponse',
378
395
  message: (0, http_status_messages_1.getStatusMessage)(res.statusCode),
379
396
  workflowId: workflowId || '',
397
+ serviceId: serviceId || '',
380
398
  traceId,
381
399
  requestId,
382
400
  deploymentId: this.deploymentId,
@@ -390,8 +408,9 @@ class UnnboundLogger {
390
408
  body: (0, logger_utils_1.safeJsonParse)(res.locals.body),
391
409
  },
392
410
  };
393
- const result = this.log(level, logEntry);
394
- return result;
411
+ const { message: logMessage, ...logData } = logEntry;
412
+ this.logger[level](logData, logMessage);
413
+ return logEntry;
395
414
  }
396
415
  /**
397
416
  * Logs an SFTP transaction
@@ -409,14 +428,16 @@ class UnnboundLogger {
409
428
  type: 'sftpTransaction',
410
429
  message: `SFTP ${operation.operation} ${operation.status} - ${operation.path}`,
411
430
  workflowId: this.workflowId,
431
+ serviceId: this.serviceId,
412
432
  traceId,
413
433
  requestId,
414
434
  deploymentId: this.deploymentId,
415
435
  duration,
416
436
  sftp: operation,
417
437
  };
418
- const result = this.log(level, logEntry);
419
- return result;
438
+ const { message: logMessage, ...logData } = logEntry;
439
+ this.logger[level](logData, logMessage);
440
+ return logEntry;
420
441
  }
421
442
  /**
422
443
  * Logs a database query transaction
@@ -434,14 +455,16 @@ class UnnboundLogger {
434
455
  type: 'dbQueryTransaction',
435
456
  message: `DB Query ${query.status} - ${query.vendor}`,
436
457
  workflowId: this.workflowId,
458
+ serviceId: this.serviceId,
437
459
  traceId,
438
460
  requestId,
439
461
  deploymentId: this.deploymentId,
440
462
  duration,
441
463
  db: query,
442
464
  };
443
- const result = this.log(level, logEntry);
444
- return result;
465
+ const { message: logMessage, ...logData } = logEntry;
466
+ this.logger[level](logData, logMessage);
467
+ return logEntry;
445
468
  }
446
469
  }
447
470
  exports.UnnboundLogger = UnnboundLogger;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unnbound-logger-sdk",
3
- "version": "2.0.7",
3
+ "version": "2.0.9",
4
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",