Repository URL to install this package:
|
Version:
1.0.0 ▾
|
| sincpro_log |
| LICENSE.md |
| README.md |
| pyproject.toml |
| PKG-INFO |
Biblioteca de logging estructurado para aplicaciones SincPro, construida sobre structlog con capacidades avanzadas de registro.
Sincpro Logger está especialmente diseñado para aplicaciones containerizadas y sistemas de observabilidad modernos:
# Configuración típica para Kubernetes logger = create_logger( "payment-service", namespace="production", pod_name=os.getenv("HOSTNAME"), version=os.getenv("APP_VERSION", "unknown") ) # Context tracing automático para microservicios with logger.tracing() as traced_logger: traced_logger.info("Processing payment", amount=100.50) # trace_id y request_id se propagan automáticamente
pip install sincpro-logger # o con Poetry poetry add sincpro-logger
⚠️ IMPORTANTE: La configuración del logger debe ser lo primero que se haga en tu aplicación, antes de cualquier import o uso de logging.
from sincpro_log import configure_global_logging # Para desarrollo (formato legible con colores) configure_global_logging(level="DEBUG") # Para producción (formato JSON estructurado) configure_global_logging(level="INFO")
# main.py import os from sincpro_log import configure_global_logging, create_logger def setup_logging(): """Configurar logging según el entorno.""" # Detectar entorno environment = os.getenv("ENVIRONMENT", "development") if environment == "production": configure_global_logging(level="INFO") # JSON estructurado else: configure_global_logging(level="DEBUG") # Formato legible return environment def main(): # PASO 1: Configurar logging ANTES que todo env = setup_logging() # PASO 2: Crear logger de la aplicación logger = create_logger( "mi-aplicacion", environment=env, version=os.getenv("APP_VERSION", "unknown") ) logger.info("Aplicación iniciada", environment=env) # Resto de la aplicación... if __name__ == "__main__": main()
from sincpro_log import create_logger # Logger básico logger = create_logger("mi-app") # Logger con contexto inicial logger = create_logger( "payment-service", environment="production", version="1.2.3", component="api" )
# Añadir campos que persisten en todos los logs logger.bind(user_id="12345", session_id="abc-def") logger.info("Usuario autenticado") # Incluirá user_id y session_id # Remover campos específicos logger.unbind("session_id") logger.info("Sesión terminada") # Solo incluirá user_id # Contexto temporal (solo dentro del bloque) with logger.context(operation="payment", amount=100.50) as temp_logger: temp_logger.info("Iniciando pago") # Incluye operation y amount temp_logger.error("Error en pago") # Incluye operation y amount logger.info("Pago finalizado") # NO incluye operation ni amount
logger.debug("Información de depuración") logger.info("Información general") logger.warning("Advertencia") logger.error("Error controlado") logger.critical("Error crítico") logger.exception("Error con stack trace") # Usar dentro de except
trace_id: Identificador único que sigue una operación completa a través de múltiples serviciosrequest_id: Identificador único para una petición HTTP específicaCasos de uso típicos:
# Escenario: Recibir trace_id de otro servicio incoming_trace_id = request.headers.get("X-Trace-ID") incoming_request_id = request.headers.get("X-Request-ID") # Usar IDs existentes with logger.tracing(trace_id=incoming_trace_id, request_id=incoming_request_id) as traced_logger: traced_logger.info("Procesando petición de otro servicio") # Todos los logs tendrán estos IDs específicos
# Generar automáticamente si no se proporcionan with logger.tracing() as traced_logger: traced_logger.info("Nueva operación iniciada") # Se generan automáticamente trace_id y request_id únicos # Obtener los IDs generados para enviar a otros servicios current_trace = traced_logger.get_current_trace_id() current_request = traced_logger.get_current_request_id() # Propagar a servicios downstream headers = traced_logger.get_traceability_headers() # headers = {"X-Trace-ID": "...", "X-Request-ID": "..."}
# Solo trace_id with logger.trace_id("existing-trace-123") as traced_logger: traced_logger.info("Operación con trace específico") # Solo request_id with logger.request_id() as request_logger: # Auto-genera si no se especifica request_logger.info("Petición con ID único") # Combinados with logger.trace_id("trace-abc") as tl: with tl.request_id("request-xyz") as full_logger: full_logger.info("Con ambos IDs específicos")
# Flask from flask import request @app.before_request def setup_request_logging(): trace_id = request.headers.get("X-Trace-ID") request_id = request.headers.get("X-Request-ID") g.logger = logger.tracing(trace_id=trace_id, request_id=request_id).__enter__() # FastAPI from fastapi import Request @app.middleware("http") async def logging_middleware(request: Request, call_next): trace_id = request.headers.get("X-Trace-ID") request_id = request.headers.get("X-Request-ID") with logger.tracing(trace_id=trace_id, request_id=request_id) as request_logger: request.state.logger = request_logger response = await call_next(request) return response
# Servicio A: Enviar petición a Servicio B with logger.tracing() as traced_logger: traced_logger.info("Llamando al servicio de pagos") # Obtener headers para propagación headers = traced_logger.get_traceability_headers() # Hacer petición HTTP con headers de trazabilidad response = requests.post( "https://payment-service/process", json={"amount": 100.50}, headers=headers # {"X-Trace-ID": "...", "X-Request-ID": "..."} ) traced_logger.info("Respuesta del servicio de pagos", status=response.status_code) # Servicio B: Recibir y usar los IDs def process_payment(request): # Extraer IDs del request trace_id = request.headers.get("X-Trace-ID") request_id = request.headers.get("X-Request-ID") # Usar los IDs recibidos with logger.tracing(trace_id=trace_id, request_id=request_id) as payment_logger: payment_logger.info("Procesando pago recibido") # Todos los logs mantendrán la trazabilidad original
def checkout_process(user_id: str, cart_items: list): """Proceso completo de checkout con trazabilidad.""" # Iniciar nueva transacción with logger.tracing() as checkout_logger: checkout_logger.info( "Iniciando checkout", user_id=user_id, items_count=len(cart_items) ) try: # Validar inventario with checkout_logger.context(step="inventory_check") as step_logger: step_logger.info("Verificando inventario") # validate_inventory(cart_items) step_logger.info("Inventario validado") # Procesar pago (enviar a servicio externo) payment_headers = checkout_logger.get_traceability_headers() with checkout_logger.context(step="payment") as payment_logger: payment_logger.info("Procesando pago") # payment_response = call_payment_service(headers=payment_headers) payment_logger.info("Pago procesado exitosamente") # Actualizar inventario with checkout_logger.context(step="inventory_update") as inv_logger: inv_logger.info("Actualizando inventario") # update_inventory(cart_items) inv_logger.info("Inventario actualizado") checkout_logger.info("Checkout completado exitosamente") except Exception as e: checkout_logger.exception("Error en checkout", error_step="unknown") raise
Diseñado con Clean Architecture (Domain-Driven Design):
Copyright © 2024 Sincpro S.R.L. Todos los derechos reservados.