@mounaji_npm/logger
v0.3.0
Published
Structured app logger with a fail-open HTTP batch shipper (LogScope ingest), opt-in console patching, secret redaction and request context via AsyncLocalStorage. Node-only, zero UI.
Maintainers
Readme
@mounaji_npm/logger
Structured app logger + fail-open HTTP batch shipper for LogScope, with
opt-in console.* patching, secret redaction (via
@mounaji_npm/error-handler) and per-request context through
AsyncLocalStorage. Node-only, zero UI.
One-liner adoption (api / worker process)
import { initLogScope } from '@mounaji_npm/logger';
const { log } = initLogScope({
service: 'api', // process identity
deploy: process.env.DEPLOY_TARGET, // 'render' | 'vps'
url: process.env.LOGSCOPE_URL, // https://…/api/logs/ingest
apiKey: process.env.LOGSCOPE_KEY, // lsk_…
});- Without
url/apiKeyit runs echo-only — safe in dev/tests. patchConsoledefaults to true: every existingconsole.log/warn/errorkeeps printing exactly as before AND ships a structured copy.- Shipping is fail-open: bounded buffer, batches of ≤200 every 5s, re-queue-once on failure, drop-oldest beyond 2000 entries. LogScope being down can never break or slow the app.
"¿Está conectado el cable?" (announce)
Fail-open significa que un deploy sin LOGSCOPE_URL se ve exactamente igual
que uno que shippea bien: cero ruido, cero error. Para que eso sea diagnosticable
desde el log del propio deploy, initLogScope imprime tres líneas por la consola
cruda (nunca vuelven al shipper):
[logscope] shipping ON → https://logscope.example.com/api/logs/ingest · service=api deploy=render · filtro=minLevel=warn · control remoto=on
[logscope] shipping OFF — falta url (LOGSCOPE_URL). Los logs quedan SOLO en la consola de este proceso. service=api deploy=render
[logscope] no se pudo entregar el primer batch: ingest responded 401 — fail-open, la app sigue normal pero esos logs se pierden. Este aviso no se repite.El destino se imprime sin query, fragmento ni credenciales: la api-key nunca sale
en el log. El fallo se avisa una sola vez (no convierte una caída de LogScope
en una tormenta de logs) y cuando la entrega se restablece sale una línea de
cierre, para no dejar un "está roto" colgado. announce: false lo apaga.
Si el destino está bien pero LogScope se ve vacío, mirá el filtro= de la línea
ON: un minLevel=warn (local o empujado por el control remoto) descarta todo el
tráfico info en origen — es la explicación más común.
Request context (Express)
import { logContextMiddleware } from '@mounaji_npm/logger';
app.use(logContextMiddleware());
// every log emitted during the request carries requestId/method/pathDirect API
log.info('user created', { userId });
log.error('payment failed', err); // Error → serialized meta.err
const payLog = log.child({ name: 'payments' });
await log.flush(); // drain now
await log.shutdown(); // flush + stop (SIGTERM hooks are automatic)Levels: debug < info < warn < error < fatal. Secrets in meta
(password, token, apiKey, …) are redacted before shipping.
Crash capture
Deliberately not handled here — compose @mounaji_npm/error-handler/node
for uncaughtException/unhandledRejection semantics.
