Spraxium logoSpraxium

Transports y configuración

Configura el logger con niveles personalizados, transports de Discord y enmascaramiento de tokens. Aprende a enviar logs a canales de Discord, usar webhooks, personalizar plantillas de embed y añadir registro de comandos.

Configurar el logger

Mantén la configuración del logger en un archivo dedicado config/logger.config.ts y referencia ese archivo desde spraxium.config.ts. Así mantienes legible la configuración raíz y dejas claro dónde se definen los niveles de log, el masking, los timestamps y el envío a Discord.

El framework aplica esta configuración durante el bootstrap, antes de que tus providers empiecen a emitir logs. En la práctica, esto significa que la primera línea que escribe tu bot ya usa el formato de timestamp, los niveles personalizados y los transports configurados.

config/logger.config.ts
import type { SpraxiumLoggerConfig } from '@spraxium/logger';

export const loggerConfig: SpraxiumLoggerConfig = {
  levels: [
    { name: 'audit', color: 'blueBright' },
    { name: 'payment', color: 'greenBright' },
  ],
  maskTokens: true,
  discord: {
    type: 'channel',
    channelId: '1234567890',
    levels: ['error', 'warn', 'command'],
  },
};
spraxium.config.ts
import { defineConfig } from '@spraxium/core';
import { loggerConfig } from './config/logger.config';

export default defineConfig((_env) => ({
  logger: loggerConfig,
}));

El arreglo levels registra niveles de log personalizados junto con sus colores de consola. Esos niveles quedan disponibles mediante Logger.extend y son entendidos por ambos transports integrados. La bandera maskTokens controla TokenMasker, que está habilitado por defecto. Desactívala solo en sesiones de depuración local muy controladas.

CampoTipoPredeterminadoPropósito
levelsCustomLogLevel[][]Nombres de niveles de log personalizados y sus colores en consola.
maskTokensbooleantrueRedacta patrones de token de Discord en todos los mensajes de log.
discordDiscordTransportConfigundefined

Configuración para enviar logs a Discord. Omítelo para deshabilitarlo.

commandLoggingbooleanfalseCuando está habilitado, registra un listener que loguea cada ejecución de slash command en el nivel command. Consulta Registro de comandos más abajo.
timestampFormatdefault | iso | time-only | custom formatterdefaultControla cómo se renderiza el prefijo de timestamp en la salida de consola. Consulta Formato de timestamp más abajo.

No desactives el masking en entornos compartidos

Si los logs pueden terminar en la salida de CI, terminales compartidas o canales de Discord, mantén habilitado el enmascaramiento de tokens. Es mucho más barato revelar un valor de forma intencional en una prueba local temporal que limpiar la filtración de un token de bot.

Formato de timestamp

La opción timestampFormat controla el prefijo que se muestra antes de cada línea de log en consola. Elige uno de los presets integrados si quieres consistencia con el resto del framework, o proporciona un formatter personalizado cuando tu bot integra logs en un estándar local ya existente.

ValorSalida de ejemploMejor caso
default12/04/2026 - 14:32:05Buena opción por defecto para la mayoría de bots y desarrollo local.
iso2026-04-12T14:32:05.000ZMejor para envío de logs, parseo y pipelines legibles por máquinas.
time-only14:32:05Útil en sesiones locales cortas donde la fecha agrega ruido.
custom formatterCualquier string que devuelvasÚsalo cuando necesites un formato propio o específico por locale.
config/logger.config.ts
import type { SpraxiumLoggerConfig } from '@spraxium/logger';

export const loggerConfig: SpraxiumLoggerConfig = {
  // Use ISO 8601 timestamps for structured log pipelines
  timestampFormat: 'iso',

  // Or provide a custom format
  // timestampFormat: (d) => d.toLocaleString('pt-BR', { timeZone: 'America/Sao_Paulo' }),
};

El transport de Discord

El transport de Discord reenvía entradas de log seleccionadas como embeds a Discord. Solo envía los niveles listados en su propio arreglo levels, así que puedes mantener en terminal los logs operativos de alto volumen y reenviar advertencias, errores o auditorías de comandos a un canal compartido.

Hay dos modos de entrega disponibles. En modo channel, el transport usa el propio cliente del bot para buscar el canal y enviar embeds. En modo webhook, envía solicitudes HTTP a una URL de webhook, lo cual resulta útil cuando el destino está operativamente separado del runtime del bot.

ModoMejor cuandoCompensación
channelEl bot ya está en el servidor y quieres gestionar un secreto externo menos.La entrega depende del ciclo de vida del cliente y de los permisos del canal.
webhookQuieres credenciales de entrega aisladas o necesitas loguear en un destino fuera del alcance de guilds del bot.Ahora gestionas una URL de webhook como secreto adicional.
import type { SpraxiumLoggerConfig } from '@spraxium/logger';

export const loggerConfig: SpraxiumLoggerConfig = {
  discord: {
    type: 'channel',
    channelId: '1234567890123456789',
    levels: ['error', 'warn'],
  },
};

En modo channel, el transport encola mensajes que llegan antes de que el cliente esté listo. Una vez que el cliente emite ready, la cola se vacía automáticamente. La cola tiene un tamaño máximo de 100 entradas para evitar crecimiento de memoria durante secuencias largas de arranque.

