azify-logger 1.0.13 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +101 -7
- package/middleware-express.d.ts +1 -1
- package/middleware-express.js +116 -9
- package/middleware-restify.js +124 -56
- package/package.json +1 -1
- package/register-restify.js +1 -185
- package/server.js +16 -0
- package/streams/bunyan.d.ts +19 -0
- package/streams/bunyan.js +4 -2
- package/streams/pino.d.ts +19 -0
- package/streams/pino.js +13 -6
package/index.js
CHANGED
|
@@ -73,7 +73,7 @@ class AzifyLogger {
|
|
|
73
73
|
})
|
|
74
74
|
} catch (_) {}
|
|
75
75
|
|
|
76
|
-
await axios.post(`${this.options.loggerUrl}
|
|
76
|
+
await axios.post(`${this.options.loggerUrl}`, logData, {
|
|
77
77
|
timeout: 5000,
|
|
78
78
|
headers
|
|
79
79
|
})
|
|
@@ -162,7 +162,6 @@ function createAzifyLoggerFromEnv() {
|
|
|
162
162
|
environment: process.env.NODE_ENV || 'development'
|
|
163
163
|
})
|
|
164
164
|
|
|
165
|
-
// Automatically intercept console methods
|
|
166
165
|
interceptConsole(logger)
|
|
167
166
|
|
|
168
167
|
return logger
|
|
@@ -181,33 +180,128 @@ function interceptConsole(logger) {
|
|
|
181
180
|
|
|
182
181
|
console.log = (...args) => {
|
|
183
182
|
originalConsoleLog(...args);
|
|
184
|
-
|
|
183
|
+
const { getRequestContext } = require('./store');
|
|
184
|
+
const ctx = getRequestContext();
|
|
185
|
+
const message = args.join(' ');
|
|
186
|
+
if (message.includes('failed after')) {
|
|
187
|
+
}
|
|
188
|
+
if (ctx && ctx.traceId) {
|
|
189
|
+
void logger.info(message, { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId });
|
|
190
|
+
} else {
|
|
191
|
+
void logger.info(message);
|
|
192
|
+
}
|
|
185
193
|
};
|
|
186
194
|
|
|
187
195
|
console.error = (...args) => {
|
|
188
196
|
originalConsoleError(...args);
|
|
189
|
-
|
|
197
|
+
const { getRequestContext } = require('./store');
|
|
198
|
+
const ctx = getRequestContext();
|
|
199
|
+
if (ctx && ctx.traceId) {
|
|
200
|
+
void logger.error(args.join(' '), { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId });
|
|
201
|
+
} else {
|
|
202
|
+
void logger.error(args.join(' '));
|
|
203
|
+
}
|
|
190
204
|
};
|
|
191
205
|
|
|
192
206
|
console.warn = (...args) => {
|
|
193
207
|
originalConsoleWarn(...args);
|
|
194
|
-
|
|
208
|
+
const { getRequestContext } = require('./store');
|
|
209
|
+
const ctx = getRequestContext();
|
|
210
|
+
if (ctx && ctx.traceId) {
|
|
211
|
+
void logger.warn(args.join(' '), { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId });
|
|
212
|
+
} else {
|
|
213
|
+
void logger.warn(args.join(' '));
|
|
214
|
+
}
|
|
195
215
|
};
|
|
196
216
|
|
|
197
217
|
console.info = (...args) => {
|
|
198
218
|
originalConsoleInfo(...args);
|
|
199
|
-
|
|
219
|
+
const { getRequestContext } = require('./store');
|
|
220
|
+
const ctx = getRequestContext();
|
|
221
|
+
if (ctx && ctx.traceId) {
|
|
222
|
+
void logger.info(args.join(' '), { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId });
|
|
223
|
+
} else {
|
|
224
|
+
void logger.info(args.join(' '));
|
|
225
|
+
}
|
|
200
226
|
};
|
|
201
227
|
|
|
202
228
|
console.debug = (...args) => {
|
|
203
229
|
originalConsoleDebug(...args);
|
|
204
|
-
|
|
230
|
+
const { getRequestContext } = require('./store');
|
|
231
|
+
const ctx = getRequestContext();
|
|
232
|
+
if (ctx && ctx.traceId) {
|
|
233
|
+
void logger.debug(args.join(' '), { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId });
|
|
234
|
+
} else {
|
|
235
|
+
void logger.debug(args.join(' '));
|
|
236
|
+
}
|
|
205
237
|
};
|
|
206
238
|
}
|
|
207
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Creates a NestJS logger configuration that sends logs to azify-logger
|
|
242
|
+
* @returns {Object} NestJS logger configuration
|
|
243
|
+
* @example
|
|
244
|
+
* const app = await NestFactory.create(AppModule, {
|
|
245
|
+
* logger: createNestLogger()
|
|
246
|
+
* });
|
|
247
|
+
*/
|
|
248
|
+
function createNestLogger() {
|
|
249
|
+
const { getRequestContext } = require('./store')
|
|
250
|
+
const pino = require('pino')
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
log: (message, context) => {
|
|
254
|
+
const ctx = getRequestContext()
|
|
255
|
+
if (ctx && ctx.traceId) {
|
|
256
|
+
pino().info(message, context || '')
|
|
257
|
+
} else {
|
|
258
|
+
pino().info(message, context || '')
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
error: (message, trace, context) => {
|
|
262
|
+
const ctx = getRequestContext()
|
|
263
|
+
if (ctx && ctx.traceId) {
|
|
264
|
+
pino().error(message, trace || '', context || '')
|
|
265
|
+
} else {
|
|
266
|
+
pino().error(message, trace || '', context || '')
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
warn: (message, context) => {
|
|
270
|
+
const ctx = getRequestContext()
|
|
271
|
+
if (ctx && ctx.traceId) {
|
|
272
|
+
pino().warn(message, context || '')
|
|
273
|
+
} else {
|
|
274
|
+
pino().warn(message, context || '')
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
debug: (message, context) => {
|
|
278
|
+
const ctx = getRequestContext()
|
|
279
|
+
if (ctx && ctx.traceId) {
|
|
280
|
+
pino().debug(message, context || '')
|
|
281
|
+
} else {
|
|
282
|
+
pino().debug(message, context || '')
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
verbose: (message, context) => {
|
|
286
|
+
const ctx = getRequestContext()
|
|
287
|
+
if (ctx && ctx.traceId) {
|
|
288
|
+
pino().info(message, context || '')
|
|
289
|
+
} else {
|
|
290
|
+
pino().info(message, context || '')
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (process.env.AZIFY_LOGGER_DISABLE !== '1') {
|
|
297
|
+
require('./init')
|
|
298
|
+
require('./register')
|
|
299
|
+
}
|
|
300
|
+
|
|
208
301
|
module.exports = AzifyLogger
|
|
209
302
|
module.exports.createAzifyLogger = createAzifyLogger
|
|
210
303
|
module.exports.createAzifyLoggerFromEnv = createAzifyLoggerFromEnv
|
|
304
|
+
module.exports.createNestLogger = createNestLogger
|
|
211
305
|
module.exports.interceptConsole = interceptConsole
|
|
212
306
|
module.exports.streams = {
|
|
213
307
|
createBunyanStream: require('./streams/bunyan'),
|
package/middleware-express.d.ts
CHANGED
package/middleware-express.js
CHANGED
|
@@ -63,14 +63,85 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
63
63
|
const requestId = req.requestId || require('uuid').v4()
|
|
64
64
|
const middlewareId = require('uuid').v4().substring(0, 8)
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
req.__azifyParentSpanId = reqCtx.parentSpanId
|
|
66
|
+
let existingTraceId = null
|
|
67
|
+
let existingSpanId = null
|
|
68
|
+
let existingParentSpanId = null
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
+
}
|
|
82
|
+
|
|
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
|
+
}
|
|
94
|
+
|
|
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
|
|
104
|
+
}
|
|
105
|
+
|
|
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
|
+
}
|
|
115
|
+
|
|
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
|
+
}
|
|
125
|
+
|
|
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
|
+
})
|
|
134
|
+
}
|
|
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
|
+
})
|
|
144
|
+
}
|
|
74
145
|
|
|
75
146
|
let baseUrl = req.url
|
|
76
147
|
if (baseUrl.includes('?')) {
|
|
@@ -79,13 +150,41 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
79
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}')
|
|
80
151
|
baseUrl = baseUrl.replace(/\/[0-9]+/g, '/{id}')
|
|
81
152
|
|
|
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
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return sanitized
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function sanitizeBody(body) {
|
|
167
|
+
if (!body || typeof body !== 'object') return body
|
|
168
|
+
|
|
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']
|
|
171
|
+
|
|
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
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return sanitized
|
|
179
|
+
}
|
|
180
|
+
|
|
82
181
|
req._azifyRequestData = {
|
|
83
182
|
requestId,
|
|
84
183
|
method: req.method,
|
|
85
184
|
url: req.url,
|
|
86
185
|
baseUrl: baseUrl,
|
|
87
186
|
path: req.url,
|
|
88
|
-
headers: req.headers || {},
|
|
187
|
+
headers: sanitizeHeaders(req.headers || {}),
|
|
89
188
|
query: req.query || {},
|
|
90
189
|
userAgent: req.headers?.['user-agent'] || 'unknown',
|
|
91
190
|
ip: req.connection?.remoteAddress || req.socket?.remoteAddress || req.ip || 'unknown',
|
|
@@ -98,7 +197,7 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
98
197
|
sendLog('info', `[REQUEST] ${req.method} ${req.url}`, req._azifyRequestData)
|
|
99
198
|
} else {
|
|
100
199
|
if (req.body !== undefined) {
|
|
101
|
-
req._azifyRequestData.requestBody = req.body
|
|
200
|
+
req._azifyRequestData.requestBody = sanitizeBody(req.body)
|
|
102
201
|
}
|
|
103
202
|
sendLog('info', `[REQUEST] ${req.method} ${req.url}`, req._azifyRequestData)
|
|
104
203
|
}
|
|
@@ -108,6 +207,10 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
108
207
|
logResponse()
|
|
109
208
|
responseLogged = true
|
|
110
209
|
}
|
|
210
|
+
console.log = originalConsole.log
|
|
211
|
+
console.info = originalConsole.info
|
|
212
|
+
console.warn = originalConsole.warn
|
|
213
|
+
console.error = originalConsole.error
|
|
111
214
|
})
|
|
112
215
|
|
|
113
216
|
res.on('close', () => {
|
|
@@ -115,6 +218,10 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
115
218
|
logResponse()
|
|
116
219
|
responseLogged = true
|
|
117
220
|
}
|
|
221
|
+
console.log = originalConsole.log
|
|
222
|
+
console.info = originalConsole.info
|
|
223
|
+
console.warn = originalConsole.warn
|
|
224
|
+
console.error = originalConsole.error
|
|
118
225
|
})
|
|
119
226
|
|
|
120
227
|
let sentBody
|
package/middleware-restify.js
CHANGED
|
@@ -1,14 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a Restify middleware for automatic request/response logging with azify-logger
|
|
3
|
+
* @param {Object} options - Configuration options
|
|
4
|
+
* @param {string} [options.serviceName] - Name of the service (defaults to APP_NAME env var or 'azipay')
|
|
5
|
+
* @param {string} [options.loggerUrl] - URL of the azify-logger service (defaults to AZIFY_LOGGER_URL env var or 'http://localhost:3001')
|
|
6
|
+
* @param {string} [options.environment] - Environment name (defaults to NODE_ENV env var or 'development')
|
|
7
|
+
* @returns {Function} Restify middleware function
|
|
8
|
+
* @example
|
|
9
|
+
* const azifyMiddleware = require('azify-logger/middleware-restify');
|
|
10
|
+
* server.use(azifyMiddleware({ serviceName: 'my-app' }));
|
|
11
|
+
*/
|
|
1
12
|
const axios = require('axios')
|
|
2
13
|
const { als, runWithRequestContext, startRequestContext, getRequestContext } = require('./store')
|
|
3
14
|
|
|
4
15
|
function createRestifyLoggingMiddleware(options = {}) {
|
|
5
16
|
const config = {
|
|
6
17
|
serviceName: options.serviceName || process.env.APP_NAME || 'azipay',
|
|
7
|
-
loggerUrl: options.loggerUrl || process.env.AZIFY_LOGGER_URL || 'http://localhost:3001',
|
|
18
|
+
loggerUrl: (options.loggerUrl || process.env.AZIFY_LOGGER_URL || 'http://localhost:3001/log').replace(/\/log$/, '') + '/log',
|
|
8
19
|
environment: options.environment || process.env.NODE_ENV || 'development'
|
|
9
20
|
}
|
|
10
21
|
|
|
11
|
-
|
|
22
|
+
const pendingLogs = new Set()
|
|
23
|
+
|
|
24
|
+
let exitHandlerInstalled = false
|
|
25
|
+
if (!exitHandlerInstalled) {
|
|
26
|
+
exitHandlerInstalled = true
|
|
27
|
+
|
|
28
|
+
process.on('uncaughtException', (err) => {
|
|
29
|
+
console.error('[AZIFY] Uncaught exception:', err.message)
|
|
30
|
+
|
|
31
|
+
if (pendingLogs.size > 0) {
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}, 500)
|
|
35
|
+
} else {
|
|
36
|
+
process.exit(1)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function sendLog(level, message, meta = {}) {
|
|
12
42
|
const logData = {
|
|
13
43
|
level,
|
|
14
44
|
message,
|
|
@@ -24,26 +54,59 @@ function createRestifyLoggingMiddleware(options = {}) {
|
|
|
24
54
|
}
|
|
25
55
|
}
|
|
26
56
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
57
|
+
const logId = Math.random().toString(36).substring(7)
|
|
58
|
+
pendingLogs.add(logId)
|
|
59
|
+
|
|
60
|
+
axios.post(`${config.loggerUrl}`, logData, {
|
|
61
|
+
timeout: 2000
|
|
62
|
+
}).then(() => {
|
|
63
|
+
pendingLogs.delete(logId)
|
|
64
|
+
}).catch(() => {
|
|
65
|
+
pendingLogs.delete(logId)
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function sanitizeHeaders(headers) {
|
|
70
|
+
const sanitized = { ...headers }
|
|
71
|
+
const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-auth-token', 'x-access-token']
|
|
72
|
+
|
|
73
|
+
for (const key of Object.keys(sanitized)) {
|
|
74
|
+
if (sensitiveHeaders.includes(key.toLowerCase())) {
|
|
75
|
+
sanitized[key] = '***'
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return sanitized
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function sanitizeBody(body) {
|
|
83
|
+
if (!body || typeof body !== 'object') return body
|
|
84
|
+
|
|
85
|
+
const sanitized = Array.isArray(body) ? [...body] : { ...body }
|
|
86
|
+
const sensitiveFields = ['password', 'token', 'secret', 'apiKey', 'api_key', 'accessToken', 'access_token', 'refreshToken', 'refresh_token', 'clientSecret', 'client_secret']
|
|
87
|
+
|
|
88
|
+
for (const key of Object.keys(sanitized)) {
|
|
89
|
+
if (sensitiveFields.includes(key) || key.toLowerCase().includes('password') || key.toLowerCase().includes('secret')) {
|
|
90
|
+
sanitized[key] = '***'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return sanitized
|
|
32
95
|
}
|
|
33
96
|
|
|
34
97
|
return function azifyLoggingMiddleware(req, res, next) {
|
|
35
98
|
const startTime = Date.now()
|
|
36
99
|
const requestId = req.requestId || require('uuid').v4()
|
|
37
|
-
const middlewareId = require('uuid').v4().substring(0, 8)
|
|
38
100
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
101
|
+
if (res._azifySetup) {
|
|
102
|
+
return next()
|
|
103
|
+
}
|
|
104
|
+
res._azifySetup = true
|
|
43
105
|
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
106
|
+
const reqCtx = startRequestContext({ requestId })
|
|
107
|
+
const requestTraceId = reqCtx.traceId
|
|
108
|
+
const requestSpanId = reqCtx.spanId
|
|
109
|
+
const requestParentSpanId = reqCtx.parentSpanId
|
|
47
110
|
|
|
48
111
|
let baseUrl = req.url
|
|
49
112
|
if (baseUrl.includes('?')) {
|
|
@@ -58,7 +121,7 @@ function createRestifyLoggingMiddleware(options = {}) {
|
|
|
58
121
|
url: req.url,
|
|
59
122
|
baseUrl: baseUrl,
|
|
60
123
|
path: req.url,
|
|
61
|
-
headers: req.headers,
|
|
124
|
+
headers: sanitizeHeaders(req.headers),
|
|
62
125
|
query: req.query,
|
|
63
126
|
userAgent: req.headers['user-agent'],
|
|
64
127
|
ip: req.connection.remoteAddress || req.socket.remoteAddress,
|
|
@@ -71,27 +134,13 @@ function createRestifyLoggingMiddleware(options = {}) {
|
|
|
71
134
|
sendLog('info', `[REQUEST] ${req.method} ${req.url}`, req._azifyRequestData)
|
|
72
135
|
} else {
|
|
73
136
|
if (req.body !== undefined) {
|
|
74
|
-
req._azifyRequestData.requestBody = req.body
|
|
137
|
+
req._azifyRequestData.requestBody = sanitizeBody(req.body)
|
|
75
138
|
}
|
|
76
139
|
sendLog('info', `[REQUEST] ${req.method} ${req.url}`, req._azifyRequestData)
|
|
77
140
|
}
|
|
78
141
|
|
|
79
|
-
res.
|
|
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
|
-
|
|
142
|
+
res._azifyResponseLogged = false
|
|
93
143
|
let sentBody
|
|
94
|
-
let responseLogged = false
|
|
95
144
|
|
|
96
145
|
const originalSend = res.send && res.send.bind(res)
|
|
97
146
|
if (originalSend) {
|
|
@@ -104,9 +153,9 @@ function createRestifyLoggingMiddleware(options = {}) {
|
|
|
104
153
|
}
|
|
105
154
|
} catch (_) {}
|
|
106
155
|
|
|
107
|
-
if (!
|
|
156
|
+
if (!res._azifyResponseLogged) {
|
|
157
|
+
res._azifyResponseLogged = true
|
|
108
158
|
logResponse()
|
|
109
|
-
responseLogged = true
|
|
110
159
|
}
|
|
111
160
|
|
|
112
161
|
return originalSend.apply(this, arguments)
|
|
@@ -165,21 +214,8 @@ function createRestifyLoggingMiddleware(options = {}) {
|
|
|
165
214
|
res._actualStatusCode = res.statusCode || 200
|
|
166
215
|
}
|
|
167
216
|
}
|
|
168
|
-
|
|
169
|
-
if (!responseLogged) {
|
|
170
|
-
logResponse()
|
|
171
|
-
responseLogged = true
|
|
172
|
-
}
|
|
173
|
-
|
|
174
217
|
return originalJsonMethod.apply(this, arguments)
|
|
175
218
|
}
|
|
176
|
-
|
|
177
|
-
res.on('finish', function() {
|
|
178
|
-
if (!responseLogged) {
|
|
179
|
-
logResponse()
|
|
180
|
-
responseLogged = true
|
|
181
|
-
}
|
|
182
|
-
})
|
|
183
219
|
|
|
184
220
|
const originalEnd = res.end
|
|
185
221
|
res.end = function(chunk, encoding) {
|
|
@@ -198,9 +234,9 @@ function createRestifyLoggingMiddleware(options = {}) {
|
|
|
198
234
|
}
|
|
199
235
|
} catch (_) {}
|
|
200
236
|
|
|
201
|
-
if (!
|
|
237
|
+
if (!res._azifyResponseLogged) {
|
|
202
238
|
logResponse()
|
|
203
|
-
|
|
239
|
+
res._azifyResponseLogged = true
|
|
204
240
|
}
|
|
205
241
|
|
|
206
242
|
originalEnd.call(this, chunk, encoding)
|
|
@@ -265,14 +301,46 @@ function createRestifyLoggingMiddleware(options = {}) {
|
|
|
265
301
|
|
|
266
302
|
req._azifyContext = reqCtx
|
|
267
303
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
304
|
+
const originalNext = next
|
|
305
|
+
const wrappedNext = (err) => {
|
|
306
|
+
if (err && !res._azifyResponseLogged) {
|
|
307
|
+
const errorData = {
|
|
308
|
+
...req._azifyRequestData,
|
|
309
|
+
statusCode: res.statusCode || 500,
|
|
310
|
+
responseTime: Date.now() - startTime,
|
|
311
|
+
error: {
|
|
312
|
+
message: err.message || String(err),
|
|
313
|
+
stack: err.stack,
|
|
314
|
+
name: err.name,
|
|
315
|
+
code: err.code
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
sendLog('error', `[ERROR] ${req.method} ${req.url}: ${err.message || String(err)}`, errorData)
|
|
319
|
+
res._azifyResponseLogged = true
|
|
320
|
+
}
|
|
321
|
+
return originalNext(err)
|
|
275
322
|
}
|
|
323
|
+
|
|
324
|
+
res.on('error', (error) => {
|
|
325
|
+
if (!res._azifyResponseLogged) {
|
|
326
|
+
const errorData = {
|
|
327
|
+
...req._azifyRequestData,
|
|
328
|
+
statusCode: res.statusCode || 500,
|
|
329
|
+
responseTime: Date.now() - startTime,
|
|
330
|
+
error: {
|
|
331
|
+
message: error.message,
|
|
332
|
+
stack: error.stack,
|
|
333
|
+
name: error.name
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
sendLog('error', `[ERROR] ${req.method} ${req.url}: ${error.message}`, errorData)
|
|
337
|
+
res._azifyResponseLogged = true
|
|
338
|
+
}
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
runWithRequestContext(reqCtx, () => {
|
|
342
|
+
wrappedNext()
|
|
343
|
+
})
|
|
276
344
|
}
|
|
277
345
|
}
|
|
278
346
|
|
package/package.json
CHANGED
package/register-restify.js
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
console.log('🔧 @azify/logger-client/register-restify carregando...')
|
|
2
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
3
|
const Module = require('module')
|
|
12
4
|
const originalRequire = Module.prototype.require
|
|
13
5
|
|
|
@@ -16,185 +8,9 @@ let patched = false
|
|
|
16
8
|
Module.prototype.require = function(id) {
|
|
17
9
|
const module = originalRequire.apply(this, arguments)
|
|
18
10
|
|
|
19
|
-
if (id && typeof id === 'string' && id.includes('restify')) {
|
|
20
|
-
}
|
|
21
|
-
|
|
22
11
|
if (!patched && (id === 'restify' || id.endsWith('/restify') || id.includes('restify/lib'))) {
|
|
23
12
|
patched = true
|
|
24
|
-
console.log(' ✅ Restify detectado!
|
|
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
|
-
}
|
|
13
|
+
console.log(' ✅ Restify detectado!')
|
|
198
14
|
}
|
|
199
15
|
|
|
200
16
|
return module
|
package/server.js
CHANGED
|
@@ -167,6 +167,22 @@ app.post('/log', async (req, res) => {
|
|
|
167
167
|
return res.status(400).json({ success: false, message: 'Level and message are required.' })
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
const shouldFilterLog = (
|
|
171
|
+
message.includes('prisma:query') ||
|
|
172
|
+
message.includes('prisma:info') ||
|
|
173
|
+
message.includes('Starting a mysql pool') ||
|
|
174
|
+
message.includes('SELECT `') ||
|
|
175
|
+
message.includes('INSERT `') ||
|
|
176
|
+
message.includes('UPDATE `') ||
|
|
177
|
+
message.includes('DELETE `') ||
|
|
178
|
+
message.includes('%s: %s') ||
|
|
179
|
+
message.includes('Application Startup Time')
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
if (shouldFilterLog) {
|
|
183
|
+
return res.json({ success: true, message: 'Log filtrado (Prisma verboso)' })
|
|
184
|
+
}
|
|
185
|
+
|
|
170
186
|
const requestId = meta?.requestId
|
|
171
187
|
|
|
172
188
|
let traceContext = null
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Writable } from 'stream';
|
|
2
|
+
|
|
3
|
+
export interface BunyanStreamOptions {
|
|
4
|
+
loggerUrl?: string;
|
|
5
|
+
serviceName?: string;
|
|
6
|
+
environment?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a Bunyan stream for azify-logger
|
|
11
|
+
* @param options - Configuration options
|
|
12
|
+
* @returns Writable stream
|
|
13
|
+
* @example
|
|
14
|
+
* const bunyanStream = require('azify-logger/streams/bunyan');
|
|
15
|
+
* const stream = bunyanStream({ loggerUrl: 'http://localhost:3001' });
|
|
16
|
+
*/
|
|
17
|
+
declare function createBunyanStream(options?: BunyanStreamOptions): Writable;
|
|
18
|
+
|
|
19
|
+
export = createBunyanStream;
|
package/streams/bunyan.js
CHANGED
|
@@ -39,8 +39,10 @@ function createBunyanStream(options = {}) {
|
|
|
39
39
|
|
|
40
40
|
const headers = {}
|
|
41
41
|
|
|
42
|
+
const { time, v, level: _, msg, name, hostname: bunyanHostname, pid, ...cleanRecord } = record
|
|
43
|
+
|
|
42
44
|
const meta = {
|
|
43
|
-
...
|
|
45
|
+
...cleanRecord,
|
|
44
46
|
service: { name: serviceName, version: record.service?.version || '1.0.0' },
|
|
45
47
|
environment,
|
|
46
48
|
timestamp: new Date().toISOString(),
|
|
@@ -52,7 +54,7 @@ function createBunyanStream(options = {}) {
|
|
|
52
54
|
|
|
53
55
|
const payload = { level, message: record.msg || record.message || 'log', meta }
|
|
54
56
|
|
|
55
|
-
axios.post(`${loggerUrl}
|
|
57
|
+
axios.post(`${loggerUrl}`, payload, { headers, timeout: 3001 }).catch(() => {})
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Transform } from 'stream';
|
|
2
|
+
|
|
3
|
+
export interface PinoStreamOptions {
|
|
4
|
+
loggerUrl?: string;
|
|
5
|
+
serviceName?: string;
|
|
6
|
+
environment?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a Pino stream for azify-logger
|
|
11
|
+
* @param options - Configuration options
|
|
12
|
+
* @returns Transform stream
|
|
13
|
+
* @example
|
|
14
|
+
* const pinoStream = require('azify-logger/streams/pino');
|
|
15
|
+
* const stream = pinoStream({ loggerUrl: 'http://localhost:3001' });
|
|
16
|
+
*/
|
|
17
|
+
declare function createPinoStream(options?: PinoStreamOptions): Transform;
|
|
18
|
+
|
|
19
|
+
export = createPinoStream;
|
package/streams/pino.js
CHANGED
|
@@ -16,11 +16,18 @@ function createPinoStream(options = {}) {
|
|
|
16
16
|
|
|
17
17
|
let traceId, spanId
|
|
18
18
|
try {
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
if (
|
|
22
|
-
traceId =
|
|
23
|
-
spanId =
|
|
19
|
+
const { getRequestContext } = require('../store')
|
|
20
|
+
const ctx = getRequestContext()
|
|
21
|
+
if (ctx && ctx.traceId) {
|
|
22
|
+
traceId = ctx.traceId
|
|
23
|
+
spanId = ctx.spanId
|
|
24
|
+
} else {
|
|
25
|
+
const span = trace.getSpan(context.active())
|
|
26
|
+
const spanContext = span?.spanContext()
|
|
27
|
+
if (spanContext) {
|
|
28
|
+
traceId = spanContext.traceId
|
|
29
|
+
spanId = spanContext.spanId
|
|
30
|
+
}
|
|
24
31
|
}
|
|
25
32
|
} catch (_) {}
|
|
26
33
|
|
|
@@ -47,7 +54,7 @@ function createPinoStream(options = {}) {
|
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
const payload = { level, message: record.msg || record.message || 'log', meta }
|
|
50
|
-
axios.post(`${loggerUrl}
|
|
57
|
+
axios.post(`${loggerUrl}`, payload, { headers, timeout: 3001 }).catch(() => {})
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
60
|
}
|