Introducción
Los archivos de log contienen timestamps en muchos formatos diferentes. Saber cómo parsearlos correctamente es esencial para análisis de logs, monitoreo y debugging.
Lo que Aprenderás
- ✅ Formatos comunes de timestamps en logs
- ✅ Expresiones regulares para cada formato
- ✅ Código de parsing en Python y JavaScript
- ✅ Normalización a formato estándar
- ✅ Manejo de zonas horarias
Formatos Comunes de Log
1. Apache/Nginx (CLF - Common Log Format)
[01/Dec/2024:10:15:30 +0000]
Regex:
REGEX1\[(\d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2} [+-]\d{4})\]
Python:
PYTHON1from datetime import datetime 2 3def parse_apache(timestamp_str): 4 # Ejemplo: "01/Dec/2024:10:15:30 +0000" 5 return datetime.strptime( 6 timestamp_str, 7 "%d/%b/%Y:%H:%M:%S %z" 8 ) 9 10log_line = '[01/Dec/2024:10:15:30 +0000] "GET / HTTP/1.1" 200' 11match = re.search(r'\[([^\]]+)\]', log_line) 12if match: 13 dt = parse_apache(match.group(1)) 14 print(dt.isoformat())
2. ISO 8601 / RFC 3339
2024-12-01T10:15:30Z
2024-12-01T10:15:30+01:00
Regex:
REGEX1\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})
JavaScript:
JAVASCRIPT1function parseIso8601(timestampStr) { 2 return new Date(timestampStr); 3} 4 5// Ejemplo 6const dt = parseIso8601("2024-12-01T10:15:30Z"); 7console.log(dt.toISOString());
3. Syslog (RFC 3164)
Dec 1 10:15:30 hostname app[123]: mensaje
Nota: Este formato NO incluye año ni zona horaria.
Python:
PYTHON1from datetime import datetime 2 3def parse_syslog(timestamp_str, year=None): 4 # Ejemplo: "Dec 1 10:15:30" 5 if year is None: 6 year = datetime.now().year 7 8 dt = datetime.strptime(timestamp_str, "%b %d %H:%M:%S") 9 return dt.replace(year=year) 10 11# Extraer del log 12import re 13log_line = "Dec 1 10:15:30 servidor app[123]: error" 14match = re.match(r'^(\w{3}\s+\d{1,2}\s\d{2}:\d{2}:\d{2})', log_line) 15if match: 16 dt = parse_syslog(match.group(1), year=2024)
4. Unix Timestamp
1701425730
1701425730000
JavaScript:
JAVASCRIPT1function parseUnixTimestamp(raw) { 2 const str = String(raw); 3 if (str.length === 10) { 4 return new Date(Number(raw) * 1000); 5 } else if (str.length === 13) { 6 return new Date(Number(raw)); 7 } 8 throw new Error('Formato desconocido'); 9}
Parser Universal
Python
PYTHON1from datetime import datetime, timezone 2from dateutil import parser as dateutil_parser 3import re 4 5def parse_log_timestamp(raw: str) -> datetime: 6 """Parser universal para timestamps de logs""" 7 s = raw.strip() 8 9 # 1. Intentar ISO 8601 / RFC 3339 10 try: 11 dt = dateutil_parser.isoparse(s) 12 if dt.tzinfo is None: 13 dt = dt.replace(tzinfo=timezone.utc) 14 return dt 15 except: 16 pass 17 18 # 2. Apache/Nginx: [01/Dec/2024:10:15:30 +0000] 19 if s.startswith('[') and s.endswith(']'): 20 inner = s[1:-1] 21 dt = datetime.strptime(inner, "%d/%b/%Y:%H:%M:%S %z") 22 return dt 23 24 # 3. Unix timestamp numérico 25 if s.isdigit(): 26 n = len(s) 27 if n == 10: 28 return datetime.fromtimestamp(int(s), tz=timezone.utc) 29 if n == 13: 30 return datetime.fromtimestamp(int(s)/1000, tz=timezone.utc) 31 32 raise ValueError(f"Formato no reconocido: {raw}")
JavaScript
JAVASCRIPT1import { DateTime } from 'luxon'; 2 3function parseLogTimestamp(raw) { 4 const s = raw.trim(); 5 6 // 1. ISO 8601 7 const iso = DateTime.fromISO(s, { setZone: true }); 8 if (iso.isValid) return iso.toUTC(); 9 10 // 2. Apache/Nginx 11 const apacheMatch = s.match( 12 /\[(\d{2}\/\w{3}\/\d{4}:\d{2}:\d{2}:\d{2} [+-]\d{4})\]/ 13 ); 14 if (apacheMatch) { 15 const dt = DateTime.fromFormat( 16 apacheMatch[1], 17 "dd/MMM/yyyy:HH:mm:ss ZZZ" 18 ); 19 if (dt.isValid) return dt.toUTC(); 20 } 21 22 // 3. Unix timestamp 23 if (/^\d+$/.test(s)) { 24 const len = s.length; 25 if (len === 10) return DateTime.fromSeconds(Number(s)); 26 if (len === 13) return DateTime.fromMillis(Number(s)); 27 } 28 29 throw new Error(`Formato no reconocido: ${raw}`); 30}
Normalización
Siempre normaliza a un formato estándar después de parsear:
PYTHON1def normalizar_timestamp(dt: datetime) -> dict: 2 """Normaliza datetime a formatos útiles""" 3 utc = dt.astimezone(timezone.utc) 4 return { 5 'iso': utc.isoformat(), 6 'unix_s': int(utc.timestamp()), 7 'unix_ms': int(utc.timestamp() * 1000), 8 'utc': utc 9 }
Mejores Prácticas
- Parsea a UTC primero - Evita problemas de zona horaria
- Valida el rango - Rechaza fechas implausibles
- Maneja años faltantes - Syslog no incluye año
- Usa bibliotecas probadas - No reinventes el wheel
- Registra errores de parsing - Para depuración
Resumen
Has aprendido a parsear timestamps de:
- Apache/Nginx (CLF)
- ISO 8601 / RFC 3339
- Syslog
- Unix timestamps
¡Usa nuestro Convertidor por Lotes para procesar múltiples timestamps!