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.
@@ -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
- const { randomUUID } = require('crypto')
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
- // Erro ao inicializar Redis - retornar noopTransport silenciosamente
111
- // Não travar aplicação se Redis não estiver disponível
112
- // Não logar - silenciar completamente para não poluir logs
113
- return noopTransport
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
- // Se Redis não estiver configurado, retornar noopTransport
118
- // Não usar fallback síncrono para não travar aplicação
119
- return noopTransport
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
- // Erro ao criar producer - retornar noopTransport silenciosamente
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
- return noopTransport
153
+ throw new Error('Falha ao criar producer Redis: producer é null')
134
154
  }
135
155
 
136
156
  let spool = null
137
- try {
138
- spool = createFileSpool({
139
- directory: redisConfig.spoolDir || path.join(process.cwd(), '.azify-logger-spool'),
140
- flushInterval: options.flushInterval,
141
- batchSize: options.batchSize,
142
- async pushFn (entries) {
143
- if (producer) {
144
- for (const entry of entries) {
145
- try {
146
- await producer.enqueue(entry).catch(() => {
147
- // Erro ao enfileirar - ignorar silenciosamente
148
- })
149
- } catch (err) {
150
- // Erro ao enfileirar - ignorar silenciosamente
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
- } catch (err) {
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
- try {
166
- ensureWorker(redisConfig, { autoRestart: true, stdio: 'inherit' })
167
- } catch (err) {
168
- // Erro ao garantir worker - continuar sem worker silenciosamente
169
- // Não logar - silenciar completamente para não poluir logs
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
- // OTIMIZAÇÃO: Remover setImmediate aqui - já estamos dentro de um setImmediate (do middleware)
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
- // OTIMIZAÇÃO: Criar entry inline para reduzir overhead
204
- // randomUUID() e Date.now() são rápidos, mas podemos otimizar verificando producer primeiro
205
- try {
206
- // Criar entry apenas quando necessário (após verificações básicas)
207
- const entry = {
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
-