azify-logger 1.0.26 → 1.0.29

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.
@@ -1,413 +1,314 @@
1
- const axios = require('axios')
2
- const { als, runWithRequestContext, startRequestContext, getRequestContext } = require('./store')
1
+ const { startRequestContext } = require('./store')
2
+ const { createHttpLoggerTransport } = require('./streams/httpQueue')
3
+ const { Worker } = require('worker_threads')
4
+ const path = require('path')
5
+ const os = require('os')
3
6
 
4
- /**
5
- * Creates an Express middleware for automatic request/response logging with azify-logger
6
- * @param {Object} options - Configuration options
7
- * @param {string} [options.serviceName] - Name of the service (defaults to APP_NAME env var or 'assemble')
8
- * @param {string} [options.loggerUrl] - URL of the azify-logger service (defaults to AZIFY_LOGGER_URL env var or 'http://localhost:3001')
9
- * @param {string} [options.environment] - Environment name (defaults to NODE_ENV env var or 'development')
10
- * @returns {Function} Express middleware function
11
- * @example
12
- * const azifyMiddleware = require('azify-logger/middleware-express');
13
- * app.use(azifyMiddleware({ serviceName: 'my-app' }));
14
- */
15
- function createExpressLoggingMiddleware(options = {}) {
16
- const config = {
17
- serviceName: options.serviceName || process.env.APP_NAME || 'assemble',
18
- loggerUrl: options.loggerUrl || process.env.AZIFY_LOGGER_URL || 'http://localhost:3001',
19
- environment: options.environment || process.env.NODE_ENV || 'development'
20
- }
7
+ function fastUUID() {
8
+ const timestamp = Date.now().toString(36)
9
+ const randomPart = Math.random().toString(36).substring(2, 15)
10
+ const randomPart2 = Math.random().toString(36).substring(2, 15)
11
+ return `${timestamp}-${randomPart}-${randomPart2}`.substring(0, 36)
12
+ }
21
13
 
22
- /**
23
- * Sends a log entry to the azify-logger service
24
- * @param {string} level - Log level (info, error, warn, debug)
25
- * @param {string} message - Log message
26
- * @param {Object} [meta={}] - Additional metadata to include in the log
27
- * @private
28
- */
29
- async function sendLog(level, message, meta = {}) {
30
- const logData = {
31
- level,
32
- message,
33
- meta: {
34
- ...meta,
35
- service: {
36
- name: config.serviceName,
37
- version: '1.0.0'
38
- },
39
- environment: config.environment,
40
- timestamp: new Date().toISOString(),
41
- hostname: require('os').hostname()
42
- }
43
- }
14
+ function sanitizeTraceHex(value) {
15
+ if (!value || typeof value !== 'string') return null
16
+ const hex = value.replace(/[^0-9a-fA-F]/g, '').toLowerCase()
17
+ if (!hex) return null
18
+ return hex.padEnd(32, '0').slice(0, 32)
19
+ }
44
20
 
21
+ function safeSerializeBody(payload) {
22
+ if (payload == null) return ''
23
+ if (typeof payload === 'string') return payload
24
+ if (Buffer.isBuffer(payload)) return payload.toString('utf8')
25
+ try {
26
+ return JSON.stringify(payload)
27
+ } catch (err) {
45
28
  try {
46
- await axios.post(`${config.loggerUrl}`, logData, {
47
- timeout: 5000
48
- })
49
- } catch (error) {
50
- console.error('Erro ao enviar log:', error.message)
29
+ return String(payload)
30
+ } catch {
31
+ return ''
51
32
  }
52
33
  }
34
+ }
53
35
 
54
- /**
55
- * Express middleware function that logs requests and responses
56
- * @param {Object} req - Express request object
57
- * @param {Object} res - Express response object
58
- * @param {Function} next - Express next function
59
- * @returns {void}
60
- */
61
- return function azifyExpressLoggingMiddleware(req, res, next) {
62
- const startTime = Date.now()
63
- const requestId = req.requestId || require('uuid').v4()
64
- const middlewareId = require('uuid').v4().substring(0, 8)
65
-
66
- let existingTraceId = null
67
- let existingSpanId = null
68
- let existingParentSpanId = null
69
-
70
- if (req.headers['x-trace-id']) {
71
- existingTraceId = req.headers['x-trace-id']
72
- existingSpanId = req.headers['x-span-id']
73
- existingParentSpanId = req.headers['x-parent-span-id']
74
- }
75
-
76
- const currentCtx = getRequestContext()
77
- if (currentCtx && currentCtx.traceId) {
78
- existingTraceId = currentCtx.traceId
79
- existingSpanId = currentCtx.spanId
80
- existingParentSpanId = currentCtx.parentSpanId
81
- }
36
+ function normalizeChunkToBuffer(chunk) {
37
+ if (chunk == null) return null
38
+ if (Buffer.isBuffer(chunk)) return chunk
39
+ if (typeof chunk === 'string') return Buffer.from(chunk)
40
+ if (chunk && chunk.type === 'Buffer' && Array.isArray(chunk.data)) {
41
+ return Buffer.from(chunk.data)
42
+ }
43
+ try {
44
+ return Buffer.from(String(chunk))
45
+ } catch {
46
+ return null
47
+ }
48
+ }
49
+
50
+ const HEADER_WHITELIST = new Set([
51
+ 'content-type',
52
+ 'content-length',
53
+ 'accept',
54
+ 'accept-encoding',
55
+ 'user-agent',
56
+ 'host',
57
+ 'x-request-id',
58
+ 'x-trace-id',
59
+ 'x-span-id',
60
+ 'x-parent-span-id'
61
+ ])
62
+
63
+ function pickHeaders(source) {
64
+ if (!source || typeof source !== 'object') {
65
+ return {}
66
+ }
67
+ const result = {}
68
+ for (const key in source) {
69
+ const lower = key.toLowerCase()
70
+ if (!HEADER_WHITELIST.has(lower)) continue
82
71
 
83
- let reqCtx
84
- if (existingTraceId) {
85
- reqCtx = {
86
- traceId: existingTraceId,
87
- spanId: existingSpanId || require('uuid').v4().substring(0, 16),
88
- parentSpanId: existingParentSpanId,
89
- requestId: requestId
90
- }
91
- } else {
92
- reqCtx = startRequestContext({ requestId })
93
- }
72
+ if (!Object.prototype.hasOwnProperty.call(source, key)) continue
94
73
 
95
- const requestTraceId = reqCtx.traceId
96
- const requestSpanId = reqCtx.spanId
97
- const requestParentSpanId = reqCtx.parentSpanId
98
-
99
- const originalConsole = {
100
- log: console.log,
101
- info: console.info,
102
- warn: console.warn,
103
- error: console.error
74
+ const value = source[key]
75
+ if (Array.isArray(value)) {
76
+ result[key] = value.map(String)
77
+ } else if (value != null) {
78
+ result[key] = String(value)
104
79
  }
80
+ }
81
+ return result
82
+ }
105
83
 
106
- console.log = (...args) => {
107
- const message = args.map(String).join(' ')
108
- sendLog('info', message, {
109
- traceId: requestTraceId,
110
- spanId: requestSpanId,
111
- parentSpanId: requestParentSpanId,
112
- requestId: requestId
113
- })
114
- }
84
+ function createExpressLoggingMiddleware(options = {}) {
85
+ const config = {
86
+ serviceName: options.serviceName || process.env.APP_NAME,
87
+ loggerUrl: options.loggerUrl || process.env.AZIFY_LOGGER_URL || 'http://localhost:3001/log',
88
+ environment: options.environment || process.env.NODE_ENV,
89
+ captureResponseBody: options.captureResponseBody !== false && process.env.AZIFY_LOGGER_CAPTURE_RESPONSE_BODY !== 'false',
90
+ captureRequestBody: options.captureRequestBody !== false && process.env.AZIFY_LOGGER_CAPTURE_REQUEST_BODY !== 'false',
91
+ logRequest: options.logRequest !== false && process.env.AZIFY_LOGGER_LOG_REQUEST !== 'false',
92
+ captureHeaders: options.captureHeaders !== undefined ? options.captureHeaders : process.env.AZIFY_LOGGER_CAPTURE_HEADERS === 'true'
93
+ }
115
94
 
116
- console.info = (...args) => {
117
- const message = args.map(String).join(' ')
118
- sendLog('info', message, {
119
- traceId: requestTraceId,
120
- spanId: requestSpanId,
121
- parentSpanId: requestParentSpanId,
122
- requestId: requestId
123
- })
124
- }
95
+ const transport = createHttpLoggerTransport(config.loggerUrl, {})
125
96
 
126
- console.warn = (...args) => {
127
- const message = args.map(String).join(' ')
128
- sendLog('warn', message, {
129
- traceId: requestTraceId,
130
- spanId: requestSpanId,
131
- parentSpanId: requestParentSpanId,
132
- requestId: requestId
133
- })
97
+ const hostname = os.hostname()
98
+
99
+ const serviceObj = config.serviceName ? { name: config.serviceName, version: '1.0.0' } : null
100
+
101
+ const workerPool = []
102
+ const cpuCount = Math.max(1, (os.cpus() || []).length || 1)
103
+ const WORKER_POOL_SIZE = Math.min(8, Math.max(2, cpuCount))
104
+ const maxWorkers = Math.min(WORKER_POOL_SIZE, cpuCount)
105
+ let workerIndex = 0
106
+ let poolInitialized = false
107
+
108
+ function initWorkerPool() {
109
+ try {
110
+ const workerPath = path.join(__dirname, 'utils', 'bodyWorker.js')
111
+ for (let i = 0; i < maxWorkers; i++) {
112
+ try {
113
+ const worker = new Worker(workerPath)
114
+ workerPool.push(worker)
115
+ } catch (err) {
116
+ break
117
+ }
118
+ }
119
+ } catch (err) {
134
120
  }
135
-
136
- console.error = (...args) => {
137
- const message = args.map(String).join(' ')
138
- sendLog('error', message, {
139
- traceId: requestTraceId,
140
- spanId: requestSpanId,
141
- parentSpanId: requestParentSpanId,
142
- requestId: requestId
143
- })
121
+ }
122
+
123
+ function ensureWorkerPool() {
124
+ if (!poolInitialized && (config.captureResponseBody || config.captureRequestBody)) {
125
+ poolInitialized = true
126
+ initWorkerPool()
144
127
  }
128
+ }
129
+
130
+ function getWorker() {
131
+ if (workerPool.length === 0) return null
132
+ const worker = workerPool[workerIndex % workerPool.length]
133
+ workerIndex++
134
+ return worker
135
+ }
136
+
137
+ function sendLog(level, message, meta = {}) {
138
+ if (!transport || typeof transport.enqueue !== 'function') return
145
139
 
146
- let baseUrl = req.url
147
- if (baseUrl.includes('?')) {
148
- baseUrl = baseUrl.substring(0, baseUrl.indexOf('?'))
149
- }
150
- baseUrl = baseUrl.replace(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '/{id}')
151
- baseUrl = baseUrl.replace(/\/[0-9]+/g, '/{id}')
140
+ transport.enqueue({
141
+ level,
142
+ message,
143
+ meta
144
+ }, { 'content-type': 'application/json' })
145
+ }
152
146
 
153
- function sanitizeHeaders(headers) {
154
- const sanitized = { ...headers }
155
- const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-auth-token', 'x-access-token']
156
-
157
- for (const key of Object.keys(sanitized)) {
158
- if (sensitiveHeaders.includes(key.toLowerCase())) {
159
- sanitized[key] = '***'
160
- }
147
+ return function azifyExpressLoggingMiddleware(req, res, next) {
148
+ const startTime = Date.now()
149
+ const method = req.method
150
+ const url = req.url
151
+ const path = req.path || url
152
+
153
+ let responseChunk = null
154
+ let responseChunkCaptured = false
155
+ let logSent = false
156
+
157
+ let requestId, traceId, spanId, parentSpanId, clientIp, query, cachedHeaders
158
+ let idsCreated = false
159
+ let headersCached = false
160
+ let reqCtx = null
161
+
162
+ next()
163
+
164
+ const logWithContext = (level, message, meta) => {
165
+ if (!reqCtx) {
166
+ const traceHex = sanitizeTraceHex(req.headers['x-trace-id'])
167
+ reqCtx = startRequestContext({
168
+ requestId: requestId || req.requestId || fastUUID(),
169
+ traceHex,
170
+ parentSpanId: req.headers['x-parent-span-id'] || null
171
+ })
161
172
  }
162
-
163
- return sanitized
173
+ meta.traceId = meta.traceId || reqCtx.traceId
174
+ meta.spanId = meta.spanId || reqCtx.spanId
175
+ meta.parentSpanId = meta.parentSpanId || reqCtx.parentSpanId
176
+ sendLog(level, message, meta)
164
177
  }
165
-
166
- function sanitizeBody(body) {
167
- if (!body || typeof body !== 'object') return body
178
+
179
+ function ensureIds() {
180
+ if (idsCreated) return
181
+ idsCreated = true
168
182
 
169
- const sanitized = Array.isArray(body) ? [...body] : { ...body }
170
- const sensitiveFields = ['password', 'token', 'secret', 'apiKey', 'api_key', 'accessToken', 'access_token', 'refreshToken', 'refresh_token', 'clientSecret', 'client_secret']
183
+ query = req.query || null
171
184
 
172
- for (const key of Object.keys(sanitized)) {
173
- if (sensitiveFields.includes(key) || key.toLowerCase().includes('password') || key.toLowerCase().includes('secret')) {
174
- sanitized[key] = '***'
175
- }
185
+ if (!reqCtx) {
186
+ const traceHex = sanitizeTraceHex(req.headers['x-trace-id'])
187
+ reqCtx = startRequestContext({
188
+ requestId: req.requestId || fastUUID(),
189
+ traceHex,
190
+ parentSpanId: req.headers['x-parent-span-id'] || null
191
+ })
176
192
  }
177
193
 
178
- return sanitized
179
- }
180
-
181
- req._azifyRequestData = {
182
- requestId,
183
- method: req.method,
184
- url: req.url,
185
- baseUrl: baseUrl,
186
- path: req.url,
187
- headers: sanitizeHeaders(req.headers || {}),
188
- query: req.query || {},
189
- userAgent: (req.headers && req.headers['user-agent']) || 'unknown',
190
- ip: (req.connection && req.connection.remoteAddress) || (req.socket && req.socket.remoteAddress) || req.ip || 'unknown',
191
- traceId: requestTraceId,
192
- spanId: requestSpanId,
193
- parentSpanId: requestParentSpanId
194
+ requestId = reqCtx.requestId || req.requestId || fastUUID()
195
+ traceId = reqCtx.traceId
196
+ spanId = reqCtx.spanId
197
+ parentSpanId = reqCtx.parentSpanId || req.headers['x-parent-span-id'] || null
198
+
199
+ clientIp = req.ip || req.connection?.remoteAddress || req.socket?.remoteAddress || 'unknown'
200
+ req.requestId = requestId
194
201
  }
195
-
196
- if (req.method === 'GET') {
197
- sendLog('info', `[REQUEST] ${req.method} ${req.url}`, req._azifyRequestData)
198
- } else {
199
- if (req.body !== undefined) {
200
- req._azifyRequestData.requestBody = sanitizeBody(req.body)
202
+
203
+ function ensureHeaders() {
204
+ if (headersCached) return
205
+ headersCached = true
206
+ if (config.captureHeaders) {
207
+ cachedHeaders = pickHeaders(req.headers || {})
208
+ } else {
209
+ cachedHeaders = {}
201
210
  }
202
- sendLog('info', `[REQUEST] ${req.method} ${req.url}`, req._azifyRequestData)
203
211
  }
204
-
205
- res.on('finish', () => {
206
- if (!responseLogged) {
207
- logResponse()
208
- responseLogged = true
212
+
213
+ function emitResponseLog(meta, chunk) {
214
+ if (!config.captureResponseBody || chunk == null) {
215
+ logWithContext('info', `[RESPONSE] ${method} ${url}`, meta)
216
+ return
209
217
  }
210
- console.log = originalConsole.log
211
- console.info = originalConsole.info
212
- console.warn = originalConsole.warn
213
- console.error = originalConsole.error
214
- })
215
218
 
216
- res.on('close', () => {
217
- if (!responseLogged) {
218
- logResponse()
219
- responseLogged = true
220
- }
221
- console.log = originalConsole.log
222
- console.info = originalConsole.info
223
- console.warn = originalConsole.warn
224
- console.error = originalConsole.error
225
- })
219
+ if (!meta.response) meta.response = {}
220
+ meta.response.body = safeSerializeBody(chunk)
221
+ logWithContext('info', `[RESPONSE] ${method} ${url}`, meta)
222
+ }
226
223
 
227
- let sentBody
228
- let responseLogged = false
229
-
230
- const originalSend = res.send && res.send.bind(res)
231
- if (originalSend) {
232
- res.send = function patchedSend() {
233
- try {
234
- if (arguments.length === 1) {
235
- sentBody = arguments[0]
236
- } else if (arguments.length >= 2) {
237
- sentBody = typeof arguments[0] === 'number' ? arguments[1] : (arguments[1] || arguments[0])
238
- }
239
- } catch (_) {}
224
+ if (config.logRequest) {
225
+ process.nextTick(() => {
226
+ ensureIds()
227
+ ensureHeaders()
240
228
 
241
- if (!responseLogged) {
242
- logResponse()
243
- responseLogged = true
229
+ const request = {
230
+ id: requestId,
231
+ method,
232
+ url,
233
+ path,
234
+ ip: clientIp
244
235
  }
245
-
246
- return originalSend.apply(this, arguments)
247
- }
248
- }
249
-
250
- const originalStatus = res.status
251
- res.status = function(code) {
252
- res._actualStatusCode = code
253
- return originalStatus.call(this, code)
254
- }
255
-
256
- const originalWriteHead = res.writeHead
257
- res.writeHead = function(statusCode, statusMessage, headers) {
258
- res._actualStatusCode = statusCode
259
- if (typeof statusMessage === 'object') {
260
- headers = statusMessage
261
- statusMessage = undefined
262
- }
263
- return originalWriteHead.call(this, statusCode, statusMessage, headers)
264
- }
265
-
266
- const originalJsonMethod = res.json
267
- res.json = function(code, body) {
268
- try {
269
- if (arguments.length === 1) {
270
- sentBody = arguments[0]
271
- } else if (arguments.length >= 2) {
272
- sentBody = typeof arguments[0] === 'number' ? arguments[1] : (arguments[1] || arguments[0])
236
+ if (query) request.query = query
237
+ if (config.captureHeaders && cachedHeaders) request.headers = cachedHeaders
238
+ if (config.captureRequestBody && req.body !== undefined && req.body != null) {
239
+ request.body = safeSerializeBody(req.body)
273
240
  }
274
- } catch (_) {}
275
-
276
- if (typeof code === 'number') {
277
- res._actualStatusCode = code
278
- } else {
279
- const errorObj = arguments.length === 1 ? arguments[0] : (typeof arguments[0] === 'number' ? arguments[1] : arguments[0])
280
241
 
281
- if (errorObj && errorObj.constructor && errorObj.constructor.name === 'ErrCtor') {
282
- const errorName = errorObj.toString()
283
- if (errorName.includes('InternalServerError') || errorName.includes('InternalError')) {
284
- res._actualStatusCode = 500
285
- } else if (errorName.includes('BadRequest') || errorName.includes('BadDigest')) {
286
- res._actualStatusCode = 400
287
- } else if (errorName.includes('NotFound')) {
288
- res._actualStatusCode = 404
289
- } else if (errorName.includes('Unauthorized')) {
290
- res._actualStatusCode = 401
291
- } else if (errorName.includes('Forbidden')) {
292
- res._actualStatusCode = 403
293
- } else {
294
- res._actualStatusCode = 500
295
- }
296
- } else {
297
- res._actualStatusCode = res.statusCode || 200
242
+ const meta = {
243
+ traceId: reqCtx.traceId,
244
+ spanId: reqCtx.spanId,
245
+ parentSpanId: reqCtx.parentSpanId || null,
246
+ requestId,
247
+ request,
248
+ timestamp: Date.now(),
249
+ hostname
298
250
  }
299
- }
300
-
301
- if (!responseLogged) {
302
- logResponse()
303
- responseLogged = true
304
- }
305
-
306
- return originalJsonMethod.apply(this, arguments)
251
+ if (serviceObj) meta.service = serviceObj
252
+ if (config.environment) meta.environment = config.environment
253
+
254
+ logWithContext('info', `[REQUEST] ${method} ${url}`, meta)
255
+ })
307
256
  }
257
+
258
+ const originalEnd = res.end.bind(res)
308
259
 
309
- res.on('finish', function() {
310
- if (!responseLogged) {
311
- logResponse()
312
- responseLogged = true
260
+ res.end = (chunk, encoding) => {
261
+ if (logSent) {
262
+ return originalEnd(chunk, encoding)
313
263
  }
314
- })
315
-
316
- const originalEnd = res.end
317
- res.end = function(chunk, encoding) {
318
- const duration = Date.now() - startTime
264
+ logSent = true
319
265
 
320
- let responseBody = sentBody
321
- try {
322
- if (responseBody == null && chunk) {
323
- if (Buffer.isBuffer(chunk)) {
324
- responseBody = chunk.toString('utf8')
325
- } else if (typeof chunk === 'string') {
326
- responseBody = chunk
327
- } else {
328
- responseBody = JSON.stringify(chunk)
329
- }
330
- }
331
- } catch (_) {}
266
+ const result = originalEnd(chunk, encoding)
332
267
 
333
- if (!responseLogged) {
334
- logResponse()
335
- responseLogged = true
268
+ if (chunk != null && config.captureResponseBody && !responseChunkCaptured) {
269
+ responseChunk = chunk
270
+ responseChunkCaptured = true
336
271
  }
337
-
338
- originalEnd.call(this, chunk, encoding)
339
- }
340
-
341
- /**
342
- * Logs the response data to azify-logger
343
- * @private
344
- */
345
- function logResponse() {
346
- const duration = Date.now() - startTime
347
272
 
348
- let responseBody = sentBody
349
-
350
- let serializedResponseBody
351
- try {
352
- if (typeof responseBody === 'string') {
353
- serializedResponseBody = responseBody
354
- } else if (Array.isArray(responseBody)) {
355
- serializedResponseBody = JSON.stringify(responseBody)
356
- } else if (responseBody && typeof responseBody === 'object') {
357
- if (responseBody.toJSON && typeof responseBody.toJSON === 'function') {
358
- serializedResponseBody = JSON.stringify(responseBody.toJSON())
359
- } else if (responseBody.toString && typeof responseBody.toString === 'function' && responseBody.toString() !== '[object Object]') {
360
- serializedResponseBody = responseBody.toString()
361
- } else {
362
- serializedResponseBody = JSON.stringify(responseBody, (key, value) => {
363
- if (typeof value === 'function') {
364
- return '[Function]'
365
- }
366
- if (value instanceof Error) {
367
- return { name: value.name, message: value.message, stack: value.stack }
368
- }
369
- return value
370
- }, null, 0)
371
- }
372
- } else {
373
- serializedResponseBody = responseBody != null ? String(responseBody) : ''
273
+ process.nextTick(() => {
274
+ ensureIds()
275
+
276
+ const statusCode = res.statusCode || 200
277
+ const duration = Date.now() - startTime
278
+ const response = { statusCode, durationMs: duration }
279
+
280
+ if (config.captureHeaders) {
281
+ ensureHeaders()
374
282
  }
375
- } catch (error) {
376
- try {
377
- serializedResponseBody = JSON.stringify(responseBody, null, 2)
378
- } catch (secondError) {
379
- serializedResponseBody = '[Complex object - serialization failed]'
283
+
284
+ const requestObj = {
285
+ id: requestId,
286
+ method,
287
+ url,
288
+ path,
289
+ ip: clientIp
380
290
  }
381
- }
382
-
383
- const statusCode = res._actualStatusCode || res._statusCode || res.statusCode || 200
384
-
385
- const responseMessage = serializedResponseBody && serializedResponseBody.length > 0
386
- ? `[RESPONSE] ${serializedResponseBody}`
387
- : `[RESPONSE] ${req.method} ${req.url} ${statusCode} ${duration}ms`
388
-
389
- const responseData = {
390
- ...req._azifyRequestData,
391
- requestBody: req.body,
392
- statusCode: statusCode,
393
- responseTime: duration,
394
- responseHeaders: res.getHeaders ? res.getHeaders() : {},
395
- responseBody: serializedResponseBody
396
- }
397
-
398
- try { res._azifyResponseLogged = true } catch (_) {}
399
- sendLog('info', responseMessage, responseData)
400
- }
401
-
402
- req._azifyContext = reqCtx
403
-
404
- try {
405
- runWithRequestContext(reqCtx, () => {
406
- next()
291
+ if (query) requestObj.query = query
292
+ if (config.captureHeaders && cachedHeaders) requestObj.headers = cachedHeaders
293
+
294
+ const meta = {
295
+ traceId: reqCtx.traceId,
296
+ spanId: reqCtx.spanId,
297
+ parentSpanId: reqCtx.parentSpanId || null,
298
+ requestId,
299
+ request: requestObj,
300
+ response,
301
+ timestamp: Date.now(),
302
+ hostname
303
+ }
304
+ if (serviceObj) meta.service = serviceObj
305
+ if (config.environment) meta.environment = config.environment
306
+
307
+ const chunkToProcess = (responseChunk !== null && responseChunkCaptured) ? responseChunk : null
308
+ emitResponseLog(meta, chunkToProcess)
407
309
  })
408
- } catch (error) {
409
- console.error('Error in azify middleware:', error)
410
- next()
310
+
311
+ return result
411
312
  }
412
313
  }
413
314
  }