Cap 2: Conceptos Core
Resource
Un Resource describe la entidad que genera la telemetría. Es un conjunto de atributos que identifican el proceso, el host y el entorno.
# Resource attributes típicos
service.name: "order-service"
service.version: "2.1.0"
service.instance.id: "pod-abc123"
host.name: "worker-node-7"
os.type: "linux"
deployment.environment: "production"
k8s.namespace.name: "payments"
k8s.pod.name: "order-service-7d8f9c"
El Resource se configura una vez al inicializar el SDK y se adjunta automáticamente a todos los traces, métricas y logs del proceso.
from opentelemetry.sdk.resources import Resource
resource = Resource.create({
"service.name": "order-service",
"service.version": "2.1.0",
"deployment.environment": "production",
})
Context y Context Propagation
El Context es el mecanismo que permite pasar información de observabilidad entre funciones y entre servicios — sin modificar las firmas de las funciones.
Context en proceso
Dentro de un proceso, el contexto viaja de forma implícita a través de variables de contexto (thread-local, async context, etc.):
# OTel guarda el span activo en el contexto implícito
with tracer.start_as_current_span("my-span") as span:
# cualquier código aquí puede obtener el span activo
resultado = procesar_pedido() # esta función puede crear sub-spans
# sin pasar nada explícitamente
Context propagation entre servicios
Cuando una request cruza un boundary de red (HTTP, gRPC, mensajes), el contexto se inyecta en los headers y se extrae en el receptor:
sequenceDiagram
participant A as Servicio A
participant B as Servicio B
A->>A: Crear span "checkout"
Note over A: trace_id=abc, span_id=111
A->>B: POST /payment\ntraceparent: 00-abc...-111-01
B->>B: Extraer contexto del header
B->>B: Crear span "process-payment"\n(hijo de span 111)
B-->>A: 200 OK
El header traceparent es parte del estándar W3C Trace Context — el formato que OTel usa por defecto.
Formato: 00-{trace_id}-{parent_span_id}-{flags}
Ejemplo: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
Propagators
OTel soporta múltiples formatos de propagación:
| Propagator | Header | Cuándo usar |
|---|---|---|
| W3C TraceContext | traceparent | Default, sistemas modernos |
| W3C Baggage | baggage | Datos de contexto cross-service |
| B3 (Zipkin) | X-B3-TraceId etc. | Sistemas legacy con Zipkin |
| Jaeger | uber-trace-id | Sistemas legacy con Jaeger |
Baggage
El Baggage permite propagar datos arbitrarios de usuario a través de toda la cadena de servicios. A diferencia del Context de trazas (que es para observabilidad), el Baggage es para datos de negocio.
from opentelemetry import baggage
# Servicio A: agrega datos al baggage
ctx = baggage.set_baggage("user.tier", "premium")
ctx = baggage.set_baggage("request.region", "eu-west-1", context=ctx)
# Servicio B, C, D... reciben automáticamente estos valores
tier = baggage.get_baggage("user.tier") # "premium"
Advertencia: El Baggage viaja en headers HTTP — no pongas datos sensibles ni grandes.
Semantic Conventions
Las Semantic Conventions son el diccionario de nombres de atributos y valores que OTel estandariza. Evitan que cada equipo invente sus propios nombres:
# Sin convenciones semánticas:
http.status → 200
response.code → 200
statusCode → 200
http_status_code → 200
# Con convenciones semánticas (todos usan):
http.response.status_code → 200
Atributos HTTP comunes
http.request.method → "GET", "POST"
http.response.status_code → 200, 404, 500
url.full → "https://api.example.com/users"
url.path → "/users"
server.address → "api.example.com"
server.port → 443
network.protocol.version → "1.1", "2"
Atributos de base de datos
db.system → "postgresql", "mysql", "redis"
db.name → "orders"
db.operation.name → "SELECT", "INSERT"
db.query.text → "SELECT * FROM orders WHERE id = ?"
server.address → "db.internal"
server.port → 5432
Atributos de mensajería
messaging.system → "kafka", "rabbitmq", "sqs"
messaging.destination.name → "orders.created"
messaging.operation.name → "publish", "receive"
messaging.message.id → "msg-abc123"
Instrumentation Scope
Cada señal lleva información de quién la instrumentó:
tracer = trace.get_tracer(
"com.mycompany.myservice", # nombre del scope
"1.0.0", # versión del scope
)
Esto permite filtrar en el backend: “muéstrame solo spans generados por el SDK de HTTP, no los de mi código de negocio.”
La jerarquía de componentes
graph TD
TP[TracerProvider\nMeterProvider\nLoggerProvider] -->|crea| T[Tracer\nMeter\nLogger]
T -->|crea| S[Span\nInstrument\nLogRecord]
S -->|adjunta| R[Resource]
S -->|propaga| C[Context]
TP -->|usa| EXP[Exporter]
TP -->|usa| SAM[Sampler]
TP -->|usa| PROC[Processor]
Provider — Fábrica de instrumentos. Se configura al inicio de la aplicación.
Tracer / Meter / Logger — Instrumentos con nombre. Cada librería o módulo tiene el suyo.
Span / Instrument / LogRecord — Las señales individuales que se generan y exportan.
Sampling
No todos los traces necesitan exportarse — en sistemas de alto tráfico, exportar el 100% sería prohibitivo. El Sampler decide qué traces capturar:
| Sampler | Comportamiento |
|---|---|
AlwaysOn | Captura el 100% de traces |
AlwaysOff | No captura nada |
TraceIdRatioBased(0.1) | Captura el 10% aleatoriamente |
ParentBased | Respeta la decisión del padre (propagada en header) |
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased, ParentBased
# Capturar 10% pero siempre respetar la decisión del upstream
sampler = ParentBased(root=TraceIdRatioBased(0.1))
El sampling ocurre en la cabeza del trace (head-based sampling) o en el Collector (tail-based sampling, más poderoso pero más complejo).