azify-logger 1.0.43 → 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/README.md +3 -3
- package/index.js +84 -7
- package/init.js +21 -11
- package/middleware-express.js +46 -44
- package/middleware-pino.js +173 -0
- package/package.json +5 -1
- package/pino-config.js +26 -0
- package/preload.js +15 -0
- package/register-http-client-early.js +816 -0
- package/register.js +1327 -372
- package/sampling.js +1 -1
- package/server.js +407 -159
- package/store.js +37 -11
- package/streams/httpQueue.js +24 -12
- package/streams/pino.js +59 -7
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) {
|
|
@@ -158,223 +382,390 @@ try {
|
|
|
158
382
|
}
|
|
159
383
|
|
|
160
384
|
const getOtelTraceContext = () => {
|
|
161
|
-
|
|
385
|
+
try {
|
|
386
|
+
const otelApi = require('@opentelemetry/api')
|
|
387
|
+
const activeContext = otelApi.context.active()
|
|
388
|
+
const span = otelApi.trace.getSpan(activeContext)
|
|
389
|
+
|
|
390
|
+
if (!span) return null
|
|
391
|
+
|
|
392
|
+
const spanContext = span.spanContext()
|
|
393
|
+
if (!spanContext || !spanContext.traceId) return null
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
traceId: spanContext.traceId,
|
|
397
|
+
spanId: spanContext.spanId,
|
|
398
|
+
parentSpanId: spanContext.parentSpanId || null
|
|
399
|
+
}
|
|
400
|
+
} catch (_) {
|
|
401
|
+
return null
|
|
402
|
+
}
|
|
403
|
+
}
|
|
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
|
|
162
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 (_) {}
|
|
163
533
|
|
|
534
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
535
|
+
try { process.stderr.write('[azify-logger] REGISTER step2 before first hook\n') } catch (_) {}
|
|
536
|
+
}
|
|
164
537
|
try {
|
|
165
|
-
const Module = require('module')
|
|
166
538
|
const originalRequire = Module.prototype.require
|
|
167
539
|
const { getRequestContext } = require('./store')
|
|
168
|
-
|
|
540
|
+
|
|
169
541
|
Module.prototype.require = function(id) {
|
|
170
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
|
+
}
|
|
171
561
|
if (id === 'pino' || id.endsWith('/pino')) {
|
|
172
562
|
if (result && typeof result === 'function') {
|
|
173
563
|
const originalPino = result
|
|
174
|
-
|
|
564
|
+
|
|
175
565
|
const patchedPino = function(options, stream) {
|
|
566
|
+
if (new.target) {
|
|
567
|
+
return originalPino.call(this, options, stream)
|
|
568
|
+
}
|
|
569
|
+
|
|
176
570
|
const logger = originalPino(options, stream)
|
|
177
|
-
|
|
571
|
+
return applyLoggerPatches(logger, options)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function applyLoggerPatches(logger, pinoOptions) {
|
|
575
|
+
if (logger.__azifyPatched) {
|
|
576
|
+
return logger
|
|
577
|
+
}
|
|
578
|
+
logger.__azifyPatched = true
|
|
579
|
+
|
|
580
|
+
const originalLog = logger.log
|
|
178
581
|
const originalInfo = logger.info
|
|
179
582
|
const originalError = logger.error
|
|
180
583
|
const originalWarn = logger.warn
|
|
181
584
|
const originalDebug = logger.debug
|
|
182
585
|
const originalFatal = logger.fatal
|
|
183
586
|
const originalTrace = logger.trace
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
obj
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
obj.spanId = traceCtx.spanId
|
|
230
|
-
obj.parentSpanId = traceCtx.parentSpanId
|
|
231
|
-
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
232
|
-
} else {
|
|
233
|
-
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return originalWarn.call(this, obj, msg, ...args)
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
logger.debug = function(obj, msg, ...args) {
|
|
240
|
-
const ctx = getRequestContext()
|
|
241
|
-
const otelCtx = !ctx || !ctx.traceId ? getOtelTraceContext() : null
|
|
242
|
-
const traceCtx = ctx || otelCtx
|
|
243
|
-
|
|
244
|
-
if (traceCtx && traceCtx.traceId) {
|
|
245
|
-
if (typeof obj === 'object' && obj !== null) {
|
|
246
|
-
obj.traceId = traceCtx.traceId
|
|
247
|
-
obj.spanId = traceCtx.spanId
|
|
248
|
-
obj.parentSpanId = traceCtx.parentSpanId
|
|
249
|
-
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
250
|
-
} else {
|
|
251
|
-
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return originalDebug.call(this, obj, msg, ...args)
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
logger.fatal = function(obj, msg, ...args) {
|
|
258
|
-
const ctx = getRequestContext()
|
|
259
|
-
const otelCtx = !ctx || !ctx.traceId ? getOtelTraceContext() : null
|
|
260
|
-
const traceCtx = ctx || otelCtx
|
|
261
|
-
|
|
262
|
-
if (traceCtx && traceCtx.traceId) {
|
|
263
|
-
if (typeof obj === 'object' && obj !== null) {
|
|
264
|
-
obj.traceId = traceCtx.traceId
|
|
265
|
-
obj.spanId = traceCtx.spanId
|
|
266
|
-
obj.parentSpanId = traceCtx.parentSpanId
|
|
267
|
-
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
268
|
-
} else {
|
|
269
|
-
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
587
|
+
const originalChild = logger.child
|
|
588
|
+
|
|
589
|
+
const patchLogMethod = (original, methodName) => {
|
|
590
|
+
return function(obj, msg, ...args) {
|
|
591
|
+
const otelCtx = getOtelTraceContext()
|
|
592
|
+
const ctx = getRequestContext()
|
|
593
|
+
const traceCtx = ctx || otelCtx
|
|
594
|
+
|
|
595
|
+
if (traceCtx && traceCtx.traceId) {
|
|
596
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
597
|
+
obj = {
|
|
598
|
+
...obj,
|
|
599
|
+
traceId: traceCtx.traceId,
|
|
600
|
+
spanId: traceCtx.spanId,
|
|
601
|
+
parentSpanId: traceCtx.parentSpanId,
|
|
602
|
+
requestId: traceCtx.requestId || ctx?.requestId
|
|
603
|
+
}
|
|
604
|
+
} else {
|
|
605
|
+
obj = {
|
|
606
|
+
traceId: traceCtx.traceId,
|
|
607
|
+
spanId: traceCtx.spanId,
|
|
608
|
+
parentSpanId: traceCtx.parentSpanId,
|
|
609
|
+
requestId: traceCtx.requestId || ctx?.requestId,
|
|
610
|
+
msg: obj
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
try {
|
|
615
|
+
const levelMap = { log: 'info', info: 'info', error: 'error', warn: 'warn', debug: 'debug', fatal: 'fatal', trace: 'trace' }
|
|
616
|
+
const level = levelMap[methodName] || 'info'
|
|
617
|
+
const message = (typeof obj === 'object' ? obj.message : obj) || msg || ''
|
|
618
|
+
|
|
619
|
+
const meta = {
|
|
620
|
+
...obj,
|
|
621
|
+
service: {
|
|
622
|
+
name: serviceName,
|
|
623
|
+
version: '1.0.0'
|
|
624
|
+
},
|
|
625
|
+
environment,
|
|
626
|
+
timestamp: new Date().toISOString(),
|
|
627
|
+
hostname: require('os').hostname()
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
sendOutboundLog(level, message, meta)
|
|
631
|
+
} catch (err) {}
|
|
270
632
|
}
|
|
633
|
+
|
|
634
|
+
return original.call(this, obj, msg, ...args)
|
|
271
635
|
}
|
|
272
|
-
return originalFatal.call(this, obj, msg, ...args)
|
|
273
636
|
}
|
|
274
|
-
|
|
275
|
-
logger.
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
} else {
|
|
287
|
-
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return originalTrace.call(this, obj, msg, ...args)
|
|
637
|
+
|
|
638
|
+
logger.log = patchLogMethod(originalLog, 'log')
|
|
639
|
+
logger.info = patchLogMethod(originalInfo, 'info')
|
|
640
|
+
logger.error = patchLogMethod(originalError, 'error')
|
|
641
|
+
logger.warn = patchLogMethod(originalWarn, 'warn')
|
|
642
|
+
logger.debug = patchLogMethod(originalDebug, 'debug')
|
|
643
|
+
logger.fatal = patchLogMethod(originalFatal, 'fatal')
|
|
644
|
+
logger.trace = patchLogMethod(originalTrace, 'trace')
|
|
645
|
+
|
|
646
|
+
logger.child = function(bindings, options) {
|
|
647
|
+
const childLogger = originalChild.call(this, bindings, options)
|
|
648
|
+
return applyLoggerPatches(childLogger, pinoOptions)
|
|
291
649
|
}
|
|
292
|
-
|
|
650
|
+
|
|
293
651
|
return logger
|
|
294
652
|
}
|
|
295
|
-
|
|
653
|
+
|
|
296
654
|
Object.setPrototypeOf(patchedPino, originalPino)
|
|
297
655
|
Object.assign(patchedPino, originalPino)
|
|
298
|
-
|
|
656
|
+
|
|
299
657
|
return patchedPino
|
|
300
658
|
}
|
|
301
659
|
}
|
|
302
|
-
|
|
660
|
+
|
|
303
661
|
return result
|
|
304
662
|
}
|
|
305
|
-
|
|
663
|
+
|
|
306
664
|
} catch (_) {}
|
|
307
665
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
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
|
|
324
681
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
return originalError.call(this, message, trace, context)
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
Logger.prototype.warn = function(message, context) {
|
|
336
|
-
const { getRequestContext } = require('./store')
|
|
337
|
-
const ctx = getRequestContext()
|
|
338
|
-
if (ctx && ctx.traceId) {
|
|
339
|
-
return originalWarn.call(this, message, context)
|
|
340
|
-
}
|
|
341
|
-
return originalWarn.call(this, message, context)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
Logger.prototype.debug = function(message, context) {
|
|
345
|
-
const { getRequestContext } = require('./store')
|
|
346
|
-
const ctx = getRequestContext()
|
|
347
|
-
if (ctx && ctx.traceId) {
|
|
348
|
-
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 }
|
|
349
688
|
}
|
|
350
|
-
return originalDebug.call(this, message, context)
|
|
351
689
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
|
360
698
|
}
|
|
361
|
-
|
|
362
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)
|
|
363
754
|
} catch (_) {}
|
|
364
755
|
|
|
365
756
|
try {
|
|
366
757
|
const originalConsoleLog = console.log
|
|
367
758
|
const originalConsoleError = console.error
|
|
368
759
|
const originalConsoleWarn = console.warn
|
|
369
|
-
|
|
760
|
+
|
|
370
761
|
console.log = function(...args) {
|
|
371
762
|
return originalConsoleLog.apply(this, args)
|
|
372
763
|
}
|
|
373
|
-
|
|
764
|
+
|
|
374
765
|
console.error = function(...args) {
|
|
375
766
|
return originalConsoleError.apply(this, args)
|
|
376
767
|
}
|
|
377
|
-
|
|
768
|
+
|
|
378
769
|
console.warn = function(...args) {
|
|
379
770
|
return originalConsoleWarn.apply(this, args)
|
|
380
771
|
}
|
|
@@ -383,130 +774,751 @@ try {
|
|
|
383
774
|
try {
|
|
384
775
|
const Module = require('module')
|
|
385
776
|
const originalRequire = Module.prototype.require
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
if (
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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 }
|
|
404
820
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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) {
|
|
823
|
+
try {
|
|
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 }
|
|
411
828
|
}
|
|
412
|
-
return originalLoggerConstructor.prototype.log.call(this, message, context)
|
|
413
829
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
830
|
+
const msg = (typeof message === 'object' && message !== null ? message.message : message) || ''
|
|
831
|
+
return { effectiveCtx, msg }
|
|
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`)
|
|
420
842
|
}
|
|
421
|
-
|
|
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 }
|
|
422
851
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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)
|
|
431
870
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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)
|
|
440
894
|
}
|
|
441
|
-
|
|
442
|
-
return instance
|
|
443
895
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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)
|
|
449
908
|
}
|
|
450
|
-
|
|
909
|
+
|
|
451
910
|
if (result && result.LoggerModule && result.LoggerModule.forRoot) {
|
|
452
911
|
const originalForRoot = result.LoggerModule.forRoot
|
|
453
|
-
|
|
912
|
+
|
|
454
913
|
result.LoggerModule.forRoot = function(options) {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
914
|
+
if (process.env.AZIFY_LOGGER_URL) {
|
|
915
|
+
try {
|
|
916
|
+
const createPinoStream = require('./streams/pino')
|
|
917
|
+
const azifyStream = createPinoStream({
|
|
918
|
+
loggerUrl: process.env.AZIFY_LOGGER_URL,
|
|
919
|
+
serviceName: process.env.APP_NAME || (options && options.pinoHttp && options.pinoHttp.name),
|
|
920
|
+
environment: process.env.NODE_ENV
|
|
921
|
+
})
|
|
922
|
+
|
|
923
|
+
const pinoHttp = (options && options.pinoHttp) || {}
|
|
924
|
+
|
|
925
|
+
if (pinoHttp.transport) {
|
|
926
|
+
return originalForRoot.call(this, options)
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
const mergedOptions = {
|
|
930
|
+
...options,
|
|
931
|
+
pinoHttp: {
|
|
932
|
+
...pinoHttp,
|
|
933
|
+
stream: azifyStream,
|
|
934
|
+
},
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
return originalForRoot.call(this, mergedOptions)
|
|
938
|
+
} catch (err) {
|
|
939
|
+
return originalForRoot.call(this, options)
|
|
940
|
+
}
|
|
464
941
|
}
|
|
465
|
-
|
|
466
|
-
return originalForRoot.call(this,
|
|
942
|
+
|
|
943
|
+
return originalForRoot.call(this, options)
|
|
467
944
|
}
|
|
468
|
-
|
|
945
|
+
|
|
469
946
|
Object.setPrototypeOf(result.LoggerModule.forRoot, originalForRoot)
|
|
470
947
|
Object.assign(result.LoggerModule.forRoot, originalForRoot)
|
|
471
948
|
}
|
|
472
949
|
}
|
|
473
|
-
|
|
474
|
-
return result
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
} catch (_) {}
|
|
478
950
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
+
}
|
|
994
|
+
}
|
|
995
|
+
Cls.prototype.handleProcessor.__azifyPatched = true
|
|
996
|
+
}
|
|
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
|
|
1015
|
+
try {
|
|
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
|
+
}
|
|
497
1027
|
}
|
|
1028
|
+
Cls.prototype.decorate.__azifyPatched = true
|
|
498
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 }
|
|
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)
|
|
1089
|
+
} catch (_) {}
|
|
1090
|
+
return original.call(this, obj, msg, ...args)
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
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
|
|
499
1119
|
}
|
|
500
|
-
|
|
501
|
-
|
|
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
|
+
)
|
|
1182
|
+
}
|
|
1183
|
+
return promise
|
|
1184
|
+
}
|
|
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)
|
|
1216
|
+
}
|
|
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
|
|
1249
|
+
}
|
|
1250
|
+
proto.request.__azifyPatched = true
|
|
1251
|
+
}
|
|
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
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
} catch (_) {}
|
|
1325
|
+
} catch (_) {}
|
|
502
1326
|
}
|
|
503
1327
|
}
|
|
504
|
-
|
|
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
|
|
1469
|
+
},
|
|
1470
|
+
(err) => {
|
|
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 })
|
|
1474
|
+
}
|
|
1475
|
+
throw err
|
|
1476
|
+
}
|
|
1477
|
+
)
|
|
1478
|
+
}
|
|
1479
|
+
globalThis.fetch.__azifyPatched = true
|
|
1480
|
+
if (debug) try { process.stderr.write('[azify-logger] patched globalThis.fetch\n') } catch (_) {}
|
|
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)
|
|
1486
|
+
}
|
|
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
|
+
}
|
|
505
1502
|
|
|
506
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
|
+
}
|
|
507
1519
|
const axios = require('axios')
|
|
508
1520
|
if (axios) {
|
|
509
|
-
const { getRequestContext, runWithRequestContext } = require('./store')
|
|
1521
|
+
const { getRequestContext, getLastJobContext, runWithRequestContext } = require('./store')
|
|
510
1522
|
|
|
511
1523
|
const buildUrl = (config) => {
|
|
512
1524
|
const url = config.url || ''
|
|
@@ -546,7 +1558,7 @@ try {
|
|
|
546
1558
|
return config
|
|
547
1559
|
}
|
|
548
1560
|
|
|
549
|
-
const ctx = getRequestContext()
|
|
1561
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
550
1562
|
const traceId = (ctx?.traceId) || randomUUID()
|
|
551
1563
|
const parentSpanId = (ctx?.spanId) || null
|
|
552
1564
|
const requestId = (ctx?.requestId) || randomUUID()
|
|
@@ -584,6 +1596,7 @@ try {
|
|
|
584
1596
|
!!traceId
|
|
585
1597
|
|
|
586
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 (_) {}
|
|
587
1600
|
sendOutboundLog('info', `[REQUEST] ${method} ${url}`, requestMeta)
|
|
588
1601
|
}
|
|
589
1602
|
|
|
@@ -615,7 +1628,7 @@ try {
|
|
|
615
1628
|
|
|
616
1629
|
if (shouldLogResponse || hasTraceHeaders) {
|
|
617
1630
|
const finalUrl = (url && url !== 'unknown') ? url : (marker?.meta?.url || response.config?.url || response.request?.responseURL || url)
|
|
618
|
-
|
|
1631
|
+
|
|
619
1632
|
if (finalUrl && finalUrl !== 'unknown') {
|
|
620
1633
|
let meta
|
|
621
1634
|
let duration = 0
|
|
@@ -633,7 +1646,7 @@ try {
|
|
|
633
1646
|
}
|
|
634
1647
|
}
|
|
635
1648
|
}
|
|
636
|
-
|
|
1649
|
+
|
|
637
1650
|
if (marker && marker.meta) {
|
|
638
1651
|
duration = Number((performance.now() - marker.start).toFixed(2))
|
|
639
1652
|
let responseBodyString = stringifyBody(response.data)
|
|
@@ -650,7 +1663,7 @@ try {
|
|
|
650
1663
|
}
|
|
651
1664
|
} else {
|
|
652
1665
|
const requestHeaders = response.config?.headers || {}
|
|
653
|
-
const ctx = getRequestContext()
|
|
1666
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
654
1667
|
const traceId = requestHeaders['x-trace-id'] || requestHeaders['X-Trace-ID'] || ctx?.traceId || randomUUID()
|
|
655
1668
|
const spanId = requestHeaders['x-span-id'] || requestHeaders['X-Span-ID'] || randomBytes(8).toString('hex')
|
|
656
1669
|
const parentSpanId = requestHeaders['x-parent-span-id'] || requestHeaders['X-Parent-Span-ID'] || ctx?.spanId || null
|
|
@@ -659,7 +1672,7 @@ try {
|
|
|
659
1672
|
if (typeof responseBodyString === 'string' && responseBodyString.length > 5000) {
|
|
660
1673
|
responseBodyString = responseBodyString.slice(0, 5000)
|
|
661
1674
|
}
|
|
662
|
-
|
|
1675
|
+
|
|
663
1676
|
meta = {
|
|
664
1677
|
traceId,
|
|
665
1678
|
spanId,
|
|
@@ -673,11 +1686,11 @@ try {
|
|
|
673
1686
|
responseBody: responseBodyString
|
|
674
1687
|
}
|
|
675
1688
|
}
|
|
676
|
-
|
|
1689
|
+
|
|
677
1690
|
markSource(meta, 'http-client')
|
|
678
1691
|
const message = `[RESPONSE] ${meta.method} ${meta.url} ${response.status} ${meta.responseTimeMs}ms`
|
|
679
1692
|
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
680
|
-
|
|
1693
|
+
|
|
681
1694
|
sendOutboundLog(level, message, meta)
|
|
682
1695
|
}
|
|
683
1696
|
}
|
|
@@ -705,7 +1718,7 @@ try {
|
|
|
705
1718
|
if (shouldLogError && url && url !== 'unknown') {
|
|
706
1719
|
let meta
|
|
707
1720
|
let duration = 0
|
|
708
|
-
|
|
1721
|
+
|
|
709
1722
|
if (marker && marker.meta) {
|
|
710
1723
|
duration = Number((performance.now() - marker.start).toFixed(2))
|
|
711
1724
|
meta = {
|
|
@@ -722,12 +1735,12 @@ try {
|
|
|
722
1735
|
}
|
|
723
1736
|
} else {
|
|
724
1737
|
const requestHeaders = config?.headers || {}
|
|
725
|
-
const ctx = getRequestContext()
|
|
1738
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
726
1739
|
const traceId = requestHeaders['x-trace-id'] || requestHeaders['X-Trace-ID'] || ctx?.traceId || randomUUID()
|
|
727
1740
|
const spanId = requestHeaders['x-span-id'] || requestHeaders['X-Span-ID'] || randomBytes(8).toString('hex')
|
|
728
1741
|
const parentSpanId = requestHeaders['x-parent-span-id'] || requestHeaders['X-Parent-Span-ID'] || ctx?.spanId || null
|
|
729
1742
|
const requestId = requestHeaders['x-request-id'] || requestHeaders['X-Request-ID'] || ctx?.requestId || randomUUID()
|
|
730
|
-
|
|
1743
|
+
|
|
731
1744
|
meta = {
|
|
732
1745
|
traceId,
|
|
733
1746
|
spanId,
|
|
@@ -746,10 +1759,10 @@ try {
|
|
|
746
1759
|
}
|
|
747
1760
|
}
|
|
748
1761
|
}
|
|
749
|
-
|
|
1762
|
+
|
|
750
1763
|
markSource(meta, 'http-client')
|
|
751
1764
|
const message = `[ERROR] ${meta.method} ${meta.url}`
|
|
752
|
-
|
|
1765
|
+
|
|
753
1766
|
sendOutboundLog('error', message, meta)
|
|
754
1767
|
}
|
|
755
1768
|
} catch (err) {
|
|
@@ -762,13 +1775,27 @@ try {
|
|
|
762
1775
|
return instance
|
|
763
1776
|
}
|
|
764
1777
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
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
|
+
}
|
|
772
1799
|
}
|
|
773
1800
|
}
|
|
774
1801
|
}
|
|
@@ -780,7 +1807,7 @@ try {
|
|
|
780
1807
|
if (!g.__azifyLoggerFetchPatched) {
|
|
781
1808
|
g.__azifyLoggerFetchPatched = true
|
|
782
1809
|
|
|
783
|
-
const { getRequestContext, runWithRequestContext } = require('./store')
|
|
1810
|
+
const { getRequestContext, getLastJobContext, runWithRequestContext } = require('./store')
|
|
784
1811
|
|
|
785
1812
|
const originalFetch = globalThis.fetch.bind(globalThis)
|
|
786
1813
|
|
|
@@ -809,11 +1836,11 @@ try {
|
|
|
809
1836
|
if (HTTP_CLIENT_MODE === 'off') {
|
|
810
1837
|
return originalFetch(input, init)
|
|
811
1838
|
}
|
|
812
|
-
|
|
1839
|
+
|
|
813
1840
|
let request
|
|
814
1841
|
let method = 'UNKNOWN'
|
|
815
1842
|
let url = String(input)
|
|
816
|
-
|
|
1843
|
+
|
|
817
1844
|
try {
|
|
818
1845
|
request = ensureRequest(input, init)
|
|
819
1846
|
method = request.method.toUpperCase()
|
|
@@ -841,7 +1868,7 @@ try {
|
|
|
841
1868
|
return originalFetch(request)
|
|
842
1869
|
}
|
|
843
1870
|
|
|
844
|
-
const ctx = getRequestContext()
|
|
1871
|
+
const ctx = getRequestContext() || getLastJobContext()
|
|
845
1872
|
const traceId = (ctx?.traceId) || randomUUID()
|
|
846
1873
|
const parentSpanId = (ctx?.spanId) || null
|
|
847
1874
|
const requestId = (ctx?.requestId) || randomUUID()
|
|
@@ -955,10 +1982,10 @@ try {
|
|
|
955
1982
|
}
|
|
956
1983
|
return {}
|
|
957
1984
|
}
|
|
958
|
-
|
|
1985
|
+
|
|
959
1986
|
let responseBodyString = null
|
|
960
1987
|
let responseHeaders = {}
|
|
961
|
-
|
|
1988
|
+
|
|
962
1989
|
try {
|
|
963
1990
|
responseHeaders = headersToObject(response.headers)
|
|
964
1991
|
const contentType = response.headers.get('content-type') || ''
|
|
@@ -973,7 +2000,7 @@ try {
|
|
|
973
2000
|
return null
|
|
974
2001
|
}
|
|
975
2002
|
}
|
|
976
|
-
|
|
2003
|
+
|
|
977
2004
|
if (contentType.includes('application/json') || contentType.includes('text/')) {
|
|
978
2005
|
try {
|
|
979
2006
|
const clonedResponse = response.clone()
|
|
@@ -1015,18 +2042,18 @@ try {
|
|
|
1015
2042
|
}
|
|
1016
2043
|
} catch (_) {
|
|
1017
2044
|
}
|
|
1018
|
-
|
|
2045
|
+
|
|
1019
2046
|
const responseMeta = {
|
|
1020
2047
|
...requestMeta,
|
|
1021
2048
|
statusCode: response.status,
|
|
1022
2049
|
responseTimeMs: duration,
|
|
1023
2050
|
responseHeaders
|
|
1024
2051
|
}
|
|
1025
|
-
|
|
2052
|
+
|
|
1026
2053
|
if (responseBodyString !== null) {
|
|
1027
2054
|
responseMeta.responseBody = responseBodyString
|
|
1028
2055
|
}
|
|
1029
|
-
|
|
2056
|
+
|
|
1030
2057
|
markSource(responseMeta, 'http-client')
|
|
1031
2058
|
const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
|
|
1032
2059
|
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
@@ -1039,77 +2066,5 @@ try {
|
|
|
1039
2066
|
}
|
|
1040
2067
|
} catch (_) {}
|
|
1041
2068
|
|
|
1042
|
-
try {
|
|
1043
|
-
const Bull = require('bull')
|
|
1044
|
-
const { runWithRequestContext } = require('./store')
|
|
1045
|
-
|
|
1046
|
-
const originalAdd = Bull.prototype.add
|
|
1047
|
-
Bull.prototype.add = function(name, data, opts) {
|
|
1048
|
-
const ctx = getRequestContext()
|
|
1049
|
-
|
|
1050
|
-
if (ctx && ctx.traceId) {
|
|
1051
|
-
data = {
|
|
1052
|
-
...data,
|
|
1053
|
-
traceId: ctx.traceId,
|
|
1054
|
-
spanId: ctx.spanId,
|
|
1055
|
-
parentSpanId: ctx.parentSpanId,
|
|
1056
|
-
requestId: ctx.requestId,
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
return originalAdd.call(this, name, data, opts)
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
const originalProcess = Bull.prototype.process
|
|
1064
|
-
Bull.prototype.process = function(name, concurrency, handler) {
|
|
1065
|
-
let actualName, actualConcurrency, actualHandler
|
|
1066
|
-
|
|
1067
|
-
if (typeof name === 'function') {
|
|
1068
|
-
actualHandler = name
|
|
1069
|
-
actualName = '__default__'
|
|
1070
|
-
actualConcurrency = 1
|
|
1071
|
-
} else if (typeof concurrency === 'function') {
|
|
1072
|
-
actualHandler = concurrency
|
|
1073
|
-
actualName = name
|
|
1074
|
-
actualConcurrency = 1
|
|
1075
|
-
} else {
|
|
1076
|
-
actualName = name
|
|
1077
|
-
actualConcurrency = concurrency
|
|
1078
|
-
actualHandler = handler
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
const wrappedHandler = function(job, done) {
|
|
1082
|
-
const { traceId, spanId, parentSpanId, requestId, ...jobData } = job.data
|
|
1083
|
-
|
|
1084
|
-
if (traceId && spanId) {
|
|
1085
|
-
const ctx = {
|
|
1086
|
-
traceId,
|
|
1087
|
-
spanId,
|
|
1088
|
-
parentSpanId,
|
|
1089
|
-
requestId,
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
return runWithRequestContext(ctx, () => {
|
|
1093
|
-
return actualHandler.call(this, job, done)
|
|
1094
|
-
})
|
|
1095
|
-
} else {
|
|
1096
|
-
const { startRequestContext } = require('./store')
|
|
1097
|
-
const newCtx = startRequestContext({ requestId: require('uuid').v4() })
|
|
1098
|
-
|
|
1099
|
-
return runWithRequestContext(newCtx, () => {
|
|
1100
|
-
return actualHandler.call(this, job, done)
|
|
1101
|
-
})
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
if (typeof name === 'function') {
|
|
1106
|
-
return originalProcess.call(this, wrappedHandler)
|
|
1107
|
-
} else if (typeof concurrency === 'function') {
|
|
1108
|
-
return originalProcess.call(this, actualName, wrappedHandler)
|
|
1109
|
-
} else {
|
|
1110
|
-
return originalProcess.call(this, actualName, actualConcurrency, wrappedHandler)
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
} catch (_) {}
|
|
1114
2069
|
} catch (_) {}
|
|
1115
2070
|
}
|