unnbound-logger-sdk 2.0.10 → 3.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 +151 -229
- package/dist/axios.d.ts +9 -0
- package/dist/axios.js +74 -0
- package/dist/http.d.ts +0 -0
- package/dist/http.js +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +9 -11
- package/dist/logger.d.ts +15 -0
- package/dist/logger.js +44 -0
- package/dist/middleware.d.ts +3 -0
- package/dist/middleware.js +70 -0
- package/dist/sftp.d.ts +10 -0
- package/dist/sftp.js +13 -0
- package/dist/span.d.ts +16 -0
- package/dist/span.js +41 -0
- package/dist/storage.d.ts +10 -0
- package/dist/storage.js +10 -0
- package/dist/types.d.ts +32 -101
- package/dist/types.js +3 -0
- package/dist/unnbound-logger.d.ts +6 -16
- package/dist/unnbound-logger.js +58 -55
- package/dist/utils/http-status-messages.js +140 -35
- package/dist/utils/logger-utils.d.ts +1 -1
- package/dist/utils.d.ts +19 -0
- package/dist/utils.js +53 -0
- package/package.json +22 -38
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Unnbound Logger
|
|
2
2
|
|
|
3
|
-
A structured logging library with TypeScript support built on Pino. Provides consistent, well-typed logging across different operational contexts. All logs are output in JSON format for better machine readability and parsing.
|
|
3
|
+
A structured logging library with TypeScript support built on Pino. Provides consistent, well-typed logging across different operational contexts with automatic trace and span tracking. All logs are output in JSON format for better machine readability and parsing.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -11,60 +11,40 @@ npm install unnbound-logger
|
|
|
11
11
|
## Basic Usage
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
// Create a new logger instance
|
|
17
|
-
const logger = new UnnboundLogger();
|
|
14
|
+
import { logger } from 'unnbound-logger';
|
|
18
15
|
|
|
19
16
|
// Log with string messages
|
|
20
17
|
logger.info('Application started');
|
|
21
18
|
logger.warn('Resource usage high');
|
|
22
|
-
logger.error(new Error('Database connection failed'));
|
|
19
|
+
logger.error({ err: new Error('Database connection failed') }, 'Something bad happened');
|
|
23
20
|
logger.debug('Debug information');
|
|
24
21
|
|
|
25
|
-
// Log with object messages (
|
|
26
|
-
logger.info({
|
|
27
|
-
|
|
28
|
-
userId: '123',
|
|
29
|
-
timestamp: new Date().toISOString()
|
|
30
|
-
});
|
|
31
|
-
// Results in: { "data": { "event": "user_login", "userId": "123", "timestamp": "..." }, "message": "Structured log data", ... }
|
|
22
|
+
// Log with object messages (merged into top level)
|
|
23
|
+
logger.info({ event: 'user_login', userId: '123' }, 'Event received.');
|
|
24
|
+
// Results in: { "event": "user_login", "userId": "123", "message": "Application started", ... }
|
|
32
25
|
|
|
33
|
-
// Log with both string message and metadata (metadata
|
|
34
|
-
logger.info('User logged in'
|
|
35
|
-
|
|
36
|
-
timestamp: new Date().toISOString()
|
|
37
|
-
});
|
|
38
|
-
// Results in: { "userId": "123", "timestamp": "...", "message": "User logged in", ... }
|
|
39
|
-
|
|
40
|
-
// Log with object message and additional metadata
|
|
41
|
-
logger.info(
|
|
42
|
-
{ event: 'user_login', userId: '123' },
|
|
43
|
-
{ timestamp: new Date().toISOString() }
|
|
44
|
-
);
|
|
45
|
-
// Results in: { "data": { "event": "user_login", "userId": "123" }, "timestamp": "...", "message": "Structured log data", ... }
|
|
26
|
+
// Log with both string message and metadata (metadata merged into top level)
|
|
27
|
+
logger.info({ userId: '123' }, 'User logged in');
|
|
28
|
+
// Results in: { "userId": "123", "message": "User logged in", ... }
|
|
46
29
|
```
|
|
47
30
|
|
|
48
31
|
## Log Format
|
|
49
32
|
|
|
50
|
-
All logs follow a standardized format:
|
|
33
|
+
All logs follow a standardized format based on Pino with additional context:
|
|
51
34
|
|
|
52
35
|
```typescript
|
|
53
36
|
interface Log<T extends LogType = 'general'> {
|
|
54
|
-
logId: string; // Unique identifier for each log entry
|
|
55
37
|
level: LogLevel; // "info" | "debug" | "error" | "warn"
|
|
56
|
-
type: T; // "general" | "httpRequest" | "httpResponse" | "sftpTransaction" | "dbQueryTransaction"
|
|
57
38
|
message: string;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
deploymentId
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
duration: number; // Duration in milliseconds
|
|
39
|
+
traceId?: string; // Automatically included when in trace context
|
|
40
|
+
spanId?: string; // Automatically included when in span context
|
|
41
|
+
type?: T; // "general" | "http" | "sftp" | "dbQueryTransaction"
|
|
42
|
+
serviceId?: string; // From UNNBOUND_SERVICE_ID environment variable
|
|
43
|
+
deploymentId?: string; // From UNNBOUND_DEPLOYMENT_ID environment variable
|
|
44
|
+
workflowId?: string; // From UNNBOUND_WORKFLOW_ID environment variable
|
|
45
|
+
environment?: string; // From ENVIRONMENT environment variable
|
|
46
|
+
err?: unknown; // Only present for Error objects
|
|
47
|
+
duration?: number; // Duration in milliseconds for span operations
|
|
68
48
|
}
|
|
69
49
|
```
|
|
70
50
|
|
|
@@ -80,15 +60,15 @@ export UNNBOUND_WORKFLOW_ID="order-processing-12345"
|
|
|
80
60
|
export UNNBOUND_WORKFLOW_URL="https://workflows.example.com/order-processing-12345"
|
|
81
61
|
export UNNBOUND_SERVICE_ID="order-service"
|
|
82
62
|
|
|
83
|
-
# Or in your deployment configuration
|
|
63
|
+
# Or in your deployment configuration
|
|
84
64
|
UNNBOUND_WORKFLOW_ID=order-processing-12345
|
|
85
65
|
UNNBOUND_WORKFLOW_URL=https://workflows.example.com/order-processing-12345
|
|
86
66
|
UNNBOUND_SERVICE_ID=order-service
|
|
87
67
|
```
|
|
88
68
|
|
|
89
69
|
```typescript
|
|
90
|
-
//
|
|
91
|
-
|
|
70
|
+
// Import the logger - workflowId and serviceId are automatically set from environment
|
|
71
|
+
import { logger } from 'unnbound-logger';
|
|
92
72
|
```
|
|
93
73
|
|
|
94
74
|
### Deployment Tracking
|
|
@@ -114,70 +94,47 @@ If the environment variables are not set, the fields will be empty strings. Thes
|
|
|
114
94
|
|
|
115
95
|
## Object Logging Behavior
|
|
116
96
|
|
|
117
|
-
The logger
|
|
97
|
+
The logger uses Pino's standard behavior for handling different message types:
|
|
118
98
|
|
|
119
99
|
### String Messages with Metadata
|
|
120
|
-
|
|
100
|
+
|
|
101
|
+
When you pass a string message with additional metadata, the metadata is merged into the top level:
|
|
121
102
|
|
|
122
103
|
```typescript
|
|
123
104
|
logger.info('User action completed', { userId: '123', action: 'login' });
|
|
124
|
-
// Result: { "message": "User action completed", "
|
|
105
|
+
// Result: { "message": "User action completed", "userId": "123", "action": "login", ... }
|
|
125
106
|
```
|
|
126
107
|
|
|
127
108
|
### Object Messages
|
|
128
|
-
When you pass an object as the message, it gets wrapped in a `data` field to prevent unknown properties from polluting the top level:
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
logger.info({ userId: '123', action: 'login', timestamp: '2025-01-01T12:00:00Z' });
|
|
132
|
-
// Result: { "message": "Structured log data", "data": { "userId": "123", "action": "login", "timestamp": "2025-01-01T12:00:00Z" }, ... }
|
|
133
|
-
```
|
|
134
109
|
|
|
135
|
-
|
|
110
|
+
When you pass an object as the message, it's merged into the top level:
|
|
136
111
|
|
|
137
112
|
```typescript
|
|
138
|
-
logger.info({
|
|
139
|
-
// Result: { "
|
|
113
|
+
logger.info({ userId: '123', action: 'login' });
|
|
114
|
+
// Result: { "userId": "123", "action": "login", "message": "Application started", ... }
|
|
140
115
|
```
|
|
141
116
|
|
|
142
117
|
### Error Objects
|
|
118
|
+
|
|
143
119
|
Error objects are handled specially and include serialized error information:
|
|
144
120
|
|
|
145
121
|
```typescript
|
|
146
|
-
logger.error(new Error('Something went wrong'));
|
|
147
|
-
// Result: { "message": "Error", "
|
|
122
|
+
logger.error({ err: new Error('Something went wrong') });
|
|
123
|
+
// Result: { "message": "Error", "err": { "name": "Error", "message": "Something went wrong", "stack": "..." }, ... }
|
|
148
124
|
```
|
|
149
125
|
|
|
150
|
-
This
|
|
126
|
+
This follows Pino's standard behavior where all object properties are merged into the top level of the log entry.
|
|
151
127
|
|
|
152
128
|
## HTTP Request/Response Logging
|
|
153
129
|
|
|
154
130
|
```typescript
|
|
155
|
-
import {
|
|
131
|
+
import { logger, traceMiddleware } from 'unnbound-logger';
|
|
156
132
|
import express from 'express';
|
|
157
133
|
|
|
158
134
|
const app = express();
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
app.use((req, res, next) => {
|
|
163
|
-
// Log the request and get the request ID
|
|
164
|
-
const requestId = logger.httpRequest(req, {
|
|
165
|
-
startTime: Date.now()
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// Store the request ID in res.locals for later use
|
|
169
|
-
res.locals.requestId = requestId;
|
|
170
|
-
|
|
171
|
-
// Add response listener to log the response
|
|
172
|
-
res.on('finish', () => {
|
|
173
|
-
logger.httpResponse(res, req, {
|
|
174
|
-
requestId,
|
|
175
|
-
startTime: res.locals.startTime
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
next();
|
|
180
|
-
});
|
|
135
|
+
|
|
136
|
+
// Apply trace middleware for automatic HTTP logging
|
|
137
|
+
app.use(traceMiddleware());
|
|
181
138
|
|
|
182
139
|
// Example route
|
|
183
140
|
app.post('/api/users', (req, res) => {
|
|
@@ -186,11 +143,13 @@ app.post('/api/users', (req, res) => {
|
|
|
186
143
|
});
|
|
187
144
|
```
|
|
188
145
|
|
|
189
|
-
The
|
|
146
|
+
The trace middleware automatically captures:
|
|
147
|
+
|
|
190
148
|
- Request method, URL, body, and headers (filtered for security)
|
|
191
149
|
- Response status code, body, and headers (filtered for security)
|
|
192
150
|
- Request duration
|
|
193
|
-
- Trace ID and
|
|
151
|
+
- Trace ID and span ID for correlation
|
|
152
|
+
- Automatic span tracking for the entire request lifecycle
|
|
194
153
|
|
|
195
154
|
### Full URL Logging for Webhook Endpoints
|
|
196
155
|
|
|
@@ -210,13 +169,12 @@ export UNNBOUND_WORKFLOW_URL="https://api.yourservice.com"
|
|
|
210
169
|
|
|
211
170
|
```typescript
|
|
212
171
|
import express from 'express';
|
|
213
|
-
import {
|
|
172
|
+
import { traceMiddleware } from 'unnbound-logger';
|
|
214
173
|
|
|
215
174
|
const app = express();
|
|
216
|
-
const logger = new UnnboundLogger();
|
|
217
175
|
|
|
218
176
|
// Apply trace middleware for automatic logging
|
|
219
|
-
app.use(
|
|
177
|
+
app.use(traceMiddleware());
|
|
220
178
|
|
|
221
179
|
// Webhook endpoints - URLs automatically logged with full domain
|
|
222
180
|
app.post('/webhooks/stripe', (req, res) => {
|
|
@@ -232,67 +190,6 @@ app.post('/webhooks/github', (req, res) => {
|
|
|
232
190
|
|
|
233
191
|
This ensures webhook logs contain the complete URL for easy debugging and monitoring.
|
|
234
192
|
|
|
235
|
-
## SFTP Transaction Logging
|
|
236
|
-
|
|
237
|
-
For logging SFTP operations:
|
|
238
|
-
|
|
239
|
-
```typescript
|
|
240
|
-
import { UnnboundLogger } from 'unnbound-logger';
|
|
241
|
-
|
|
242
|
-
const logger = new UnnboundLogger();
|
|
243
|
-
|
|
244
|
-
// Log an SFTP upload
|
|
245
|
-
logger.sftpTransaction({
|
|
246
|
-
host: 'sftp.example.com',
|
|
247
|
-
username: 'ftpuser',
|
|
248
|
-
operation: 'upload',
|
|
249
|
-
path: '/uploads/file.txt',
|
|
250
|
-
status: 'success',
|
|
251
|
-
bytesTransferred: 1024
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// Log an SFTP download with failure
|
|
255
|
-
logger.sftpTransaction({
|
|
256
|
-
host: 'sftp.example.com',
|
|
257
|
-
username: 'ftpuser',
|
|
258
|
-
operation: 'download',
|
|
259
|
-
path: '/downloads/file.txt',
|
|
260
|
-
status: 'failure'
|
|
261
|
-
}, {
|
|
262
|
-
startTime: Date.now() - 5000 // Started 5 seconds ago
|
|
263
|
-
});
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## Database Query Transaction Logging
|
|
267
|
-
|
|
268
|
-
For logging database operations:
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
import { UnnboundLogger } from 'unnbound-logger';
|
|
272
|
-
|
|
273
|
-
const logger = new UnnboundLogger();
|
|
274
|
-
|
|
275
|
-
// Log a successful database query
|
|
276
|
-
logger.dbQueryTransaction({
|
|
277
|
-
instance: 'localhost:5432',
|
|
278
|
-
vendor: 'postgres',
|
|
279
|
-
query: 'SELECT * FROM users WHERE active = true',
|
|
280
|
-
status: 'success',
|
|
281
|
-
rowsReturned: 150
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
// Log a failed database operation
|
|
285
|
-
logger.dbQueryTransaction({
|
|
286
|
-
instance: 'prod-db-cluster',
|
|
287
|
-
vendor: 'mysql',
|
|
288
|
-
query: 'UPDATE users SET last_login = NOW()',
|
|
289
|
-
status: 'failure',
|
|
290
|
-
rowsAffected: 0
|
|
291
|
-
}, {
|
|
292
|
-
duration: 2500 // Operation took 2.5 seconds
|
|
293
|
-
});
|
|
294
|
-
```
|
|
295
|
-
|
|
296
193
|
## Middleware Usage
|
|
297
194
|
|
|
298
195
|
### Express Trace Middleware
|
|
@@ -300,155 +197,180 @@ logger.dbQueryTransaction({
|
|
|
300
197
|
The library provides a comprehensive trace middleware for Express applications that automatically handles trace context and HTTP logging:
|
|
301
198
|
|
|
302
199
|
```typescript
|
|
303
|
-
import {
|
|
200
|
+
import { traceMiddleware } from 'unnbound-logger';
|
|
304
201
|
import express from 'express';
|
|
305
202
|
|
|
306
203
|
const app = express();
|
|
307
|
-
const logger = new UnnboundLogger();
|
|
308
204
|
|
|
309
205
|
// Apply the comprehensive trace middleware globally
|
|
310
|
-
app.use(
|
|
206
|
+
app.use(traceMiddleware());
|
|
311
207
|
```
|
|
312
208
|
|
|
313
209
|
The trace middleware automatically:
|
|
210
|
+
|
|
314
211
|
- Generates and maintains trace IDs across the request lifecycle
|
|
315
|
-
- Logs incoming requests with method, URL, headers, and body
|
|
212
|
+
- Logs incoming requests with method, URL, headers, and body
|
|
316
213
|
- Logs outgoing responses with status code, headers, body, and duration
|
|
317
214
|
- Measures request duration automatically
|
|
318
215
|
- Handles errors and logs them appropriately
|
|
319
216
|
- Captures response bodies for logging
|
|
217
|
+
- Creates spans for the entire request lifecycle
|
|
320
218
|
|
|
321
219
|
### Axios Trace Middleware
|
|
322
220
|
|
|
323
221
|
For comprehensive logging of outgoing HTTP requests made with Axios:
|
|
324
222
|
|
|
325
223
|
```typescript
|
|
326
|
-
import {
|
|
224
|
+
import { traceAxios } from 'unnbound-logger';
|
|
327
225
|
import axios from 'axios';
|
|
328
226
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
// Add both request and response interceptors for complete HTTP logging
|
|
332
|
-
axios.interceptors.request.use(
|
|
333
|
-
logger.axiosTraceMiddleware.onFulfilled,
|
|
334
|
-
logger.axiosTraceMiddleware.onRejected
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
axios.interceptors.response.use(
|
|
338
|
-
logger.axiosResponseInterceptor.onFulfilled,
|
|
339
|
-
logger.axiosResponseInterceptor.onRejected
|
|
340
|
-
);
|
|
227
|
+
// Create an axios instance and wrap it with tracing
|
|
228
|
+
const client = traceAxios(axios.create());
|
|
341
229
|
|
|
342
|
-
// All requests made with
|
|
343
|
-
|
|
230
|
+
// All requests made with this client will be automatically logged
|
|
231
|
+
client.get('https://api.example.com/data');
|
|
344
232
|
```
|
|
345
233
|
|
|
346
234
|
The Axios middleware:
|
|
347
|
-
|
|
235
|
+
|
|
236
|
+
- Logs outgoing requests with method, URL, headers, and body
|
|
348
237
|
- Maintains trace context across requests by propagating trace IDs
|
|
349
238
|
- Logs successful responses with status, headers, body, and duration
|
|
350
239
|
- Logs error responses with detailed error information
|
|
240
|
+
- Creates spans for each HTTP request
|
|
351
241
|
- Supports request/response filtering through configuration
|
|
352
242
|
|
|
353
|
-
## Function Tracing with
|
|
243
|
+
## Function Tracing with startSpan
|
|
354
244
|
|
|
355
|
-
The `
|
|
245
|
+
The `startSpan` function allows you to wrap any async operation with automatic span tracking and logging. This is particularly useful for maintaining consistent trace IDs across async operations and distributed systems:
|
|
356
246
|
|
|
357
247
|
```typescript
|
|
358
|
-
import {
|
|
359
|
-
import { withTrace } from 'unnbound-logger/utils/with-trace';
|
|
360
|
-
import { traceContext } from 'unnbound-logger/utils/trace-context';
|
|
361
|
-
|
|
362
|
-
const logger = new UnnboundLogger();
|
|
248
|
+
import { logger, startSpan } from 'unnbound-logger';
|
|
363
249
|
|
|
364
|
-
// Example: Wrapping a function with
|
|
365
|
-
const operation = (value: number) => {
|
|
366
|
-
|
|
367
|
-
logger.info('Processing value', { value, traceId });
|
|
250
|
+
// Example: Wrapping a function with span tracking
|
|
251
|
+
const operation = async (value: number) => {
|
|
252
|
+
logger.info('Processing value', { value });
|
|
368
253
|
return value * 2;
|
|
369
254
|
};
|
|
370
255
|
|
|
371
|
-
// Wrap the function with
|
|
372
|
-
const
|
|
256
|
+
// Wrap the function with span tracking
|
|
257
|
+
const result = await startSpan('Processing operation', operation, () => ({
|
|
258
|
+
operationType: 'calculation',
|
|
259
|
+
}));
|
|
373
260
|
|
|
374
261
|
// Execute the function
|
|
375
|
-
const result =
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
### Using Custom Trace IDs
|
|
379
|
-
|
|
380
|
-
You can provide your own trace ID when wrapping a function:
|
|
381
|
-
|
|
382
|
-
```typescript
|
|
383
|
-
const customTraceId = 'custom-trace-123';
|
|
384
|
-
const tracedOperation = withTrace(operation, customTraceId);
|
|
262
|
+
const result = await startSpan('Processing operation', () => operation(21)); // Returns 42
|
|
385
263
|
```
|
|
386
264
|
|
|
387
265
|
### Async Operations
|
|
388
266
|
|
|
389
|
-
The
|
|
267
|
+
The span context is maintained across async operations:
|
|
390
268
|
|
|
391
269
|
```typescript
|
|
392
270
|
const asyncOperation = async (value: number) => {
|
|
393
|
-
|
|
394
|
-
logger.info('First step', { traceId: traceId1 });
|
|
271
|
+
logger.info('First step', { value });
|
|
395
272
|
|
|
396
273
|
await someAsyncWork();
|
|
397
274
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
// traceId1 and traceId2 will be the same
|
|
275
|
+
logger.info('Second step', { value });
|
|
276
|
+
return value * 2;
|
|
401
277
|
};
|
|
402
278
|
|
|
403
|
-
const
|
|
404
|
-
|
|
279
|
+
const result = await startSpan('Async operation', asyncOperation, () => ({
|
|
280
|
+
operationType: 'async_calculation',
|
|
281
|
+
}));
|
|
405
282
|
```
|
|
406
283
|
|
|
407
284
|
### Benefits
|
|
408
285
|
|
|
409
|
-
- Automatic
|
|
286
|
+
- Automatic span ID generation and tracking
|
|
410
287
|
- Consistent trace context across async operations
|
|
411
|
-
-
|
|
288
|
+
- Automatic duration measurement
|
|
289
|
+
- Error handling and logging
|
|
412
290
|
- Type-safe implementation
|
|
413
|
-
- Works with
|
|
414
|
-
- Maintains separate
|
|
415
|
-
|
|
416
|
-
> **Note:** When using
|
|
417
|
-
>
|
|
418
|
-
> ```typescript
|
|
419
|
-
> const operation = (value: number) => {
|
|
420
|
-
> logger.info('Processing value', { value }); // Trace ID is automatically included
|
|
421
|
-
> return value * 2;
|
|
422
|
-
> };
|
|
423
|
-
> ```
|
|
291
|
+
- Works with async functions
|
|
292
|
+
- Maintains separate span contexts for different operations
|
|
293
|
+
|
|
294
|
+
> **Note:** When using the logger within spans, you don't need to manually manage trace IDs. The logger automatically includes the current trace ID and span ID in all log entries.
|
|
424
295
|
|
|
425
296
|
## API Reference
|
|
426
297
|
|
|
427
|
-
###
|
|
298
|
+
### logger
|
|
428
299
|
|
|
429
|
-
The main logger
|
|
300
|
+
The main logger instance that provides all logging functionality using Pino.
|
|
430
301
|
|
|
431
|
-
####
|
|
302
|
+
#### Usage
|
|
432
303
|
|
|
433
304
|
```typescript
|
|
434
|
-
|
|
305
|
+
import { logger } from 'unnbound-logger';
|
|
435
306
|
```
|
|
436
307
|
|
|
437
|
-
|
|
438
|
-
- `traceHeaderKey?: string` - Custom trace header name (default: 'unnbound-trace-id')
|
|
439
|
-
- `ignoreTraceRoutes?: string[]` - Routes to ignore in Express middleware
|
|
440
|
-
- `ignoreAxiosTraceRoutes?: string[]` - Routes to ignore in Axios middleware
|
|
441
|
-
|
|
442
|
-
**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.
|
|
308
|
+
The logger is a Pino instance with additional context automatically included from environment variables and trace context.
|
|
443
309
|
|
|
444
310
|
#### Methods
|
|
445
311
|
|
|
446
|
-
- `
|
|
447
|
-
- `
|
|
448
|
-
- `
|
|
449
|
-
- `
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
312
|
+
- `logger.info(object: {}, message: string): void`
|
|
313
|
+
- `logger.warn(object: {}, message: string): void`
|
|
314
|
+
- `logger.error(object: {}, message: string): void`
|
|
315
|
+
- `logger.debug(object: {}, message: string): void`
|
|
316
|
+
|
|
317
|
+
### traceMiddleware
|
|
318
|
+
|
|
319
|
+
Express middleware for automatic HTTP request/response logging and trace context management.
|
|
320
|
+
|
|
321
|
+
#### Usage
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
import { traceMiddleware } from 'unnbound-logger';
|
|
325
|
+
|
|
326
|
+
app.use(traceMiddleware(options?: HttpOptions));
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**HttpOptions:**
|
|
330
|
+
|
|
331
|
+
- `traceHeaderKey?: string` - Custom trace header name (default: 'x-unnbound-trace-id')
|
|
332
|
+
- `ignoreTraceRoutes?: string[]` - Routes to ignore in middleware (default: ['/health', '/healthcheck'])
|
|
333
|
+
|
|
334
|
+
### traceAxios
|
|
335
|
+
|
|
336
|
+
Wraps an Axios instance with automatic request/response logging and trace context propagation.
|
|
337
|
+
|
|
338
|
+
#### Usage
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
import { traceAxios } from 'unnbound-logger';
|
|
342
|
+
import axios from 'axios';
|
|
343
|
+
|
|
344
|
+
const client = traceAxios(axios.create(), options?: HttpOptions);
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### startSpan
|
|
348
|
+
|
|
349
|
+
Creates a span for tracking async operations with automatic logging and duration measurement.
|
|
350
|
+
|
|
351
|
+
#### Usage
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
import { startSpan } from 'unnbound-logger';
|
|
355
|
+
|
|
356
|
+
const result = await startSpan<T>(
|
|
357
|
+
spanName: string,
|
|
358
|
+
callback: () => Promise<T>,
|
|
359
|
+
getter?: LogPayloadGetter<T>
|
|
360
|
+
);
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Parameters:**
|
|
364
|
+
|
|
365
|
+
- `spanName`: The name of the span for logging
|
|
366
|
+
- `callback`: The async function to execute within the span
|
|
367
|
+
- `getter`: Optional function to generate log payload based on operation result/error
|
|
368
|
+
|
|
369
|
+
### Environment Variables
|
|
370
|
+
|
|
371
|
+
- `UNNBOUND_WORKFLOW_ID` - Workflow identifier (included in all logs)
|
|
372
|
+
- `UNNBOUND_SERVICE_ID` - Service identifier (included in all logs)
|
|
373
|
+
- `UNNBOUND_DEPLOYMENT_ID` - Deployment identifier (included in all logs)
|
|
374
|
+
- `UNNBOUND_WORKFLOW_URL` - Base URL for webhook endpoint logging
|
|
375
|
+
- `ENVIRONMENT` - Environment name (included in all logs)
|
|
376
|
+
- `LOG_LEVEL` - Log level (default: 'info')
|
package/dist/axios.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Axios } from 'axios';
|
|
2
|
+
import { HttpOptions } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Wraps an axios instance to add tracing and span tracking
|
|
5
|
+
* @param axios - The axios instance to wrap
|
|
6
|
+
* @param options - Configuration options for HTTP tracing
|
|
7
|
+
* @returns The wrapped axios instance with span tracking
|
|
8
|
+
*/
|
|
9
|
+
export declare const traceAxios: (client: Axios, { ignoreTraceRoutes, traceHeaderKey, }?: HttpOptions) => Axios;
|
package/dist/axios.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.traceAxios = void 0;
|
|
4
|
+
const axios_1 = require("axios");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
const storage_1 = require("./storage");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
const span_1 = require("./span");
|
|
9
|
+
const buildOutgoingHttpPayload = (config, res) => ({
|
|
10
|
+
type: 'http',
|
|
11
|
+
http: {
|
|
12
|
+
url: [config.baseURL, config.url].filter(Boolean).join(''),
|
|
13
|
+
method: config.method?.toUpperCase() || 'GET',
|
|
14
|
+
incoming: false,
|
|
15
|
+
request: {
|
|
16
|
+
headers: config.headers,
|
|
17
|
+
body: (0, utils_1.safeJsonParse)(config.data),
|
|
18
|
+
},
|
|
19
|
+
response: res
|
|
20
|
+
? {
|
|
21
|
+
headers: res?.headers,
|
|
22
|
+
status: res.status,
|
|
23
|
+
body: (0, utils_1.safeJsonParse)(res.data),
|
|
24
|
+
}
|
|
25
|
+
: undefined,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Wraps an axios instance to add tracing and span tracking
|
|
30
|
+
* @param axios - The axios instance to wrap
|
|
31
|
+
* @param options - Configuration options for HTTP tracing
|
|
32
|
+
* @returns The wrapped axios instance with span tracking
|
|
33
|
+
*/
|
|
34
|
+
const traceAxios = (client, { ignoreTraceRoutes = types_1.defaultIgnoreTraceRoutes, traceHeaderKey = types_1.defaultTraceHeaderKey, } = {
|
|
35
|
+
ignoreTraceRoutes: types_1.defaultIgnoreTraceRoutes,
|
|
36
|
+
traceHeaderKey: types_1.defaultTraceHeaderKey,
|
|
37
|
+
}) => {
|
|
38
|
+
const createSpanWrappedRequest = (originalMethod, method) => {
|
|
39
|
+
const { headers: defaultHeaders, ...partialDefaultConfig } = client.defaults;
|
|
40
|
+
const headers = { ...defaultHeaders.common, ...(method && defaultHeaders[method]) };
|
|
41
|
+
const defaultConfig = { ...partialDefaultConfig, headers };
|
|
42
|
+
return async (config) => {
|
|
43
|
+
config = (0, axios_1.mergeConfig)(defaultConfig, config);
|
|
44
|
+
// Determine the actual config and URL
|
|
45
|
+
const url = [config.baseURL, config.url].filter(Boolean).join('');
|
|
46
|
+
// Check if this request should be ignored
|
|
47
|
+
if ((0, utils_1.shouldIgnorePath)(url, ignoreTraceRoutes))
|
|
48
|
+
return originalMethod(config);
|
|
49
|
+
const traceId = storage_1.storage.getStore()?.[storage_1.ContextAttribute.TraceId];
|
|
50
|
+
config = { ...config, headers: { ...config.headers, [traceHeaderKey]: traceId } };
|
|
51
|
+
// Execute the request within a span
|
|
52
|
+
return (0, span_1.startSpan)(`Outgoing HTTP request`, () => originalMethod(config), (options) => {
|
|
53
|
+
if (!options)
|
|
54
|
+
return buildOutgoingHttpPayload(config);
|
|
55
|
+
if (options.error)
|
|
56
|
+
return buildOutgoingHttpPayload(config, (0, axios_1.isAxiosError)(options.error) ? options.error.response : undefined);
|
|
57
|
+
return buildOutgoingHttpPayload(config, options.result);
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
const request = client.request.bind(client);
|
|
62
|
+
const tracedRequest = createSpanWrappedRequest(request);
|
|
63
|
+
client.request = tracedRequest;
|
|
64
|
+
['post', 'put', 'patch'].forEach((method) => {
|
|
65
|
+
const func = createSpanWrappedRequest(request, method);
|
|
66
|
+
client[method] = (url, data, config) => func({ ...config, url, data });
|
|
67
|
+
});
|
|
68
|
+
['delete', 'get', 'head', 'options'].forEach((method) => {
|
|
69
|
+
const func = createSpanWrappedRequest(request, method);
|
|
70
|
+
client[method] = (url, config) => func({ ...config, url });
|
|
71
|
+
});
|
|
72
|
+
return client;
|
|
73
|
+
};
|
|
74
|
+
exports.traceAxios = traceAxios;
|
package/dist/http.d.ts
ADDED
|
File without changes
|
package/dist/http.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* A structured logging library built on Pino with TypeScript support.
|
|
5
5
|
* Provides consistent, well-typed logging across different operational contexts.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export {
|
|
7
|
+
export type { LogLevel, LogType, HttpMethod, Log, LogTransaction, SftpLog, HttpLog, SftpPayload, } from './types';
|
|
8
|
+
export type { UnnboundLogger } from './logger';
|
|
9
|
+
export { logger } from './logger';
|
|
10
|
+
export { startSpan } from './span';
|
|
11
|
+
export { traceAxios } from './axios';
|
|
12
|
+
export { traceMiddleware } from './middleware';
|