azify-logger 1.0.54 → 1.0.55
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/package.json +1 -1
- package/register-http-client-early.js +69 -25
- package/register.js +56 -20
- package/server.js +21 -9
package/package.json
CHANGED
|
@@ -28,13 +28,70 @@ try {
|
|
|
28
28
|
const MAX_EARLY_LOG_QUEUE = 2000
|
|
29
29
|
const earlyLogQueue = []
|
|
30
30
|
|
|
31
|
+
function normalizePathEarly(p) {
|
|
32
|
+
if (!p) return '/'
|
|
33
|
+
const trimmed = String(p).replace(/\/+$/, '')
|
|
34
|
+
return trimmed === '' ? '/' : trimmed
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Ignora esquema (http vs https): undici muitas vezes resolve como https e AZIFY_LOGGER_URL é http em dev. */
|
|
31
38
|
function isLoggerUrl(urlStr) {
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
const loggerUrlRaw = process.env.AZIFY_LOGGER_URL || 'http://localhost:3001/log'
|
|
40
|
+
if (typeof urlStr !== 'string' || !urlStr.trim()) return false
|
|
41
|
+
try {
|
|
42
|
+
const base = new URL(String(loggerUrlRaw).trim())
|
|
43
|
+
const cand = new URL(String(urlStr).trim())
|
|
44
|
+
if (base.hostname.toLowerCase() !== cand.hostname.toLowerCase()) return false
|
|
45
|
+
const portBase = base.port || (base.protocol === 'https:' ? '443' : '80')
|
|
46
|
+
const portCand = cand.port || (cand.protocol === 'https:' ? '443' : '80')
|
|
47
|
+
if (String(portBase) !== String(portCand)) return false
|
|
48
|
+
const lp = normalizePathEarly(base.pathname)
|
|
49
|
+
const tp = normalizePathEarly(cand.pathname)
|
|
50
|
+
return tp === lp || tp.startsWith(lp + '/')
|
|
51
|
+
} catch (_) {
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** undici.request(url, opts) / request(opts) — muitas chamadas não trazem origin; path pode ser URL absoluta ou só path + hostname. */
|
|
57
|
+
function resolveUrlStrFromUndiciRequestArgs(url, options) {
|
|
58
|
+
const opts = (typeof url === 'object' && url !== null && !(url instanceof URL)) ? url : options
|
|
59
|
+
const urlArg = (typeof url === 'string' || (url && (url.href || url instanceof URL))) ? url : (opts && (opts.url || opts.uri))
|
|
60
|
+
if (typeof urlArg === 'string') return urlArg
|
|
61
|
+
if (urlArg && typeof urlArg.href === 'string') return urlArg.href
|
|
62
|
+
if (urlArg && typeof urlArg.toString === 'function') return urlArg.toString()
|
|
63
|
+
if (opts && typeof opts.origin === 'string' && opts.path != null) {
|
|
64
|
+
return opts.origin + (String(opts.path).startsWith('/') ? '' : '/') + String(opts.path)
|
|
65
|
+
}
|
|
66
|
+
if (opts && typeof opts.path === 'string' && /^https?:\/\//i.test(opts.path)) {
|
|
67
|
+
return opts.path
|
|
68
|
+
}
|
|
69
|
+
if (opts && (opts.hostname || opts.host)) {
|
|
70
|
+
const h = String(opts.hostname || String(opts.host || '').split(':')[0]).trim()
|
|
71
|
+
if (h) {
|
|
72
|
+
const hl = h.toLowerCase()
|
|
73
|
+
const isLocal = hl === 'localhost' || hl === '127.0.0.1' || hl === '::1'
|
|
74
|
+
const proto = (opts.protocol && String(opts.protocol).replace(/:$/, '')) || (isLocal ? 'http' : 'https')
|
|
75
|
+
const pnum = opts.port != null && opts.port !== '' ? Number(opts.port) : NaN
|
|
76
|
+
const port = !Number.isNaN(pnum) && pnum !== 80 && pnum !== 443 ? ':' + pnum : ''
|
|
77
|
+
const p = opts.path != null ? String(opts.path) : '/'
|
|
78
|
+
return proto + '://' + h + port + (p.startsWith('/') ? p : '/' + p)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return 'unknown'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function resolveUrlStrFromDispatcherOpts(opts) {
|
|
85
|
+
if (!opts || typeof opts !== 'object') return 'unknown'
|
|
86
|
+
const origin = (opts.origin) || ''
|
|
87
|
+
const pathPart = opts.path != null ? opts.path : '/'
|
|
88
|
+
const pathStr = String(pathPart)
|
|
89
|
+
if (/^https?:\/\//i.test(pathStr)) return pathStr
|
|
90
|
+
if (origin) return origin + (pathStr.startsWith('/') ? pathStr : '/' + pathStr)
|
|
91
|
+
if (opts.hostname || opts.host) {
|
|
92
|
+
return resolveUrlStrFromUndiciRequestArgs(null, opts)
|
|
93
|
+
}
|
|
94
|
+
return 'unknown'
|
|
38
95
|
}
|
|
39
96
|
|
|
40
97
|
function send(level, message, meta) {
|
|
@@ -118,12 +175,7 @@ try {
|
|
|
118
175
|
exports.request = function (url, options, callback) {
|
|
119
176
|
const opts = (typeof url === 'object' && url !== null && !(url instanceof URL)) ? url : options
|
|
120
177
|
const method = ((opts && opts.method) || 'GET').toUpperCase()
|
|
121
|
-
|
|
122
|
-
const urlArg = (typeof url === 'string' || (url && (url.href || url instanceof URL))) ? url : (opts && (opts.url || opts.uri))
|
|
123
|
-
if (typeof urlArg === 'string') urlStr = urlArg
|
|
124
|
-
else if (urlArg && typeof urlArg.href === 'string') urlStr = urlArg.href
|
|
125
|
-
else if (urlArg && typeof urlArg.toString === 'function') urlStr = urlArg.toString()
|
|
126
|
-
else if (opts && typeof opts.origin === 'string' && opts.path != null) urlStr = opts.origin + (String(opts.path).startsWith('/') ? '' : '/') + String(opts.path)
|
|
178
|
+
const urlStr = resolveUrlStrFromUndiciRequestArgs(url, options)
|
|
127
179
|
if (process.env.AZIFY_LOGGER_DEBUG === '1') { try { process.stderr.write('[AZIFY-PATCH] undici.request ' + method + ' ' + urlStr.slice(0, 80) + '\n') } catch (_) {} }
|
|
128
180
|
const _ep = process.env.AZIFY_DEBUG_LOG_PATH
|
|
129
181
|
if (_ep) { try { require('fs').appendFileSync(_ep, new Date().toISOString() + ' [AZIFY] WRAPPER exports.request ' + method + ' ' + urlStr.slice(0, 100) + '\n') } catch (_) {} }
|
|
@@ -174,9 +226,7 @@ try {
|
|
|
174
226
|
const origDisp = proto.request
|
|
175
227
|
proto.request = function (opts, callback) {
|
|
176
228
|
const methodStr = String((opts && opts.method) || 'GET').toUpperCase()
|
|
177
|
-
const
|
|
178
|
-
const path = (opts && opts.path) != null ? opts.path : '/'
|
|
179
|
-
const urlStr = origin ? (origin + (path.startsWith('/') ? path : '/' + path)) : 'unknown'
|
|
229
|
+
const urlStr = resolveUrlStrFromDispatcherOpts(opts)
|
|
180
230
|
httpLog('WRAPPER Dispatcher.request ' + methodStr + ' ' + urlStr.slice(0, 80))
|
|
181
231
|
const ctx = getRequestContext() || getLastJobContext()
|
|
182
232
|
const otelCtx = getOtelTraceContext()
|
|
@@ -255,9 +305,7 @@ try {
|
|
|
255
305
|
if (typeof origReq !== 'function') return d
|
|
256
306
|
d.request = function (opts, callback) {
|
|
257
307
|
const methodStr = String((opts && opts.method) || 'GET').toUpperCase()
|
|
258
|
-
const
|
|
259
|
-
const pathPart = (opts && opts.path) != null ? opts.path : '/'
|
|
260
|
-
const urlStr = origin ? (origin + (pathPart.startsWith('/') ? pathPart : '/' + pathPart)) : 'unknown'
|
|
308
|
+
const urlStr = resolveUrlStrFromDispatcherOpts(opts)
|
|
261
309
|
httpLog('WRAPPER getGlobalDispatcher().request ' + methodStr + ' ' + urlStr.slice(0, 80))
|
|
262
310
|
const ctx = getRequestContext ? getRequestContext() : (getLastJobContext ? getLastJobContext() : null)
|
|
263
311
|
const otelCtx = getOtelTraceContext()
|
|
@@ -333,9 +381,7 @@ try {
|
|
|
333
381
|
const HTTP_CLIENT_MODE = deps ? deps.HTTP_CLIENT_MODE : 'all'
|
|
334
382
|
d.request = function (opts, callback) {
|
|
335
383
|
const methodStr = String((opts && opts.method) || 'GET').toUpperCase()
|
|
336
|
-
const
|
|
337
|
-
const pathPart = (opts && opts.path) != null ? opts.path : '/'
|
|
338
|
-
const urlStr = origin ? (origin + (pathPart.startsWith('/') ? pathPart : '/' + pathPart)) : 'unknown'
|
|
384
|
+
const urlStr = resolveUrlStrFromDispatcherOpts(opts)
|
|
339
385
|
httpLog('WRAPPER globalThis.dispatcher.request ' + methodStr + ' ' + urlStr.slice(0, 80))
|
|
340
386
|
const _dp = process.env.AZIFY_DEBUG_LOG_PATH
|
|
341
387
|
if (_dp) { try { require('fs').appendFileSync(_dp, new Date().toISOString() + ' [AZIFY] WRAPPER globalDispatcher.request ' + methodStr + ' ' + urlStr.slice(0, 100) + '\n') } catch (_) {} }
|
|
@@ -608,14 +654,12 @@ try {
|
|
|
608
654
|
const RequestHandler = mod.exports.RequestHandler
|
|
609
655
|
mod.exports = function wrappedApiRequest(opts, callback) {
|
|
610
656
|
const methodStr = String((opts && opts.method) || 'GET').toUpperCase()
|
|
611
|
-
const
|
|
657
|
+
const urlStr = resolveUrlStrFromDispatcherOpts(opts)
|
|
658
|
+
const urlPart = urlStr !== 'unknown' ? urlStr.slice(0, 80) : ((opts && opts.origin) ? String(opts.origin).slice(0, 80) : (opts && opts.path) || '')
|
|
612
659
|
if (HTTP_DEBUG) try { process.stderr.write('[AZIFY-PATCH] api-request ' + methodStr + ' ' + urlPart + '\n') } catch (_) {}
|
|
613
660
|
if (HTTP_VERBOSE || HTTP_DEBUG) {
|
|
614
661
|
try { process.stderr.write('[AZIFY] HTTP wrapper api-request ' + methodStr + ' ' + urlPart + '\n') } catch (_) {}
|
|
615
662
|
}
|
|
616
|
-
const origin = (opts && opts.origin) || ''
|
|
617
|
-
const pathPart = (opts && opts.path) != null ? opts.path : '/'
|
|
618
|
-
const urlStr = origin ? (origin + (pathPart.startsWith('/') ? pathPart : '/' + pathPart)) : 'unknown'
|
|
619
663
|
httpLog('WRAPPER api-request ' + methodStr + ' ' + urlStr.slice(0, 80))
|
|
620
664
|
const ctx = getRequestContext() || getLastJobContext()
|
|
621
665
|
const otelCtx = getOtelTraceContext()
|
package/register.js
CHANGED
|
@@ -10,7 +10,12 @@ try {
|
|
|
10
10
|
}
|
|
11
11
|
const ModuleForRequire = require('module')
|
|
12
12
|
const nodeRequireOriginal = ModuleForRequire.prototype.require
|
|
13
|
-
|
|
13
|
+
let bunyan = null
|
|
14
|
+
try {
|
|
15
|
+
bunyan = require('bunyan')
|
|
16
|
+
} catch (_) {
|
|
17
|
+
/* bunyan é opcional; sem ele o patch Bunyan não aplica, mas HTTP/Pino/axios devem continuar */
|
|
18
|
+
}
|
|
14
19
|
const createBunyanStream = require('./streams/bunyan')
|
|
15
20
|
const { createHttpLoggerTransport } = require('./streams/httpQueue')
|
|
16
21
|
const { getRequestContext } = require('./store')
|
|
@@ -145,12 +150,34 @@ try {
|
|
|
145
150
|
|
|
146
151
|
const debug = process.env.AZIFY_LOGGER_DEBUG === '1'
|
|
147
152
|
const httpVerbose = process.env.AZIFY_LOGGER_HTTP_VERBOSE === '1'
|
|
153
|
+
|
|
154
|
+
function extractUrlFromReqResMessage(msgStr) {
|
|
155
|
+
const s = String(msgStr)
|
|
156
|
+
const m1 = s.match(/\[(?:REQUEST|RESPONSE)\]\s+\S+\s+(https?:\/\/\S+)/i)
|
|
157
|
+
if (m1) return m1[1].replace(/[)\]}>.,;]+$/, '')
|
|
158
|
+
const m2 = s.match(/\[(?:REQUEST|RESPONSE)\]\s+\S+\s+(\S+)/i)
|
|
159
|
+
if (m2 && /^https?:\/\//i.test(m2[1])) return m2[1].replace(/[)\]}>.,;]+$/, '')
|
|
160
|
+
return null
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const OPAQUE_NO_URL = 'https://opaque.invalid/azify-logger-no-url'
|
|
164
|
+
|
|
148
165
|
function sendOutboundLog(level, message, meta) {
|
|
149
166
|
try {
|
|
150
167
|
const msgStr = String(message)
|
|
151
168
|
const isReqRes = msgStr.includes('[REQUEST]') || msgStr.includes('[RESPONSE]')
|
|
169
|
+
if (isReqRes && meta && typeof meta === 'object') {
|
|
170
|
+
const u = meta.url
|
|
171
|
+
const badUrl =
|
|
172
|
+
u === 'unknown' ||
|
|
173
|
+
!String(u || '').trim() ||
|
|
174
|
+
String(u).toLowerCase() === 'unknown'
|
|
175
|
+
if (badUrl) {
|
|
176
|
+
const fromMsg = extractUrlFromReqResMessage(msgStr)
|
|
177
|
+
meta = fromMsg ? { ...meta, url: fromMsg } : { ...meta, url: OPAQUE_NO_URL }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
152
180
|
if (isReqRes && meta && meta.url && isLoggerApiCall({ url: meta.url })) return
|
|
153
|
-
if (isReqRes && meta && (meta.url === 'unknown' || !String(meta.url || '').trim() || String(meta.url).toLowerCase() === 'unknown')) return
|
|
154
181
|
const source = meta && meta.__source
|
|
155
182
|
if (debug && source === 'pino-stdout') {
|
|
156
183
|
if (debug) try { process.stderr.write('[azify-logger] SENDOUTBOUND_ENTER level=' + level + ' source=' + source + ' msg=' + msgStr.slice(0, 60) + '\n') } catch (_) {}
|
|
@@ -350,9 +377,16 @@ try {
|
|
|
350
377
|
|
|
351
378
|
try {
|
|
352
379
|
const target = new URL(candidate, normalizedLoggerOrigin)
|
|
353
|
-
|
|
380
|
+
if (loggerEndpoint.hostname.toLowerCase() !== target.hostname.toLowerCase()) {
|
|
381
|
+
return false
|
|
382
|
+
}
|
|
383
|
+
const portLogger = loggerEndpoint.port || (loggerEndpoint.protocol === 'https:' ? '443' : '80')
|
|
384
|
+
const portTarget = target.port || (target.protocol === 'https:' ? '443' : '80')
|
|
385
|
+
if (String(portLogger) !== String(portTarget)) {
|
|
386
|
+
return false
|
|
387
|
+
}
|
|
354
388
|
const targetPath = normalizePath(target.pathname)
|
|
355
|
-
return
|
|
389
|
+
return targetPath === normalizedLoggerPath || targetPath.startsWith(normalizedLoggerPath + '/')
|
|
356
390
|
} catch (_) {
|
|
357
391
|
if (typeof candidate === 'string') {
|
|
358
392
|
const relativePath = normalizePath(candidate)
|
|
@@ -363,22 +397,24 @@ try {
|
|
|
363
397
|
return false
|
|
364
398
|
}
|
|
365
399
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
400
|
+
if (bunyan && typeof bunyan.createLogger === 'function') {
|
|
401
|
+
const originalCreate = bunyan.createLogger
|
|
402
|
+
bunyan.createLogger = function patchedCreateLogger(options) {
|
|
403
|
+
const logger = originalCreate.call(bunyan, options)
|
|
404
|
+
try {
|
|
405
|
+
const level = process.env.AZIFY_LOG_LEVEL || (options && options.level) || 'info'
|
|
406
|
+
const loggerUrl = process.env.AZIFY_LOGGER_URL
|
|
407
|
+
const serviceName = process.env.APP_NAME || (options && options.name)
|
|
408
|
+
const environment = process.env.NODE_ENV
|
|
409
|
+
|
|
410
|
+
logger.addStream({
|
|
411
|
+
level,
|
|
412
|
+
type: 'raw',
|
|
413
|
+
stream: createBunyanStream({ loggerUrl, serviceName, environment })
|
|
414
|
+
})
|
|
415
|
+
} catch (_) {}
|
|
416
|
+
return logger
|
|
417
|
+
}
|
|
382
418
|
}
|
|
383
419
|
|
|
384
420
|
const getOtelTraceContext = () => {
|
package/server.js
CHANGED
|
@@ -186,7 +186,11 @@ async function ensureIndexTemplate() {
|
|
|
186
186
|
settings: {
|
|
187
187
|
number_of_shards: 1,
|
|
188
188
|
number_of_replicas: 0,
|
|
189
|
-
'index.refresh_interval': '5s'
|
|
189
|
+
'index.refresh_interval': '5s',
|
|
190
|
+
'index.mapping.total_fields.limit': Math.min(
|
|
191
|
+
Math.max(Number(process.env.AZIFY_LOGGER_OPENSEARCH_TOTAL_FIELDS_LIMIT) || 5000, 1000),
|
|
192
|
+
20000
|
|
193
|
+
)
|
|
190
194
|
},
|
|
191
195
|
mappings: {
|
|
192
196
|
properties: {
|
|
@@ -2327,14 +2331,22 @@ function _drainOpenSearchQueue() {
|
|
|
2327
2331
|
if (_openSearchCircuitRetryTimer.unref) _openSearchCircuitRetryTimer.unref()
|
|
2328
2332
|
}
|
|
2329
2333
|
}
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2334
|
+
const status = error?.response?.status
|
|
2335
|
+
const rawMsg = error?.response?.data?.error?.reason ||
|
|
2336
|
+
error?.response?.data?.error?.type ||
|
|
2337
|
+
error?.response?.data?.message ||
|
|
2338
|
+
error?.message ||
|
|
2339
|
+
'Erro desconhecido'
|
|
2340
|
+
const errorMsg = typeof rawMsg === 'string' ? rawMsg.slice(0, 800) : String(rawMsg).slice(0, 800)
|
|
2341
|
+
const logPayload = {
|
|
2342
|
+
index: job.indexName,
|
|
2343
|
+
serviceName: job.serviceName,
|
|
2344
|
+
status,
|
|
2345
|
+
message: errorMsg
|
|
2346
|
+
}
|
|
2347
|
+
console.error('❌ Falha ao enviar log para OpenSearch', logPayload)
|
|
2348
|
+
if (error?.code && _openSearchFailuresInRow <= 10) {
|
|
2349
|
+
console.error('⚙️ Código de erro:', error.code)
|
|
2338
2350
|
}
|
|
2339
2351
|
})
|
|
2340
2352
|
.finally(() => {
|