Logging en Python: guía completa para principiantes

Publicado el: 11/07/2026
Tempo de leitura: 5 minutos
Configuração de logs em aplicações Python usando logging

El logging en Python permite registrar lo que ocurre durante la ejecución de un programa. En lugar de depender de mensajes temporales con print(), puedes clasificar eventos por gravedad, añadir fechas, guardar registros en archivos y conservar tracebacks completos cuando ocurre un error.

Esta herramienta resulta especialmente útil en automatizaciones, aplicaciones web, tareas programadas y proyectos que se ejecutan sin una persona observando el terminal. El módulo forma parte de la biblioteca estándar, por lo que no requiere instalación.

Logging frente a print()

print() es adecuado para mostrar información al usuario o hacer una comprobación rápida. Logging está diseñado para diagnóstico y operación:

  • incluye niveles como DEBUG, INFO y ERROR;
  • añade fechas y nombres de módulos;
  • puede escribir en varios destinos;
  • filtra mensajes según el entorno;
  • registra excepciones con traceback;
  • rota archivos para controlar su tamaño.

La guía de print() en Python explica cuándo la salida normal sigue siendo la mejor opción.

Los niveles de logging

Python define cinco niveles habituales:

  • DEBUG: detalles técnicos para investigar el estado interno.
  • INFO: operaciones normales completadas correctamente.
  • WARNING: una situación inesperada que no detuvo el programa.
  • ERROR: una operación concreta no pudo completarse.
  • CRITICAL: un fallo grave puede impedir que la aplicación continúe.

Por defecto, el logger raíz muestra WARNING y niveles superiores. Por eso un mensaje INFO puede no aparecer hasta configurar el sistema.

Primer ejemplo

import logging

logging.basicConfig(level=logging.DEBUG)

logging.debug("Información detallada")
logging.info("La aplicación comenzó")
logging.warning("Queda poco espacio")
logging.error("No se pudo procesar el archivo")
logging.critical("La aplicación no puede continuar")

El nivel configurado funciona como umbral. Con logging.ERROR, solamente se emitirían ERROR y CRITICAL.

El Logging HOWTO oficial de Python presenta la configuración básica y patrones recomendados.

Formatear los mensajes

import logging

logging.basicConfig(
    level=logging.INFO,
    format=(
        "%(asctime)s | %(levelname)s | "
        "%(name)s | %(message)s"
    ),
)

logging.info("Aplicación preparada")

Campos frecuentes:

  • %(asctime)s: fecha y hora;
  • %(levelname)s: nivel;
  • %(name)s: nombre del logger;
  • %(module)s: módulo que creó el mensaje;
  • %(lineno)d: línea del código;
  • %(message)s: texto final.

Añadir valores sin f-strings

La API de logging admite formato diferido:

user_id = 417
filename = "report.csv"

logging.info(
    "El usuario %s comenzó a procesar %s",
    user_id,
    filename,
)

El mensaje se formatea solamente si supera los filtros. Esto evita trabajo innecesario en mensajes DEBUG desactivados.

Guardar logs en un archivo

import logging

logging.basicConfig(
    filename="application.log",
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s",
    encoding="utf-8",
)

logging.info("Importación iniciada")
logging.error("No se pudo guardar el registro 208")

Una ruta relativa se resuelve desde el directorio actual, que puede diferir de la carpeta del script. La guía de pathlib en Python explica cómo construir una ruta explícita y portable.

El modo predeterminado añade mensajes al archivo. Utiliza filemode="w" solo cuando realmente quieras reemplazar el historial en cada ejecución.

Registrar excepciones y tracebacks

import logging

try:
    result = 10 / 0
except ZeroDivisionError:
    logging.exception("Error durante el cálculo")

logging.exception() emite un ERROR e incluye automáticamente el traceback actual. Debe utilizarse normalmente dentro de un bloque except.

Logging no sustituye el manejo de errores. Primero decide si debes recuperar, reintentar, omitir o propagar. La guía de try y except en Python explica ese control de flujo.

Crear un logger por módulo

import logging

logger = logging.getLogger(__name__)


def load_configuration():
    logger.info("Cargando configuración")

__name__ identifica el módulo, lo que permite distinguir mensajes de shop.payments y shop.inventory. Una práctica habitual es que los módulos creen loggers y que el punto de entrada configure handlers y niveles.

Handlers y formatters

El logger crea registros. Un handler decide el destino y un formatter define la apariencia. El siguiente ejemplo muestra INFO en la consola y guarda DEBUG en un archivo:

import logging

logger = logging.getLogger("inventory")
logger.setLevel(logging.DEBUG)

console = logging.StreamHandler()
console.setLevel(logging.INFO)

file_handler = logging.FileHandler(
    "inventory.log",
    encoding="utf-8",
)
file_handler.setLevel(logging.DEBUG)

formatter = logging.Formatter(
    "%(asctime)s | %(levelname)s | "
    "%(name)s | %(message)s"
)

console.setFormatter(formatter)
file_handler.setFormatter(formatter)

logger.addHandler(console)
logger.addHandler(file_handler)

logger.debug("Cálculo detallado")
logger.info("Inventario actualizado")

La consola recibe el evento INFO. El archivo recibe INFO y DEBUG.

