@ -250,6 +250,100 @@ logger.timeEnd('fetch', 'perf', 'operation done'); // emits INFO with durationM
---
## Framework Logger Contract
El contrato minimo para cualquier modulo vive en `$libs/logr` :
```ts
import type { Logger, LogInput, LogMessage } from '$libs/logr';
type LogFn = (category: string, message: LogMessage, input?: LogInput) => void;
export interface Logger {
trace: LogFn;
debug: LogFn;
info: LogFn;
warn: LogFn;
error: LogFn;
fatal: LogFn;
}
```
Los artefactos no deben declarar mini-loggers locales (`logDebug`, `logInfo` ,
`ConnectionLogger` , etc.). Si un modulo necesita loggear libremente, recibe
`logger?: Logger` y llama al nivel que corresponda.
`EngineLogger` vive en `arts/logr` y extiende ese contrato con capacidades de
runtime: transports, history, children, timers, flush y dispose. El resto del
framework no necesita conocer esas capacidades para emitir logs.
## Framework Diagnostics
`Diagnostics` es una capa opcional encima de `Logger` , pensada para eventos
internos repetibles del framework: listener que lanza, reconnect agotado,
validacion fallida, cache invalidada, etc.
```ts
import { createCatalogDiagnostics, LogLevel, type Diagnostics } from '$libs/logr';
import type { Logger } from '$libs/logr';
type ConnEvent =
| { artifact: 'conn'; type: 'reconnect_exhausted'; meta: { attempts: number } }
| { artifact: 'conn'; type: 'transport_error'; meta: { error: unknown } };
function createConnDiagnostics(logger?: Logger): Diagnostics< ConnEvent > {
return createCatalogDiagnostics({
logger,
defaultCategory: 'conn',
catalog: {
reconnect_exhausted: {
level: LogLevel.WARN,
message: 'reconnect attempts exhausted'
},
transport_error: {
level: LogLevel.ERROR,
message: 'transport error'
}
}
});
}
```
La idea no es reemplazar `logger.info(...)` ni obligar a declarar cada log como
evento. La regla es:
- Usa `logger.info(...)` , `logger.warn(...)` , etc. para logs libres de negocio o
de modulo.
- Usa `Diagnostics.emit(...)` para eventos internos catalogados que queremos
mantener homogeneos, con categoria/mensaje/nivel centralizados.
- El diagnostic conserva `diagnostics.logger` , asi que sigue siendo un logger
normal por debajo.
Los diagnostics pueden activar/desactivar por nivel mediante mapa explicito, no
por comparacion tradicional `level >= minLevel` :
```ts
const diagnostics = createCatalogDiagnostics({
logger,
catalog,
levels: {
[LogLevel.WARN]: { enabled: true },
[LogLevel.ERROR]: { enabled: true },
[LogLevel.DEBUG]: { enabled: false }
},
events: {
transport_error: { level: LogLevel.ERROR },
reconnect_exhausted: false
}
});
```
El `EngineLogger` sigue siendo quien decide finalmente si la entrada se emite,
se guarda, pasa filtros de transporte o se manda a Sentry/Datadog/Loki/etc.
`Diagnostics` solo traduce un evento interno a una llamada normal del logger.
---
## Transport interface
```ts