azify-logger 1.0.2
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 +295 -0
- package/index.js +114 -0
- package/middleware-express.js +277 -0
- package/middleware-restify.js +280 -0
- package/package.json +47 -0
- package/register-otel.js +39 -0
- package/register-restify.js +203 -0
- package/server.js +229 -0
- package/store.js +42 -0
- package/streams/bunyan.js +60 -0
- package/streams/pino.js +55 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
const axios = require('axios')
|
|
2
|
+
const { als, runWithRequestContext, startRequestContext, getRequestContext } = require('./store')
|
|
3
|
+
|
|
4
|
+
function createRestifyLoggingMiddleware(options = {}) {
|
|
5
|
+
const config = {
|
|
6
|
+
serviceName: options.serviceName || process.env.APP_NAME || 'azipay',
|
|
7
|
+
loggerUrl: options.loggerUrl || process.env.AZIFY_LOGGER_URL || 'http://localhost:3000',
|
|
8
|
+
environment: options.environment || process.env.NODE_ENV || 'development'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function sendLog(level, message, meta = {}) {
|
|
12
|
+
const logData = {
|
|
13
|
+
level,
|
|
14
|
+
message,
|
|
15
|
+
meta: {
|
|
16
|
+
...meta,
|
|
17
|
+
service: {
|
|
18
|
+
name: config.serviceName,
|
|
19
|
+
version: '1.0.0'
|
|
20
|
+
},
|
|
21
|
+
environment: config.environment,
|
|
22
|
+
timestamp: new Date().toISOString(),
|
|
23
|
+
hostname: require('os').hostname()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
await axios.post(`${config.loggerUrl}/log`, logData, {
|
|
29
|
+
timeout: 5000
|
|
30
|
+
})
|
|
31
|
+
} catch (error) {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return function azifyLoggingMiddleware(req, res, next) {
|
|
35
|
+
const startTime = Date.now()
|
|
36
|
+
const requestId = req.requestId || require('uuid').v4()
|
|
37
|
+
const middlewareId = require('uuid').v4().substring(0, 8)
|
|
38
|
+
|
|
39
|
+
const reqCtx = startRequestContext({ requestId })
|
|
40
|
+
req.__azifyTraceId = reqCtx.traceId
|
|
41
|
+
req.__azifySpanId = reqCtx.spanId
|
|
42
|
+
req.__azifyParentSpanId = reqCtx.parentSpanId
|
|
43
|
+
|
|
44
|
+
const requestTraceId = req.__azifyTraceId
|
|
45
|
+
const requestSpanId = req.__azifySpanId
|
|
46
|
+
const requestParentSpanId = req.__azifyParentSpanId
|
|
47
|
+
|
|
48
|
+
let baseUrl = req.url
|
|
49
|
+
if (baseUrl.includes('?')) {
|
|
50
|
+
baseUrl = baseUrl.substring(0, baseUrl.indexOf('?'))
|
|
51
|
+
}
|
|
52
|
+
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}')
|
|
53
|
+
baseUrl = baseUrl.replace(/\/[0-9]+/g, '/{id}')
|
|
54
|
+
|
|
55
|
+
req._azifyRequestData = {
|
|
56
|
+
requestId,
|
|
57
|
+
method: req.method,
|
|
58
|
+
url: req.url,
|
|
59
|
+
baseUrl: baseUrl,
|
|
60
|
+
path: req.url,
|
|
61
|
+
headers: req.headers,
|
|
62
|
+
query: req.query,
|
|
63
|
+
userAgent: req.headers['user-agent'],
|
|
64
|
+
ip: req.connection.remoteAddress || req.socket.remoteAddress,
|
|
65
|
+
traceId: requestTraceId,
|
|
66
|
+
spanId: requestSpanId,
|
|
67
|
+
parentSpanId: requestParentSpanId
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (req.method === 'GET') {
|
|
71
|
+
sendLog('info', `[REQUEST] ${req.method} ${req.url}`, req._azifyRequestData)
|
|
72
|
+
} else {
|
|
73
|
+
if (req.body !== undefined) {
|
|
74
|
+
req._azifyRequestData.requestBody = req.body
|
|
75
|
+
}
|
|
76
|
+
sendLog('info', `[REQUEST] ${req.method} ${req.url}`, req._azifyRequestData)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
res.on('finish', () => {
|
|
80
|
+
if (!responseLogged) {
|
|
81
|
+
logResponse()
|
|
82
|
+
responseLogged = true
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
res.on('close', () => {
|
|
87
|
+
if (!responseLogged) {
|
|
88
|
+
logResponse()
|
|
89
|
+
responseLogged = true
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
let sentBody
|
|
94
|
+
let responseLogged = false
|
|
95
|
+
|
|
96
|
+
const originalSend = res.send && res.send.bind(res)
|
|
97
|
+
if (originalSend) {
|
|
98
|
+
res.send = function patchedSend() {
|
|
99
|
+
try {
|
|
100
|
+
if (arguments.length === 1) {
|
|
101
|
+
sentBody = arguments[0]
|
|
102
|
+
} else if (arguments.length >= 2) {
|
|
103
|
+
sentBody = typeof arguments[0] === 'number' ? arguments[1] : (arguments[1] || arguments[0])
|
|
104
|
+
}
|
|
105
|
+
} catch (_) {}
|
|
106
|
+
|
|
107
|
+
if (!responseLogged) {
|
|
108
|
+
logResponse()
|
|
109
|
+
responseLogged = true
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return originalSend.apply(this, arguments)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
const originalStatus = res.status
|
|
118
|
+
res.status = function(code) {
|
|
119
|
+
res._actualStatusCode = code
|
|
120
|
+
return originalStatus.call(this, code)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const originalWriteHead = res.writeHead
|
|
124
|
+
res.writeHead = function(statusCode, statusMessage, headers) {
|
|
125
|
+
res._actualStatusCode = statusCode
|
|
126
|
+
if (typeof statusMessage === 'object') {
|
|
127
|
+
headers = statusMessage
|
|
128
|
+
statusMessage = undefined
|
|
129
|
+
}
|
|
130
|
+
return originalWriteHead.call(this, statusCode, statusMessage, headers)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const originalJsonMethod = res.json
|
|
134
|
+
res.json = function(code, body) {
|
|
135
|
+
try {
|
|
136
|
+
if (arguments.length === 1) {
|
|
137
|
+
sentBody = arguments[0]
|
|
138
|
+
} else if (arguments.length >= 2) {
|
|
139
|
+
sentBody = typeof arguments[0] === 'number' ? arguments[1] : (arguments[1] || arguments[0])
|
|
140
|
+
}
|
|
141
|
+
} catch (_) {}
|
|
142
|
+
|
|
143
|
+
if (typeof code === 'number') {
|
|
144
|
+
res._actualStatusCode = code
|
|
145
|
+
} else {
|
|
146
|
+
const errorObj = arguments.length === 1 ? arguments[0] : (typeof arguments[0] === 'number' ? arguments[1] : arguments[0])
|
|
147
|
+
|
|
148
|
+
if (errorObj && errorObj.constructor && errorObj.constructor.name === 'ErrCtor') {
|
|
149
|
+
const errorName = errorObj.toString()
|
|
150
|
+
if (errorName.includes('InternalServerError') || errorName.includes('InternalError')) {
|
|
151
|
+
res._actualStatusCode = 500
|
|
152
|
+
res._actualStatusCode = 500
|
|
153
|
+
} else if (errorName.includes('BadRequest') || errorName.includes('BadDigest')) {
|
|
154
|
+
res._actualStatusCode = 400
|
|
155
|
+
} else if (errorName.includes('NotFound')) {
|
|
156
|
+
res._actualStatusCode = 404
|
|
157
|
+
} else if (errorName.includes('Unauthorized')) {
|
|
158
|
+
res._actualStatusCode = 401
|
|
159
|
+
} else if (errorName.includes('Forbidden')) {
|
|
160
|
+
res._actualStatusCode = 403
|
|
161
|
+
} else {
|
|
162
|
+
res._actualStatusCode = 500
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
res._actualStatusCode = res.statusCode || 200
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!responseLogged) {
|
|
170
|
+
logResponse()
|
|
171
|
+
responseLogged = true
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return originalJsonMethod.apply(this, arguments)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
res.on('finish', function() {
|
|
178
|
+
if (!responseLogged) {
|
|
179
|
+
logResponse()
|
|
180
|
+
responseLogged = true
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const originalEnd = res.end
|
|
185
|
+
res.end = function(chunk, encoding) {
|
|
186
|
+
const duration = Date.now() - startTime
|
|
187
|
+
|
|
188
|
+
let responseBody = sentBody
|
|
189
|
+
try {
|
|
190
|
+
if (responseBody == null && chunk) {
|
|
191
|
+
if (Buffer.isBuffer(chunk)) {
|
|
192
|
+
responseBody = chunk.toString('utf8')
|
|
193
|
+
} else if (typeof chunk === 'string') {
|
|
194
|
+
responseBody = chunk
|
|
195
|
+
} else {
|
|
196
|
+
responseBody = JSON.stringify(chunk)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} catch (_) {}
|
|
200
|
+
|
|
201
|
+
if (!responseLogged) {
|
|
202
|
+
logResponse()
|
|
203
|
+
responseLogged = true
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
originalEnd.call(this, chunk, encoding)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function logResponse() {
|
|
210
|
+
const duration = Date.now() - startTime
|
|
211
|
+
|
|
212
|
+
let responseBody = sentBody
|
|
213
|
+
|
|
214
|
+
let serializedResponseBody
|
|
215
|
+
try {
|
|
216
|
+
if (typeof responseBody === 'string') {
|
|
217
|
+
serializedResponseBody = responseBody
|
|
218
|
+
} else if (Array.isArray(responseBody)) {
|
|
219
|
+
serializedResponseBody = JSON.stringify(responseBody)
|
|
220
|
+
} else if (responseBody && typeof responseBody === 'object') {
|
|
221
|
+
if (responseBody.toJSON && typeof responseBody.toJSON === 'function') {
|
|
222
|
+
serializedResponseBody = JSON.stringify(responseBody.toJSON())
|
|
223
|
+
} else if (responseBody.toString && typeof responseBody.toString === 'function' && responseBody.toString() !== '[object Object]') {
|
|
224
|
+
serializedResponseBody = responseBody.toString()
|
|
225
|
+
} else {
|
|
226
|
+
serializedResponseBody = JSON.stringify(responseBody, (key, value) => {
|
|
227
|
+
if (typeof value === 'function') {
|
|
228
|
+
return '[Function]'
|
|
229
|
+
}
|
|
230
|
+
if (value instanceof Error) {
|
|
231
|
+
return { name: value.name, message: value.message, stack: value.stack }
|
|
232
|
+
}
|
|
233
|
+
return value
|
|
234
|
+
}, null, 0)
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
serializedResponseBody = responseBody != null ? String(responseBody) : ''
|
|
238
|
+
}
|
|
239
|
+
} catch (error) {
|
|
240
|
+
try {
|
|
241
|
+
serializedResponseBody = JSON.stringify(responseBody, null, 2)
|
|
242
|
+
} catch (secondError) {
|
|
243
|
+
serializedResponseBody = '[Complex object - serialization failed]'
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const statusCode = res._actualStatusCode || res._statusCode || res.statusCode || 200
|
|
248
|
+
|
|
249
|
+
const responseMessage = serializedResponseBody && serializedResponseBody.length > 0
|
|
250
|
+
? `[RESPONSE] ${serializedResponseBody}`
|
|
251
|
+
: `[RESPONSE] ${req.method} ${req.url} ${statusCode} ${duration}ms`
|
|
252
|
+
|
|
253
|
+
const responseData = {
|
|
254
|
+
...req._azifyRequestData,
|
|
255
|
+
requestBody: req.body,
|
|
256
|
+
statusCode: statusCode,
|
|
257
|
+
responseTime: duration,
|
|
258
|
+
responseHeaders: res.getHeaders ? res.getHeaders() : {},
|
|
259
|
+
responseBody: serializedResponseBody
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
try { res._azifyResponseLogged = true } catch (_) {}
|
|
263
|
+
sendLog('info', responseMessage, responseData)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
req._azifyContext = reqCtx
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
runWithRequestContext(reqCtx, () => {
|
|
270
|
+
next()
|
|
271
|
+
})
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error('Error in azify middleware:', error)
|
|
274
|
+
next()
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
module.exports = createRestifyLoggingMiddleware
|
|
280
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "azify-logger",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Azify Logger Client - Centralized logging for OpenSearch",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"No tests specified\" && exit 0"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"logging",
|
|
12
|
+
"opensearch",
|
|
13
|
+
"centralized",
|
|
14
|
+
"azify"
|
|
15
|
+
],
|
|
16
|
+
"author": "Azify",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@opentelemetry/api": "^1.7.0",
|
|
20
|
+
"@opentelemetry/auto-instrumentations-node": "^0.40.0",
|
|
21
|
+
"@opentelemetry/core": "^1.28.0",
|
|
22
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.45.0",
|
|
23
|
+
"@opentelemetry/resources": "^1.28.0",
|
|
24
|
+
"@opentelemetry/sdk-node": "^0.45.0",
|
|
25
|
+
"@opentelemetry/semantic-conventions": "^1.28.0",
|
|
26
|
+
"axios": "^1.6.0",
|
|
27
|
+
"cors": "^2.8.5",
|
|
28
|
+
"express": "^4.18.2",
|
|
29
|
+
"require-in-the-middle": "^7.4.0",
|
|
30
|
+
"uuid": "^9.0.1"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=16.0.0"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"index.js",
|
|
37
|
+
"store.js",
|
|
38
|
+
"register-otel.js",
|
|
39
|
+
"register-restify.js",
|
|
40
|
+
"middleware-restify.js",
|
|
41
|
+
"middleware-express.js",
|
|
42
|
+
"server.js",
|
|
43
|
+
"streams/",
|
|
44
|
+
"package.json",
|
|
45
|
+
"README.md"
|
|
46
|
+
]
|
|
47
|
+
}
|
package/register-otel.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
try {
|
|
2
|
+
const { NodeSDK } = require('@opentelemetry/sdk-node')
|
|
3
|
+
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')
|
|
4
|
+
|
|
5
|
+
const serviceName = process.env.OTEL_SERVICE_NAME || process.env.APP_NAME || 'app'
|
|
6
|
+
const serviceVersion = process.env.OTEL_SERVICE_VERSION || '1.0.0'
|
|
7
|
+
|
|
8
|
+
process.env.OTEL_SERVICE_NAME = serviceName
|
|
9
|
+
process.env.OTEL_SERVICE_VERSION = serviceVersion
|
|
10
|
+
|
|
11
|
+
console.log(`🔧 Initializing OpenTelemetry for service: ${serviceName}`)
|
|
12
|
+
|
|
13
|
+
const sdk = new NodeSDK({
|
|
14
|
+
serviceName: serviceName,
|
|
15
|
+
serviceVersion: serviceVersion,
|
|
16
|
+
instrumentations: [getNodeAutoInstrumentations({
|
|
17
|
+
'@opentelemetry/instrumentation-http': {
|
|
18
|
+
enabled: true,
|
|
19
|
+
requireParentforOutgoingSpans: false,
|
|
20
|
+
requireParentforIncomingSpans: false
|
|
21
|
+
},
|
|
22
|
+
'@opentelemetry/instrumentation-express': { enabled: true },
|
|
23
|
+
'@opentelemetry/instrumentation-restify': { enabled: true }
|
|
24
|
+
})]
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
sdk.start()
|
|
28
|
+
console.log(`✅ OpenTelemetry initialized for service: ${serviceName}`)
|
|
29
|
+
|
|
30
|
+
process.once('SIGTERM', () => {
|
|
31
|
+
sdk.shutdown()
|
|
32
|
+
.then(() => console.log('OpenTelemetry shut down successfully'))
|
|
33
|
+
.catch((error) => console.error('Error shutting down OpenTelemetry:', error))
|
|
34
|
+
.finally(() => process.exit(0))
|
|
35
|
+
})
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.warn('⚠️ OpenTelemetry não pôde ser inicializado:', error.message)
|
|
38
|
+
console.error('Error details:', error)
|
|
39
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
console.log('🔧 @azify/logger-client/register-restify carregando...')
|
|
2
|
+
|
|
3
|
+
function generateTraceId() {
|
|
4
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Date.now().toString(36)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function generateSpanId() {
|
|
8
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 7)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const Module = require('module')
|
|
12
|
+
const originalRequire = Module.prototype.require
|
|
13
|
+
|
|
14
|
+
let patched = false
|
|
15
|
+
|
|
16
|
+
Module.prototype.require = function(id) {
|
|
17
|
+
const module = originalRequire.apply(this, arguments)
|
|
18
|
+
|
|
19
|
+
if (id && typeof id === 'string' && id.includes('restify')) {
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!patched && (id === 'restify' || id.endsWith('/restify') || id.includes('restify/lib'))) {
|
|
23
|
+
patched = true
|
|
24
|
+
console.log(' ✅ Restify detectado! Aplicando patches...')
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
let trace, context
|
|
28
|
+
try {
|
|
29
|
+
const otel = require('@opentelemetry/api')
|
|
30
|
+
trace = otel.trace
|
|
31
|
+
context = otel.context
|
|
32
|
+
} catch (_) {}
|
|
33
|
+
|
|
34
|
+
const ServerProto = module.Server && module.Server.prototype
|
|
35
|
+
|
|
36
|
+
if (!ServerProto) return module
|
|
37
|
+
|
|
38
|
+
function wrapAsyncMiddleware(handler) {
|
|
39
|
+
const isAsync = handler && handler.constructor && handler.constructor.name === 'AsyncFunction'
|
|
40
|
+
const takesThree = typeof handler === 'function' && handler.length === 3
|
|
41
|
+
|
|
42
|
+
if (isAsync && takesThree) {
|
|
43
|
+
return function wrappedAsyncMiddleware(req, res, next) {
|
|
44
|
+
try {
|
|
45
|
+
const promise = handler(req, res, next)
|
|
46
|
+
if (promise && typeof promise.then === 'function') {
|
|
47
|
+
promise.catch(next)
|
|
48
|
+
}
|
|
49
|
+
} catch (err) {
|
|
50
|
+
next(err)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return handler
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (ServerProto && !ServerProto.__azifyPatchedUse) {
|
|
58
|
+
const originalUse = ServerProto.use
|
|
59
|
+
ServerProto.use = function patchedUse(...handlers) {
|
|
60
|
+
const patched = handlers.map(h => wrapAsyncMiddleware(h))
|
|
61
|
+
return originalUse.apply(this, patched)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const originalPre = ServerProto.pre
|
|
65
|
+
ServerProto.pre = function patchedPre(...handlers) {
|
|
66
|
+
const patched = handlers.map(h => wrapAsyncMiddleware(h))
|
|
67
|
+
return originalPre.apply(this, patched)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
ServerProto.__azifyPatchedUse = true
|
|
71
|
+
console.log('✅ Restify 11 async middleware patch aplicado')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (ServerProto && !ServerProto.__azifyReqResLogged) {
|
|
75
|
+
const { createAzifyLoggerFromEnv } = require('./index.js')
|
|
76
|
+
const azifyLogger = createAzifyLoggerFromEnv()
|
|
77
|
+
|
|
78
|
+
ServerProto.use(function azifyAutoRR (req, res, next) {
|
|
79
|
+
if (req.__azifyLogged) return next()
|
|
80
|
+
req.__azifyLogged = true
|
|
81
|
+
const start = Date.now()
|
|
82
|
+
|
|
83
|
+
let traceId, spanId
|
|
84
|
+
|
|
85
|
+
if (trace && context) {
|
|
86
|
+
const span = trace.getSpan(context.active())
|
|
87
|
+
const spanContext = span?.spanContext()
|
|
88
|
+
|
|
89
|
+
if (spanContext) {
|
|
90
|
+
traceId = spanContext.traceId
|
|
91
|
+
spanId = spanContext.spanId
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!traceId) {
|
|
96
|
+
traceId = generateTraceId()
|
|
97
|
+
spanId = generateSpanId()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
req.__azifyTrace = { traceId, spanId }
|
|
101
|
+
|
|
102
|
+
const requestId = req.requestId || req.id || (req.getId && req.getId())
|
|
103
|
+
|
|
104
|
+
const requestMeta = {
|
|
105
|
+
requestId,
|
|
106
|
+
method: req.method,
|
|
107
|
+
url: req.url,
|
|
108
|
+
path: req.path(),
|
|
109
|
+
headers: req.headers,
|
|
110
|
+
query: req.query,
|
|
111
|
+
params: req.params,
|
|
112
|
+
userAgent: req.headers?.['user-agent'],
|
|
113
|
+
ip: (req.connection && req.connection.remoteAddress) || (req.socket && req.socket.remoteAddress),
|
|
114
|
+
requestBody: req.body,
|
|
115
|
+
traceId,
|
|
116
|
+
spanId
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
azifyLogger.info(`[REQUEST] ${req.method} ${req.url}`, requestMeta)
|
|
120
|
+
|
|
121
|
+
const originalSend = res.send
|
|
122
|
+
const originalJson = res.json
|
|
123
|
+
|
|
124
|
+
function logResponse(methodName, ...args) {
|
|
125
|
+
const statusCode = res.statusCode || (typeof args[0] === 'number' ? args[0] : 200)
|
|
126
|
+
const body = (args.length === 1) ? args[0] : (typeof args[0] === 'number' ? args[1] : (args[1] || args[0]))
|
|
127
|
+
|
|
128
|
+
const { traceId, spanId } = req.__azifyTrace || {}
|
|
129
|
+
|
|
130
|
+
const responseMeta = {
|
|
131
|
+
requestId,
|
|
132
|
+
method: req.method,
|
|
133
|
+
url: req.url,
|
|
134
|
+
statusCode,
|
|
135
|
+
responseTime: Date.now() - start,
|
|
136
|
+
responseBody: body,
|
|
137
|
+
responseHeaders: res.getHeaders?.() || {},
|
|
138
|
+
traceId,
|
|
139
|
+
spanId,
|
|
140
|
+
responseMethod: methodName
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const message = (typeof body === 'string' && body.length > 0)
|
|
144
|
+
? body
|
|
145
|
+
: `[RESPONSE] ${req.method} ${req.url} ${statusCode} ${Date.now() - start}ms`
|
|
146
|
+
azifyLogger.info(message, responseMeta)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
res.send = function wrappedSend (...args) {
|
|
150
|
+
logResponse('send', ...args)
|
|
151
|
+
res.__azifyResponseLogged = true
|
|
152
|
+
return originalSend.apply(this, args)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (originalJson) {
|
|
156
|
+
res.json = function wrappedJson (...args) {
|
|
157
|
+
logResponse('json', ...args)
|
|
158
|
+
res.__azifyResponseLogged = true
|
|
159
|
+
return originalJson.apply(this, args)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const originalEnd = res.end
|
|
164
|
+
res.end = function wrappedEnd(chunk, encoding) {
|
|
165
|
+
if (!res.__azifyResponseLogged && chunk) {
|
|
166
|
+
const { traceId, spanId } = req.__azifyTrace || {}
|
|
167
|
+
|
|
168
|
+
const responseMeta = {
|
|
169
|
+
requestId,
|
|
170
|
+
method: req.method,
|
|
171
|
+
url: req.url,
|
|
172
|
+
statusCode: res.statusCode,
|
|
173
|
+
responseTime: Date.now() - start,
|
|
174
|
+
responseBody: chunk,
|
|
175
|
+
responseHeaders: res.getHeaders?.() || {},
|
|
176
|
+
traceId,
|
|
177
|
+
spanId,
|
|
178
|
+
responseMethod: 'end'
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const message = (typeof chunk === 'string' && chunk.length > 0)
|
|
182
|
+
? chunk
|
|
183
|
+
: `[RESPONSE] ${req.method} ${req.url} ${res.statusCode} ${Date.now() - start}ms`
|
|
184
|
+
azifyLogger.info(message, responseMeta)
|
|
185
|
+
res.__azifyResponseLogged = true
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return originalEnd.call(this, chunk, encoding)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
next()
|
|
192
|
+
})
|
|
193
|
+
ServerProto.__azifyReqResLogged = true
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error('❌ Erro ao aplicar patches no Restify:', error.message)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return module
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
console.log(' ✅ Hook de interceptação do Restify registrado!')
|