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/README.md
CHANGED
|
@@ -95,16 +95,16 @@ O `azify-logger` inclui um OpenTelemetry Collector configurado para receber trac
|
|
|
95
95
|
Para habilitar o envio de traces, configure a variável de ambiente na sua aplicação:
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
|
-
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:
|
|
98
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:3001/v1/traces
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
### URLs
|
|
102
102
|
|
|
103
103
|
| Ambiente | URL |
|
|
104
104
|
|----------|-----|
|
|
105
|
-
| **Development** | `http://localhost:
|
|
105
|
+
| **Development (Docker)** | `http://localhost:3001/v1/traces` |
|
|
106
106
|
| **Staging** | `https://logsdashboard.azify.dev/v1/traces` |
|
|
107
|
-
| **Production** | `https://cadence.aztech.host/v1/traces` |
|
|
107
|
+
| **Production** | `https://cadence.aztech.host/v1/traces` |
|
|
108
108
|
|
|
109
109
|
## 🔍 Como Funciona
|
|
110
110
|
|
package/index.js
CHANGED
|
@@ -1,3 +1,71 @@
|
|
|
1
|
+
if (process.env.AZIFY_LOGGER_DISABLE !== '1') {
|
|
2
|
+
try {
|
|
3
|
+
require('./register-http-client-early')
|
|
4
|
+
} catch (_) {}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
if (typeof global.__AZIFY_NODE_REQUIRE === 'undefined') {
|
|
8
|
+
try {
|
|
9
|
+
const Mod = require('module')
|
|
10
|
+
global.__AZIFY_NODE_REQUIRE = Mod.prototype.require
|
|
11
|
+
} catch (_) {}
|
|
12
|
+
}
|
|
13
|
+
if (process.env.AZIFY_LOGGER_DISABLE !== '1') {
|
|
14
|
+
let earlyPatch
|
|
15
|
+
try {
|
|
16
|
+
earlyPatch = require('./register-http-client-early')
|
|
17
|
+
if (earlyPatch && typeof earlyPatch.patchUndiciInCache === 'function') {
|
|
18
|
+
try { earlyPatch.patchUndiciInCache() } catch (_) {}
|
|
19
|
+
}
|
|
20
|
+
} catch (e) {
|
|
21
|
+
earlyPatch = null
|
|
22
|
+
}
|
|
23
|
+
try { require('./register') } catch (_) {}
|
|
24
|
+
if (earlyPatch && typeof earlyPatch.patchUndiciInCache === 'function') {
|
|
25
|
+
try {
|
|
26
|
+
earlyPatch.patchUndiciInCache()
|
|
27
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
28
|
+
try { process.stderr.write('[azify-logger] INDEX: patchUndiciInCache() called\n') } catch (_) {}
|
|
29
|
+
}
|
|
30
|
+
} catch (_) {}
|
|
31
|
+
if (typeof setImmediate === 'function') setImmediate(earlyPatch.patchUndiciInCache)
|
|
32
|
+
if (typeof earlyPatch.patchGlobalDispatcherInPlace === 'function') {
|
|
33
|
+
let tick = 0
|
|
34
|
+
const iv = setInterval(function () {
|
|
35
|
+
try { earlyPatch.patchUndiciInCache() } catch (_) {}
|
|
36
|
+
try { earlyPatch.patchGlobalDispatcherInPlace() } catch (_) {}
|
|
37
|
+
if (++tick >= 600) clearInterval(iv)
|
|
38
|
+
}, 100)
|
|
39
|
+
}
|
|
40
|
+
if (typeof setTimeout === 'function') {
|
|
41
|
+
setTimeout(earlyPatch.patchUndiciInCache, 100)
|
|
42
|
+
setTimeout(earlyPatch.patchUndiciInCache, 500)
|
|
43
|
+
setTimeout(earlyPatch.patchUndiciInCache, 1500)
|
|
44
|
+
setTimeout(earlyPatch.patchUndiciInCache, 3000)
|
|
45
|
+
setTimeout(earlyPatch.patchUndiciInCache, 5000)
|
|
46
|
+
setTimeout(function () {
|
|
47
|
+
earlyPatch.patchUndiciInCache()
|
|
48
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] patchUndiciInCache 7s delay done\n') } catch (_) {}
|
|
49
|
+
}, 7000)
|
|
50
|
+
setTimeout(function () {
|
|
51
|
+
earlyPatch.patchUndiciInCache()
|
|
52
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] patchUndiciInCache 10s delay done\n') } catch (_) {}
|
|
53
|
+
}, 10000)
|
|
54
|
+
setTimeout(function () {
|
|
55
|
+
earlyPatch.patchUndiciInCache()
|
|
56
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] patchUndiciInCache 15s delay done\n') } catch (_) {}
|
|
57
|
+
}, 15000)
|
|
58
|
+
setTimeout(function () {
|
|
59
|
+
earlyPatch.patchUndiciInCache()
|
|
60
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] patchUndiciInCache 20s delay done\n') } catch (_) {}
|
|
61
|
+
}, 20000)
|
|
62
|
+
setTimeout(function () {
|
|
63
|
+
earlyPatch.patchUndiciInCache()
|
|
64
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] patchUndiciInCache 25s delay done\n') } catch (_) {}
|
|
65
|
+
}, 25000)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
1
69
|
require('./otel-env')
|
|
2
70
|
const { createHttpLoggerTransport } = require('./streams/httpQueue')
|
|
3
71
|
const nativeConsole = {
|
|
@@ -25,7 +93,6 @@ try {
|
|
|
25
93
|
|
|
26
94
|
if (process.env.AZIFY_LOGGER_AUTOREG_DISABLE !== '1') {
|
|
27
95
|
try { require('./register-otel') } catch (_) {}
|
|
28
|
-
try { require('./register') } catch (_) {}
|
|
29
96
|
try { require('./register-restify') } catch (_) {}
|
|
30
97
|
}
|
|
31
98
|
|
|
@@ -54,7 +121,7 @@ class AzifyLogger {
|
|
|
54
121
|
: process.env.AZIFY_LOGGER_AWAIT_DELIVERY === 'true',
|
|
55
122
|
...options
|
|
56
123
|
}
|
|
57
|
-
|
|
124
|
+
|
|
58
125
|
this.transport = createHttpLoggerTransport(this.options.loggerUrl, {
|
|
59
126
|
awaitDelivery: this.options.awaitDelivery
|
|
60
127
|
})
|
|
@@ -73,7 +140,7 @@ class AzifyLogger {
|
|
|
73
140
|
async log(level, message, meta = {}) {
|
|
74
141
|
const span = trace.getSpan(context.active())
|
|
75
142
|
const spanContext = span && span.spanContext()
|
|
76
|
-
|
|
143
|
+
|
|
77
144
|
const logData = {
|
|
78
145
|
level,
|
|
79
146
|
message,
|
|
@@ -194,9 +261,18 @@ function createAzifyLoggerFromEnv() {
|
|
|
194
261
|
loggerUrl: process.env.AZIFY_LOGGER_URL,
|
|
195
262
|
environment: process.env.NODE_ENV
|
|
196
263
|
})
|
|
197
|
-
|
|
264
|
+
|
|
198
265
|
interceptConsole(logger)
|
|
199
|
-
|
|
266
|
+
|
|
267
|
+
if (process.env.AZIFY_LOGGER_DISABLE !== '1') {
|
|
268
|
+
try {
|
|
269
|
+
process.stderr.write('[AZIFY] createAzifyLoggerFromEnv: patching undici in cache\n')
|
|
270
|
+
const early = require('./register-http-client-early')
|
|
271
|
+
if (typeof early.patchUndiciInCache === 'function') early.patchUndiciInCache()
|
|
272
|
+
if (typeof early.flushEarlyLogQueue === 'function') early.flushEarlyLogQueue()
|
|
273
|
+
} catch (_) {}
|
|
274
|
+
}
|
|
275
|
+
|
|
200
276
|
return logger
|
|
201
277
|
}
|
|
202
278
|
|
|
@@ -327,8 +403,9 @@ function createNestLogger() {
|
|
|
327
403
|
}
|
|
328
404
|
|
|
329
405
|
if (process.env.AZIFY_LOGGER_DISABLE !== '1') {
|
|
406
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] INDEX loading init\n') } catch (_) {}
|
|
330
407
|
require('./init')
|
|
331
|
-
|
|
408
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') try { process.stderr.write('[azify-logger] INDEX register already loaded at top\n') } catch (_) {}
|
|
332
409
|
}
|
|
333
410
|
|
|
334
411
|
module.exports = AzifyLogger
|
|
@@ -347,4 +424,4 @@ module.exports.middleware = {
|
|
|
347
424
|
}
|
|
348
425
|
module.exports.startLoggerWorker = require('./queue/workerManager').startLoggerWorker
|
|
349
426
|
module.exports.stopLoggerWorker = require('./queue/workerManager').stopLoggerWorker
|
|
350
|
-
module.exports.ensureLoggerWorker = require('./queue/workerManager').ensureWorker
|
|
427
|
+
module.exports.ensureLoggerWorker = require('./queue/workerManager').ensureWorker
|
package/init.js
CHANGED
|
@@ -7,14 +7,24 @@ const originalRequire = Module.prototype.require
|
|
|
7
7
|
|
|
8
8
|
Module.prototype.require = function(id) {
|
|
9
9
|
const result = originalRequire.call(this, id)
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
const idStr = typeof id === 'string' ? id : ''
|
|
12
|
+
if (idStr === 'undici' || (idStr.indexOf('undici') !== -1 && idStr.indexOf('undici-package') === -1)) {
|
|
13
|
+
if (result && typeof result === 'object' && (result.request || result.fetch)) {
|
|
14
|
+
try {
|
|
15
|
+
const early = require('./register-http-client-early')
|
|
16
|
+
if (early && typeof early.patchUndiciExports === 'function') early.patchUndiciExports(result)
|
|
17
|
+
} catch (_) {}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
if (id === '@nestjs/common') {
|
|
12
22
|
if (result && result.Logger) {
|
|
13
23
|
const originalLoggerConstructor = result.Logger
|
|
14
|
-
|
|
24
|
+
|
|
15
25
|
function PatchedLogger(context) {
|
|
16
26
|
const instance = new originalLoggerConstructor(context)
|
|
17
|
-
|
|
27
|
+
|
|
18
28
|
instance.log = function(message, context) {
|
|
19
29
|
const { getRequestContext } = require('./store')
|
|
20
30
|
const ctx = getRequestContext()
|
|
@@ -23,7 +33,7 @@ Module.prototype.require = function(id) {
|
|
|
23
33
|
}
|
|
24
34
|
return originalLoggerConstructor.prototype.log.call(this, message, context)
|
|
25
35
|
}
|
|
26
|
-
|
|
36
|
+
|
|
27
37
|
instance.error = function(message, trace, context) {
|
|
28
38
|
const { getRequestContext } = require('./store')
|
|
29
39
|
const ctx = getRequestContext()
|
|
@@ -32,7 +42,7 @@ Module.prototype.require = function(id) {
|
|
|
32
42
|
}
|
|
33
43
|
return originalLoggerConstructor.prototype.error.call(this, message, trace, context)
|
|
34
44
|
}
|
|
35
|
-
|
|
45
|
+
|
|
36
46
|
instance.warn = function(message, context) {
|
|
37
47
|
const { getRequestContext } = require('./store')
|
|
38
48
|
const ctx = getRequestContext()
|
|
@@ -41,7 +51,7 @@ Module.prototype.require = function(id) {
|
|
|
41
51
|
}
|
|
42
52
|
return originalLoggerConstructor.prototype.warn.call(this, message, context)
|
|
43
53
|
}
|
|
44
|
-
|
|
54
|
+
|
|
45
55
|
instance.debug = function(message, context) {
|
|
46
56
|
const { getRequestContext } = require('./store')
|
|
47
57
|
const ctx = getRequestContext()
|
|
@@ -50,7 +60,7 @@ Module.prototype.require = function(id) {
|
|
|
50
60
|
}
|
|
51
61
|
return originalLoggerConstructor.prototype.debug.call(this, message, context)
|
|
52
62
|
}
|
|
53
|
-
|
|
63
|
+
|
|
54
64
|
instance.verbose = function(message, context) {
|
|
55
65
|
const { getRequestContext } = require('./store')
|
|
56
66
|
const ctx = getRequestContext()
|
|
@@ -59,17 +69,17 @@ Module.prototype.require = function(id) {
|
|
|
59
69
|
}
|
|
60
70
|
return originalLoggerConstructor.prototype.verbose.call(this, message, context)
|
|
61
71
|
}
|
|
62
|
-
|
|
72
|
+
|
|
63
73
|
return instance
|
|
64
74
|
}
|
|
65
|
-
|
|
75
|
+
|
|
66
76
|
Object.setPrototypeOf(PatchedLogger, originalLoggerConstructor)
|
|
67
77
|
Object.assign(PatchedLogger, originalLoggerConstructor)
|
|
68
|
-
|
|
78
|
+
|
|
69
79
|
result.Logger = PatchedLogger
|
|
70
80
|
}
|
|
71
81
|
}
|
|
72
|
-
|
|
82
|
+
|
|
73
83
|
return result
|
|
74
84
|
}
|
|
75
85
|
}
|
package/middleware-express.js
CHANGED
|
@@ -105,7 +105,7 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
105
105
|
}
|
|
106
106
|
const config = {
|
|
107
107
|
serviceName: svcName,
|
|
108
|
-
loggerUrl: options.loggerUrl || process.env.AZIFY_LOGGER_URL || 'http://localhost:3001/log',
|
|
108
|
+
loggerUrl: options.loggerUrl || process.env.AZIFY_LOGGER_URL || process.env.LOG_URL || 'http://localhost:3001/log',
|
|
109
109
|
environment: options.environment || process.env.NODE_ENV,
|
|
110
110
|
captureResponseBody: options.captureResponseBody !== false && process.env.AZIFY_LOGGER_CAPTURE_RESPONSE_BODY !== 'false',
|
|
111
111
|
captureRequestBody: options.captureRequestBody !== false && process.env.AZIFY_LOGGER_CAPTURE_REQUEST_BODY !== 'false',
|
|
@@ -114,7 +114,12 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
const transport = createHttpLoggerTransport(config.loggerUrl, {})
|
|
117
|
-
|
|
117
|
+
if (process.env.AZIFY_LOGGER_DEBUG === '1') {
|
|
118
|
+
try {
|
|
119
|
+
const usingRedis = !!(process.env.AZIFY_LOGGER_REDIS_URL && process.env.AZIFY_LOGGER_REDIS_PASSWORD)
|
|
120
|
+
process.stderr.write(`[azify-logger] Express middleware created service=${config.serviceName || 'unknown'} loggerUrl=${(config.loggerUrl || '').replace(/\/log.*$/, '/log')} transport=${usingRedis ? 'redis' : 'http'}\n`)
|
|
121
|
+
} catch (_) {}
|
|
122
|
+
}
|
|
118
123
|
const hostname = os.hostname()
|
|
119
124
|
|
|
120
125
|
const serviceObj = config.serviceName ? { name: config.serviceName, version: '1.0.0' } : null
|
|
@@ -279,38 +284,41 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
279
284
|
|
|
280
285
|
if (config.logRequest) {
|
|
281
286
|
process.nextTick(() => {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
287
|
+
try {
|
|
288
|
+
runWithRequestContext(reqCtx, () => {
|
|
289
|
+
ensureIds()
|
|
290
|
+
ensureHeaders()
|
|
291
|
+
const request = {
|
|
292
|
+
id: requestId,
|
|
293
|
+
method,
|
|
294
|
+
url,
|
|
295
|
+
path,
|
|
296
|
+
ip: clientIp
|
|
297
|
+
}
|
|
298
|
+
if (query) request.query = query
|
|
299
|
+
if (config.captureHeaders && cachedHeaders) request.headers = cachedHeaders
|
|
300
|
+
let requestBody = null
|
|
301
|
+
if (config.captureRequestBody && req.body !== undefined && req.body != null) {
|
|
302
|
+
requestBody = safeSerializeBody(req.body)
|
|
303
|
+
request.body = requestBody
|
|
304
|
+
}
|
|
305
|
+
const meta = {
|
|
306
|
+
traceId: reqCtx.traceId,
|
|
307
|
+
spanId: reqCtx.spanId,
|
|
308
|
+
parentSpanId: reqCtx.parentSpanId || null,
|
|
309
|
+
requestId,
|
|
310
|
+
request,
|
|
311
|
+
requestBody,
|
|
312
|
+
timestamp: Date.now(),
|
|
313
|
+
hostname
|
|
314
|
+
}
|
|
315
|
+
if (serviceObj) meta.service = serviceObj
|
|
316
|
+
if (config.environment) meta.environment = config.environment
|
|
317
|
+
logWithContext('info', `[REQUEST] ${method} ${url}`, meta)
|
|
318
|
+
})
|
|
319
|
+
} catch (err) {
|
|
320
|
+
try { process.stderr.write(`[azify-logger] [REQUEST] log error: ${err && err.message}\n`) } catch (_) {}
|
|
309
321
|
}
|
|
310
|
-
if (serviceObj) meta.service = serviceObj
|
|
311
|
-
if (config.environment) meta.environment = config.environment
|
|
312
|
-
|
|
313
|
-
logWithContext('info', `[REQUEST] ${method} ${url}`, meta)
|
|
314
322
|
})
|
|
315
323
|
}
|
|
316
324
|
|
|
@@ -326,19 +334,14 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
326
334
|
|
|
327
335
|
if (!logSent) {
|
|
328
336
|
logSent = true
|
|
329
|
-
|
|
330
337
|
process.nextTick(() => {
|
|
331
338
|
try {
|
|
339
|
+
runWithRequestContext(reqCtx, () => {
|
|
332
340
|
ensureIds()
|
|
333
|
-
|
|
334
341
|
const statusCode = res.statusCode || 200
|
|
335
342
|
const duration = Date.now() - startTime
|
|
336
343
|
const response = { statusCode, durationMs: duration }
|
|
337
|
-
|
|
338
|
-
if (config.captureHeaders) {
|
|
339
|
-
ensureHeaders()
|
|
340
|
-
}
|
|
341
|
-
|
|
344
|
+
if (config.captureHeaders) ensureHeaders()
|
|
342
345
|
const requestObj = {
|
|
343
346
|
id: requestId,
|
|
344
347
|
method,
|
|
@@ -348,7 +351,6 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
348
351
|
}
|
|
349
352
|
if (query) requestObj.query = query
|
|
350
353
|
if (config.captureHeaders && cachedHeaders) requestObj.headers = cachedHeaders
|
|
351
|
-
|
|
352
354
|
const meta = {
|
|
353
355
|
traceId: reqCtx.traceId,
|
|
354
356
|
spanId: reqCtx.spanId,
|
|
@@ -361,7 +363,6 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
361
363
|
}
|
|
362
364
|
if (serviceObj) meta.service = serviceObj
|
|
363
365
|
if (config.environment) meta.environment = config.environment
|
|
364
|
-
|
|
365
366
|
const chunkToProcess = (responseChunk !== null && responseChunkCaptured) ? responseChunk : null
|
|
366
367
|
emitResponseLog(meta, chunkToProcess)
|
|
367
368
|
if (meta.traceId && meta.spanId && config.serviceName) {
|
|
@@ -379,6 +380,7 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
379
380
|
url
|
|
380
381
|
})
|
|
381
382
|
}
|
|
383
|
+
})
|
|
382
384
|
} catch (err) {
|
|
383
385
|
try {
|
|
384
386
|
ensureIds()
|
|
@@ -420,12 +422,12 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
420
422
|
url
|
|
421
423
|
})
|
|
422
424
|
}
|
|
423
|
-
} catch (
|
|
425
|
+
} catch (innerErr) {
|
|
426
|
+
try { process.stderr.write(`[azify-logger] [RESPONSE] log error: ${innerErr && innerErr.message}\n`) } catch (_) {}
|
|
424
427
|
}
|
|
425
428
|
}
|
|
426
429
|
})
|
|
427
430
|
}
|
|
428
|
-
|
|
429
431
|
return result
|
|
430
432
|
}
|
|
431
433
|
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
try { require('./register') } catch (_) {}
|
|
2
|
+
require('./otel-env')
|
|
3
|
+
const { startRequestContext, runWithRequestContext, getRequestContext } = require('./store')
|
|
4
|
+
const { createHttpLoggerTransport } = require('./streams/httpQueue')
|
|
5
|
+
const { sendSpanToOtel, setEndpointOverride } = require('./trace-export')
|
|
6
|
+
const os = require('os')
|
|
7
|
+
|
|
8
|
+
let trace, otelContext
|
|
9
|
+
try {
|
|
10
|
+
const otelApi = require('@opentelemetry/api')
|
|
11
|
+
trace = otelApi.trace
|
|
12
|
+
otelContext = otelApi.context
|
|
13
|
+
} catch (_) {
|
|
14
|
+
trace = { getSpan: () => null }
|
|
15
|
+
otelContext = { active: () => ({}) }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function fastUUID() {
|
|
19
|
+
const timestamp = Date.now().toString(36)
|
|
20
|
+
const randomPart = Math.random().toString(36).substring(2, 15)
|
|
21
|
+
const randomPart2 = Math.random().toString(36).substring(2, 15)
|
|
22
|
+
return `${timestamp}-${randomPart}-${randomPart2}`.substring(0, 36)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function sanitizeTraceHex(value) {
|
|
26
|
+
if (!value || typeof value !== 'string') return null
|
|
27
|
+
const hex = value.replace(/[^0-9a-fA-F]/g, '').toLowerCase()
|
|
28
|
+
if (!hex) return null
|
|
29
|
+
return hex.padEnd(32, '0').slice(0, 32)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createPinoHttpLoggingMiddleware(options = {}) {
|
|
33
|
+
const svcName = options.serviceName || process.env.APP_NAME
|
|
34
|
+
if (svcName) {
|
|
35
|
+
process.env.OTEL_SERVICE_NAME = svcName
|
|
36
|
+
process.env.SERVICE_NAME = svcName
|
|
37
|
+
}
|
|
38
|
+
const otelEndpoint = options.otelEndpoint || options.otelExporterEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
|
|
39
|
+
if (otelEndpoint) {
|
|
40
|
+
setEndpointOverride(otelEndpoint)
|
|
41
|
+
}
|
|
42
|
+
const config = {
|
|
43
|
+
serviceName: svcName,
|
|
44
|
+
loggerUrl: options.loggerUrl || process.env.AZIFY_LOGGER_URL || 'http://localhost:3001/log',
|
|
45
|
+
environment: options.environment || process.env.NODE_ENV,
|
|
46
|
+
logRequest: options.logRequest !== false && process.env.AZIFY_LOGGER_LOG_REQUEST !== 'false',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const transport = createHttpLoggerTransport(config.loggerUrl, {})
|
|
50
|
+
const hostname = os.hostname()
|
|
51
|
+
const serviceObj = config.serviceName ? { name: config.serviceName, version: '1.0.0' } : null
|
|
52
|
+
|
|
53
|
+
function getOtelTraceContext() {
|
|
54
|
+
try {
|
|
55
|
+
const activeContext = otelContext.active()
|
|
56
|
+
const span = trace.getSpan(activeContext)
|
|
57
|
+
if (span) {
|
|
58
|
+
const spanContext = span.spanContext()
|
|
59
|
+
if (spanContext && spanContext.traceId && spanContext.spanId) {
|
|
60
|
+
const traceHex = spanContext.traceId.replace(/-/g, '')
|
|
61
|
+
return {
|
|
62
|
+
traceId: traceHex.length === 32 ? `${traceHex.substring(0, 8)}-${traceHex.substring(8, 12)}-${traceHex.substring(12, 16)}-${traceHex.substring(16, 20)}-${traceHex.substring(20, 32)}` : spanContext.traceId,
|
|
63
|
+
spanId: spanContext.spanId,
|
|
64
|
+
parentSpanId: null
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch (_) {}
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function sendLog(level, message, meta = {}) {
|
|
73
|
+
if (!transport || typeof transport.enqueue !== 'function') return
|
|
74
|
+
|
|
75
|
+
transport.enqueue({
|
|
76
|
+
level,
|
|
77
|
+
message,
|
|
78
|
+
meta
|
|
79
|
+
}, { 'content-type': 'application/json' })
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return function azifyPinoLoggingMiddleware(req, res, next) {
|
|
83
|
+
const startTime = Date.now()
|
|
84
|
+
const method = req.method
|
|
85
|
+
const url = req.url
|
|
86
|
+
const path = req.path || url
|
|
87
|
+
|
|
88
|
+
let reqCtx = null
|
|
89
|
+
|
|
90
|
+
function ensureRequestContext() {
|
|
91
|
+
if (reqCtx) return reqCtx
|
|
92
|
+
|
|
93
|
+
const otelCtx = getOtelTraceContext()
|
|
94
|
+
const traceHex = otelCtx ? otelCtx.traceId.replace(/-/g, '').substring(0, 32) : sanitizeTraceHex(req.headers['x-trace-id'])
|
|
95
|
+
|
|
96
|
+
reqCtx = startRequestContext({
|
|
97
|
+
requestId: req.requestId || fastUUID(),
|
|
98
|
+
traceHex: traceHex || undefined,
|
|
99
|
+
parentSpanId: otelCtx?.parentSpanId || req.headers['x-parent-span-id'] || null
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
if (otelCtx) {
|
|
103
|
+
reqCtx.traceId = otelCtx.traceId
|
|
104
|
+
reqCtx.spanId = otelCtx.spanId
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return reqCtx
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const ctx = ensureRequestContext()
|
|
111
|
+
|
|
112
|
+
req.traceId = ctx.traceId
|
|
113
|
+
req.spanId = ctx.spanId
|
|
114
|
+
req.parentSpanId = ctx.parentSpanId
|
|
115
|
+
req.requestId = ctx.requestId
|
|
116
|
+
|
|
117
|
+
const logWithContext = (level, message, meta) => {
|
|
118
|
+
const otelCtx = getOtelTraceContext()
|
|
119
|
+
const currentCtx = getRequestContext() || ensureRequestContext()
|
|
120
|
+
meta.traceId = otelCtx?.traceId || meta.traceId || currentCtx.traceId
|
|
121
|
+
meta.spanId = otelCtx?.spanId || meta.spanId || currentCtx.spanId
|
|
122
|
+
meta.parentSpanId = otelCtx?.parentSpanId || meta.parentSpanId || currentCtx.parentSpanId
|
|
123
|
+
sendLog(level, message, meta)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const sameTraceMeta = () => ({
|
|
127
|
+
traceId: ctx.traceId,
|
|
128
|
+
spanId: ctx.spanId,
|
|
129
|
+
parentSpanId: ctx.parentSpanId,
|
|
130
|
+
requestId: ctx.requestId
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
if (config.logRequest) {
|
|
134
|
+
sendLog('info', `[REQUEST] ${method} ${path}`, {
|
|
135
|
+
method,
|
|
136
|
+
url: path,
|
|
137
|
+
hostname,
|
|
138
|
+
service: serviceObj,
|
|
139
|
+
environment: config.environment,
|
|
140
|
+
...sameTraceMeta()
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const originalEnd = res.end
|
|
145
|
+
res.end = function(...args) {
|
|
146
|
+
res.end = originalEnd
|
|
147
|
+
|
|
148
|
+
const duration = Date.now() - startTime
|
|
149
|
+
const statusCode = res.statusCode
|
|
150
|
+
|
|
151
|
+
if (config.logRequest) {
|
|
152
|
+
sendLog('info', `[RESPONSE] ${method} ${path}`, {
|
|
153
|
+
method,
|
|
154
|
+
url: path,
|
|
155
|
+
statusCode,
|
|
156
|
+
duration,
|
|
157
|
+
hostname,
|
|
158
|
+
service: serviceObj,
|
|
159
|
+
environment: config.environment,
|
|
160
|
+
...sameTraceMeta()
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return res.end.apply(res, args)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
runWithRequestContext(ctx, () => {
|
|
168
|
+
next()
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = createPinoHttpLoggingMiddleware
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azify-logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.45",
|
|
4
4
|
"description": "Azify Logger Client - Centralized logging for OpenSearch",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -82,6 +82,8 @@
|
|
|
82
82
|
"azify-logger-worker": "scripts/redis-worker.js"
|
|
83
83
|
},
|
|
84
84
|
"files": [
|
|
85
|
+
"preload.js",
|
|
86
|
+
"register-http-client-early.js",
|
|
85
87
|
"trace-export.js",
|
|
86
88
|
"otel-env.js",
|
|
87
89
|
"index.js",
|
|
@@ -94,9 +96,11 @@
|
|
|
94
96
|
"middleware-restify.js",
|
|
95
97
|
"middleware-express.js",
|
|
96
98
|
"middleware-express.d.ts",
|
|
99
|
+
"middleware-pino.js",
|
|
97
100
|
"middleware-fastify.js",
|
|
98
101
|
"server.js",
|
|
99
102
|
"sampling.js",
|
|
103
|
+
"pino-config.js",
|
|
100
104
|
"queue/",
|
|
101
105
|
"scripts/redis-worker.js",
|
|
102
106
|
"streams/",
|
package/pino-config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const createPinoStream = require('./streams/pino')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Helper para configurar Pino com azify-logger de forma simples
|
|
5
|
+
*/
|
|
6
|
+
function createAzifyPinoTransport(options = {}) {
|
|
7
|
+
const loggerUrl = options.loggerUrl || process.env.AZIFY_LOGGER_URL
|
|
8
|
+
const serviceName = options.serviceName || process.env.APP_NAME
|
|
9
|
+
const environment = options.environment || process.env.NODE_ENV
|
|
10
|
+
|
|
11
|
+
if (!loggerUrl) {
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
target: require.resolve('./streams/pino'),
|
|
17
|
+
options: {
|
|
18
|
+
loggerUrl,
|
|
19
|
+
serviceName,
|
|
20
|
+
environment,
|
|
21
|
+
...options
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = { createAzifyPinoTransport }
|
package/preload.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
if (process.env.AZIFY_LOGGER_DISABLE === '1') return
|
|
3
|
+
try {
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const early = require(path.join(__dirname, 'register-http-client-early.js'))
|
|
6
|
+
if (!early || typeof early.patchUndiciExports !== 'function') return
|
|
7
|
+
try {
|
|
8
|
+
const cwd = process.cwd()
|
|
9
|
+
const resolvePaths = cwd ? [cwd, path.join(cwd, 'dist'), path.join(cwd, 'src')] : undefined
|
|
10
|
+
const undiciPath = resolvePaths ? require.resolve('undici', { paths: resolvePaths }) : require.resolve('undici')
|
|
11
|
+
require(undiciPath)
|
|
12
|
+
} catch (_) {}
|
|
13
|
+
if (early.patchUndiciInCache) early.patchUndiciInCache()
|
|
14
|
+
require(path.join(__dirname, 'index.js'))
|
|
15
|
+
} catch (_) {}
|