Evitar mensajes duplicados

Los duplicados suelen aparecer cuando se añaden handlers varias veces o cuando un registro se propaga a un logger padre que también tiene handlers.

Configura el sistema una sola vez, durante el inicio. Para un logger completamente aislado, puedes utilizar:

logger.propagate = False

No desactives la propagación sin entender la jerarquía, porque la configuración central depende de ella en muchos proyectos.

Rotar archivos de log

import logging
from logging.handlers import RotatingFileHandler

logger = logging.getLogger("service")
logger.setLevel(logging.INFO)

handler = RotatingFileHandler(
    "service.log",
    maxBytes=1_000_000,
    backupCount=3,
    encoding="utf-8",
)

handler.setFormatter(
    logging.Formatter(
        "%(asctime)s | %(levelname)s | %(message)s"
    )
)

logger.addHandler(handler)
logger.info("Servicio iniciado")

Cuando el archivo alcanza aproximadamente un megabyte, comienza uno nuevo y conserva hasta tres copias anteriores. Para rotación por tiempo existe TimedRotatingFileHandler.

Ejemplo práctico de automatización

import logging
from pathlib import Path

logging.basicConfig(
    filename="organizer.log",
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
    encoding="utf-8",
)

source = Path("incoming")
processed = 0
failed = 0

logging.info("Proceso iniciado")

for path in source.iterdir():
    if not path.is_file():
        continue

    try:
        size = path.stat().st_size
        logging.debug(
            "Archivo detectado: %s, %s bytes",
            path.name,
            size,
        )
        processed += 1
    except OSError:
        failed += 1
        logging.exception(
            "No se pudo procesar %s",
            path,
        )

logging.info(
    "Proceso terminado: %s correctos, %s fallos",
    processed,
    failed,
)

La guía de automatización con Python presenta scripts donde un historial como este resulta indispensable.

Configuración mediante diccionarios

Para aplicaciones grandes, logging.config.dictConfig() permite declarar loggers, handlers y formatos en una estructura central:

import logging.config

CONFIG = {
    "version": 1,
    "formatters": {
        "standard": {
            "format": "%(asctime)s %(levelname)s %(name)s %(message)s",
        }
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "standard",
            "level": "INFO",
        }
    },
    "root": {
        "handlers": ["console"],
        "level": "INFO",
    },
}

logging.config.dictConfig(CONFIG)

Seguridad y privacidad

No registres contraseñas, tokens, claves privadas, cookies de sesión, números completos de tarjetas ni datos personales innecesarios. Los logs suelen copiarse, archivarse y enviarse a servicios externos.

Utiliza identificadores internos, enmascara valores y define políticas de retención. Un mensaje útil describe el evento sin exponer secretos.

Depuración y logging

Logging conserva un historial, mientras que un depurador permite detener el programa e inspeccionar variables. Son herramientas complementarias. La guía de depuración de Python en VS Code explica breakpoints y seguimiento paso a paso.

Errores frecuentes

  • Llamar a basicConfig() después de emitir mensajes.
  • Registrar todo con el mismo nivel.
  • Usar logger.error() sin traceback en errores inesperados.
  • Añadir handlers repetidamente.
  • Guardar datos sensibles.
  • No rotar archivos de procesos permanentes.
  • Escribir mensajes vagos sin identificadores útiles.

Referencia oficial

La referencia oficial del módulo logging documenta loggers, handlers, filtros, formatters y configuración.

Conclusión

Logging convierte mensajes aislados en un registro operativo. Empieza con niveles y basicConfig(), añade fechas y contexto, guarda los eventos importantes en archivos y utiliza logger.exception() para fallos inesperados. En proyectos grandes, configura handlers una sola vez y crea un logger por módulo.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Dicas para melhorar performance de scripts Python lentos
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Por qué Python puede ser lento y cómo mejorar su rendimiento

    Descubre por qué Python puede ser lento y mejora su rendimiento con cProfile, algoritmos, sets, generadores, NumPy, caché y concurrencia.

    Ler mais

    Tempo de leitura: 5 minutos
    12/07/2026
    Leitura segura de senhas no terminal usando Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Cómo leer contraseñas de forma segura en el terminal con Python

    Lee contraseñas de forma segura con getpass, valida entradas, evita logs y texto plano y almacena credenciales con hashing adecuado.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Exemplo de testes unitários em Python com código de unittest para validação automatizada
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Tests unitarios en Python: unittest, pytest y mocks

    Aprende tests unitarios en Python con unittest, pytest, fixtures, parametrización, mocks, cobertura y buenas prácticas para evitar regresiones.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Proteção de API Flask usando autenticação JWT em Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Cómo proteger una API Flask con JWT

    Protege una API Flask con JWT, access y refresh tokens, bcrypt, roles, revocación, variables de entorno, HTTPS y pruebas de

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Enums en Python: evita valores mágicos y errores

    Aprende enums en Python con Enum, IntEnum, StrEnum, auto, unique, Flag, validación, JSON, bases de datos y buenas prácticas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Uso de dataclasses para simplificar classes em Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Dataclasses en Python: clases de datos más limpias

    Aprende dataclasses en Python: campos, valores predeterminados, field, frozen, order, __post_init__, herencia, asdict y buenas prácticas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026