Por qué esta página
Los logs llegan con formatos mixtos, zonas horarias y precisiones diferentes. Un timestamp incorrecto rompe el ordenamiento, dashboards y líneas de tiempo de incidentes. Esta guía te da verificaciones rápidas, plantillas regex y fragmentos de código para normalizar tiempos de logs rápidamente—y te dirige a convertidores cuando necesitas verificar casos límite.
Lista de verificación de diagnóstico rápido
- Identificar formato: ISO 8601/RFC 3339, Apache/Nginx (
[dd/Mon/yyyy:HH:mm:ss Z]), syslog (MMM d HH:mm:ss), o personalizado. - Verificar zona horaria: desplazamiento explícito (
+0100,Z) vs. local implícito. Usar UTC por defecto si falta. - Verificar precisión: segundos vs. milisegundos vs. microsegundos; asegurar longitud consistente.
- Manejar bordes DST: parsear a UTC primero; evitar parsing local naive.
- Aplicar guardias de rango: rechazar años implausibles (ej.,
<2000o>2100).
Formatos de log comunes (plantillas)
- ISO 8601 / RFC 3339:
2024-12-01T10:15:30Z,2024-12-01T18:15:30+01:00 - Apache/Nginx:
[01/Dec/2024:10:15:30 +0000] - Syslog:
Dec 1 10:15:30 hostname app[123]: mensaje(sin año/desplazamiento) - Numérico personalizado:
1701425730(segundos),1701425730000(ms)
Pasos de normalización
- Detectar formato y zona horaria. Si falta, asumir UTC.
- Parsear a datetime aware (UTC).
- Si es epoch numérico: escalar por longitud (10s/13ms/16µs/19ns).
- Almacenar en columna canónica (ej., millis UTC) y opcionalmente mantener la cadena raw.
- Validar rango; descartar o marcar valores atípicos antes de indexar.
Fragmentos de código
JavaScript / Node.js
JAVASCRIPT1import { DateTime } from "luxon"; 2 3export function parseLogTime(raw) { 4 const trimmed = raw.trim(); 5 // ISO/RFC primero 6 const iso = DateTime.fromISO(trimmed, { setZone: true }); 7 if (iso.isValid) return iso.toUTC().toMillis(); 8 9 // Apache/Nginx: [01/Dec/2024:10:15:30 +0000] 10 const m = trimmed.match(/\[(\d{2}\/\w{3}\/\d{4}:\d{2}:\d{2}:\d{2} [+-]\d{4})\]/); 11 if (m) { 12 const dt = DateTime.fromFormat(m[1], "dd/MMM/yyyy:HH:mm:ss ZZZZ", { zone: "utc" }); 13 if (dt.isValid) return dt.toMillis(); 14 } 15 16 // Epoch numérico (segundos/ms/us/ns) 17 if (/^\d+$/.test(trimmed)) { 18 const len = trimmed.length; 19 if (len === 10) return Number(trimmed) * 1000; 20 if (len === 13) return Number(trimmed); 21 if (len === 16) return Number(trimmed) / 1000; 22 if (len === 19) return Number(trimmed) / 1_000_000; 23 } 24 25 throw new Error("Timestamp de log no reconocido"); 26}
Python
PYTHON1from datetime import datetime, timezone, timedelta 2from dateutil import parser 3 4def parse_log_time(raw: str) -> int: 5 s = raw.strip() 6 # ISO/RFC 3339, syslog con tz, etc. 7 try: 8 dt = parser.isoparse(s) 9 if dt.tzinfo is None: 10 dt = dt.replace(tzinfo=timezone.utc) 11 return int(dt.astimezone(timezone.utc).timestamp() * 1000) 12 except Exception: 13 pass 14 15 # Apache/Nginx: [01/Dec/2024:10:15:30 +0000] 16 if s.startswith("[") and s.endswith("]"): 17 inner = s[1:-1] 18 dt = datetime.strptime(inner, "%d/%b/%Y:%H:%M:%S %z") 19 return int(dt.astimezone(timezone.utc).timestamp() * 1000) 20 21 # Epoch numérico 22 if s.isdigit(): 23 n = len(s) 24 if n == 10: 25 return int(s) * 1000 26 if n == 13: 27 return int(s) 28 if n == 16: 29 return int(int(s) / 1000) 30 if n == 19: 31 return int(int(s) / 1_000_000) 32 raise ValueError("Timestamp de log no reconocido")
Plantillas Regex
REGEX1# ISO 8601 / RFC 3339 con desplazamiento 2^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})$ 3 4# Apache/Nginx 5^\[\d{2}/[A-Za-z]{3}/\d{4}:\d{2}:\d{2}:\d{2} [+-]\d{4}\]$ 6 7# Syslog (sin año/desplazamiento, añadir externamente) 8^[A-Za-z]{3}\s+\d{1,2}\s\d{2}:\d{2}:\d{2}\s.+$
FAQ
- ¿Qué hacer si falta la zona horaria? Asumir UTC y documentar la suposición.
- ¿Cómo manejar logs de múltiples fuentes? Normalizar todo a UTC millis antes de agregación.
- ¿Qué hay de los logs syslog sin año? Usar el año actual o inferir del contexto del archivo.