You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
4.9 KiB
148 lines
4.9 KiB
import type {
|
|
LingInstance,
|
|
LingString
|
|
} from '@/ling/lib';
|
|
|
|
import type {
|
|
LogrOptions,
|
|
LogEntry,
|
|
MessageCategory,
|
|
LogFilters,
|
|
Logr,
|
|
Transport
|
|
} from './types.ts';
|
|
import { LogLevel } from './types.ts';
|
|
import { consoleTransport } from './transports.ts';
|
|
|
|
// ============================================================================
|
|
// ENGINE
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Crea una instancia de `Logr` vinculada a una instancia de i18n.
|
|
*
|
|
* El logger no gestiona el locale internamente — lo delega al sistema i18n.
|
|
* Cuando cambia el locale en i18n, los mensajes siguientes se resuelven
|
|
* automáticamente al nuevo locale sin ninguna reconfiguración.
|
|
*
|
|
* Cada entrada se emite a todos los transports registrados.
|
|
* Si no se especifican transports, usa `consoleTransport()` por defecto.
|
|
*
|
|
* @param ling - Instancia de i18n para resolución de mensajes localizados
|
|
* @param options - Configuración de nivel, historial y transports
|
|
*
|
|
* @example
|
|
* export const logr = createLogr(i18n, {
|
|
* level : LogLevel.WARN,
|
|
* transports: [
|
|
* consoleTransport(),
|
|
* httpTransport({ url: 'https://logs.myapp.com', level: LogLevel.ERROR }),
|
|
* ]
|
|
* });
|
|
*/
|
|
export function createLogr(ling: LingInstance, options: LogrOptions = {}): Logr {
|
|
|
|
let level : LogLevel = options.level ?? LogLevel.WARN;
|
|
let maxLogs : number = options.maxLogs ?? 1000;
|
|
let transports : Transport[] = options.transports ?? [consoleTransport()];
|
|
let entries : LogEntry[] = [];
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Configuración
|
|
// -------------------------------------------------------------------------
|
|
|
|
function setLevel(l: LogLevel): void {
|
|
level = l;
|
|
}
|
|
|
|
function setMaxLogs(max: number): void {
|
|
maxLogs = max;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Core interno
|
|
// -------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Centraliza el procesamiento de todos los niveles.
|
|
* Aplica el filtro de nivel, construye la entrada, gestiona el historial
|
|
* y emite a todos los transports.
|
|
*/
|
|
function log(
|
|
lvl : LogLevel,
|
|
category: MessageCategory,
|
|
message : LingString,
|
|
context?: Record<string, unknown>
|
|
): void {
|
|
if (lvl < level) return;
|
|
|
|
const entry: LogEntry = {
|
|
timestamp: new Date(),
|
|
level : lvl,
|
|
category,
|
|
message,
|
|
context,
|
|
};
|
|
|
|
// Historial en memoria
|
|
entries.push(entry);
|
|
if (entries.length > maxLogs) entries.shift();
|
|
|
|
// Resuelve el mensaje una sola vez y lo emite a todos los transports
|
|
const resolvedMessage = ling.ts(entry.message);
|
|
transports.forEach(t => t.write(entry, resolvedMessage));
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// API pública
|
|
// -------------------------------------------------------------------------
|
|
|
|
function debug(category: MessageCategory, message: LingString, context?: Record<string, unknown>): void {
|
|
log(LogLevel.DEBUG, category, message, context);
|
|
}
|
|
|
|
function info(category: MessageCategory, message: LingString, context?: Record<string, unknown>): void {
|
|
log(LogLevel.INFO, category, message, context);
|
|
}
|
|
|
|
function warn(category: MessageCategory, message: LingString, context?: Record<string, unknown>): void {
|
|
log(LogLevel.WARN, category, message, context);
|
|
}
|
|
|
|
function error(category: MessageCategory, message: LingString, context?: Record<string, unknown>): void {
|
|
log(LogLevel.ERROR, category, message, context);
|
|
}
|
|
|
|
function getLogs(filters?: LogFilters): LogEntry[] {
|
|
let result = entries;
|
|
|
|
if (filters?.level !== undefined) result = result.filter(e => e.level === filters.level);
|
|
if (filters?.category !== undefined) result = result.filter(e => e.category === filters.category);
|
|
if (filters?.since !== undefined) result = result.filter(e => e.timestamp >= filters.since!);
|
|
|
|
return result;
|
|
}
|
|
|
|
function clear(): void {
|
|
entries = [];
|
|
}
|
|
|
|
/**
|
|
* Los mensajes se resuelven al locale activo en el momento
|
|
* de llamar a serialization(), no al momento en que se registraron.
|
|
*/
|
|
function serialize(): string {
|
|
return JSON.stringify(
|
|
entries.map(e => ({
|
|
...e,
|
|
message : ling.ts(e.message),
|
|
locale : ling.getLocale(),
|
|
timestamp: e.timestamp.toISOString(),
|
|
})),
|
|
null,
|
|
2
|
|
);
|
|
}
|
|
|
|
return { debug, info, warn, error, getLogs, clear, serialize, setLevel, setMaxLogs };
|
|
} |