azify-logger 1.0.28 → 1.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -4
- package/index.js +2 -1
- package/middleware-express.js +213 -163
- package/middleware-fastify.js +348 -0
- package/middleware-restify.js +74 -59
- package/package.json +16 -17
- package/queue/redisQueue.js +42 -44
- package/sampling.js +1 -1
- package/scripts/redis-worker.js +25 -53
- package/server.js +44 -47
- package/store.js +10 -4
- package/streams/httpQueue.js +65 -80
package/streams/httpQueue.js
CHANGED
|
@@ -2,7 +2,13 @@ const axios = require('axios')
|
|
|
2
2
|
const http = require('http')
|
|
3
3
|
const https = require('https')
|
|
4
4
|
const path = require('path')
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
function fastUUID() {
|
|
7
|
+
const timestamp = Date.now().toString(36)
|
|
8
|
+
const randomPart = Math.random().toString(36).substring(2, 15)
|
|
9
|
+
const randomPart2 = Math.random().toString(36).substring(2, 15)
|
|
10
|
+
return `${timestamp}-${randomPart}-${randomPart2}`.substring(0, 36)
|
|
11
|
+
}
|
|
6
12
|
|
|
7
13
|
const { createRedisProducer, DEFAULT_STREAM_KEY, DEFAULT_REDIS_URL } = require('../queue/redisQueue')
|
|
8
14
|
const { createFileSpool } = require('../queue/fileQueue')
|
|
@@ -107,16 +113,32 @@ function createHttpLoggerTransport (loggerUrl, overrides) {
|
|
|
107
113
|
try {
|
|
108
114
|
return createRedisStreamTransport(loggerUrl, options, redisConfig)
|
|
109
115
|
} catch (err) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
const errorMsg = `[azify-logger] ❌ ERRO: Redis é obrigatório mas falhou ao inicializar.\n` +
|
|
117
|
+
` Mensagem: ${err.message}\n` +
|
|
118
|
+
` Verifique se:\n` +
|
|
119
|
+
` 1. ioredis está instalado: npm install ioredis\n` +
|
|
120
|
+
` 2. Redis está configurado corretamente (AZIFY_LOGGER_REDIS_URL)\n` +
|
|
121
|
+
` 3. Redis está rodando e acessível\n`
|
|
122
|
+
throw new Error(errorMsg)
|
|
114
123
|
}
|
|
115
124
|
}
|
|
116
125
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
const defaultRedisConfig = {
|
|
127
|
+
url: DEFAULT_REDIS_URL,
|
|
128
|
+
streamKey: DEFAULT_STREAM_KEY
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
return createRedisStreamTransport(loggerUrl, options, defaultRedisConfig)
|
|
133
|
+
} catch (err) {
|
|
134
|
+
const errorMsg = `[azify-logger] ❌ ERRO: Redis é obrigatório mas não está disponível.\n` +
|
|
135
|
+
` Mensagem: ${err.message}\n` +
|
|
136
|
+
` Verifique se:\n` +
|
|
137
|
+
` 1. ioredis está instalado: npm install ioredis\n` +
|
|
138
|
+
` 2. Redis está rodando em ${DEFAULT_REDIS_URL}\n` +
|
|
139
|
+
` 3. Configure AZIFY_LOGGER_REDIS_URL se Redis estiver em outro endereço\n`
|
|
140
|
+
throw new Error(errorMsg)
|
|
141
|
+
}
|
|
120
142
|
}
|
|
121
143
|
|
|
122
144
|
function createRedisStreamTransport (loggerUrl, options, redisConfig) {
|
|
@@ -124,111 +146,76 @@ function createRedisStreamTransport (loggerUrl, options, redisConfig) {
|
|
|
124
146
|
try {
|
|
125
147
|
producer = createRedisProducer(redisConfig)
|
|
126
148
|
} catch (err) {
|
|
127
|
-
|
|
128
|
-
// Não logar - silenciar completamente para não poluir logs
|
|
129
|
-
return noopTransport
|
|
149
|
+
throw new Error(`Falha ao criar producer Redis: ${err.message}`)
|
|
130
150
|
}
|
|
131
151
|
|
|
132
152
|
if (!producer) {
|
|
133
|
-
|
|
153
|
+
throw new Error('Falha ao criar producer Redis: producer é null')
|
|
134
154
|
}
|
|
135
155
|
|
|
136
156
|
let spool = null
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
157
|
+
if (createFileSpool) {
|
|
158
|
+
try {
|
|
159
|
+
spool = createFileSpool({
|
|
160
|
+
directory: redisConfig.spoolDir || path.join(process.cwd(), '.azify-logger-spool'),
|
|
161
|
+
flushInterval: options.flushInterval,
|
|
162
|
+
batchSize: options.batchSize,
|
|
163
|
+
async pushFn (entries) {
|
|
164
|
+
if (producer) {
|
|
165
|
+
for (const entry of entries) {
|
|
166
|
+
try {
|
|
167
|
+
await producer.enqueue(entry).catch(() => {
|
|
168
|
+
})
|
|
169
|
+
} catch (err) {
|
|
170
|
+
}
|
|
151
171
|
}
|
|
152
172
|
}
|
|
153
173
|
}
|
|
154
|
-
}
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
// Erro ao criar spool - continuar sem spool silenciosamente
|
|
158
|
-
// Não logar - silenciar completamente para não poluir logs
|
|
174
|
+
})
|
|
175
|
+
} catch (err) {
|
|
176
|
+
}
|
|
159
177
|
}
|
|
160
178
|
|
|
161
179
|
if (spool) {
|
|
162
180
|
spool.flush().catch(() => {})
|
|
163
181
|
}
|
|
164
182
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
183
|
+
if (ensureWorker) {
|
|
184
|
+
try {
|
|
185
|
+
ensureWorker(redisConfig, { autoRestart: true, stdio: 'inherit' })
|
|
186
|
+
} catch (err) {
|
|
187
|
+
process.stderr.write(`[azify-logger] ⚠️ Aviso: Falha ao inicializar worker: ${err.message}\n`)
|
|
188
|
+
}
|
|
170
189
|
}
|
|
171
190
|
|
|
172
191
|
function pushEntry(entry) {
|
|
173
|
-
|
|
174
|
-
// producer.enqueue() já faz seu próprio setImmediate
|
|
175
|
-
// Isso reduz de 3 para 2 níveis de setImmediate aninhados
|
|
176
|
-
try {
|
|
177
|
-
if (!producer) {
|
|
178
|
-
// Se producer não estiver disponível, tentar spool
|
|
179
|
-
if (spool) {
|
|
180
|
-
spool.append(entry).catch(() => {})
|
|
181
|
-
}
|
|
182
|
-
return
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Não aguardar - fazer fire-and-forget para não bloquear
|
|
186
|
-
// producer.enqueue() já faz setImmediate internamente
|
|
187
|
-
producer.enqueue(entry).catch(() => {
|
|
188
|
-
// Erro ao enfileirar no Redis - tentar spool
|
|
189
|
-
if (spool) {
|
|
190
|
-
spool.append(entry).catch(() => {})
|
|
191
|
-
}
|
|
192
|
-
})
|
|
193
|
-
} catch (err) {
|
|
194
|
-
// Erro ao preparar entrada - ignorar silenciosamente
|
|
192
|
+
if (!producer) {
|
|
195
193
|
if (spool) {
|
|
196
194
|
spool.append(entry).catch(() => {})
|
|
197
195
|
}
|
|
196
|
+
return
|
|
198
197
|
}
|
|
198
|
+
|
|
199
|
+
producer.enqueue(entry)
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
return {
|
|
202
203
|
enqueue (payload, headers = {}) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
id: randomUUID(),
|
|
209
|
-
loggerUrl,
|
|
210
|
-
headers,
|
|
211
|
-
payload,
|
|
212
|
-
createdAt: Date.now(),
|
|
213
|
-
attempts: 0
|
|
214
|
-
}
|
|
215
|
-
// pushEntry não tem setImmediate agora - chama direto producer.enqueue()
|
|
216
|
-
// producer.enqueue() faz setImmediate → client.xadd() (Redis I/O assíncrono)
|
|
217
|
-
pushEntry(entry)
|
|
218
|
-
} catch (err) {
|
|
219
|
-
// Erro ao criar entrada - ignorar silenciosamente
|
|
220
|
-
// Não travar aplicação por erro no logger
|
|
204
|
+
const entry = {
|
|
205
|
+
id: fastUUID(),
|
|
206
|
+
loggerUrl,
|
|
207
|
+
headers: headers || {},
|
|
208
|
+
payload
|
|
221
209
|
}
|
|
210
|
+
pushEntry(entry)
|
|
222
211
|
},
|
|
223
212
|
async flush () {
|
|
224
213
|
try {
|
|
225
214
|
if (spool) {
|
|
226
215
|
await spool.flush().catch(() => {
|
|
227
|
-
// Erro ao fazer flush - ignorar silenciosamente
|
|
228
216
|
})
|
|
229
217
|
}
|
|
230
218
|
} catch (err) {
|
|
231
|
-
// Erro ao fazer flush - ignorar silenciosamente
|
|
232
219
|
}
|
|
233
220
|
}
|
|
234
221
|
}
|
|
@@ -303,7 +290,6 @@ function buildInlineTransport (loggerUrl, options) {
|
|
|
303
290
|
}
|
|
304
291
|
}
|
|
305
292
|
} catch (_) {
|
|
306
|
-
// remaining items already reinserted in queue
|
|
307
293
|
} finally {
|
|
308
294
|
flushing = false
|
|
309
295
|
if (queue.length) {
|
|
@@ -354,4 +340,3 @@ function createHttpAgents (options) {
|
|
|
354
340
|
module.exports = {
|
|
355
341
|
createHttpLoggerTransport
|
|
356
342
|
}
|
|
357
|
-
|