OpenTelemetry estandariza la generación y el transporte de traces y métricas. Los spans representan etapas relacionadas de una operación y permiten localizar latencia y errores entre servicios.
Un trace suele comenzar cuando una petición entra en un servicio y sigue las llamadas a bases de datos, colas y APIs. Cada span tiene tiempos, contexto, atributos y una relación con su padre. Esas relaciones reconstruyen la operación entre procesos. OpenTelemetry define APIs, SDKs, convenciones semánticas y OTLP, pero no almacena ni consulta telemetría. El Collector y el backend de observabilidad cumplen esas funciones.
Distinguir API, SDK, instrumentación y Collector
La API es el contrato que usa el código y las bibliotecas instrumentadas. El SDK implementa muestreo, procesamiento y exportación. Una biblioteca reutilizable debería depender normalmente de la API para que la aplicación decida qué SDK y destino usar. La aplicación configura el SDK una sola vez al arrancar, antes de crear trabajo concurrente.
La instrumentación automática envuelve frameworks y clientes compatibles para crear spans en fronteras habituales. La instrumentación manual añade significado del dominio a las operaciones importantes. Ambas se complementan. Inspecciona los spans automáticos antes de crear otros: duplicar la misma llamada HTTP añade ruido y coste.
El Collector es un servicio separado que recibe telemetría, ejecuta pipelines y exporta a uno o más destinos. Permite mantener credenciales y rutas del backend fuera de las aplicaciones. También puede agrupar, filtrar y controlar memoria. No elimina la responsabilidad de la aplicación de evitar datos sensibles.
Crear un span
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("tienda.pedidos")
def calcular_total(items: list[int]) -> int:
with tracer.start_as_current_span("calcular_total") as span:
span.set_attribute("pedido.cantidad_items", len(items))
return sum(items)
La consola sirve para aprender. En producción, envía OTLP a un Collector y procesa en lotes. No adjuntes correos, tokens ni cuerpos sensibles.
Puedes configurar un exportador OTLP por gRPC:
python -m pip install opentelemetry-exporter-otlp-proto-grpc
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
exporter = OTLPSpanExporter(endpoint="http://collector:4317", insecure=True)
provider.add_span_processor(BatchSpanProcessor(exporter))
Reserva insecure=True para una red local deliberadamente sin TLS, como desarrollo. En producción, autentica el destino, valida certificados y entrega credenciales mediante un mecanismo de secrets. Las variables estándar, como OTEL_EXPORTER_OTLP_ENDPOINT, son preferibles si la configuración cambia entre despliegues.
BatchSpanProcessor exporta fuera del camino de la petición y es apropiado para servicios. SimpleSpanProcessor espera cada exportación, por lo que sirve sobre todo en tests y depuración. Antes de terminar un worker corto, cierra el provider de forma ordenada para dar salida a los lotes pendientes.
Registrar estado, excepciones y eventos
Una operación fallida debe tener estado de error, pero no todo código HTTP alto representa un fallo interno. Sigue las convenciones semánticas correspondientes. En spans manuales, registra excepciones sin adjuntar secretos:
from opentelemetry.trace import Status, StatusCode
with tracer.start_as_current_span("pedido.reservar") as span:
try:
reservar_inventario()
except SinExistencias as error:
span.record_exception(error)
span.set_status(Status(StatusCode.ERROR, "inventario no disponible"))
raise
Los mensajes de excepción pueden incluir valores inesperados. Revisa qué exponen tus excepciones y aplica redacción antes de exportar cuando sea necesario. Los eventos representan sucesos puntuales dentro del span, como un reintento. No conviertas cada línea de log en evento, pues duplicaría volumen sin mejorar el diagnóstico.
Las bibliotecas de instrumentación crean spans para frameworks y clientes. Revisa campos y versiones. Propaga contexto por las fronteras de red; una ContextVar no atraviesa la red sola. Consulta contextvars en Python.
En la red, un propagador inyecta identificadores en cabeceras y el receptor los extrae. W3C Trace Context utiliza traceparent y, opcionalmente, tracestate. Nunca uses el contexto recibido como autorización o identidad: sirve para correlación, no para control de acceso. En fronteras no confiables, limita el baggage porque sus pares adicionales pueden propagarse por muchos servicios.
Las colas necesitan tratamiento explícito. El productor inyecta el contexto en los metadatos del mensaje; el consumidor lo extrae antes de crear su span. Un worker no debe conservar el contexto de una tarea anterior. Para procesamiento por lotes, consulta la convención aplicable y considera links cuando varias entradas independientes contribuyen a la operación.
Diseñar nombres y atributos sostenibles
El nombre describe una operación estable, no una instancia. Prefiere HTTP GET /pedidos/{id} o pedido.procesar a una URL completa o un ID. Los atributos útiles permiten agrupar: método, ruta normalizada, sistema de base de datos o resultado con pocos valores. Los UUID y valores únicos aumentan cardinalidad y coste. Si un identificador es imprescindible, quizá pertenezca a logs correlacionados con acceso restringido.
No adjuntes:
- cabeceras de autorización, cookies ni tokens;
- cuerpos completos de peticiones y respuestas;
- correos, documentos de identidad o direcciones personales;
- consultas SQL con parámetros interpolados;
- nombres de archivo o errores que puedan incluir datos del cliente.
Define y prueba una política de atributos, y añade filtrado defensivo en el Collector. El filtrado posterior reduce exposición en el backend, pero el valor ya atravesó el proceso y la red. La mejor protección es no generarlo.
Equilibrar muestreo, coste y diagnóstico
El muestreo decide qué traces registrar. Un sampler basado en el padre mantiene la decisión recibida y evita traces fragmentados; uno por proporción limita volumen. La decisión inicial no conoce el resultado futuro, por lo que una tasa demasiado baja puede ocultar errores raros. Algunos Collectors y backends permiten muestreo posterior cuando ya conocen más del trace, con coste adicional.
Mide la tasa real, los spans por trace y el tamaño de atributos antes de elegir porcentajes. Mantén una vía controlada para depuración, sin permitir que un cliente externo fuerce muestreo costoso. En tests, usa un exportador en memoria y verifica nombres, relaciones y ausencia de datos prohibidos. No bases las pruebas en IDs aleatorios.
Prepararse para fallos de telemetría
La observabilidad no debe derribar la aplicación. Configura límites de cola y timeouts, vigila spans descartados y decide qué ocurre si el Collector no responde. A la vez, un fallo silencioso deja al equipo ciego. Expón métricas internas del pipeline y alerta ante pérdidas persistentes.
Despliega la instrumentación por etapas. Empieza por una frontera, inspecciona los datos exportados, estima el volumen y comprueba la propagación con una llamada real al servicio siguiente. Crea una búsqueda o vista que responda una pregunta conocida de incidentes. Así confirmas que la señal es útil, no solo que existe. Documenta qué equipo mantiene el pipeline del Collector y cuál define la semántica de spans. Al actualizar paquetes, compara nombres y atributos: un cambio de convenciones puede afectar consultas guardadas, reglas de muestreo y costes aunque la aplicación siga funcionando igual.
Usa nombres estables y atributos con cardinalidad controlada. Combina traces con logs estructurados y métricas.
La documentación oficial de OpenTelemetry Python y la especificación oficial de traces, consultadas el 22 de julio de 2026, explican conceptos, configuración y estado de las señales. Verifica el estado antes de usar APIs experimentales y fija versiones compatibles de la instrumentación.