azify-logger 1.0.44 → 1.0.45
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/index.js +84 -7
- package/init.js +21 -11
- package/middleware-express.js +46 -44
- package/middleware-pino.js +19 -10
- package/package.json +3 -1
- package/preload.js +15 -0
- package/register-http-client-early.js +816 -0
- package/register.js +1219 -366
- package/sampling.js +1 -1
- package/server.js +77 -10
- package/store.js +37 -11
- package/streams/httpQueue.js +24 -12
- package/streams/pino.js +45 -10
package/register.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
if (process.env.AZIFY_LOGGER_DISABLE === '1') {
|
|
2
2
|
module.exports = {}
|
|
3
3
|
} else {
|
|
4
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
5
|
+
try { process.stderr.write('[azify-logger] REGISTER_START register.js loading\n') } catch (_) {}
|
|
6
|
+
}
|
|
4
7
|
try {
|
|
8
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
9
|
+
try { process.stderr.write('[azify-logger] REGISTER step1 top try\n') } catch (_) {}
|
|
10
|
+
}
|
|
11
|
+
const ModuleForRequire = require('module')
|
|
12
|
+
const nodeRequireOriginal = ModuleForRequire.prototype.require
|
|
5
13
|
const bunyan = require('bunyan')
|
|
6
14
|
const createBunyanStream = require('./streams/bunyan')
|
|
7
15
|
const { createHttpLoggerTransport } = require('./streams/httpQueue')
|
|
@@ -13,6 +21,10 @@ try {
|
|
|
13
21
|
|
|
14
22
|
const { shouldSample, markSource, HTTP_CLIENT_MODE } = require('./sampling')
|
|
15
23
|
|
|
24
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
25
|
+
try { process.stderr.write('[azify-logger] REGISTER step1b after requires\n') } catch (_) {}
|
|
26
|
+
try { process.stderr.write('[azify-logger] REGISTER step2-early (right after step1b)\n') } catch (_) {}
|
|
27
|
+
}
|
|
16
28
|
const serviceName = process.env.APP_NAME
|
|
17
29
|
const environment = process.env.NODE_ENV
|
|
18
30
|
const loggerUrlFromEnv = process.env.AZIFY_LOGGER_URL
|
|
@@ -25,11 +37,64 @@ try {
|
|
|
25
37
|
}
|
|
26
38
|
|
|
27
39
|
const loggerUrlString = loggerEndpoint.toString()
|
|
28
|
-
|
|
40
|
+
let transport = null
|
|
41
|
+
const MAX_PENDING_OUTBOUND = 2000
|
|
42
|
+
|
|
43
|
+
function sendRequestResponseDirectHttp(payload) {
|
|
44
|
+
try {
|
|
45
|
+
const body = typeof payload === 'string' ? payload : JSON.stringify(payload)
|
|
46
|
+
const isHttps = loggerEndpoint.protocol === 'https:'
|
|
47
|
+
const lib = isHttps ? require('https') : require('http')
|
|
48
|
+
const path = (loggerEndpoint.pathname && loggerEndpoint.pathname !== '/') ? loggerEndpoint.pathname : '/log'
|
|
49
|
+
const port = loggerEndpoint.port ? parseInt(loggerEndpoint.port, 10) : (isHttps ? 443 : 80)
|
|
50
|
+
const opts = {
|
|
51
|
+
hostname: loggerEndpoint.hostname,
|
|
52
|
+
port: Number.isFinite(port) ? port : (isHttps ? 443 : 80),
|
|
53
|
+
path,
|
|
54
|
+
method: 'POST',
|
|
55
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body, 'utf8') }
|
|
56
|
+
}
|
|
57
|
+
const debug = process.env.AZIFY_LOGGER_DEBUG === '1'
|
|
58
|
+
const req = lib.request(opts, function (res) {
|
|
59
|
+
res.resume()
|
|
60
|
+
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
61
|
+
try {
|
|
62
|
+
process.stderr.write(`[azify-logger] REQUEST/RESPONSE log POST failed: server responded ${res.statusCode} (check log server at ${loggerUrlString})\n`)
|
|
63
|
+
} catch (_) {}
|
|
64
|
+
if (debug) try { process.stderr.write(`[azify-logger] direct HTTP log server responded ${res.statusCode}\n`) } catch (_) {}
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
req.on('error', function (err) {
|
|
68
|
+
try {
|
|
69
|
+
process.stderr.write(`[azify-logger] REQUEST/RESPONSE log POST failed: ${err && err.message} (is log server running at ${loggerUrlString}?)\n`)
|
|
70
|
+
} catch (_) {}
|
|
71
|
+
if (debug) try { process.stderr.write(`[azify-logger] direct HTTP to log server failed: ${err && err.message}\n`) } catch (_) {}
|
|
72
|
+
})
|
|
73
|
+
req.setTimeout(5000, function () { req.destroy() })
|
|
74
|
+
req.write(body)
|
|
75
|
+
req.end()
|
|
76
|
+
} catch (e) {
|
|
77
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write(`[azify-logger] sendRequestResponseDirectHttp error: ${e && e.message}\n`) } catch (_) {}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const pendingOutboundLogs = []
|
|
81
|
+
const flushTransport = () => transport && typeof transport.flush === 'function' ? transport.flush().catch(() => {}) : Promise.resolve()
|
|
82
|
+
function setTransport(t) {
|
|
83
|
+
transport = t
|
|
84
|
+
if (t && pendingOutboundLogs.length > 0) {
|
|
85
|
+
const toFlush = pendingOutboundLogs.splice(0, pendingOutboundLogs.length)
|
|
86
|
+
toFlush.forEach(function (item) {
|
|
87
|
+
try {
|
|
88
|
+
if (typeof transport.enqueue === 'function') transport.enqueue(item.payload, item.headers || { 'content-type': 'application/json' })
|
|
89
|
+
} catch (_) {}
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
if (t) { process.once('beforeExit', flushTransport); process.once('exit', flushTransport) }
|
|
93
|
+
}
|
|
29
94
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
95
|
+
try {
|
|
96
|
+
setTransport(createHttpLoggerTransport(loggerUrlString, {}))
|
|
97
|
+
} catch (_) {}
|
|
33
98
|
|
|
34
99
|
const normalizedLoggerOrigin = `${loggerEndpoint.protocol}//${loggerEndpoint.host}`
|
|
35
100
|
const normalizedLoggerPath = normalizePath(loggerEndpoint.pathname || '/')
|
|
@@ -78,20 +143,38 @@ try {
|
|
|
78
143
|
return sanitized
|
|
79
144
|
}
|
|
80
145
|
|
|
146
|
+
const debug = process.env.AZIFY_LOGGER_DEBUG === '1'
|
|
147
|
+
const httpVerbose = process.env.AZIFY_LOGGER_HTTP_VERBOSE === '1'
|
|
81
148
|
function sendOutboundLog(level, message, meta) {
|
|
82
149
|
try {
|
|
150
|
+
const msgStr = String(message)
|
|
151
|
+
const isReqRes = msgStr.includes('[REQUEST]') || msgStr.includes('[RESPONSE]')
|
|
152
|
+
if (isReqRes && meta && meta.url && isLoggerApiCall({ url: meta.url })) return
|
|
153
|
+
if (isReqRes && meta && (meta.url === 'unknown' || !String(meta.url || '').trim() || String(meta.url).toLowerCase() === 'unknown')) return
|
|
83
154
|
const source = meta && meta.__source
|
|
155
|
+
if (debug && source === 'pino-stdout') {
|
|
156
|
+
if (debug) try { process.stderr.write('[azify-logger] SENDOUTBOUND_ENTER level=' + level + ' source=' + source + ' msg=' + msgStr.slice(0, 60) + '\n') } catch (_) {}
|
|
157
|
+
}
|
|
84
158
|
if (!shouldSample(level, source)) {
|
|
159
|
+
if (debug && (isReqRes || msgStr.includes('failed after'))) {
|
|
160
|
+
if (debug) process.stderr.write('[azify-logger] SENDOUTBOUND_SKIP shouldSample level=' + level + ' source=' + source + '\n')
|
|
161
|
+
}
|
|
85
162
|
return
|
|
86
163
|
}
|
|
164
|
+
if (debug && source === 'pino-stdout') {
|
|
165
|
+
if (debug) try { process.stderr.write('[azify-logger] SENDOUTBOUND_ENQUEUE level=' + level + ' msg=' + msgStr.slice(0, 50) + '\n') } catch (_) {}
|
|
166
|
+
}
|
|
87
167
|
|
|
168
|
+
const forceHttpClientSource = source === 'http-client' || isReqRes
|
|
169
|
+
const effectiveServiceName = serviceName || process.env.APP_NAME || process.env.SERVICE_NAME || (meta && meta.service && meta.service.name) || 'unknown-app'
|
|
88
170
|
const payload = {
|
|
89
171
|
level,
|
|
90
172
|
message,
|
|
91
173
|
meta: {
|
|
92
174
|
...meta,
|
|
175
|
+
...(forceHttpClientSource && { source: 'http-client' }),
|
|
93
176
|
service: {
|
|
94
|
-
name:
|
|
177
|
+
name: effectiveServiceName,
|
|
95
178
|
version: (meta && meta.service && meta.service.version) || '1.0.0'
|
|
96
179
|
},
|
|
97
180
|
environment,
|
|
@@ -99,15 +182,156 @@ try {
|
|
|
99
182
|
hostname: os.hostname()
|
|
100
183
|
}
|
|
101
184
|
}
|
|
185
|
+
const headers = { 'content-type': 'application/json' }
|
|
186
|
+
|
|
187
|
+
if (isReqRes && loggerUrlString) {
|
|
188
|
+
if (debug) try { process.stderr.write(`[AZIFY] REQUEST/RESPONSE -> direct HTTP source=${source || 'n/a'} ${msgStr.slice(0, 72)}\n`) } catch (_) {}
|
|
189
|
+
setImmediate(function () { sendRequestResponseDirectHttp(payload) })
|
|
190
|
+
return
|
|
191
|
+
}
|
|
102
192
|
|
|
103
193
|
if (transport && typeof transport.enqueue === 'function') {
|
|
104
|
-
transport.enqueue(payload,
|
|
105
|
-
|
|
106
|
-
|
|
194
|
+
transport.enqueue(payload, headers)
|
|
195
|
+
} else {
|
|
196
|
+
if (pendingOutboundLogs.length >= MAX_PENDING_OUTBOUND) pendingOutboundLogs.shift()
|
|
197
|
+
pendingOutboundLogs.push({ payload, headers })
|
|
198
|
+
if (isReqRes && debug) {
|
|
199
|
+
try { process.stderr.write(`[AZIFY] REQUEST/RESPONSE PENDING (no transport yet) source=${source || 'n/a'} ${msgStr.slice(0, 60)}\n`) } catch (_) {}
|
|
200
|
+
}
|
|
107
201
|
}
|
|
108
202
|
} catch (err) {
|
|
203
|
+
if (debug) process.stderr.write(`[azify-logger] sendOutboundLog error: ${err && err.message}\n`)
|
|
109
204
|
}
|
|
110
205
|
}
|
|
206
|
+
if (typeof global !== 'undefined') global.__AZIFY_SEND_OUTBOUND_LOG = sendOutboundLog
|
|
207
|
+
try {
|
|
208
|
+
const early = require('./register-http-client-early')
|
|
209
|
+
if (typeof early.flushEarlyLogQueue === 'function') early.flushEarlyLogQueue()
|
|
210
|
+
if (typeof early.patchUndiciInCache === 'function') early.patchUndiciInCache()
|
|
211
|
+
} catch (_) {}
|
|
212
|
+
|
|
213
|
+
const MAX_LINE_BUFFER_BYTES = 2 * 1024 * 1024
|
|
214
|
+
function makePinoCaptureHandler(streamName) {
|
|
215
|
+
let inCapture = false
|
|
216
|
+
let lineBuffer = ''
|
|
217
|
+
function trySendLine(line) {
|
|
218
|
+
const trimmed = line.trim()
|
|
219
|
+
if (debug && trimmed.startsWith('{') && (trimmed.includes('"msg":') || trimmed.includes('"message":'))) {
|
|
220
|
+
if (debug) try { process.stderr.write('[azify-logger] TRYSENDLINE_IN stream=' + streamName + ' len=' + trimmed.length + ' preview=' + trimmed.slice(0, 80) + '...\n') } catch (_) {}
|
|
221
|
+
}
|
|
222
|
+
if (!trimmed.startsWith('{') || (!trimmed.includes('"msg":') && !trimmed.includes('"message":'))) {
|
|
223
|
+
if (debug && trimmed.length > 0 && trimmed.length < 200) {
|
|
224
|
+
if (debug) try { process.stderr.write('[azify-logger] TRYSENDLINE_SKIP no json/msg stream=' + streamName + ' preview=' + trimmed.slice(0, 60) + '\n') } catch (_) {}
|
|
225
|
+
}
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const record = JSON.parse(trimmed)
|
|
230
|
+
const msg = record.msg || record.message || ''
|
|
231
|
+
if (!msg || typeof record.level !== 'number') {
|
|
232
|
+
if (debug) try { process.stderr.write(`[azify-logger] TRYSENDLINE_SKIP no level/msg stream=${streamName}\n`) } catch (_) {}
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
inCapture = true
|
|
236
|
+
const levelMap = { 60: 'fatal', 50: 'error', 40: 'warn', 30: 'info', 20: 'debug', 10: 'trace' }
|
|
237
|
+
const level = levelMap[record.level] || 'info'
|
|
238
|
+
const { getRequestContext, getLastJobContext, toTraceIdHex } = require('./store')
|
|
239
|
+
let ctx = getRequestContext()
|
|
240
|
+
if (!ctx || !ctx.traceId) ctx = getLastJobContext()
|
|
241
|
+
let traceId = (ctx && ctx.traceId) ? toTraceIdHex(String(ctx.traceId)) : null
|
|
242
|
+
let spanId = ctx && ctx.spanId != null ? String(ctx.spanId).slice(0, 16) : null
|
|
243
|
+
if (!traceId && typeof msg === 'string' && /traceId/i.test(msg)) {
|
|
244
|
+
const m = msg.match(/"traceId"\s*:\s*"([^"]+)"/)
|
|
245
|
+
if (m) traceId = toTraceIdHex(m[1])
|
|
246
|
+
}
|
|
247
|
+
if (!traceId) {
|
|
248
|
+
try {
|
|
249
|
+
const { startRequestContext } = require('./store')
|
|
250
|
+
const c = startRequestContext({})
|
|
251
|
+
traceId = c.traceId
|
|
252
|
+
spanId = c.spanId
|
|
253
|
+
} catch (_) {
|
|
254
|
+
traceId = require('crypto').randomUUID ? require('crypto').randomUUID().replace(/-/g, '') : String(Date.now())
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const meta = { traceId, spanId, parentSpanId: ctx && ctx.parentSpanId, requestId: ctx && ctx.requestId, __source: 'pino-stdout' }
|
|
258
|
+
if (debug) try { process.stderr.write(`[azify-logger] TRYSENDLINE_SEND level=${level} msg=${String(msg).slice(0, 50)}\n`) } catch (_) {}
|
|
259
|
+
sendOutboundLog(level, msg, meta)
|
|
260
|
+
if (debug) process.stderr.write(`[azify-logger] TRYSENDLINE_DONE ${streamName} sent: ${String(msg).slice(0, 60)}\n`)
|
|
261
|
+
} catch (e) {
|
|
262
|
+
if (debug) try { process.stderr.write(`[azify-logger] TRYSENDLINE_ERR stream=${streamName} ${e && e.message}\n`) } catch (_) {}
|
|
263
|
+
} finally {
|
|
264
|
+
inCapture = false
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return function handleChunk(str) {
|
|
268
|
+
if (typeof str !== 'string' || !str || inCapture) return
|
|
269
|
+
if (debug && str.trim().startsWith('{') && (str.includes('"level":') || str.includes('"msg":'))) {
|
|
270
|
+
if (debug) try { process.stderr.write('[azify-logger] CAPTURE_CHUNK stream=' + streamName + ' len=' + str.length + ' preview=' + str.slice(0, 70).replace(/\n/g, ' ') + '...\n') } catch (_) {}
|
|
271
|
+
}
|
|
272
|
+
lineBuffer += str
|
|
273
|
+
if (lineBuffer.length > MAX_LINE_BUFFER_BYTES) {
|
|
274
|
+
const lastNewline = lineBuffer.lastIndexOf('\n')
|
|
275
|
+
if (lastNewline > 0) {
|
|
276
|
+
const keep = lineBuffer.slice(lastNewline + 1)
|
|
277
|
+
lineBuffer = lineBuffer.slice(0, lastNewline + 1)
|
|
278
|
+
const lines = lineBuffer.split('\n')
|
|
279
|
+
lineBuffer = lines.pop() || ''
|
|
280
|
+
for (let i = 0; i < lines.length; i++) trySendLine(lines[i])
|
|
281
|
+
lineBuffer = keep
|
|
282
|
+
} else {
|
|
283
|
+
lineBuffer = lineBuffer.slice(-1024)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const lines = lineBuffer.split('\n')
|
|
287
|
+
lineBuffer = lines.pop() || ''
|
|
288
|
+
for (let i = 0; i < lines.length; i++) trySendLine(lines[i])
|
|
289
|
+
if (lineBuffer.trim().startsWith('{') && lineBuffer.trim().endsWith('}')) {
|
|
290
|
+
trySendLine(lineBuffer)
|
|
291
|
+
lineBuffer = ''
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const stdoutCapture = makePinoCaptureHandler('stdout')
|
|
296
|
+
const stderrCapture = makePinoCaptureHandler('stderr')
|
|
297
|
+
|
|
298
|
+
function patchStreamAtWrite(stream, streamName, capture) {
|
|
299
|
+
if (!stream || stream.__azifyLoggerWritePatched) return
|
|
300
|
+
const origWrite = stream.write
|
|
301
|
+
if (typeof origWrite !== 'function') return
|
|
302
|
+
stream.write = function(chunk, encoding, callback) {
|
|
303
|
+
const str = (typeof chunk === 'string' ? chunk : (chunk && chunk.toString ? chunk.toString() : ''))
|
|
304
|
+
capture(str)
|
|
305
|
+
return origWrite.apply(this, arguments)
|
|
306
|
+
}
|
|
307
|
+
stream.__azifyLoggerWritePatched = true
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function patchStreamAt_Writer(stream, streamName, capture) {
|
|
311
|
+
if (!stream || !stream._write || stream.__azifyLogger_WriterPatched) return
|
|
312
|
+
const orig_Writer = stream._write.bind(stream)
|
|
313
|
+
stream._write = function(chunk, encoding, callback) {
|
|
314
|
+
const str = (typeof chunk === 'string' ? chunk : (chunk && chunk.toString ? chunk.toString() : ''))
|
|
315
|
+
capture(str)
|
|
316
|
+
return orig_Writer(chunk, encoding, callback)
|
|
317
|
+
}
|
|
318
|
+
stream.__azifyLogger_WriterPatched = true
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
if (!global.__AZIFY_LOGGER_STDOUT_PATCHED) {
|
|
323
|
+
global.__AZIFY_LOGGER_STDOUT_PATCHED = true
|
|
324
|
+
patchStreamAtWrite(process.stdout, 'stdout', stdoutCapture)
|
|
325
|
+
patchStreamAt_Writer(process.stdout, 'stdout', stdoutCapture)
|
|
326
|
+
}
|
|
327
|
+
} catch (_) {}
|
|
328
|
+
try {
|
|
329
|
+
if (!global.__AZIFY_LOGGER_STDERR_PATCHED) {
|
|
330
|
+
global.__AZIFY_LOGGER_STDERR_PATCHED = true
|
|
331
|
+
patchStreamAtWrite(process.stderr, 'stderr', stderrCapture)
|
|
332
|
+
patchStreamAt_Writer(process.stderr, 'stderr', stderrCapture)
|
|
333
|
+
}
|
|
334
|
+
} catch (_) {}
|
|
111
335
|
|
|
112
336
|
function normalizePath(path) {
|
|
113
337
|
if (!path) {
|
|
@@ -162,12 +386,12 @@ try {
|
|
|
162
386
|
const otelApi = require('@opentelemetry/api')
|
|
163
387
|
const activeContext = otelApi.context.active()
|
|
164
388
|
const span = otelApi.trace.getSpan(activeContext)
|
|
165
|
-
|
|
389
|
+
|
|
166
390
|
if (!span) return null
|
|
167
|
-
|
|
391
|
+
|
|
168
392
|
const spanContext = span.spanContext()
|
|
169
393
|
if (!spanContext || !spanContext.traceId) return null
|
|
170
|
-
|
|
394
|
+
|
|
171
395
|
return {
|
|
172
396
|
traceId: spanContext.traceId,
|
|
173
397
|
spanId: spanContext.spanId,
|
|
@@ -178,32 +402,181 @@ try {
|
|
|
178
402
|
}
|
|
179
403
|
}
|
|
180
404
|
|
|
405
|
+
const Module = require('module')
|
|
406
|
+
const originalRequireForEarly = Module.prototype.require
|
|
407
|
+
function patchUndiciExportsEarly(exports) {
|
|
408
|
+
if (!exports || typeof exports.request !== 'function' || exports.request.__azifyPatched) return exports
|
|
409
|
+
const { randomBytes } = require('crypto')
|
|
410
|
+
const { performance } = require('perf_hooks')
|
|
411
|
+
const { getRequestContext, getLastJobContext, toTraceIdHex } = require('./store')
|
|
412
|
+
const origRequest = exports.request
|
|
413
|
+
exports.request = function(url, options, callback) {
|
|
414
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
415
|
+
const otelCtx = getOtelTraceContext()
|
|
416
|
+
const traceCtx = ctx || otelCtx
|
|
417
|
+
const method = (options?.method || 'GET').toUpperCase()
|
|
418
|
+
const urlString = typeof url === 'string' ? url : (url && url.toString && url.toString()) || 'unknown'
|
|
419
|
+
const rawTraceId = traceCtx?.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
420
|
+
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
421
|
+
const requestMeta = { traceId, spanId: traceCtx?.spanId || null, parentSpanId: traceCtx?.parentSpanId || null, requestId: traceCtx?.requestId || null, method, url: urlString }
|
|
422
|
+
markSource(requestMeta, 'http-client')
|
|
423
|
+
const startTime = performance.now()
|
|
424
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
425
|
+
sendOutboundLog('info', `[REQUEST] ${method} ${urlString}`, requestMeta)
|
|
426
|
+
}
|
|
427
|
+
const wrappedCb = callback ? function(err, data) {
|
|
428
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
429
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
430
|
+
if (err) sendOutboundLog('error', `[RESPONSE] ${method} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
431
|
+
else if (data) sendOutboundLog('info', `[RESPONSE] ${method} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
432
|
+
}
|
|
433
|
+
return callback(err, data)
|
|
434
|
+
} : undefined
|
|
435
|
+
if (wrappedCb) return origRequest.call(this, url, options, wrappedCb)
|
|
436
|
+
const promise = origRequest.call(this, url, options)
|
|
437
|
+
if (promise && typeof promise.then === 'function') {
|
|
438
|
+
return promise.then(
|
|
439
|
+
(data) => {
|
|
440
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
441
|
+
if (HTTP_CLIENT_MODE !== 'off' && data) {
|
|
442
|
+
sendOutboundLog('info', `[RESPONSE] ${method} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
443
|
+
}
|
|
444
|
+
return data
|
|
445
|
+
},
|
|
446
|
+
(err) => {
|
|
447
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
448
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
449
|
+
sendOutboundLog('error', `[RESPONSE] ${method} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: (err && err.message) || String(err), responseTimeMs: duration })
|
|
450
|
+
}
|
|
451
|
+
throw err
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
}
|
|
455
|
+
return promise
|
|
456
|
+
}
|
|
457
|
+
exports.request.__azifyPatched = true
|
|
458
|
+
if (exports.Dispatcher && exports.Dispatcher.prototype && typeof exports.Dispatcher.prototype.request === 'function' && !exports.Dispatcher.prototype.request.__azifyPatched) {
|
|
459
|
+
const proto = exports.Dispatcher.prototype
|
|
460
|
+
const origDispRequest = proto.request
|
|
461
|
+
proto.request = function(opts, callback) {
|
|
462
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
463
|
+
const otelCtx = getOtelTraceContext()
|
|
464
|
+
const traceCtx = ctx || otelCtx
|
|
465
|
+
const methodStr = String((opts && opts.method) || 'GET').toUpperCase()
|
|
466
|
+
const origin = (opts && opts.origin) || ''
|
|
467
|
+
const path = (opts && opts.path) != null ? opts.path : '/'
|
|
468
|
+
const urlString = origin ? (origin + (path.startsWith('/') ? path : '/' + path)) : 'unknown'
|
|
469
|
+
const rawTraceId = traceCtx?.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
470
|
+
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
471
|
+
const requestMeta = { traceId, spanId: traceCtx?.spanId || null, parentSpanId: traceCtx?.parentSpanId || null, requestId: traceCtx?.requestId || null, method: methodStr, url: urlString }
|
|
472
|
+
markSource(requestMeta, 'http-client')
|
|
473
|
+
const startTime = performance.now()
|
|
474
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
475
|
+
sendOutboundLog('info', `[REQUEST] ${methodStr} ${urlString}`, requestMeta)
|
|
476
|
+
}
|
|
477
|
+
const wrappedCb = typeof callback === 'function' ? function(err, data) {
|
|
478
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
479
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
480
|
+
if (err) sendOutboundLog('error', `[RESPONSE] ${methodStr} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
481
|
+
else if (data) sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
482
|
+
}
|
|
483
|
+
return callback(err, data)
|
|
484
|
+
} : undefined
|
|
485
|
+
const ret = wrappedCb ? origDispRequest.call(this, opts, wrappedCb) : origDispRequest.call(this, opts)
|
|
486
|
+
if (ret && typeof ret.then === 'function' && !wrappedCb) {
|
|
487
|
+
return ret.then(
|
|
488
|
+
(data) => {
|
|
489
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
490
|
+
if (HTTP_CLIENT_MODE !== 'off' && data) {
|
|
491
|
+
sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
492
|
+
}
|
|
493
|
+
return data
|
|
494
|
+
},
|
|
495
|
+
(err) => {
|
|
496
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
497
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
498
|
+
sendOutboundLog('error', `[RESPONSE] ${methodStr} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: (err && err.message) || String(err), responseTimeMs: duration })
|
|
499
|
+
}
|
|
500
|
+
throw err
|
|
501
|
+
}
|
|
502
|
+
)
|
|
503
|
+
}
|
|
504
|
+
return ret
|
|
505
|
+
}
|
|
506
|
+
proto.request.__azifyPatched = true
|
|
507
|
+
}
|
|
508
|
+
return exports
|
|
509
|
+
}
|
|
510
|
+
try {
|
|
511
|
+
const origLoad = Module._load
|
|
512
|
+
if (origLoad && origLoad.__azifyEarlyPatched) {
|
|
513
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] Module._load keeping early hook (not overwriting)\n') } catch (_) {}
|
|
514
|
+
} else if (typeof origLoad === 'function' && !Module._load.__azifyPatched) {
|
|
515
|
+
Module._load = function (request, parent, isMain) {
|
|
516
|
+
const result = origLoad.apply(this, arguments)
|
|
517
|
+
const pathStr = typeof request === 'string' ? request.replace(/\\/g, '/') : ''
|
|
518
|
+
const isUndici = pathStr === 'undici' || (pathStr.indexOf('undici') !== -1 && pathStr.indexOf('undici-package') === -1)
|
|
519
|
+
if (isUndici) {
|
|
520
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write(`[azify-logger] Module._load UNDICI path=${pathStr.slice(-90)}\n`) } catch (_) {}
|
|
521
|
+
try {
|
|
522
|
+
patchUndiciExportsEarly(result)
|
|
523
|
+
} catch (e) {
|
|
524
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] Module._load patchUndiciExportsEarly threw: ' + (e && e.message) + '\n') } catch (_) {}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return result
|
|
528
|
+
}
|
|
529
|
+
Module._load.__azifyPatched = true
|
|
530
|
+
if (debug) try { process.stderr.write('[azify-logger] Module._load hook installed (early)\n') } catch (_) {}
|
|
531
|
+
}
|
|
532
|
+
} catch (_) {}
|
|
533
|
+
|
|
534
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
535
|
+
try { process.stderr.write('[azify-logger] REGISTER step2 before first hook\n') } catch (_) {}
|
|
536
|
+
}
|
|
181
537
|
try {
|
|
182
|
-
const Module = require('module')
|
|
183
538
|
const originalRequire = Module.prototype.require
|
|
184
539
|
const { getRequestContext } = require('./store')
|
|
185
|
-
|
|
540
|
+
|
|
186
541
|
Module.prototype.require = function(id) {
|
|
187
542
|
const result = originalRequire.call(this, id)
|
|
543
|
+
const idStr = typeof id === 'string' ? id : ''
|
|
544
|
+
const idLooksLikeUndici = idStr === 'undici' || (idStr.length > 0 && idStr.replace(/\\/g, '/').indexOf('undici') !== -1 && idStr.indexOf('undici-package') === -1)
|
|
545
|
+
const looksLikeUndici = result && (typeof result.request === 'function' || typeof result.fetch === 'function') && (result.request && !result.request.__azifyPatched || result.fetch && !result.fetch.__azifyPatched)
|
|
546
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1' && (idLooksLikeUndici || looksLikeUndici)) {
|
|
547
|
+
try { process.stderr.write('[azify-logger] require undici-like id=' + idStr.slice(-70) + ' hasRequest=' + !!(result && result.request) + ' hasFetch=' + !!(result && result.fetch) + '\n') } catch (_) {}
|
|
548
|
+
}
|
|
549
|
+
if (debug && (idLooksLikeUndici || id === 'nestjs-pino')) {
|
|
550
|
+
try { process.stderr.write('[azify-logger] require hook id=' + id + '\n') } catch (_) {}
|
|
551
|
+
}
|
|
552
|
+
if ((idLooksLikeUndici || looksLikeUndici) && result) {
|
|
553
|
+
if (process.env.AZIFY_LOGGER_HTTP_DEBUG === '1' || process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
554
|
+
try { process.stderr.write('[AZIFY-HTTP] REGISTER_HOOK1 patch id=' + idStr.slice(-70) + '\n') } catch (_) {}
|
|
555
|
+
}
|
|
556
|
+
try {
|
|
557
|
+
const early = require('./register-http-client-early')
|
|
558
|
+
if (typeof early.patchUndiciExports === 'function') early.patchUndiciExports(result)
|
|
559
|
+
} catch (_) {}
|
|
560
|
+
}
|
|
188
561
|
if (id === 'pino' || id.endsWith('/pino')) {
|
|
189
562
|
if (result && typeof result === 'function') {
|
|
190
563
|
const originalPino = result
|
|
191
|
-
|
|
564
|
+
|
|
192
565
|
const patchedPino = function(options, stream) {
|
|
193
566
|
if (new.target) {
|
|
194
567
|
return originalPino.call(this, options, stream)
|
|
195
568
|
}
|
|
196
|
-
|
|
569
|
+
|
|
197
570
|
const logger = originalPino(options, stream)
|
|
198
571
|
return applyLoggerPatches(logger, options)
|
|
199
572
|
}
|
|
200
|
-
|
|
573
|
+
|
|
201
574
|
function applyLoggerPatches(logger, pinoOptions) {
|
|
202
575
|
if (logger.__azifyPatched) {
|
|
203
576
|
return logger
|
|
204
577
|
}
|
|
205
578
|
logger.__azifyPatched = true
|
|
206
|
-
|
|
579
|
+
|
|
207
580
|
const originalLog = logger.log
|
|
208
581
|
const originalInfo = logger.info
|
|
209
582
|
const originalError = logger.error
|
|
@@ -212,13 +585,13 @@ try {
|
|
|
212
585
|
const originalFatal = logger.fatal
|
|
213
586
|
const originalTrace = logger.trace
|
|
214
587
|
const originalChild = logger.child
|
|
215
|
-
|
|
588
|
+
|
|
216
589
|
const patchLogMethod = (original, methodName) => {
|
|
217
590
|
return function(obj, msg, ...args) {
|
|
218
591
|
const otelCtx = getOtelTraceContext()
|
|
219
592
|
const ctx = getRequestContext()
|
|
220
|
-
const traceCtx =
|
|
221
|
-
|
|
593
|
+
const traceCtx = ctx || otelCtx
|
|
594
|
+
|
|
222
595
|
if (traceCtx && traceCtx.traceId) {
|
|
223
596
|
if (typeof obj === 'object' && obj !== null) {
|
|
224
597
|
obj = {
|
|
@@ -229,20 +602,20 @@ try {
|
|
|
229
602
|
requestId: traceCtx.requestId || ctx?.requestId
|
|
230
603
|
}
|
|
231
604
|
} else {
|
|
232
|
-
obj = {
|
|
233
|
-
traceId: traceCtx.traceId,
|
|
234
|
-
spanId: traceCtx.spanId,
|
|
235
|
-
parentSpanId: traceCtx.parentSpanId,
|
|
236
|
-
requestId: traceCtx.requestId || ctx?.requestId,
|
|
237
|
-
msg: obj
|
|
605
|
+
obj = {
|
|
606
|
+
traceId: traceCtx.traceId,
|
|
607
|
+
spanId: traceCtx.spanId,
|
|
608
|
+
parentSpanId: traceCtx.parentSpanId,
|
|
609
|
+
requestId: traceCtx.requestId || ctx?.requestId,
|
|
610
|
+
msg: obj
|
|
238
611
|
}
|
|
239
612
|
}
|
|
240
|
-
|
|
613
|
+
|
|
241
614
|
try {
|
|
242
615
|
const levelMap = { log: 'info', info: 'info', error: 'error', warn: 'warn', debug: 'debug', fatal: 'fatal', trace: 'trace' }
|
|
243
616
|
const level = levelMap[methodName] || 'info'
|
|
244
617
|
const message = (typeof obj === 'object' ? obj.message : obj) || msg || ''
|
|
245
|
-
|
|
618
|
+
|
|
246
619
|
const meta = {
|
|
247
620
|
...obj,
|
|
248
621
|
service: {
|
|
@@ -253,15 +626,15 @@ try {
|
|
|
253
626
|
timestamp: new Date().toISOString(),
|
|
254
627
|
hostname: require('os').hostname()
|
|
255
628
|
}
|
|
256
|
-
|
|
629
|
+
|
|
257
630
|
sendOutboundLog(level, message, meta)
|
|
258
631
|
} catch (err) {}
|
|
259
632
|
}
|
|
260
|
-
|
|
633
|
+
|
|
261
634
|
return original.call(this, obj, msg, ...args)
|
|
262
635
|
}
|
|
263
636
|
}
|
|
264
|
-
|
|
637
|
+
|
|
265
638
|
logger.log = patchLogMethod(originalLog, 'log')
|
|
266
639
|
logger.info = patchLogMethod(originalInfo, 'info')
|
|
267
640
|
logger.error = patchLogMethod(originalError, 'error')
|
|
@@ -269,97 +642,130 @@ try {
|
|
|
269
642
|
logger.debug = patchLogMethod(originalDebug, 'debug')
|
|
270
643
|
logger.fatal = patchLogMethod(originalFatal, 'fatal')
|
|
271
644
|
logger.trace = patchLogMethod(originalTrace, 'trace')
|
|
272
|
-
|
|
645
|
+
|
|
273
646
|
logger.child = function(bindings, options) {
|
|
274
647
|
const childLogger = originalChild.call(this, bindings, options)
|
|
275
648
|
return applyLoggerPatches(childLogger, pinoOptions)
|
|
276
649
|
}
|
|
277
|
-
|
|
650
|
+
|
|
278
651
|
return logger
|
|
279
652
|
}
|
|
280
|
-
|
|
653
|
+
|
|
281
654
|
Object.setPrototypeOf(patchedPino, originalPino)
|
|
282
655
|
Object.assign(patchedPino, originalPino)
|
|
283
|
-
|
|
656
|
+
|
|
284
657
|
return patchedPino
|
|
285
658
|
}
|
|
286
659
|
}
|
|
287
|
-
|
|
660
|
+
|
|
288
661
|
return result
|
|
289
662
|
}
|
|
290
|
-
|
|
663
|
+
|
|
291
664
|
} catch (_) {}
|
|
292
665
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return originalLog.call(this, message, context)
|
|
666
|
+
function patchNestLogger(Logger) {
|
|
667
|
+
if (!Logger || !Logger.prototype || Logger.prototype.__azifyNestLoggerPatched) return
|
|
668
|
+
const { getRequestContext, getLastJobContext, toTraceIdHex } = require('./store')
|
|
669
|
+
Logger.prototype.__azifyNestLoggerPatched = true
|
|
670
|
+
const originalLog = Logger.prototype.log
|
|
671
|
+
const originalError = Logger.prototype.error
|
|
672
|
+
const originalWarn = Logger.prototype.warn
|
|
673
|
+
const originalDebug = Logger.prototype.debug
|
|
674
|
+
const originalVerbose = Logger.prototype.verbose
|
|
675
|
+
|
|
676
|
+
function nestLoggerMeta(message) {
|
|
677
|
+
let ctx = getRequestContext()
|
|
678
|
+
if (!ctx || !ctx.traceId) {
|
|
679
|
+
const jobCtx = getLastJobContext()
|
|
680
|
+
if (jobCtx && jobCtx.traceId) ctx = jobCtx
|
|
309
681
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
return originalError.call(this, message, trace, context)
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
Logger.prototype.warn = function(message, context) {
|
|
321
|
-
const { getRequestContext } = require('./store')
|
|
322
|
-
const ctx = getRequestContext()
|
|
323
|
-
if (ctx && ctx.traceId) {
|
|
324
|
-
return originalWarn.call(this, message, context)
|
|
325
|
-
}
|
|
326
|
-
return originalWarn.call(this, message, context)
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
Logger.prototype.debug = function(message, context) {
|
|
330
|
-
const { getRequestContext } = require('./store')
|
|
331
|
-
const ctx = getRequestContext()
|
|
332
|
-
if (ctx && ctx.traceId) {
|
|
333
|
-
return originalDebug.call(this, message, context)
|
|
682
|
+
if (!ctx || !ctx.traceId) {
|
|
683
|
+
try {
|
|
684
|
+
const { startRequestContext } = require('./store')
|
|
685
|
+
ctx = startRequestContext({})
|
|
686
|
+
} catch (_) {
|
|
687
|
+
ctx = { traceId: require('crypto').randomUUID ? require('crypto').randomUUID().replace(/-/g, '') : String(Date.now()), spanId: null, parentSpanId: null, requestId: null }
|
|
334
688
|
}
|
|
335
|
-
return originalDebug.call(this, message, context)
|
|
336
689
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
690
|
+
const traceId = ctx.traceId ? toTraceIdHex(String(ctx.traceId)) : null
|
|
691
|
+
const msg = typeof message === 'string' ? message : (message && message.message) || (message && message.msg) || String(message)
|
|
692
|
+
return {
|
|
693
|
+
traceId,
|
|
694
|
+
spanId: ctx.spanId != null ? String(ctx.spanId).slice(0, 16) : null,
|
|
695
|
+
parentSpanId: ctx.parentSpanId ?? null,
|
|
696
|
+
requestId: ctx.requestId ?? null,
|
|
697
|
+
message: msg
|
|
345
698
|
}
|
|
346
|
-
|
|
347
699
|
}
|
|
700
|
+
|
|
701
|
+
function skipUndefinedMessage(msg) {
|
|
702
|
+
return msg == null || (typeof msg === 'string' && msg.trim() === '')
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
Logger.prototype.log = function(message, context) {
|
|
706
|
+
if (skipUndefinedMessage(message)) return
|
|
707
|
+
try {
|
|
708
|
+
const meta = nestLoggerMeta(message)
|
|
709
|
+
if (meta.traceId) sendOutboundLog('info', meta.message || message, meta)
|
|
710
|
+
} catch (_) {}
|
|
711
|
+
return originalLog.call(this, message, context)
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
Logger.prototype.error = function(message, trace, context) {
|
|
715
|
+
if (skipUndefinedMessage(message)) return
|
|
716
|
+
try {
|
|
717
|
+
const meta = nestLoggerMeta(message)
|
|
718
|
+
if (meta.traceId) sendOutboundLog('error', meta.message || message, meta)
|
|
719
|
+
} catch (_) {}
|
|
720
|
+
return originalError.call(this, message, trace, context)
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
Logger.prototype.warn = function(message, context) {
|
|
724
|
+
if (skipUndefinedMessage(message)) return
|
|
725
|
+
try {
|
|
726
|
+
const meta = nestLoggerMeta(message)
|
|
727
|
+
if (meta.traceId) sendOutboundLog('warn', meta.message || message, meta)
|
|
728
|
+
} catch (_) {}
|
|
729
|
+
return originalWarn.call(this, message, context)
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
Logger.prototype.debug = function(message, context) {
|
|
733
|
+
if (skipUndefinedMessage(message)) return
|
|
734
|
+
try {
|
|
735
|
+
const meta = nestLoggerMeta(message)
|
|
736
|
+
if (meta.traceId) sendOutboundLog('debug', meta.message || message, meta)
|
|
737
|
+
} catch (_) {}
|
|
738
|
+
return originalDebug.call(this, message, context)
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
Logger.prototype.verbose = function(message, context) {
|
|
742
|
+
if (skipUndefinedMessage(message)) return
|
|
743
|
+
try {
|
|
744
|
+
const meta = nestLoggerMeta(message)
|
|
745
|
+
if (meta.traceId) sendOutboundLog('debug', meta.message || message, meta)
|
|
746
|
+
} catch (_) {}
|
|
747
|
+
return originalVerbose.call(this, message, context)
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
try {
|
|
752
|
+
const { Logger } = require('@nestjs/common')
|
|
753
|
+
patchNestLogger(Logger)
|
|
348
754
|
} catch (_) {}
|
|
349
755
|
|
|
350
756
|
try {
|
|
351
757
|
const originalConsoleLog = console.log
|
|
352
758
|
const originalConsoleError = console.error
|
|
353
759
|
const originalConsoleWarn = console.warn
|
|
354
|
-
|
|
760
|
+
|
|
355
761
|
console.log = function(...args) {
|
|
356
762
|
return originalConsoleLog.apply(this, args)
|
|
357
763
|
}
|
|
358
|
-
|
|
764
|
+
|
|
359
765
|
console.error = function(...args) {
|
|
360
766
|
return originalConsoleError.apply(this, args)
|
|
361
767
|
}
|
|
362
|
-
|
|
768
|
+
|
|
363
769
|
console.warn = function(...args) {
|
|
364
770
|
return originalConsoleWarn.apply(this, args)
|
|
365
771
|
}
|
|
@@ -368,54 +774,142 @@ try {
|
|
|
368
774
|
try {
|
|
369
775
|
const Module = require('module')
|
|
370
776
|
const originalRequire = Module.prototype.require
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
777
|
+
function isAzifyLoggerInternal(id) {
|
|
778
|
+
if (typeof id !== 'string') return false
|
|
779
|
+
const n = id.replace(/\\/g, '/')
|
|
780
|
+
if (n === './store' || n === 'store' || n.endsWith('/store') || n.endsWith('/store.js')) return true
|
|
781
|
+
if (n === './middleware-express' || n === 'middleware-express' || n.includes('middleware-express')) return true
|
|
782
|
+
if (n === './streams/httpQueue' || n.includes('httpQueue')) return true
|
|
783
|
+
return false
|
|
784
|
+
}
|
|
785
|
+
function callerIsAzifyLogger() {
|
|
786
|
+
try {
|
|
787
|
+
const fn = (this && this.filename) ? this.filename : (this && this.id) ? this.id : ''
|
|
788
|
+
return typeof fn === 'string' && fn.replace(/\\/g, '/').includes('azify-logger')
|
|
789
|
+
} catch (_) { return false }
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
const bypassRequire = (typeof global.__AZIFY_NODE_REQUIRE === 'function') ? global.__AZIFY_NODE_REQUIRE : nodeRequireOriginal
|
|
793
|
+
const patchableIds = ['undici', 'pino', 'bull', 'bullmq', 'nestjs-pino', '@nestjs/common']
|
|
794
|
+
function applyPatchesToModule(result, id) {
|
|
795
|
+
const pathNorm = typeof id === 'string' ? id.replace(/\\/g, '/') : ''
|
|
796
|
+
const is = (name) => id === name || pathNorm.includes(name)
|
|
797
|
+
if (is('@nestjs/common')) {
|
|
798
|
+
try {
|
|
799
|
+
if (result && result.Logger) patchNestLogger(result.Logger)
|
|
800
|
+
} catch (_) {}
|
|
801
|
+
}
|
|
802
|
+
if (is('nestjs-pino')) {
|
|
803
|
+
function patchPinoLoggerClass(LoggerClass) {
|
|
804
|
+
if (!LoggerClass || !LoggerClass.prototype || LoggerClass.prototype.__azifyPinoLoggerPatched) return
|
|
805
|
+
if (debug) process.stderr.write('[azify-logger] patching nestjs-pino Logger\n')
|
|
806
|
+
LoggerClass.prototype.__azifyPinoLoggerPatched = true
|
|
807
|
+
const { getRequestContext, getLastJobContext, toTraceIdHex } = require('./store')
|
|
808
|
+
const proto = LoggerClass.prototype
|
|
809
|
+
|
|
810
|
+
function pinoLoggerCtx(message) {
|
|
811
|
+
let ctx = getRequestContext()
|
|
812
|
+
const jobCtx = getLastJobContext()
|
|
813
|
+
if ((!ctx || !ctx.traceId) && jobCtx && jobCtx.traceId) ctx = jobCtx
|
|
814
|
+
const fromPayload = typeof message === 'object' && message !== null && (message.traceId || (message && message.data && message.data.traceId))
|
|
815
|
+
let traceId = fromPayload ? (message.traceId || (message.data && message.data.traceId)) : (ctx && ctx.traceId)
|
|
816
|
+
let spanId = fromPayload ? (message.spanId || (message.data && message.data.spanId)) : (ctx && ctx.spanId)
|
|
817
|
+
if (!traceId && typeof message === 'string' && /traceId/i.test(message)) {
|
|
818
|
+
const m = message.match(/"traceId"\s*:\s*"([^"]+)"/)
|
|
819
|
+
if (m) { traceId = m[1]; const s = message.match(/"spanId"\s*:\s*"([^"]+)"/); spanId = s ? s[1] : null }
|
|
820
|
+
}
|
|
821
|
+
let effectiveCtx = traceId ? { traceId: toTraceIdHex(String(traceId)), spanId: spanId != null ? String(spanId).slice(0, 16) : null, parentSpanId: (fromPayload && message && (message.parentSpanId != null || (message.data && message.data.parentSpanId != null)) ? (message.parentSpanId || (message.data && message.data.parentSpanId)) : ctx?.parentSpanId) ?? null, requestId: (fromPayload && message && (message.requestId != null || (message.data && message.data.requestId != null)) ? (message.requestId || (message.data && message.data.requestId)) : ctx?.requestId) ?? null } : ctx
|
|
822
|
+
if (!effectiveCtx || !effectiveCtx.traceId) {
|
|
395
823
|
try {
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
...(typeof message === 'object' ? message : {}),
|
|
402
|
-
traceId: ctx.traceId,
|
|
403
|
-
spanId: ctx.spanId,
|
|
404
|
-
parentSpanId: ctx.parentSpanId,
|
|
405
|
-
requestId: ctx.requestId
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
sendOutboundLog(level, msg, meta)
|
|
409
|
-
} catch (err) {}
|
|
824
|
+
const { startRequestContext } = require('./store')
|
|
825
|
+
effectiveCtx = startRequestContext({})
|
|
826
|
+
} catch (_) {
|
|
827
|
+
effectiveCtx = { traceId: require('crypto').randomUUID ? require('crypto').randomUUID().replace(/-/g, '') : String(Date.now()), spanId: null, parentSpanId: null, requestId: null }
|
|
828
|
+
}
|
|
410
829
|
}
|
|
411
|
-
|
|
412
|
-
return
|
|
830
|
+
const msg = (typeof message === 'object' && message !== null ? message.message : message) || ''
|
|
831
|
+
return { effectiveCtx, msg }
|
|
413
832
|
}
|
|
833
|
+
|
|
834
|
+
function pinoLoggerSend(level, message, meta) {
|
|
835
|
+
try {
|
|
836
|
+
const msg = (typeof message === 'string' ? message : (meta && meta.msg)) || (typeof message === 'object' && message !== null ? message.message : null) || ''
|
|
837
|
+
if (!msg && level !== 'debug' && level !== 'trace') return
|
|
838
|
+
const payload = { traceId: meta.effectiveCtx.traceId, spanId: meta.effectiveCtx.spanId, parentSpanId: meta.effectiveCtx.parentSpanId, requestId: meta.effectiveCtx.requestId, __source: 'pino-stdout', ...(typeof message === 'object' && message !== null ? message : {}) }
|
|
839
|
+
sendOutboundLog(level, msg, payload)
|
|
840
|
+
if (debug && (String(msg).includes('failed after') || String(msg).includes('[REQUEST]') || String(msg).includes('[RESPONSE]'))) {
|
|
841
|
+
process.stderr.write(`[azify-logger] nestjs-pino sent: ${String(msg).slice(0, 70)}\n`)
|
|
842
|
+
}
|
|
843
|
+
} catch (_) {}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const originalCall = proto.call
|
|
847
|
+
proto.call = function(callMethod, message, ...optionalParams) {
|
|
848
|
+
const { effectiveCtx, msg } = pinoLoggerCtx(message)
|
|
849
|
+
if (typeof message === 'object' && message !== null) {
|
|
850
|
+
message = { ...message, traceId: effectiveCtx.traceId, spanId: effectiveCtx.spanId, parentSpanId: effectiveCtx.parentSpanId, requestId: effectiveCtx.requestId }
|
|
851
|
+
}
|
|
852
|
+
pinoLoggerSend({ log: 'info', info: 'info', error: 'error', warn: 'warn', debug: 'debug', fatal: 'fatal', trace: 'trace', verbose: 'debug' }[callMethod] || 'info', message, { effectiveCtx, msg })
|
|
853
|
+
return originalCall.apply(this, [callMethod, message, ...optionalParams])
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
const origError = proto.error
|
|
857
|
+
const origLog = proto.log
|
|
858
|
+
const origWarn = proto.warn
|
|
859
|
+
const origDebug = proto.debug
|
|
860
|
+
const origVerbose = proto.verbose
|
|
861
|
+
function skipUndefinedMsg(msg) {
|
|
862
|
+
return msg == null || (typeof msg === 'string' && msg.trim() === '')
|
|
863
|
+
}
|
|
864
|
+
if (typeof origError === 'function') {
|
|
865
|
+
proto.error = function(message, trace, context) {
|
|
866
|
+
if (skipUndefinedMsg(message)) return
|
|
867
|
+
const meta = pinoLoggerCtx(message)
|
|
868
|
+
pinoLoggerSend('error', message, meta)
|
|
869
|
+
return origError.call(this, message, trace, context)
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
if (typeof origLog === 'function') {
|
|
873
|
+
proto.log = function(message, context) {
|
|
874
|
+
if (skipUndefinedMsg(message)) return
|
|
875
|
+
const meta = pinoLoggerCtx(message)
|
|
876
|
+
pinoLoggerSend('info', message, meta)
|
|
877
|
+
return origLog.call(this, message, context)
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (typeof origWarn === 'function') {
|
|
881
|
+
proto.warn = function(message, context) {
|
|
882
|
+
if (skipUndefinedMsg(message)) return
|
|
883
|
+
const meta = pinoLoggerCtx(message)
|
|
884
|
+
pinoLoggerSend('warn', message, meta)
|
|
885
|
+
return origWarn.call(this, message, context)
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (typeof origDebug === 'function') {
|
|
889
|
+
proto.debug = function(message, context) {
|
|
890
|
+
if (skipUndefinedMsg(message)) return
|
|
891
|
+
const meta = pinoLoggerCtx(message)
|
|
892
|
+
pinoLoggerSend('debug', message, meta)
|
|
893
|
+
return origDebug.call(this, message, context)
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (typeof origVerbose === 'function') {
|
|
897
|
+
proto.verbose = function(message, context) {
|
|
898
|
+
if (skipUndefinedMsg(message)) return
|
|
899
|
+
const meta = pinoLoggerCtx(message)
|
|
900
|
+
pinoLoggerSend('debug', message, meta)
|
|
901
|
+
return origVerbose.call(this, message, context)
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
if (result && result.Logger) patchPinoLoggerClass(result.Logger)
|
|
906
|
+
if (result && typeof result === 'function' && result.prototype && (result.prototype.call != null || result.prototype.error != null) && !result.prototype.__azifyPinoLoggerPatched) {
|
|
907
|
+
patchPinoLoggerClass(result)
|
|
414
908
|
}
|
|
415
|
-
|
|
909
|
+
|
|
416
910
|
if (result && result.LoggerModule && result.LoggerModule.forRoot) {
|
|
417
911
|
const originalForRoot = result.LoggerModule.forRoot
|
|
418
|
-
|
|
912
|
+
|
|
419
913
|
result.LoggerModule.forRoot = function(options) {
|
|
420
914
|
if (process.env.AZIFY_LOGGER_URL) {
|
|
421
915
|
try {
|
|
@@ -425,13 +919,13 @@ try {
|
|
|
425
919
|
serviceName: process.env.APP_NAME || (options && options.pinoHttp && options.pinoHttp.name),
|
|
426
920
|
environment: process.env.NODE_ENV
|
|
427
921
|
})
|
|
428
|
-
|
|
922
|
+
|
|
429
923
|
const pinoHttp = (options && options.pinoHttp) || {}
|
|
430
|
-
|
|
924
|
+
|
|
431
925
|
if (pinoHttp.transport) {
|
|
432
926
|
return originalForRoot.call(this, options)
|
|
433
927
|
}
|
|
434
|
-
|
|
928
|
+
|
|
435
929
|
const mergedOptions = {
|
|
436
930
|
...options,
|
|
437
931
|
pinoHttp: {
|
|
@@ -439,176 +933,592 @@ try {
|
|
|
439
933
|
stream: azifyStream,
|
|
440
934
|
},
|
|
441
935
|
}
|
|
442
|
-
|
|
936
|
+
|
|
443
937
|
return originalForRoot.call(this, mergedOptions)
|
|
444
938
|
} catch (err) {
|
|
445
939
|
return originalForRoot.call(this, options)
|
|
446
940
|
}
|
|
447
941
|
}
|
|
448
|
-
|
|
942
|
+
|
|
449
943
|
return originalForRoot.call(this, options)
|
|
450
944
|
}
|
|
451
|
-
|
|
945
|
+
|
|
452
946
|
Object.setPrototypeOf(result.LoggerModule.forRoot, originalForRoot)
|
|
453
947
|
Object.assign(result.LoggerModule.forRoot, originalForRoot)
|
|
454
948
|
}
|
|
455
949
|
}
|
|
456
|
-
|
|
457
|
-
return result
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
} catch (_) {}
|
|
461
950
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
...options,
|
|
506
|
-
headers: {
|
|
507
|
-
...headers,
|
|
508
|
-
'X-Trace-ID': traceCtx.traceId,
|
|
509
|
-
'X-Span-ID': spanId,
|
|
510
|
-
'X-Parent-Span-ID': traceCtx.parentSpanId || '',
|
|
511
|
-
'X-Request-ID': requestId
|
|
951
|
+
const skipBullPatch = process.env.AZIFY_LOGGER_NO_BULL_PATCH === '1'
|
|
952
|
+
if (!skipBullPatch && pathNorm.includes('explorer') && (pathNorm.includes('@nestjs/bull') || pathNorm.includes('nestjs/bull')) && !pathNorm.includes('bullmq')) {
|
|
953
|
+
try {
|
|
954
|
+
const Cls = (result && result.BullExplorer) || result
|
|
955
|
+
if (Cls && Cls.prototype && typeof Cls.prototype.handleProcessor === 'function' && !Cls.prototype.handleProcessor.__azifyPatched) {
|
|
956
|
+
const store = require('./store')
|
|
957
|
+
const toTraceIdHex = store.toTraceIdHex
|
|
958
|
+
const startRequestContext = store.startRequestContext
|
|
959
|
+
const setLastJobContext = store.setLastJobContext
|
|
960
|
+
const originalHandleProcessor = Cls.prototype.handleProcessor
|
|
961
|
+
Cls.prototype.handleProcessor = function(instance, key, queue, moduleRef, isRequestScoped, options) {
|
|
962
|
+
const self = this
|
|
963
|
+
const origArgs = [instance, key, queue, moduleRef, isRequestScoped, options]
|
|
964
|
+
const queueRef = queue
|
|
965
|
+
const wrapProcessor = (processor) => {
|
|
966
|
+
if (typeof processor !== 'function') return processor
|
|
967
|
+
return function(job) {
|
|
968
|
+
let ctx = null
|
|
969
|
+
try {
|
|
970
|
+
const data = job && job.data
|
|
971
|
+
const rawTraceId = data && data.traceId
|
|
972
|
+
const traceId = rawTraceId ? toTraceIdHex(String(rawTraceId)) : null
|
|
973
|
+
const spanId = data && data.spanId != null ? String(data.spanId).slice(0, 16) : null
|
|
974
|
+
if (traceId && spanId) ctx = { traceId, spanId, parentSpanId: data?.parentSpanId ?? null, requestId: data?.requestId ?? null }
|
|
975
|
+
else { let r = ''; try { r = (require('crypto').randomUUID && require('crypto').randomUUID()) || '' } catch (_) {}; ctx = startRequestContext({ requestId: r }) }
|
|
976
|
+
} catch (_) {}
|
|
977
|
+
if (!ctx) ctx = startRequestContext({})
|
|
978
|
+
setLastJobContext(ctx)
|
|
979
|
+
return processor(job)
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
const origProcess = queueRef.process
|
|
983
|
+
queueRef.process = function(...args) {
|
|
984
|
+
if (args.length > 0 && typeof args[args.length - 1] === 'function') {
|
|
985
|
+
args[args.length - 1] = wrapProcessor(args[args.length - 1])
|
|
986
|
+
}
|
|
987
|
+
return origProcess.apply(this, args)
|
|
988
|
+
}
|
|
989
|
+
try {
|
|
990
|
+
return originalHandleProcessor.apply(self, origArgs)
|
|
991
|
+
} finally {
|
|
992
|
+
queueRef.process = origProcess
|
|
993
|
+
}
|
|
512
994
|
}
|
|
995
|
+
Cls.prototype.handleProcessor.__azifyPatched = true
|
|
513
996
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
997
|
+
} catch (_) {}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
if (!skipBullPatch && pathNorm.includes('bullmq') && pathNorm.includes('processor-decorator')) {
|
|
1001
|
+
try {
|
|
1002
|
+
const Cls = (result && result.ProcessorDecoratorService) || result
|
|
1003
|
+
if (Cls && Cls.prototype && typeof Cls.prototype.decorate === 'function' && !Cls.prototype.decorate.__azifyPatched) {
|
|
1004
|
+
const store = require('./store')
|
|
1005
|
+
const als = store.als
|
|
1006
|
+
const toTraceIdHex = store.toTraceIdHex
|
|
1007
|
+
const startRequestContext = store.startRequestContext
|
|
1008
|
+
const setLastJobContext = store.setLastJobContext
|
|
1009
|
+
const originalDecorate = Cls.prototype.decorate
|
|
1010
|
+
Cls.prototype.decorate = function(processor) {
|
|
1011
|
+
const decorated = originalDecorate.call(this, processor)
|
|
1012
|
+
if (typeof decorated !== 'function') return decorated
|
|
1013
|
+
return function(job, token, signal) {
|
|
1014
|
+
let ctx = null
|
|
521
1015
|
try {
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
1016
|
+
const data = job && job.data
|
|
1017
|
+
const rawTraceId = data && data.traceId
|
|
1018
|
+
const traceId = rawTraceId ? toTraceIdHex(String(rawTraceId)) : null
|
|
1019
|
+
const spanId = data && data.spanId != null ? String(data.spanId).slice(0, 16) : null
|
|
1020
|
+
if (traceId && spanId) ctx = { traceId, spanId, parentSpanId: data?.parentSpanId ?? null, requestId: data?.requestId ?? null }
|
|
1021
|
+
else { let r = ''; try { r = (require('crypto').randomUUID && require('crypto').randomUUID()) || '' } catch (_) {}; ctx = startRequestContext({ requestId: r }) }
|
|
1022
|
+
} catch (_) {}
|
|
1023
|
+
if (!ctx) ctx = startRequestContext({})
|
|
1024
|
+
setLastJobContext(ctx)
|
|
1025
|
+
return als.run(ctx, function() { return decorated(job, token, signal) })
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
Cls.prototype.decorate.__azifyPatched = true
|
|
1029
|
+
}
|
|
1030
|
+
} catch (_) {}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const isPino = id === 'pino' || (typeof id === 'string' && (id.endsWith('/pino') || (pathNorm.includes('/pino') && !pathNorm.includes('nestjs-pino'))))
|
|
1034
|
+
if (isPino) {
|
|
1035
|
+
if (result && typeof result === 'function') {
|
|
1036
|
+
if (debug) process.stderr.write(`[azify-logger] require hook patching pino id=${id}\n`)
|
|
1037
|
+
const { getRequestContext, getLastJobContext } = require('./store')
|
|
1038
|
+
const originalPino = result
|
|
1039
|
+
const patchedPino = function(options, stream) {
|
|
1040
|
+
if (new.target) {
|
|
1041
|
+
return originalPino.call(this, options, stream)
|
|
1042
|
+
}
|
|
1043
|
+
const logger = originalPino(options, stream)
|
|
1044
|
+
if (logger.__azifyPatched) return logger
|
|
1045
|
+
logger.__azifyPatched = true
|
|
1046
|
+
const originalLog = logger.log
|
|
1047
|
+
const originalInfo = logger.info
|
|
1048
|
+
const originalError = logger.error
|
|
1049
|
+
const originalWarn = logger.warn
|
|
1050
|
+
const originalDebug = logger.debug
|
|
1051
|
+
const originalFatal = logger.fatal
|
|
1052
|
+
const originalTrace = logger.trace
|
|
1053
|
+
const originalChild = logger.child
|
|
1054
|
+
const levelMap = { log: 'info', info: 'info', error: 'error', warn: 'warn', debug: 'debug', fatal: 'fatal', trace: 'trace' }
|
|
1055
|
+
const { toTraceIdHex } = require('./store')
|
|
1056
|
+
const patchLog = (original, methodName) => {
|
|
1057
|
+
return function(obj, msg, ...args) {
|
|
1058
|
+
let ctx = getRequestContext()
|
|
1059
|
+
if (!ctx || !ctx.traceId) {
|
|
1060
|
+
const jobCtx = getLastJobContext()
|
|
1061
|
+
if (jobCtx && jobCtx.traceId) ctx = jobCtx
|
|
1062
|
+
}
|
|
1063
|
+
const otelCtx = getOtelTraceContext()
|
|
1064
|
+
let traceId = ctx?.traceId
|
|
1065
|
+
let spanId = ctx?.spanId
|
|
1066
|
+
if (typeof obj === 'object' && obj !== null && (obj.traceId || obj.data?.traceId)) {
|
|
1067
|
+
traceId = obj.traceId || (obj.data && obj.data.traceId)
|
|
1068
|
+
spanId = obj.spanId != null ? obj.spanId : (obj.data && obj.data.spanId)
|
|
1069
|
+
}
|
|
1070
|
+
const msgStr = (typeof obj === 'object' ? obj?.message : obj) ?? msg ?? ''
|
|
1071
|
+
if (!traceId && typeof msgStr === 'string' && /traceId/i.test(msgStr)) {
|
|
1072
|
+
const m = msgStr.match(/"traceId"\s*:\s*"([^"]+)"/)
|
|
1073
|
+
if (m) { traceId = m[1]; const s = msgStr.match(/"spanId"\s*:\s*"([^"]+)"/); spanId = s ? s[1] : null }
|
|
1074
|
+
}
|
|
1075
|
+
let traceCtx = traceId ? { traceId: toTraceIdHex(String(traceId)), spanId: spanId != null ? String(spanId).slice(0, 16) : null, parentSpanId: ctx?.parentSpanId ?? null, requestId: ctx?.requestId ?? null } : (ctx || otelCtx)
|
|
1076
|
+
if (!traceCtx || !traceCtx.traceId) {
|
|
1077
|
+
try {
|
|
1078
|
+
const { startRequestContext } = require('./store')
|
|
1079
|
+
traceCtx = startRequestContext({})
|
|
1080
|
+
} catch (_) {
|
|
1081
|
+
traceCtx = { traceId: require('crypto').randomUUID ? require('crypto').randomUUID().replace(/-/g, '') : String(Date.now()), spanId: null, parentSpanId: null, requestId: null }
|
|
525
1082
|
}
|
|
1083
|
+
}
|
|
1084
|
+
try {
|
|
1085
|
+
const out = (typeof obj === 'object' && obj !== null) ? { ...obj, traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId } : { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
1086
|
+
const message = (typeof out === 'object' ? out.message : out) || msg || ''
|
|
1087
|
+
const meta = { ...out, service: { name: serviceName, version: '1.0.0' }, environment, timestamp: new Date().toISOString(), hostname: require('os').hostname() }
|
|
1088
|
+
sendOutboundLog(levelMap[methodName] || 'info', message, meta)
|
|
526
1089
|
} catch (_) {}
|
|
1090
|
+
return original.call(this, obj, msg, ...args)
|
|
527
1091
|
}
|
|
528
1092
|
}
|
|
529
|
-
|
|
1093
|
+
logger.log = patchLog(originalLog, 'log')
|
|
1094
|
+
logger.info = patchLog(originalInfo, 'info')
|
|
1095
|
+
logger.error = patchLog(originalError, 'error')
|
|
1096
|
+
logger.warn = patchLog(originalWarn, 'warn')
|
|
1097
|
+
logger.debug = patchLog(originalDebug, 'debug')
|
|
1098
|
+
logger.fatal = patchLog(originalFatal, 'fatal')
|
|
1099
|
+
logger.trace = patchLog(originalTrace, 'trace')
|
|
1100
|
+
logger.child = function(bindings, options) {
|
|
1101
|
+
const childLogger = originalChild.call(this, bindings, options)
|
|
1102
|
+
if (childLogger && !childLogger.__azifyPatched) {
|
|
1103
|
+
childLogger.__azifyPatched = true
|
|
1104
|
+
childLogger.log = patchLog(childLogger.log || (() => {}), 'log')
|
|
1105
|
+
childLogger.info = patchLog(childLogger.info || (() => {}), 'info')
|
|
1106
|
+
childLogger.error = patchLog(childLogger.error || (() => {}), 'error')
|
|
1107
|
+
childLogger.warn = patchLog(childLogger.warn || (() => {}), 'warn')
|
|
1108
|
+
childLogger.debug = patchLog(childLogger.debug || (() => {}), 'debug')
|
|
1109
|
+
childLogger.fatal = patchLog(childLogger.fatal || (() => {}), 'fatal')
|
|
1110
|
+
childLogger.trace = patchLog(childLogger.trace || (() => {}), 'trace')
|
|
1111
|
+
}
|
|
1112
|
+
return childLogger
|
|
1113
|
+
}
|
|
1114
|
+
return logger
|
|
1115
|
+
}
|
|
1116
|
+
Object.setPrototypeOf(patchedPino, originalPino)
|
|
1117
|
+
Object.assign(patchedPino, originalPino)
|
|
1118
|
+
return patchedPino
|
|
530
1119
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (
|
|
536
|
-
|
|
537
|
-
if (
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
if (id === 'undici' || id.includes('undici')) {
|
|
1123
|
+
try {
|
|
1124
|
+
if (debug) try { process.stderr.write(`[azify-logger] applyPatchesToModule UNDICI id=${(typeof id === 'string' ? id.slice(-50) : id)} hasRequest=${!!(result && result.request)}\n`) } catch (_) {}
|
|
1125
|
+
const patchUndiciRequest = (target, label) => {
|
|
1126
|
+
if (!target || typeof target.request !== 'function' || target.request.__azifyPatched) return
|
|
1127
|
+
if (debug) process.stderr.write(`[azify-logger] patching undici ${label}\n`)
|
|
1128
|
+
const { randomBytes } = require('crypto')
|
|
1129
|
+
const { performance } = require('perf_hooks')
|
|
1130
|
+
const { markSource, HTTP_CLIENT_MODE } = require('./sampling')
|
|
1131
|
+
const { getRequestContext, toTraceIdHex } = require('./store')
|
|
1132
|
+
const originalRequest = target.request
|
|
1133
|
+
target.request = function(url, options, callback) {
|
|
1134
|
+
const { getLastJobContext } = require('./store')
|
|
1135
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
1136
|
+
const otelCtx = getOtelTraceContext()
|
|
1137
|
+
const traceCtx = ctx || otelCtx
|
|
1138
|
+
const method = (options?.method || 'GET').toUpperCase()
|
|
1139
|
+
const urlString = typeof url === 'string' ? url : (url && url.toString && url.toString()) || 'unknown'
|
|
1140
|
+
const rawTraceId = traceCtx?.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
1141
|
+
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
1142
|
+
const parentSpanId = traceCtx?.spanId || null
|
|
1143
|
+
const requestId = traceCtx?.requestId || ctx?.requestId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
1144
|
+
const spanId = randomBytes(8).toString('hex')
|
|
1145
|
+
const requestMeta = { traceId, spanId, parentSpanId, requestId, method, url: urlString }
|
|
1146
|
+
markSource(requestMeta, 'http-client')
|
|
1147
|
+
const startTime = performance.now()
|
|
1148
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1149
|
+
sendOutboundLog('info', `[REQUEST] ${method} ${urlString}`, requestMeta)
|
|
1150
|
+
}
|
|
1151
|
+
if (traceCtx && traceCtx.traceId) {
|
|
1152
|
+
const headers = (options && options.headers) || {}
|
|
1153
|
+
options = { ...options, headers: { ...headers, 'X-Trace-ID': traceId, 'X-Span-ID': spanId, 'X-Parent-Span-ID': traceCtx.parentSpanId || '', 'X-Request-ID': requestId } }
|
|
1154
|
+
}
|
|
1155
|
+
const wrappedCb = callback ? function(err, data) {
|
|
1156
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1157
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1158
|
+
if (err) sendOutboundLog('error', `[RESPONSE] ${method} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: err.message, responseTimeMs: duration })
|
|
1159
|
+
else if (data) sendOutboundLog('info', `[RESPONSE] ${method} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
1160
|
+
}
|
|
1161
|
+
return callback(err, data)
|
|
1162
|
+
} : undefined
|
|
1163
|
+
if (wrappedCb) return originalRequest.call(this, url, options, wrappedCb)
|
|
1164
|
+
const promise = originalRequest.call(this, url, options)
|
|
1165
|
+
if (promise && typeof promise.then === 'function') {
|
|
1166
|
+
return promise.then(
|
|
1167
|
+
(data) => {
|
|
1168
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1169
|
+
if (HTTP_CLIENT_MODE !== 'off' && data) {
|
|
1170
|
+
sendOutboundLog('info', `[RESPONSE] ${method} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
1171
|
+
}
|
|
1172
|
+
return data
|
|
1173
|
+
},
|
|
1174
|
+
(err) => {
|
|
1175
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1176
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1177
|
+
sendOutboundLog('error', `[RESPONSE] ${method} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: (err && err.message) || String(err), responseTimeMs: duration })
|
|
1178
|
+
}
|
|
1179
|
+
throw err
|
|
1180
|
+
}
|
|
1181
|
+
)
|
|
542
1182
|
}
|
|
543
|
-
|
|
1183
|
+
return promise
|
|
544
1184
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
if (
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
1185
|
+
target.request.__azifyPatched = true
|
|
1186
|
+
}
|
|
1187
|
+
if (result && result.request) patchUndiciRequest(result, 'request')
|
|
1188
|
+
if (result && result.Dispatcher && result.Dispatcher.prototype && typeof result.Dispatcher.prototype.request === 'function' && !result.Dispatcher.prototype.request.__azifyPatched) {
|
|
1189
|
+
if (debug) process.stderr.write('[azify-logger] patching undici Dispatcher.prototype.request\n')
|
|
1190
|
+
const { randomBytes } = require('crypto')
|
|
1191
|
+
const { performance } = require('perf_hooks')
|
|
1192
|
+
const { markSource, HTTP_CLIENT_MODE } = require('./sampling')
|
|
1193
|
+
const { getRequestContext, toTraceIdHex } = require('./store')
|
|
1194
|
+
const proto = result.Dispatcher.prototype
|
|
1195
|
+
const origDispRequest = proto.request
|
|
1196
|
+
proto.request = function(opts, callback) {
|
|
1197
|
+
const { getLastJobContext } = require('./store')
|
|
1198
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
1199
|
+
const otelCtx = getOtelTraceContext()
|
|
1200
|
+
const traceCtx = ctx || otelCtx
|
|
1201
|
+
const method = (opts && (opts.method || 'GET')) || 'GET'
|
|
1202
|
+
const methodStr = String(method).toUpperCase()
|
|
1203
|
+
const origin = (opts && opts.origin) || ''
|
|
1204
|
+
const path = (opts && opts.path) != null ? opts.path : '/'
|
|
1205
|
+
const urlString = origin ? (origin + (path.startsWith('/') ? path : '/' + path)) : 'unknown'
|
|
1206
|
+
const rawTraceId = traceCtx?.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
1207
|
+
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
1208
|
+
const parentSpanId = traceCtx?.spanId || null
|
|
1209
|
+
const requestId = traceCtx?.requestId || ctx?.requestId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
1210
|
+
const spanId = randomBytes(8).toString('hex')
|
|
1211
|
+
const requestMeta = { traceId, spanId, parentSpanId, requestId, method: methodStr, url: urlString }
|
|
1212
|
+
markSource(requestMeta, 'http-client')
|
|
1213
|
+
const startTime = performance.now()
|
|
1214
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1215
|
+
sendOutboundLog('info', `[REQUEST] ${methodStr} ${urlString}`, requestMeta)
|
|
554
1216
|
}
|
|
555
|
-
|
|
1217
|
+
if (traceCtx && traceCtx.traceId && opts && typeof opts === 'object') {
|
|
1218
|
+
const headers = { ...(opts.headers || {}), 'X-Trace-ID': traceId, 'X-Span-ID': spanId, 'X-Parent-Span-ID': traceCtx.parentSpanId || '', 'X-Request-ID': requestId }
|
|
1219
|
+
opts = { ...opts, headers }
|
|
1220
|
+
}
|
|
1221
|
+
const wrappedCb = typeof callback === 'function' ? function(err, data) {
|
|
1222
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1223
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1224
|
+
if (err) sendOutboundLog('error', `[RESPONSE] ${methodStr} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
1225
|
+
else if (data) sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
1226
|
+
}
|
|
1227
|
+
return callback(err, data)
|
|
1228
|
+
} : undefined
|
|
1229
|
+
const ret = wrappedCb ? origDispRequest.call(this, opts, wrappedCb) : origDispRequest.call(this, opts)
|
|
1230
|
+
if (ret && typeof ret.then === 'function' && !wrappedCb) {
|
|
1231
|
+
return ret.then(
|
|
1232
|
+
(data) => {
|
|
1233
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1234
|
+
if (HTTP_CLIENT_MODE !== 'off' && data) {
|
|
1235
|
+
sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
1236
|
+
}
|
|
1237
|
+
return data
|
|
1238
|
+
},
|
|
1239
|
+
(err) => {
|
|
1240
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1241
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1242
|
+
sendOutboundLog('error', `[RESPONSE] ${methodStr} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: (err && err.message) || String(err), responseTimeMs: duration })
|
|
1243
|
+
}
|
|
1244
|
+
throw err
|
|
1245
|
+
}
|
|
1246
|
+
)
|
|
1247
|
+
}
|
|
1248
|
+
return ret
|
|
556
1249
|
}
|
|
1250
|
+
proto.request.__azifyPatched = true
|
|
557
1251
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
1252
|
+
try {
|
|
1253
|
+
const cache = require.cache
|
|
1254
|
+
if (cache && typeof cache === 'object') {
|
|
1255
|
+
for (const key of Object.keys(cache)) {
|
|
1256
|
+
if (typeof key !== 'string') continue
|
|
1257
|
+
const p = key.replace(/\\/g, '/')
|
|
1258
|
+
if (p.indexOf('node_modules') === -1 || p.indexOf('undici') === -1 || p.includes('undici-package')) continue
|
|
1259
|
+
const mod = cache[key]
|
|
1260
|
+
if (!mod || !mod.exports || mod.exports === result) continue
|
|
1261
|
+
const ex = mod.exports
|
|
1262
|
+
if (ex && ex.request) patchUndiciRequest(ex, 'request(cache)')
|
|
1263
|
+
if (ex && ex.Dispatcher && ex.Dispatcher.prototype && typeof ex.Dispatcher.prototype.request === 'function' && !ex.Dispatcher.prototype.request.__azifyPatched) {
|
|
1264
|
+
const proto = ex.Dispatcher.prototype
|
|
1265
|
+
const origDispRequest = proto.request
|
|
1266
|
+
proto.request = function(opts, callback) {
|
|
1267
|
+
const { getLastJobContext } = require('./store')
|
|
1268
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
1269
|
+
const otelCtx = getOtelTraceContext()
|
|
1270
|
+
const traceCtx = ctx || otelCtx
|
|
1271
|
+
const method = (opts && (opts.method || 'GET')) || 'GET'
|
|
1272
|
+
const methodStr = String(method).toUpperCase()
|
|
1273
|
+
const origin = (opts && opts.origin) || ''
|
|
1274
|
+
const path = (opts && opts.path) != null ? opts.path : '/'
|
|
1275
|
+
const urlString = origin ? (origin + (path.startsWith('/') ? path : '/' + path)) : 'unknown'
|
|
1276
|
+
const rawTraceId = traceCtx?.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
1277
|
+
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
1278
|
+
const parentSpanId = traceCtx?.spanId || null
|
|
1279
|
+
const requestId = traceCtx?.requestId || ctx?.requestId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
1280
|
+
const spanId = randomBytes(8).toString('hex')
|
|
1281
|
+
const requestMeta = { traceId, spanId, parentSpanId, requestId, method: methodStr, url: urlString }
|
|
1282
|
+
markSource(requestMeta, 'http-client')
|
|
1283
|
+
const startTime = performance.now()
|
|
1284
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1285
|
+
sendOutboundLog('info', `[REQUEST] ${methodStr} ${urlString}`, requestMeta)
|
|
1286
|
+
}
|
|
1287
|
+
if (traceCtx && traceCtx.traceId && opts && typeof opts === 'object') {
|
|
1288
|
+
const headers = { ...(opts.headers || {}), 'X-Trace-ID': traceId, 'X-Span-ID': spanId, 'X-Parent-Span-ID': traceCtx.parentSpanId || '', 'X-Request-ID': requestId }
|
|
1289
|
+
opts = { ...opts, headers }
|
|
1290
|
+
}
|
|
1291
|
+
const wrappedCb = typeof callback === 'function' ? function(err, data) {
|
|
1292
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1293
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1294
|
+
if (err) sendOutboundLog('error', `[RESPONSE] ${methodStr} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
1295
|
+
else if (data) sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
1296
|
+
}
|
|
1297
|
+
return callback(err, data)
|
|
1298
|
+
} : undefined
|
|
1299
|
+
const ret = wrappedCb ? origDispRequest.call(this, opts, wrappedCb) : origDispRequest.call(this, opts)
|
|
1300
|
+
if (ret && typeof ret.then === 'function' && !wrappedCb) {
|
|
1301
|
+
return ret.then(
|
|
1302
|
+
(data) => {
|
|
1303
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1304
|
+
if (HTTP_CLIENT_MODE !== 'off' && data) {
|
|
1305
|
+
sendOutboundLog('info', `[RESPONSE] ${methodStr} ${urlString} ${data.statusCode} ${duration}ms`, { ...requestMeta, statusCode: data.statusCode, responseTimeMs: duration })
|
|
1306
|
+
}
|
|
1307
|
+
return data
|
|
1308
|
+
},
|
|
1309
|
+
(err) => {
|
|
1310
|
+
const duration = Number((performance.now() - startTime).toFixed(2))
|
|
1311
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1312
|
+
sendOutboundLog('error', `[RESPONSE] ${methodStr} ${urlString} ERROR ${duration}ms`, { ...requestMeta, error: (err && err.message) || String(err), responseTimeMs: duration })
|
|
1313
|
+
}
|
|
1314
|
+
throw err
|
|
1315
|
+
}
|
|
1316
|
+
)
|
|
1317
|
+
}
|
|
1318
|
+
return ret
|
|
1319
|
+
}
|
|
1320
|
+
proto.request.__azifyPatched = true
|
|
580
1321
|
}
|
|
581
|
-
sendOutboundLog('info', `[RESPONSE] ${method} ${urlString} ${statusCode} ${duration}ms`, responseMeta)
|
|
582
1322
|
}
|
|
583
|
-
|
|
584
|
-
|
|
1323
|
+
}
|
|
1324
|
+
} catch (_) {}
|
|
1325
|
+
} catch (_) {}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
try {
|
|
1329
|
+
const origLoad = Module._load
|
|
1330
|
+
if (origLoad && origLoad.__azifyEarlyPatched) {
|
|
1331
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] Module._load (late) keeping early hook (not overwriting)\n') } catch (_) {}
|
|
1332
|
+
} else if (typeof origLoad === 'function' && !Module._load.__azifyPatched) {
|
|
1333
|
+
Module._load = function (request, parent, isMain) {
|
|
1334
|
+
const result = origLoad.apply(this, arguments)
|
|
1335
|
+
const pathStr = typeof request === 'string' ? request.replace(/\\/g, '/') : ''
|
|
1336
|
+
const isUndici = pathStr === 'undici' || (pathStr.indexOf('undici') !== -1 && pathStr.indexOf('undici-package') === -1)
|
|
1337
|
+
if (isUndici) {
|
|
1338
|
+
if (debug) try { process.stderr.write(`[azify-logger] Module._load UNDICI path=${pathStr.slice(-70)}\n`) } catch (_) {}
|
|
1339
|
+
try {
|
|
1340
|
+
applyPatchesToModule(result, pathStr)
|
|
1341
|
+
} catch (_) {}
|
|
1342
|
+
}
|
|
1343
|
+
return result
|
|
1344
|
+
}
|
|
1345
|
+
Module._load.__azifyPatched = true
|
|
1346
|
+
if (debug) try { process.stderr.write('[azify-logger] Module._load hook installed\n') } catch (_) {}
|
|
1347
|
+
}
|
|
1348
|
+
} catch (_) {}
|
|
1349
|
+
try {
|
|
1350
|
+
const Ritm = require('require-in-the-middle')
|
|
1351
|
+
const Hook = Ritm && (Ritm.Hook || Ritm)
|
|
1352
|
+
if (typeof Hook === 'function') {
|
|
1353
|
+
new Hook(['undici', 'nestjs-pino', 'pino'], function (exports, name) {
|
|
1354
|
+
const replaced = applyPatchesToModule(exports, name)
|
|
1355
|
+
return (replaced !== undefined && replaced !== null) ? replaced : exports
|
|
1356
|
+
})
|
|
1357
|
+
}
|
|
1358
|
+
} catch (_) {}
|
|
1359
|
+
Module.prototype.require = function(id) {
|
|
1360
|
+
const idStr = typeof id === 'string' ? id : ''
|
|
1361
|
+
const pathNorm = idStr.replace(/\\/g, '/')
|
|
1362
|
+
const isPinoOrNest = id === 'pino' || id === 'nestjs-pino' || pathNorm.includes('nestjs-pino') || pathNorm.includes('/pino')
|
|
1363
|
+
if (debug && isPinoOrNest) {
|
|
1364
|
+
try { process.stderr.write(`[azify-logger] REQUIRE_HOOK_BEFORE id=${idStr.slice(-80)}\n`) } catch (_) {}
|
|
1365
|
+
}
|
|
1366
|
+
if (isAzifyLoggerInternal(id)) return bypassRequire.call(this, id)
|
|
1367
|
+
if (callerIsAzifyLogger.call(this)) {
|
|
1368
|
+
const isPatchable = patchableIds.some(m => id === m || (typeof id === 'string' && id.includes(m)))
|
|
1369
|
+
if (!isPatchable) return bypassRequire.call(this, id)
|
|
1370
|
+
}
|
|
1371
|
+
const result = originalRequire.call(this, id)
|
|
1372
|
+
const idLooksLikeUndici = idStr === 'undici' || (pathNorm.indexOf('undici') !== -1 && pathNorm.indexOf('undici-package') === -1)
|
|
1373
|
+
const undiciNeedsPatch = result && (typeof result.request === 'function' && !result.request.__azifyPatched || typeof result.fetch === 'function' && !result.fetch.__azifyPatched)
|
|
1374
|
+
if (idLooksLikeUndici || undiciNeedsPatch) {
|
|
1375
|
+
if (debug) try { process.stderr.write('[AZIFY] REGISTER require undici caller=' + (this && typeof this.filename === 'string' ? String(this.filename).replace(/\\/g, '/').slice(-85) : '') + ' patched=' + !!(result && result.request && result.request.__azifyPatched) + '\n') } catch (_) {}
|
|
1376
|
+
if (process.env.AZIFY_LOGGER_HTTP_DEBUG === '1' || process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
1377
|
+
try { process.stderr.write('[AZIFY-HTTP] REGISTER_HOOK2 patch id=' + idStr.slice(-70) + '\n') } catch (_) {}
|
|
1378
|
+
}
|
|
1379
|
+
try {
|
|
1380
|
+
const early = require('./register-http-client-early')
|
|
1381
|
+
if (typeof early.patchUndiciExports === 'function') early.patchUndiciExports(result)
|
|
1382
|
+
} catch (_) {}
|
|
1383
|
+
}
|
|
1384
|
+
if (debug && (idLooksLikeUndici || undiciNeedsPatch)) {
|
|
1385
|
+
try { process.stderr.write(`[azify-logger] REQUIRE_HOOK undici id=${idStr.slice(-60)} hasRequest=${!!(result && result.request)}\n`) } catch (_) {}
|
|
1386
|
+
}
|
|
1387
|
+
if (debug && isPinoOrNest) {
|
|
1388
|
+
try { process.stderr.write(`[azify-logger] REQUIRE_HOOK_AFTER id=${idStr.slice(-80)} hasResult=${!!result}\n`) } catch (_) {}
|
|
1389
|
+
}
|
|
1390
|
+
const replaced = applyPatchesToModule(result, id)
|
|
1391
|
+
return (replaced !== undefined && replaced !== null) ? replaced : result
|
|
1392
|
+
}
|
|
1393
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
1394
|
+
try { process.stderr.write('[azify-logger] REGISTER step3 second hook set\n') } catch (_) {}
|
|
1395
|
+
}
|
|
1396
|
+
let walkRunCount = 0
|
|
1397
|
+
function walkCacheAndPatch() {
|
|
1398
|
+
try {
|
|
1399
|
+
walkRunCount++
|
|
1400
|
+
const cache = require.cache
|
|
1401
|
+
const keys = cache && typeof cache === 'object' ? Object.keys(cache) : []
|
|
1402
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
1403
|
+
try { process.stderr.write(`[azify-logger] walkCache #${walkRunCount} keys=${keys.length}\n`) } catch (_) {}
|
|
1404
|
+
}
|
|
1405
|
+
if (cache && typeof cache === 'object') {
|
|
1406
|
+
if (debug && keys.length > 0) {
|
|
1407
|
+
const pinoRelated = keys.filter(k => typeof k === 'string' && (k.includes('pino') || k.includes('nestjs') || k.includes('undici')))
|
|
1408
|
+
if (walkRunCount <= 3 || pinoRelated.length > 0) {
|
|
1409
|
+
try {
|
|
1410
|
+
const preview = pinoRelated.length ? ' -> ' + pinoRelated.map(k => k.replace(/\\/g, '/').slice(-55)).join(' | ') : ''
|
|
1411
|
+
process.stderr.write(`[azify-logger] walkCache #${walkRunCount}: ${keys.length} keys, ${pinoRelated.length} pino/nest/undici${preview}\n`)
|
|
1412
|
+
} catch (_) {}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
for (const key of keys) {
|
|
1416
|
+
if (typeof key !== 'string') continue
|
|
1417
|
+
const pathNorm = key.replace(/\\/g, '/')
|
|
1418
|
+
if (!pathNorm.includes('undici') && !pathNorm.includes('nestjs-pino') && !pathNorm.includes('/pino') && !pathNorm.includes('bullmq') && !pathNorm.includes('/bull') && !pathNorm.includes('@nestjs/common')) continue
|
|
1419
|
+
const mod = cache[key]
|
|
1420
|
+
if (!mod || !mod.exports) continue
|
|
1421
|
+
if (debug && (pathNorm.includes('nestjs-pino') || pathNorm.includes('undici'))) {
|
|
1422
|
+
try { process.stderr.write(`[azify-logger] walkCache PATCHING key=${pathNorm.slice(-70)}\n`) } catch (_) {}
|
|
1423
|
+
}
|
|
1424
|
+
const replaced = applyPatchesToModule(mod.exports, key)
|
|
1425
|
+
if (replaced !== undefined && replaced !== null) mod.exports = replaced
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
} catch (e) {
|
|
1429
|
+
if (debug) try { process.stderr.write(`[azify-logger] walkCache err: ${e && e.message}\n`) } catch (_) {}
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
1433
|
+
try { process.stderr.write('[azify-logger] about to call walkCacheAndPatch\n') } catch (_) {}
|
|
1434
|
+
}
|
|
1435
|
+
walkCacheAndPatch()
|
|
1436
|
+
try {
|
|
1437
|
+
setTransport(createHttpLoggerTransport(loggerUrlString))
|
|
1438
|
+
} catch (_) {}
|
|
1439
|
+
try {
|
|
1440
|
+
require('undici')
|
|
1441
|
+
if (debug) try { process.stderr.write('[azify-logger] eager require(undici) done\n') } catch (_) {}
|
|
1442
|
+
} catch (_) {}
|
|
1443
|
+
walkCacheAndPatch()
|
|
1444
|
+
try {
|
|
1445
|
+
if (typeof globalThis.fetch === 'function' && !globalThis.fetch.__azifyPatched) {
|
|
1446
|
+
const origFetch = globalThis.fetch
|
|
1447
|
+
globalThis.fetch = function(url, opts) {
|
|
1448
|
+
const { getRequestContext, getLastJobContext, toTraceIdHex } = require('./store')
|
|
1449
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
1450
|
+
const otelCtx = getOtelTraceContext()
|
|
1451
|
+
const traceCtx = ctx || otelCtx
|
|
1452
|
+
const method = (opts && opts.method) ? String(opts.method).toUpperCase() : 'GET'
|
|
1453
|
+
const urlStr = typeof url === 'string' ? url : (url && url.url) ? url.url : (url && url.toString && url.toString()) || 'unknown'
|
|
1454
|
+
const rawTraceId = traceCtx?.traceId || (require('crypto').randomUUID && require('crypto').randomUUID())
|
|
1455
|
+
const traceId = typeof rawTraceId === 'string' ? toTraceIdHex(rawTraceId) : rawTraceId
|
|
1456
|
+
const requestMeta = { traceId, spanId: traceCtx?.spanId || null, parentSpanId: traceCtx?.parentSpanId || null, requestId: traceCtx?.requestId || null, method, url: urlStr }
|
|
1457
|
+
markSource(requestMeta, 'http-client')
|
|
1458
|
+
const start = require('perf_hooks').performance.now()
|
|
1459
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1460
|
+
sendOutboundLog('info', `[REQUEST] ${method} ${urlStr}`, requestMeta)
|
|
1461
|
+
}
|
|
1462
|
+
return origFetch.apply(this, arguments).then(
|
|
1463
|
+
(res) => {
|
|
1464
|
+
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
1465
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1466
|
+
sendOutboundLog('info', `[RESPONSE] ${method} ${urlStr} ${res.status} ${duration}ms`, { ...requestMeta, statusCode: res.status, responseTimeMs: duration })
|
|
1467
|
+
}
|
|
1468
|
+
return res
|
|
585
1469
|
},
|
|
586
1470
|
(err) => {
|
|
587
|
-
const duration = Number((performance.now() -
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
const errorMeta = {
|
|
591
|
-
...requestMeta,
|
|
592
|
-
error: err.message || String(err),
|
|
593
|
-
responseTimeMs: duration
|
|
594
|
-
}
|
|
595
|
-
sendOutboundLog('error', `[RESPONSE] ${method} ${urlString} ERROR ${duration}ms`, errorMeta)
|
|
1471
|
+
const duration = Number((require('perf_hooks').performance.now() - start).toFixed(2))
|
|
1472
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
1473
|
+
sendOutboundLog('error', `[RESPONSE] ${method} ${urlStr} ERROR ${duration}ms`, { ...requestMeta, error: err && err.message, responseTimeMs: duration })
|
|
596
1474
|
}
|
|
597
|
-
|
|
598
1475
|
throw err
|
|
599
1476
|
}
|
|
600
1477
|
)
|
|
601
1478
|
}
|
|
602
|
-
|
|
603
|
-
|
|
1479
|
+
globalThis.fetch.__azifyPatched = true
|
|
1480
|
+
if (debug) try { process.stderr.write('[azify-logger] patched globalThis.fetch\n') } catch (_) {}
|
|
604
1481
|
}
|
|
1482
|
+
} catch (_) {}
|
|
1483
|
+
if (debug) try { process.stderr.write('[azify-logger] REGISTER_END Module.prototype.require hook installed + walkCacheAndPatch done\n') } catch (_) {}
|
|
1484
|
+
if (typeof setImmediate === 'function') {
|
|
1485
|
+
setImmediate(walkCacheAndPatch)
|
|
605
1486
|
}
|
|
606
|
-
|
|
1487
|
+
;[0, 50, 200, 500, 1000].forEach(function (delay) {
|
|
1488
|
+
if (typeof setTimeout === 'function') {
|
|
1489
|
+
setTimeout(walkCacheAndPatch, delay)
|
|
1490
|
+
}
|
|
1491
|
+
})
|
|
1492
|
+
} catch (e) {
|
|
1493
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
1494
|
+
try {
|
|
1495
|
+
process.stderr.write('[azify-logger] REGISTER main catch hit\n')
|
|
1496
|
+
const msg = e && (e.message || (e.stack && e.stack.split('\n')[0]) || String(e))
|
|
1497
|
+
process.stderr.write('[azify-logger] REGISTER main catch: ' + msg + '\n')
|
|
1498
|
+
if (e && e.stack) process.stderr.write(e.stack + '\n')
|
|
1499
|
+
} catch (_) {}
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
607
1502
|
|
|
608
1503
|
try {
|
|
1504
|
+
const ModuleForAxios = require('module')
|
|
1505
|
+
const origRequireAxios = ModuleForAxios.prototype.require
|
|
1506
|
+
let applyAxiosPatch = null
|
|
1507
|
+
if (typeof origRequireAxios === 'function' && !origRequireAxios.__azifyAxiosHookInstalled) {
|
|
1508
|
+
ModuleForAxios.prototype.require = function (id) {
|
|
1509
|
+
const result = origRequireAxios.apply(this, arguments)
|
|
1510
|
+
const idStr = typeof id === 'string' ? id.replace(/\\/g, '/') : ''
|
|
1511
|
+
const isAxios = idStr === 'axios' || idStr.endsWith('/axios') || (idStr.includes('axios') && idStr.indexOf('axios-') === -1)
|
|
1512
|
+
if (isAxios && result && typeof result === 'object' && !result.__azifyLoggerPatched && applyAxiosPatch) {
|
|
1513
|
+
try { applyAxiosPatch(result) } catch (_) {}
|
|
1514
|
+
}
|
|
1515
|
+
return result
|
|
1516
|
+
}
|
|
1517
|
+
ModuleForAxios.prototype.require.__azifyAxiosHookInstalled = true
|
|
1518
|
+
}
|
|
609
1519
|
const axios = require('axios')
|
|
610
1520
|
if (axios) {
|
|
611
|
-
const { getRequestContext, runWithRequestContext } = require('./store')
|
|
1521
|
+
const { getRequestContext, getLastJobContext, runWithRequestContext } = require('./store')
|
|
612
1522
|
|
|
613
1523
|
const buildUrl = (config) => {
|
|
614
1524
|
const url = config.url || ''
|
|
@@ -648,7 +1558,7 @@ try {
|
|
|
648
1558
|
return config
|
|
649
1559
|
}
|
|
650
1560
|
|
|
651
|
-
const ctx = getRequestContext()
|
|
1561
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
652
1562
|
const traceId = (ctx?.traceId) || randomUUID()
|
|
653
1563
|
const parentSpanId = (ctx?.spanId) || null
|
|
654
1564
|
const requestId = (ctx?.requestId) || randomUUID()
|
|
@@ -686,6 +1596,7 @@ try {
|
|
|
686
1596
|
!!traceId
|
|
687
1597
|
|
|
688
1598
|
if (shouldLogRequest) {
|
|
1599
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[AZIFY-DBG] axios REQUEST ' + method + ' ' + String(url).slice(0, 80) + '\n') } catch (_) {}
|
|
689
1600
|
sendOutboundLog('info', `[REQUEST] ${method} ${url}`, requestMeta)
|
|
690
1601
|
}
|
|
691
1602
|
|
|
@@ -717,7 +1628,7 @@ try {
|
|
|
717
1628
|
|
|
718
1629
|
if (shouldLogResponse || hasTraceHeaders) {
|
|
719
1630
|
const finalUrl = (url && url !== 'unknown') ? url : (marker?.meta?.url || response.config?.url || response.request?.responseURL || url)
|
|
720
|
-
|
|
1631
|
+
|
|
721
1632
|
if (finalUrl && finalUrl !== 'unknown') {
|
|
722
1633
|
let meta
|
|
723
1634
|
let duration = 0
|
|
@@ -735,7 +1646,7 @@ try {
|
|
|
735
1646
|
}
|
|
736
1647
|
}
|
|
737
1648
|
}
|
|
738
|
-
|
|
1649
|
+
|
|
739
1650
|
if (marker && marker.meta) {
|
|
740
1651
|
duration = Number((performance.now() - marker.start).toFixed(2))
|
|
741
1652
|
let responseBodyString = stringifyBody(response.data)
|
|
@@ -752,7 +1663,7 @@ try {
|
|
|
752
1663
|
}
|
|
753
1664
|
} else {
|
|
754
1665
|
const requestHeaders = response.config?.headers || {}
|
|
755
|
-
const ctx = getRequestContext()
|
|
1666
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
756
1667
|
const traceId = requestHeaders['x-trace-id'] || requestHeaders['X-Trace-ID'] || ctx?.traceId || randomUUID()
|
|
757
1668
|
const spanId = requestHeaders['x-span-id'] || requestHeaders['X-Span-ID'] || randomBytes(8).toString('hex')
|
|
758
1669
|
const parentSpanId = requestHeaders['x-parent-span-id'] || requestHeaders['X-Parent-Span-ID'] || ctx?.spanId || null
|
|
@@ -761,7 +1672,7 @@ try {
|
|
|
761
1672
|
if (typeof responseBodyString === 'string' && responseBodyString.length > 5000) {
|
|
762
1673
|
responseBodyString = responseBodyString.slice(0, 5000)
|
|
763
1674
|
}
|
|
764
|
-
|
|
1675
|
+
|
|
765
1676
|
meta = {
|
|
766
1677
|
traceId,
|
|
767
1678
|
spanId,
|
|
@@ -775,11 +1686,11 @@ try {
|
|
|
775
1686
|
responseBody: responseBodyString
|
|
776
1687
|
}
|
|
777
1688
|
}
|
|
778
|
-
|
|
1689
|
+
|
|
779
1690
|
markSource(meta, 'http-client')
|
|
780
1691
|
const message = `[RESPONSE] ${meta.method} ${meta.url} ${response.status} ${meta.responseTimeMs}ms`
|
|
781
1692
|
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
782
|
-
|
|
1693
|
+
|
|
783
1694
|
sendOutboundLog(level, message, meta)
|
|
784
1695
|
}
|
|
785
1696
|
}
|
|
@@ -807,7 +1718,7 @@ try {
|
|
|
807
1718
|
if (shouldLogError && url && url !== 'unknown') {
|
|
808
1719
|
let meta
|
|
809
1720
|
let duration = 0
|
|
810
|
-
|
|
1721
|
+
|
|
811
1722
|
if (marker && marker.meta) {
|
|
812
1723
|
duration = Number((performance.now() - marker.start).toFixed(2))
|
|
813
1724
|
meta = {
|
|
@@ -824,12 +1735,12 @@ try {
|
|
|
824
1735
|
}
|
|
825
1736
|
} else {
|
|
826
1737
|
const requestHeaders = config?.headers || {}
|
|
827
|
-
const ctx = getRequestContext()
|
|
1738
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
828
1739
|
const traceId = requestHeaders['x-trace-id'] || requestHeaders['X-Trace-ID'] || ctx?.traceId || randomUUID()
|
|
829
1740
|
const spanId = requestHeaders['x-span-id'] || requestHeaders['X-Span-ID'] || randomBytes(8).toString('hex')
|
|
830
1741
|
const parentSpanId = requestHeaders['x-parent-span-id'] || requestHeaders['X-Parent-Span-ID'] || ctx?.spanId || null
|
|
831
1742
|
const requestId = requestHeaders['x-request-id'] || requestHeaders['X-Request-ID'] || ctx?.requestId || randomUUID()
|
|
832
|
-
|
|
1743
|
+
|
|
833
1744
|
meta = {
|
|
834
1745
|
traceId,
|
|
835
1746
|
spanId,
|
|
@@ -848,10 +1759,10 @@ try {
|
|
|
848
1759
|
}
|
|
849
1760
|
}
|
|
850
1761
|
}
|
|
851
|
-
|
|
1762
|
+
|
|
852
1763
|
markSource(meta, 'http-client')
|
|
853
1764
|
const message = `[ERROR] ${meta.method} ${meta.url}`
|
|
854
|
-
|
|
1765
|
+
|
|
855
1766
|
sendOutboundLog('error', message, meta)
|
|
856
1767
|
}
|
|
857
1768
|
} catch (err) {
|
|
@@ -864,13 +1775,27 @@ try {
|
|
|
864
1775
|
return instance
|
|
865
1776
|
}
|
|
866
1777
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1778
|
+
applyAxiosPatch = function (ax) {
|
|
1779
|
+
if (!ax || ax.__azifyLoggerPatched) return
|
|
1780
|
+
patchInstance(ax)
|
|
1781
|
+
if (ax.create) {
|
|
1782
|
+
const originalCreate = ax.create
|
|
1783
|
+
ax.create = function (config) {
|
|
1784
|
+
const instance = originalCreate.call(this, config)
|
|
1785
|
+
patchInstance(instance)
|
|
1786
|
+
return instance
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
applyAxiosPatch(axios)
|
|
1791
|
+
for (const key of Object.keys(require.cache || {})) {
|
|
1792
|
+
if (typeof key !== 'string') continue
|
|
1793
|
+
const keyNorm = key.replace(/\\/g, '/')
|
|
1794
|
+
if (keyNorm === 'axios' || keyNorm.endsWith('/axios') || (keyNorm.includes('node_modules') && keyNorm.includes('/axios'))) {
|
|
1795
|
+
const mod = require.cache[key]
|
|
1796
|
+
if (mod && mod.exports && typeof mod.exports === 'object' && !mod.exports.__azifyLoggerPatched) {
|
|
1797
|
+
try { applyAxiosPatch(mod.exports) } catch (_) {}
|
|
1798
|
+
}
|
|
874
1799
|
}
|
|
875
1800
|
}
|
|
876
1801
|
}
|
|
@@ -882,7 +1807,7 @@ try {
|
|
|
882
1807
|
if (!g.__azifyLoggerFetchPatched) {
|
|
883
1808
|
g.__azifyLoggerFetchPatched = true
|
|
884
1809
|
|
|
885
|
-
const { getRequestContext, runWithRequestContext } = require('./store')
|
|
1810
|
+
const { getRequestContext, getLastJobContext, runWithRequestContext } = require('./store')
|
|
886
1811
|
|
|
887
1812
|
const originalFetch = globalThis.fetch.bind(globalThis)
|
|
888
1813
|
|
|
@@ -911,11 +1836,11 @@ try {
|
|
|
911
1836
|
if (HTTP_CLIENT_MODE === 'off') {
|
|
912
1837
|
return originalFetch(input, init)
|
|
913
1838
|
}
|
|
914
|
-
|
|
1839
|
+
|
|
915
1840
|
let request
|
|
916
1841
|
let method = 'UNKNOWN'
|
|
917
1842
|
let url = String(input)
|
|
918
|
-
|
|
1843
|
+
|
|
919
1844
|
try {
|
|
920
1845
|
request = ensureRequest(input, init)
|
|
921
1846
|
method = request.method.toUpperCase()
|
|
@@ -943,7 +1868,7 @@ try {
|
|
|
943
1868
|
return originalFetch(request)
|
|
944
1869
|
}
|
|
945
1870
|
|
|
946
|
-
const ctx = getRequestContext()
|
|
1871
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
947
1872
|
const traceId = (ctx?.traceId) || randomUUID()
|
|
948
1873
|
const parentSpanId = (ctx?.spanId) || null
|
|
949
1874
|
const requestId = (ctx?.requestId) || randomUUID()
|
|
@@ -1057,10 +1982,10 @@ try {
|
|
|
1057
1982
|
}
|
|
1058
1983
|
return {}
|
|
1059
1984
|
}
|
|
1060
|
-
|
|
1985
|
+
|
|
1061
1986
|
let responseBodyString = null
|
|
1062
1987
|
let responseHeaders = {}
|
|
1063
|
-
|
|
1988
|
+
|
|
1064
1989
|
try {
|
|
1065
1990
|
responseHeaders = headersToObject(response.headers)
|
|
1066
1991
|
const contentType = response.headers.get('content-type') || ''
|
|
@@ -1075,7 +2000,7 @@ try {
|
|
|
1075
2000
|
return null
|
|
1076
2001
|
}
|
|
1077
2002
|
}
|
|
1078
|
-
|
|
2003
|
+
|
|
1079
2004
|
if (contentType.includes('application/json') || contentType.includes('text/')) {
|
|
1080
2005
|
try {
|
|
1081
2006
|
const clonedResponse = response.clone()
|
|
@@ -1117,18 +2042,18 @@ try {
|
|
|
1117
2042
|
}
|
|
1118
2043
|
} catch (_) {
|
|
1119
2044
|
}
|
|
1120
|
-
|
|
2045
|
+
|
|
1121
2046
|
const responseMeta = {
|
|
1122
2047
|
...requestMeta,
|
|
1123
2048
|
statusCode: response.status,
|
|
1124
2049
|
responseTimeMs: duration,
|
|
1125
2050
|
responseHeaders
|
|
1126
2051
|
}
|
|
1127
|
-
|
|
2052
|
+
|
|
1128
2053
|
if (responseBodyString !== null) {
|
|
1129
2054
|
responseMeta.responseBody = responseBodyString
|
|
1130
2055
|
}
|
|
1131
|
-
|
|
2056
|
+
|
|
1132
2057
|
markSource(responseMeta, 'http-client')
|
|
1133
2058
|
const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
|
|
1134
2059
|
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
@@ -1141,77 +2066,5 @@ try {
|
|
|
1141
2066
|
}
|
|
1142
2067
|
} catch (_) {}
|
|
1143
2068
|
|
|
1144
|
-
try {
|
|
1145
|
-
const Bull = require('bull')
|
|
1146
|
-
const { runWithRequestContext } = require('./store')
|
|
1147
|
-
|
|
1148
|
-
const originalAdd = Bull.prototype.add
|
|
1149
|
-
Bull.prototype.add = function(name, data, opts) {
|
|
1150
|
-
const ctx = getRequestContext()
|
|
1151
|
-
|
|
1152
|
-
if (ctx && ctx.traceId) {
|
|
1153
|
-
data = {
|
|
1154
|
-
...data,
|
|
1155
|
-
traceId: ctx.traceId,
|
|
1156
|
-
spanId: ctx.spanId,
|
|
1157
|
-
parentSpanId: ctx.parentSpanId,
|
|
1158
|
-
requestId: ctx.requestId,
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
return originalAdd.call(this, name, data, opts)
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
const originalProcess = Bull.prototype.process
|
|
1166
|
-
Bull.prototype.process = function(name, concurrency, handler) {
|
|
1167
|
-
let actualName, actualConcurrency, actualHandler
|
|
1168
|
-
|
|
1169
|
-
if (typeof name === 'function') {
|
|
1170
|
-
actualHandler = name
|
|
1171
|
-
actualName = '__default__'
|
|
1172
|
-
actualConcurrency = 1
|
|
1173
|
-
} else if (typeof concurrency === 'function') {
|
|
1174
|
-
actualHandler = concurrency
|
|
1175
|
-
actualName = name
|
|
1176
|
-
actualConcurrency = 1
|
|
1177
|
-
} else {
|
|
1178
|
-
actualName = name
|
|
1179
|
-
actualConcurrency = concurrency
|
|
1180
|
-
actualHandler = handler
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
const wrappedHandler = function(job, done) {
|
|
1184
|
-
const { traceId, spanId, parentSpanId, requestId, ...jobData } = job.data
|
|
1185
|
-
|
|
1186
|
-
if (traceId && spanId) {
|
|
1187
|
-
const ctx = {
|
|
1188
|
-
traceId,
|
|
1189
|
-
spanId,
|
|
1190
|
-
parentSpanId,
|
|
1191
|
-
requestId,
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
return runWithRequestContext(ctx, () => {
|
|
1195
|
-
return actualHandler.call(this, job, done)
|
|
1196
|
-
})
|
|
1197
|
-
} else {
|
|
1198
|
-
const { startRequestContext } = require('./store')
|
|
1199
|
-
const newCtx = startRequestContext({ requestId: require('uuid').v4() })
|
|
1200
|
-
|
|
1201
|
-
return runWithRequestContext(newCtx, () => {
|
|
1202
|
-
return actualHandler.call(this, job, done)
|
|
1203
|
-
})
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
if (typeof name === 'function') {
|
|
1208
|
-
return originalProcess.call(this, wrappedHandler)
|
|
1209
|
-
} else if (typeof concurrency === 'function') {
|
|
1210
|
-
return originalProcess.call(this, actualName, wrappedHandler)
|
|
1211
|
-
} else {
|
|
1212
|
-
return originalProcess.call(this, actualName, actualConcurrency, wrappedHandler)
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
} catch (_) {}
|
|
1216
2069
|
} catch (_) {}
|
|
1217
2070
|
}
|