El transport también deduplica entradas. Si se envían el mismo nivel, contexto y mensaje dentro de un segundo, el segundo envío se suprime. Esto protege los canales operativos frente a ráfagas duplicadas accidentales causadas por rutas de reintento o handlers de eventos superpuestos.

Plantillas de embed personalizadas

De forma predeterminada, los embeds de Discord usan el nivel como título, el mensaje como descripción, un color correspondiente y un timestamp ISO. Sobrescribe esto con una plantilla embed personalizada cuando quieras un layout más operativo, por ejemplo incluyendo shard, guild o fields de metadata en posiciones predecibles.

config/logger.config.ts
import type { SpraxiumLoggerConfig } from '@spraxium/logger';

export const loggerConfig: SpraxiumLoggerConfig = {
  discord: {
    type: 'channel',
    channelId: '1234567890123456789',
    levels: ['error', 'warn', 'command'],
    embed: {
      title: '{{level}} Log',
      description: "```\n{{message}}\n```",
      color: 0xff6b6b,
      timestamp: true,
      footer: { text: "Shard {{shard}} \u00b7 {{date}} {{time}}" },
      fields: [
        { name: 'Context', value: '{{context}}', inline: true },
        { name: 'Level', value: '{{level}}', inline: true },
      ],
    },
  },
};

Las variables placeholder disponibles se resuelven desde la entrada de log en el momento del envío. La variable shard muestra el ID de shard cuando el bot usa sharding, o "N/A" en un solo proceso. La metadata pasada mediante log también se expone como placeholders, y eso es lo que hace especialmente útiles los logs de comando y auditoría en Discord.

PlaceholderOrigen
levelNombre de nivel en mayúsculas (INFO, ERROR, etc.)
messageEl texto del mensaje de log
contextNombre de contexto del logger, vacío si no está definido
shardID de shard o "N/A"
timestampTimestamp ISO 8601
dateFormateado como DD/MM/YYYY
timeFormateado como HH:MM:SS (24h)

Registro de comandos

El servicio CommandLogger registra automáticamente cada ejecución de slash command. Se enlaza al evento interactionCreate del cliente y captura nombre del comando, tag del usuario, ID de usuario, nombre del guild, ID del guild e ID del canal. Cada ejecución emite una entrada de log en el nivel command con metadata estructurada que puedes reutilizar en plantillas de embed.

La forma estándar de habilitar el registro de comandos es mediante spraxium.config.ts. Establece commandLogging en true dentro del bloque logger y el framework llama a CommandLogger.bind automáticamente durante el cableado del cliente. Esta es la configuración recomendada para la mayoría de bots porque se mantiene dentro del ciclo de vida normal del framework.

config/logger.config.ts
import type { SpraxiumLoggerConfig } from '@spraxium/logger';

export const loggerConfig: SpraxiumLoggerConfig = {
  maskTokens: true,
  commandLogging: true,
  discord: {
    type: 'channel',
    channelId: '1234567890123456789',
    levels: ['command'],
    embed: {
      title: 'Command Executed',
      description: '`/{{command}}` by **{{user}}**',
      timestamp: true,
      footer: { text: '{{guild}} ({{guildId}})' },
    },
  },
};

Si usas el logger fuera del framework o necesitas enlazar el registro de comandos manualmente, llama a CommandLogger.bind directamente con el cliente de Discord después de que esté listo. La metadata de comando, usuario, guild y canal queda entonces disponible para tu plantilla de embed.

src/main.ts
import { CommandLogger } from '@spraxium/logger';

// Call after the client is ready
CommandLogger.bind(client);

Transports personalizados

Crea un transport personalizado cuando la salida en consola y el envío a Discord no sean suficientes, por ejemplo al escribir en archivos, stacks externos de observabilidad o buses de eventos internos. Un transport implementa LogTransport, expone un name y proporciona un método log que recibe un LogEntry.

Los fallos de transport están aislados del resto de la app. Si un transport lanza una excepción o rechaza, el logger absorbe ese fallo para que el logging nunca se convierta en un punto único de falla para el runtime de tu bot.

src/transports/file.transport.ts
import { appendFileSync } from 'node:fs';
import type { LogEntry, LogTransport } from '@spraxium/logger';

export class FileTransport implements LogTransport {
  readonly name = 'file';

  constructor(private readonly path: string) {}

  log(entry: LogEntry): void {
    const line = `[${entry.timestamp.toISOString()}] ${entry.level.toUpperCase()} ${entry.context ?? ''} ${entry.message}\n`;
    appendFileSync(this.path, line);
  }
}

Registra el transport con Logger.addTransport. Si ya existe un transport con el mismo nombre, se reemplaza. Puedes eliminar un transport por nombre con Logger.removeTransport. ConsoleTransport siempre se registra por defecto y usa el nombre "console".

src/main.ts
import { Logger } from '@spraxium/logger';
import { FileTransport } from './transports/file.transport';

Logger.addTransport(new FileTransport('./logs/bot.log'));

Si tu transport necesita el cliente de Discord (por ejemplo, para resolver nombres de canal o datos de guild), implementa la interfaz ClientAwareTransport en su lugar. Agrega un método setClient que el framework llama automáticamente cuando el cliente está listo. El DiscordTransport integrado usa esta interfaz internamente.

Página siguiente

Continúa con Visión general de internacionalización.