azify-logger 1.0.55-test → 1.0.55-test-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/package.json +2 -1
- package/register-http-client-early.js +122 -24
- package/register.js +107 -28
- package/utils/undiciLogBodies.js +83 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azify-logger",
|
|
3
|
-
"version": "1.0.55-test",
|
|
3
|
+
"version": "1.0.55-test-1",
|
|
4
4
|
"description": "Azify Logger Client - Centralized logging for OpenSearch",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -111,6 +111,7 @@
|
|
|
111
111
|
"queue/",
|
|
112
112
|
"scripts/redis-worker.js",
|
|
113
113
|
"streams/",
|
|
114
|
+
"utils/undiciLogBodies.js",
|
|
114
115
|
"package.json",
|
|
115
116
|
"README.md"
|
|
116
117
|
]
|
|
@@ -11,6 +11,11 @@ try {
|
|
|
11
11
|
const Module = require('module')
|
|
12
12
|
const path = require('path')
|
|
13
13
|
const EARLY_DIR = __dirname
|
|
14
|
+
const {
|
|
15
|
+
resolveUndiciRequestOpts,
|
|
16
|
+
serializeUndiciRequestBody,
|
|
17
|
+
restoreUndiciResponseBodyAfterReadForLog
|
|
18
|
+
} = require(path.join(EARLY_DIR, 'utils/undiciLogBodies'))
|
|
14
19
|
|
|
15
20
|
function getOtelTraceContext() {
|
|
16
21
|
try {
|
|
@@ -199,26 +204,50 @@ try {
|
|
|
199
204
|
const traceCtx = ctx || otelCtx
|
|
200
205
|
const rawTraceId = traceCtx && traceCtx.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
201
206
|
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
207
|
+
const reqOpts = resolveUndiciRequestOpts(url, options)
|
|
208
|
+
const requestBodyStr = serializeUndiciRequestBody(reqOpts)
|
|
202
209
|
const requestMeta = { traceId, spanId: (traceCtx && traceCtx.spanId) || null, parentSpanId: (traceCtx && traceCtx.parentSpanId) || null, requestId: (traceCtx && traceCtx.requestId) || null, method, url: urlStr }
|
|
210
|
+
if (requestBodyStr != null) requestMeta.requestBody = requestBodyStr
|
|
203
211
|
markSource(requestMeta, 'http-client')
|
|
204
212
|
const start = require('perf_hooks').performance.now()
|
|
205
213
|
const skipLog = isLoggerUrl(urlStr)
|
|
206
214
|
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) send('info', `[REQUEST] ${method} ${urlStr}`, requestMeta)
|
|
207
215
|
const wrappedCb = callback ? function (err, data) {
|
|
208
216
|
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
209
|
-
if (
|
|
210
|
-
if (
|
|
211
|
-
|
|
217
|
+
if (err) {
|
|
218
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
219
|
+
send('error', `[RESPONSE] ${method} ${urlStr} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
220
|
+
}
|
|
221
|
+
return callback(err, data)
|
|
212
222
|
}
|
|
213
|
-
return callback(err, data)
|
|
223
|
+
if (!data) return callback(err, data)
|
|
224
|
+
restoreUndiciResponseBodyAfterReadForLog(data).then(({ logStr, data: restored }) => {
|
|
225
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
226
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
227
|
+
if (logStr != null) meta.responseBody = logStr
|
|
228
|
+
send('info', `[RESPONSE] ${method} ${urlStr} ${restored.statusCode} ${duration}ms`, meta)
|
|
229
|
+
}
|
|
230
|
+
return callback(null, restored)
|
|
231
|
+
}).catch(() => {
|
|
232
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
233
|
+
send('info', `[RESPONSE] ${method} ${urlStr} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
234
|
+
}
|
|
235
|
+
return callback(null, data)
|
|
236
|
+
})
|
|
214
237
|
} : undefined
|
|
215
238
|
if (wrappedCb) return origRequest.call(this, url, options, wrappedCb)
|
|
216
239
|
const p = origRequest.call(this, url, options)
|
|
217
240
|
if (p && typeof p.then === 'function') {
|
|
218
241
|
return p.then(
|
|
219
|
-
(data) => {
|
|
242
|
+
async (data) => {
|
|
220
243
|
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
221
|
-
if (HTTP_CLIENT_MODE !== 'off' && !skipLog && data)
|
|
244
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog && data) {
|
|
245
|
+
const { logStr, data: restored } = await restoreUndiciResponseBodyAfterReadForLog(data)
|
|
246
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
247
|
+
if (logStr != null) meta.responseBody = logStr
|
|
248
|
+
send('info', `[RESPONSE] ${method} ${urlStr} ${restored.statusCode} ${duration}ms`, meta)
|
|
249
|
+
return restored
|
|
250
|
+
}
|
|
222
251
|
return data
|
|
223
252
|
},
|
|
224
253
|
(err) => {
|
|
@@ -244,25 +273,48 @@ try {
|
|
|
244
273
|
const traceCtx = ctx || otelCtx
|
|
245
274
|
const rawTraceId = (traceCtx && traceCtx.traceId) || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
246
275
|
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
276
|
+
const requestBodyStr = serializeUndiciRequestBody(opts || {})
|
|
247
277
|
const requestMeta = { traceId, spanId: (traceCtx && traceCtx.spanId) || null, parentSpanId: (traceCtx && traceCtx.parentSpanId) || null, requestId: (traceCtx && traceCtx.requestId) || null, method: methodStr, url: urlStr }
|
|
278
|
+
if (requestBodyStr != null) requestMeta.requestBody = requestBodyStr
|
|
248
279
|
markSource(requestMeta, 'http-client')
|
|
249
280
|
const start = require('perf_hooks').performance.now()
|
|
250
281
|
const skipLog = isLoggerUrl(urlStr)
|
|
251
282
|
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) send('info', `[REQUEST] ${methodStr} ${urlStr}`, requestMeta)
|
|
252
283
|
const wrappedCb = typeof callback === 'function' ? function (err, data) {
|
|
253
284
|
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
254
|
-
if (
|
|
255
|
-
if (
|
|
256
|
-
|
|
285
|
+
if (err) {
|
|
286
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
287
|
+
send('error', `[RESPONSE] ${methodStr} ${urlStr} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
288
|
+
}
|
|
289
|
+
return callback(err, data)
|
|
257
290
|
}
|
|
258
|
-
return callback(err, data)
|
|
291
|
+
if (!data) return callback(err, data)
|
|
292
|
+
restoreUndiciResponseBodyAfterReadForLog(data).then(({ logStr, data: restored }) => {
|
|
293
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
294
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
295
|
+
if (logStr != null) meta.responseBody = logStr
|
|
296
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${restored.statusCode} ${duration}ms`, meta)
|
|
297
|
+
}
|
|
298
|
+
return callback(null, restored)
|
|
299
|
+
}).catch(() => {
|
|
300
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
301
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
302
|
+
}
|
|
303
|
+
return callback(null, data)
|
|
304
|
+
})
|
|
259
305
|
} : undefined
|
|
260
306
|
const ret = wrappedCb ? origDisp.call(this, opts, wrappedCb) : origDisp.call(this, opts)
|
|
261
307
|
if (ret && typeof ret.then === 'function' && !wrappedCb) {
|
|
262
308
|
return ret.then(
|
|
263
|
-
(data) => {
|
|
309
|
+
async (data) => {
|
|
264
310
|
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
265
|
-
if (HTTP_CLIENT_MODE !== 'off' && !skipLog && data)
|
|
311
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog && data) {
|
|
312
|
+
const { logStr, data: restored } = await restoreUndiciResponseBodyAfterReadForLog(data)
|
|
313
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
314
|
+
if (logStr != null) meta.responseBody = logStr
|
|
315
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${restored.statusCode} ${duration}ms`, meta)
|
|
316
|
+
return restored
|
|
317
|
+
}
|
|
266
318
|
return data
|
|
267
319
|
},
|
|
268
320
|
(err) => {
|
|
@@ -323,25 +375,48 @@ try {
|
|
|
323
375
|
const traceCtx = ctx || otelCtx
|
|
324
376
|
const rawTraceId = (traceCtx && traceCtx.traceId) || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
325
377
|
const traceId = typeof rawTraceId === 'string' ? (toTraceIdHex ? toTraceIdHex(rawTraceId) : rawTraceId) : rawTraceId
|
|
378
|
+
const requestBodyStr = serializeUndiciRequestBody(opts || {})
|
|
326
379
|
const requestMeta = { traceId, spanId: (traceCtx && traceCtx.spanId) || null, parentSpanId: (traceCtx && traceCtx.parentSpanId) || null, requestId: (traceCtx && traceCtx.requestId) || null, method: methodStr, url: urlStr }
|
|
380
|
+
if (requestBodyStr != null) requestMeta.requestBody = requestBodyStr
|
|
327
381
|
if (markSource) markSource(requestMeta, 'http-client')
|
|
328
382
|
const start = require('perf_hooks').performance.now()
|
|
329
383
|
const skipLog = isLoggerUrl(urlStr)
|
|
330
384
|
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) send('info', `[REQUEST] ${methodStr} ${urlStr}`, requestMeta)
|
|
331
385
|
const wrappedCb = typeof callback === 'function' ? function (err, data) {
|
|
332
386
|
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
333
|
-
if (
|
|
334
|
-
if (
|
|
335
|
-
|
|
387
|
+
if (err) {
|
|
388
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
389
|
+
send('error', `[RESPONSE] ${methodStr} ${urlStr} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
390
|
+
}
|
|
391
|
+
return callback(err, data)
|
|
336
392
|
}
|
|
337
|
-
return callback(err, data)
|
|
393
|
+
if (!data) return callback(err, data)
|
|
394
|
+
restoreUndiciResponseBodyAfterReadForLog(data).then(({ logStr, data: restored }) => {
|
|
395
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
396
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
397
|
+
if (logStr != null) meta.responseBody = logStr
|
|
398
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${restored.statusCode} ${duration}ms`, meta)
|
|
399
|
+
}
|
|
400
|
+
return callback(null, restored)
|
|
401
|
+
}).catch(() => {
|
|
402
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
403
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
404
|
+
}
|
|
405
|
+
return callback(null, data)
|
|
406
|
+
})
|
|
338
407
|
} : undefined
|
|
339
408
|
const ret = wrappedCb ? origReq.call(this, opts, wrappedCb) : origReq.call(this, opts)
|
|
340
409
|
if (ret && typeof ret.then === 'function' && !wrappedCb) {
|
|
341
410
|
return ret.then(
|
|
342
|
-
(data) => {
|
|
411
|
+
async (data) => {
|
|
343
412
|
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
344
|
-
if (HTTP_CLIENT_MODE !== 'off' && !skipLog && data)
|
|
413
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog && data) {
|
|
414
|
+
const { logStr, data: restored } = await restoreUndiciResponseBodyAfterReadForLog(data)
|
|
415
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
416
|
+
if (logStr != null) meta.responseBody = logStr
|
|
417
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${restored.statusCode} ${duration}ms`, meta)
|
|
418
|
+
return restored
|
|
419
|
+
}
|
|
345
420
|
return data
|
|
346
421
|
},
|
|
347
422
|
(err) => {
|
|
@@ -401,25 +476,48 @@ try {
|
|
|
401
476
|
const traceCtx = ctx || otelCtx
|
|
402
477
|
const rawTraceId = (traceCtx && traceCtx.traceId) || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
403
478
|
const traceId = typeof rawTraceId === 'string' ? (toTraceIdHex ? toTraceIdHex(rawTraceId) : rawTraceId) : rawTraceId
|
|
479
|
+
const requestBodyStr = serializeUndiciRequestBody(opts || {})
|
|
404
480
|
const requestMeta = { traceId, spanId: (traceCtx && traceCtx.spanId) || null, parentSpanId: (traceCtx && traceCtx.parentSpanId) || null, requestId: (traceCtx && traceCtx.requestId) || null, method: methodStr, url: urlStr }
|
|
481
|
+
if (requestBodyStr != null) requestMeta.requestBody = requestBodyStr
|
|
405
482
|
if (markSource) markSource(requestMeta, 'http-client')
|
|
406
483
|
const start = require('perf_hooks').performance.now()
|
|
407
484
|
const skipLog = isLoggerUrl(urlStr)
|
|
408
485
|
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) send('info', `[REQUEST] ${methodStr} ${urlStr}`, requestMeta)
|
|
409
486
|
const wrappedCb = typeof callback === 'function' ? function (err, data) {
|
|
410
487
|
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
411
|
-
if (
|
|
412
|
-
if (
|
|
413
|
-
|
|
488
|
+
if (err) {
|
|
489
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
490
|
+
send('error', `[RESPONSE] ${methodStr} ${urlStr} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
491
|
+
}
|
|
492
|
+
return callback(err, data)
|
|
414
493
|
}
|
|
415
|
-
return callback(err, data)
|
|
494
|
+
if (!data) return callback(err, data)
|
|
495
|
+
restoreUndiciResponseBodyAfterReadForLog(data).then(({ logStr, data: restored }) => {
|
|
496
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
497
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
498
|
+
if (logStr != null) meta.responseBody = logStr
|
|
499
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${restored.statusCode} ${duration}ms`, meta)
|
|
500
|
+
}
|
|
501
|
+
return callback(null, restored)
|
|
502
|
+
}).catch(() => {
|
|
503
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog) {
|
|
504
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
505
|
+
}
|
|
506
|
+
return callback(null, data)
|
|
507
|
+
})
|
|
416
508
|
} : undefined
|
|
417
509
|
const ret = wrappedCb ? origReq.call(this, opts, wrappedCb) : origReq.call(this, opts)
|
|
418
510
|
if (ret && typeof ret.then === 'function' && !wrappedCb) {
|
|
419
511
|
return ret.then(
|
|
420
|
-
(data) => {
|
|
512
|
+
async (data) => {
|
|
421
513
|
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
422
|
-
if (HTTP_CLIENT_MODE !== 'off' && !skipLog && data)
|
|
514
|
+
if (HTTP_CLIENT_MODE !== 'off' && !skipLog && data) {
|
|
515
|
+
const { logStr, data: restored } = await restoreUndiciResponseBodyAfterReadForLog(data)
|
|
516
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
517
|
+
if (logStr != null) meta.responseBody = logStr
|
|
518
|
+
send('info', `[RESPONSE] ${methodStr} ${urlStr} ${restored.statusCode} ${duration}ms`, meta)
|
|
519
|
+
return restored
|
|
520
|
+
}
|
|
423
521
|
return data
|
|
424
522
|
},
|
|
425
523
|
(err) => {
|
package/register.js
CHANGED
|
@@ -445,16 +445,24 @@ try {
|
|
|
445
445
|
const { randomBytes } = require('crypto')
|
|
446
446
|
const { performance } = require('perf_hooks')
|
|
447
447
|
const { getRequestContext, getLastJobContext, toTraceIdHex } = require('./store')
|
|
448
|
+
const {
|
|
449
|
+
resolveUndiciRequestOpts,
|
|
450
|
+
serializeUndiciRequestBody,
|
|
451
|
+
restoreUndiciResponseBodyAfterReadForLog
|
|
452
|
+
} = require('./utils/undiciLogBodies')
|
|
448
453
|
const origRequest = exports.request
|
|
449
454
|
exports.request = function(url, options, callback) {
|
|
450
455
|
const ctx = getRequestContext() || getLastJobContext()
|
|
451
456
|
const otelCtx = getOtelTraceContext()
|
|
452
457
|
const traceCtx = ctx || otelCtx
|
|
453
|
-
const
|
|
458
|
+
const reqOpts = resolveUndiciRequestOpts(url, options)
|
|
459
|
+
const method = (reqOpts.method || options?.method || 'GET').toUpperCase()
|
|
454
460
|
const urlString = typeof url === 'string' ? url : (url && url.toString && url.toString()) || 'unknown'
|
|
455
461
|
const rawTraceId = traceCtx?.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
456
462
|
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
463
|
+
const requestBodyStr = serializeUndiciRequestBody(reqOpts)
|
|
457
464
|
const requestMeta = { traceId, spanId: traceCtx?.spanId || null, parentSpanId: traceCtx?.parentSpanId || null, requestId: traceCtx?.requestId || null, method, url: urlString }
|
|
465
|
+
if (requestBodyStr != null) requestMeta.requestBody = requestBodyStr
|
|
458
466
|
markSource(requestMeta, 'http-client')
|
|
459
467
|
const startTime = performance.now()
|
|
460
468
|
if (HTTP_CLIENT_MODE !== 'off') {
|
|
@@ -462,20 +470,39 @@ try {
|
|
|
462
470
|
}
|
|
463
471
|
const wrappedCb = callback ? function(err, data) {
|
|
464
472
|
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
465
|
-
if (
|
|
466
|
-
if (
|
|
467
|
-
|
|
473
|
+
if (err) {
|
|
474
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
475
|
+
sendOutboundLog('error', `[RESPONSE] ${method} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
476
|
+
}
|
|
477
|
+
return callback(err, data)
|
|
468
478
|
}
|
|
469
|
-
return callback(err, data)
|
|
479
|
+
if (!data) return callback(err, data)
|
|
480
|
+
restoreUndiciResponseBodyAfterReadForLog(data).then(({ logStr, data: restored }) => {
|
|
481
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
482
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
483
|
+
if (logStr != null) meta.responseBody = logStr
|
|
484
|
+
sendOutboundLog('info', `[RESPONSE] ${method} ${urlString} ${restored.statusCode} ${duration}ms`, meta)
|
|
485
|
+
}
|
|
486
|
+
return callback(null, restored)
|
|
487
|
+
}).catch(() => {
|
|
488
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
489
|
+
sendOutboundLog('info', `[RESPONSE] ${method} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
490
|
+
}
|
|
491
|
+
return callback(null, data)
|
|
492
|
+
})
|
|
470
493
|
} : undefined
|
|
471
494
|
if (wrappedCb) return origRequest.call(this, url, options, wrappedCb)
|
|
472
495
|
const promise = origRequest.call(this, url, options)
|
|
473
496
|
if (promise && typeof promise.then === 'function') {
|
|
474
497
|
return promise.then(
|
|
475
|
-
(data) => {
|
|
498
|
+
async (data) => {
|
|
476
499
|
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
477
500
|
if (HTTP_CLIENT_MODE !== 'off' && data) {
|
|
478
|
-
|
|
501
|
+
const { logStr, data: restored } = await restoreUndiciResponseBodyAfterReadForLog(data)
|
|
502
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
503
|
+
if (logStr != null) meta.responseBody = logStr
|
|
504
|
+
sendOutboundLog('info', `[RESPONSE] ${method} ${urlString} ${restored.statusCode} ${duration}ms`, meta)
|
|
505
|
+
return restored
|
|
479
506
|
}
|
|
480
507
|
return data
|
|
481
508
|
},
|
|
@@ -504,7 +531,9 @@ try {
|
|
|
504
531
|
const urlString = origin ? (origin + (path.startsWith('/') ? path : '/' + path)) : 'unknown'
|
|
505
532
|
const rawTraceId = traceCtx?.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
506
533
|
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
534
|
+
const requestBodyStr = serializeUndiciRequestBody(opts || {})
|
|
507
535
|
const requestMeta = { traceId, spanId: traceCtx?.spanId || null, parentSpanId: traceCtx?.parentSpanId || null, requestId: traceCtx?.requestId || null, method: methodStr, url: urlString }
|
|
536
|
+
if (requestBodyStr != null) requestMeta.requestBody = requestBodyStr
|
|
508
537
|
markSource(requestMeta, 'http-client')
|
|
509
538
|
const startTime = performance.now()
|
|
510
539
|
if (HTTP_CLIENT_MODE !== 'off') {
|
|
@@ -512,19 +541,38 @@ try {
|
|
|
512
541
|
}
|
|
513
542
|
const wrappedCb = typeof callback === 'function' ? function(err, data) {
|
|
514
543
|
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
515
|
-
if (
|
|
516
|
-
if (
|
|
517
|
-
|
|
544
|
+
if (err) {
|
|
545
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
546
|
+
sendOutboundLog('error', `[RESPONSE] ${methodStr} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
547
|
+
}
|
|
548
|
+
return callback(err, data)
|
|
518
549
|
}
|
|
519
|
-
return callback(err, data)
|
|
550
|
+
if (!data) return callback(err, data)
|
|
551
|
+
restoreUndiciResponseBodyAfterReadForLog(data).then(({ logStr, data: restored }) => {
|
|
552
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
553
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
554
|
+
if (logStr != null) meta.responseBody = logStr
|
|
555
|
+
sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${restored.statusCode} ${duration}ms`, meta)
|
|
556
|
+
}
|
|
557
|
+
return callback(null, restored)
|
|
558
|
+
}).catch(() => {
|
|
559
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
560
|
+
sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
561
|
+
}
|
|
562
|
+
return callback(null, data)
|
|
563
|
+
})
|
|
520
564
|
} : undefined
|
|
521
565
|
const ret = wrappedCb ? origDispRequest.call(this, opts, wrappedCb) : origDispRequest.call(this, opts)
|
|
522
566
|
if (ret && typeof ret.then === 'function' && !wrappedCb) {
|
|
523
567
|
return ret.then(
|
|
524
|
-
(data) => {
|
|
568
|
+
async (data) => {
|
|
525
569
|
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
526
570
|
if (HTTP_CLIENT_MODE !== 'off' && data) {
|
|
527
|
-
|
|
571
|
+
const { logStr, data: restored } = await restoreUndiciResponseBodyAfterReadForLog(data)
|
|
572
|
+
const meta = { ...requestMeta, statusCode: restored.statusCode, responseTimeMs: duration }
|
|
573
|
+
if (logStr != null) meta.responseBody = logStr
|
|
574
|
+
sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${restored.statusCode} ${duration}ms`, meta)
|
|
575
|
+
return restored
|
|
528
576
|
}
|
|
529
577
|
return data
|
|
530
578
|
},
|
|
@@ -1966,19 +2014,35 @@ try {
|
|
|
1966
2014
|
} catch (_) {
|
|
1967
2015
|
}
|
|
1968
2016
|
|
|
2017
|
+
const maxFetchBodyChars = Math.min(
|
|
2018
|
+
Math.max(parseInt(String(process.env.AZIFY_LOGGER_HTTP_BODY_MAX_CHARS || '5000'), 10) || 5000, 100),
|
|
2019
|
+
100000
|
|
2020
|
+
)
|
|
2021
|
+
const clipFetchBody = (s) => {
|
|
2022
|
+
if (typeof s !== 'string' || !s.length) return null
|
|
2023
|
+
return s.length > maxFetchBodyChars ? s.slice(0, maxFetchBodyChars) : s
|
|
2024
|
+
}
|
|
2025
|
+
|
|
1969
2026
|
let requestBodyString = null
|
|
1970
|
-
|
|
1971
|
-
|
|
2027
|
+
try {
|
|
2028
|
+
if (init && init.body !== null && init.body !== undefined) {
|
|
1972
2029
|
if (typeof init.body === 'string') {
|
|
1973
|
-
requestBodyString = init.body
|
|
2030
|
+
requestBodyString = clipFetchBody(init.body)
|
|
1974
2031
|
} else if (init.body instanceof FormData || init.body instanceof URLSearchParams) {
|
|
1975
2032
|
requestBodyString = '[FormData/URLSearchParams]'
|
|
1976
|
-
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
} catch (_) {
|
|
2036
|
+
}
|
|
2037
|
+
if (requestBodyString == null && request.body != null && method !== 'GET' && method !== 'HEAD') {
|
|
2038
|
+
try {
|
|
2039
|
+
const clone = request.clone()
|
|
2040
|
+
const text = await Promise.race([
|
|
2041
|
+
clone.text(),
|
|
2042
|
+
new Promise((resolve) => setTimeout(() => resolve(null), 4000))
|
|
2043
|
+
])
|
|
2044
|
+
if (typeof text === 'string' && text.length) {
|
|
2045
|
+
requestBodyString = clipFetchBody(text)
|
|
1982
2046
|
}
|
|
1983
2047
|
} catch (_) {
|
|
1984
2048
|
}
|
|
@@ -2085,10 +2149,15 @@ try {
|
|
|
2085
2149
|
}
|
|
2086
2150
|
}
|
|
2087
2151
|
|
|
2152
|
+
const responseReadMs = Math.min(
|
|
2153
|
+
Math.max(parseInt(String(process.env.AZIFY_LOGGER_HTTP_RESPONSE_READ_MS || '4000'), 10) || 4000, 200),
|
|
2154
|
+
30000
|
|
2155
|
+
)
|
|
2156
|
+
|
|
2088
2157
|
if (contentType.includes('application/json') || contentType.includes('text/')) {
|
|
2089
2158
|
try {
|
|
2090
2159
|
const clonedResponse = response.clone()
|
|
2091
|
-
const bodyText = await readBodyWithTimeout(clonedResponse,
|
|
2160
|
+
const bodyText = await readBodyWithTimeout(clonedResponse, responseReadMs)
|
|
2092
2161
|
if (bodyText) {
|
|
2093
2162
|
if (contentType.includes('application/json')) {
|
|
2094
2163
|
try {
|
|
@@ -2099,13 +2168,13 @@ try {
|
|
|
2099
2168
|
} else {
|
|
2100
2169
|
responseBodyString = bodyText
|
|
2101
2170
|
}
|
|
2102
|
-
if (typeof responseBodyString === 'string' && responseBodyString.length >
|
|
2103
|
-
responseBodyString = responseBodyString.slice(0,
|
|
2171
|
+
if (typeof responseBodyString === 'string' && responseBodyString.length > maxFetchBodyChars) {
|
|
2172
|
+
responseBodyString = responseBodyString.slice(0, maxFetchBodyChars)
|
|
2104
2173
|
}
|
|
2105
2174
|
}
|
|
2106
2175
|
} catch (_) {
|
|
2107
2176
|
try {
|
|
2108
|
-
const bodyText = await readBodyWithTimeout(response,
|
|
2177
|
+
const bodyText = await readBodyWithTimeout(response, responseReadMs)
|
|
2109
2178
|
if (bodyText) {
|
|
2110
2179
|
if (contentType.includes('application/json')) {
|
|
2111
2180
|
try {
|
|
@@ -2116,13 +2185,23 @@ try {
|
|
|
2116
2185
|
} else {
|
|
2117
2186
|
responseBodyString = bodyText
|
|
2118
2187
|
}
|
|
2119
|
-
if (typeof responseBodyString === 'string' && responseBodyString.length >
|
|
2120
|
-
responseBodyString = responseBodyString.slice(0,
|
|
2188
|
+
if (typeof responseBodyString === 'string' && responseBodyString.length > maxFetchBodyChars) {
|
|
2189
|
+
responseBodyString = responseBodyString.slice(0, maxFetchBodyChars)
|
|
2121
2190
|
}
|
|
2122
2191
|
}
|
|
2123
2192
|
} catch (_) {
|
|
2124
2193
|
}
|
|
2125
2194
|
}
|
|
2195
|
+
} else if (response.status !== 204 && response.status !== 205 && response.status !== 304) {
|
|
2196
|
+
try {
|
|
2197
|
+
const clonedResponse = response.clone()
|
|
2198
|
+
const bodyText = await readBodyWithTimeout(clonedResponse, responseReadMs)
|
|
2199
|
+
if (bodyText && bodyText.length) {
|
|
2200
|
+
responseBodyString =
|
|
2201
|
+
bodyText.length > maxFetchBodyChars ? bodyText.slice(0, maxFetchBodyChars) : bodyText
|
|
2202
|
+
}
|
|
2203
|
+
} catch (_) {
|
|
2204
|
+
}
|
|
2126
2205
|
}
|
|
2127
2206
|
} catch (_) {
|
|
2128
2207
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function maxBodyChars() {
|
|
4
|
+
return Math.min(
|
|
5
|
+
Math.max(parseInt(String(process.env.AZIFY_LOGGER_HTTP_BODY_MAX_CHARS || '5000'), 10) || 5000, 100),
|
|
6
|
+
100000
|
|
7
|
+
)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function clip(s) {
|
|
11
|
+
const m = maxBodyChars()
|
|
12
|
+
if (typeof s !== 'string' || !s.length) return null
|
|
13
|
+
return s.length > m ? s.slice(0, m) : s
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** undici: request(url, opts) ou request(opts) — retorna o objeto de opções com body/method. */
|
|
17
|
+
function resolveUndiciRequestOpts(url, options) {
|
|
18
|
+
if (typeof url === 'object' && url !== null && !(url instanceof URL)) {
|
|
19
|
+
return url
|
|
20
|
+
}
|
|
21
|
+
return options && typeof options === 'object' ? options : {}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function serializeUndiciRequestBody(opts) {
|
|
25
|
+
if (!opts || opts.body == null || opts.body === undefined) return null
|
|
26
|
+
try {
|
|
27
|
+
if (typeof opts.body === 'string') return clip(opts.body)
|
|
28
|
+
if (Buffer.isBuffer(opts.body)) return clip(opts.body.toString('utf8'))
|
|
29
|
+
if (opts.body && typeof opts.body.pipe === 'function') return '[Stream]'
|
|
30
|
+
return clip(String(opts.body))
|
|
31
|
+
} catch (_) {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function responseReadTimeoutMs() {
|
|
37
|
+
return Math.min(
|
|
38
|
+
Math.max(parseInt(String(process.env.AZIFY_LOGGER_HTTP_RESPONSE_READ_MS || '4000'), 10) || 4000, 200),
|
|
39
|
+
30000
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Lê o body da resposta undici para log e substitui `data.body` por um objeto com .text()/.json()
|
|
45
|
+
* compatível com o que o undici expõe, para o chamador ainda conseguir fazer parse.
|
|
46
|
+
*/
|
|
47
|
+
async function restoreUndiciResponseBodyAfterReadForLog(data) {
|
|
48
|
+
if (!data || !data.body || typeof data.body.text !== 'function') {
|
|
49
|
+
return { logStr: null, data }
|
|
50
|
+
}
|
|
51
|
+
const timeoutMs = responseReadTimeoutMs()
|
|
52
|
+
try {
|
|
53
|
+
const text = await Promise.race([
|
|
54
|
+
data.body.text(),
|
|
55
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeoutMs))
|
|
56
|
+
])
|
|
57
|
+
if (text == null || typeof text !== 'string') {
|
|
58
|
+
return { logStr: null, data }
|
|
59
|
+
}
|
|
60
|
+
const logStr = clip(text)
|
|
61
|
+
data.body = {
|
|
62
|
+
async text() {
|
|
63
|
+
return text
|
|
64
|
+
},
|
|
65
|
+
async json() {
|
|
66
|
+
return JSON.parse(text)
|
|
67
|
+
},
|
|
68
|
+
async arrayBuffer() {
|
|
69
|
+
return Buffer.from(text, 'utf8').buffer
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { logStr, data }
|
|
73
|
+
} catch (_) {
|
|
74
|
+
return { logStr: null, data }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
resolveUndiciRequestOpts,
|
|
80
|
+
serializeUndiciRequestBody,
|
|
81
|
+
restoreUndiciResponseBodyAfterReadForLog,
|
|
82
|
+
maxBodyChars
|
|
83
|
+
}
|