|
| 1 | +--- |
| 2 | +title: Instrumentación |
| 3 | +aliases: [manual] |
| 4 | +weight: 20 |
| 5 | +description: Instrumentación manual para OpenTelemetry Python |
| 6 | +cSpell:ignore: millis ottrace textmap |
| 7 | +default_lang_commit: 9b53527853049b249f60f12a000c0d85b9e5f5dc |
| 8 | +--- |
| 9 | + |
| 10 | +<!-- markdownlint-disable no-duplicate-heading --> |
| 11 | + |
| 12 | +{{% docs/languages/instrumentation-intro %}} |
| 13 | + |
| 14 | +## Configuración |
| 15 | + |
| 16 | +Primero, asegúrate de tener los paquetes API y SDK: |
| 17 | + |
| 18 | +```shell |
| 19 | +pip install opentelemetry-api |
| 20 | +pip install opentelemetry-sdk |
| 21 | +``` |
| 22 | + |
| 23 | +## Trazas |
| 24 | + |
| 25 | +### Adquirir el trazador |
| 26 | + |
| 27 | +Para comenzar a realizar trazas, necesitarás inicializar un |
| 28 | +[`TracerProvider`](/docs/concepts/signals/traces/#tracer-provider) y |
| 29 | +opcionalmente configurarlo como el proveedor global predeterminado. |
| 30 | + |
| 31 | +```python |
| 32 | +from opentelemetry import trace |
| 33 | +from opentelemetry.sdk.trace import TracerProvider |
| 34 | +from opentelemetry.sdk.trace.export import ( |
| 35 | + BatchSpanProcessor, |
| 36 | + ConsoleSpanExporter, |
| 37 | +) |
| 38 | + |
| 39 | +provider = TracerProvider() |
| 40 | +processor = BatchSpanProcessor(ConsoleSpanExporter()) |
| 41 | +provider.add_span_processor(processor) |
| 42 | + |
| 43 | +# Establece el proveedor de tracer global predeterminado |
| 44 | +trace.set_tracer_provider(provider) |
| 45 | + |
| 46 | +# Crea un tracer a partir del proveedor de tracer global |
| 47 | +tracer = trace.get_tracer("my.tracer.name") |
| 48 | +``` |
| 49 | + |
| 50 | +### Crear spans |
| 51 | + |
| 52 | +Para crear un [span](/docs/concepts/signals/traces/#spans), normalmente querrás |
| 53 | +iniciarlo como el span actual. |
| 54 | + |
| 55 | +```python |
| 56 | +def do_work(): |
| 57 | + with tracer.start_as_current_span("span-name") as span: |
| 58 | + # realiza algún trabajo que 'span' rastreará |
| 59 | + print("haciendo algún trabajo...") |
| 60 | + # Cuando el bloque 'with' sale del contexto, 'span' se cierra automáticamente |
| 61 | +``` |
| 62 | + |
| 63 | +También puedes usar `start_span` para crear un span sin hacerlo el span actual. |
| 64 | +Esto se suele hacer para rastrear operaciones concurrentes o asíncronas. |
| 65 | + |
| 66 | +### Crear spans anidados |
| 67 | + |
| 68 | +Si tienes una sub-operación distinta que deseas rastrear como parte de otra, |
| 69 | +puedes crear [spans](/docs/concepts/signals/traces/#spans) para representar la |
| 70 | +relación: |
| 71 | + |
| 72 | +```python |
| 73 | +def do_work(): |
| 74 | + with tracer.start_as_current_span("parent") as parent: |
| 75 | + # realiza algún trabajo que 'parent' rastreará |
| 76 | + print("haciendo algún trabajo...") |
| 77 | + # Crea un span anidado para rastrear el trabajo anidado |
| 78 | + with tracer.start_as_current_span("child") as child: |
| 79 | + # realiza algún trabajo que 'child' rastreará |
| 80 | + print("haciendo trabajo anidado...") |
| 81 | + # el span anidado se cierra cuando sale del contexto |
| 82 | + |
| 83 | + # Este span también se cierra cuando sale del contexto |
| 84 | +``` |
| 85 | + |
| 86 | +Cuando veas spans en una herramienta de visualización de trazas, `child` se |
| 87 | +rastreará como un span anidado bajo `parent`. |
| 88 | + |
| 89 | +### Crear spans con decoradores |
| 90 | + |
| 91 | +Es común que un único [span](/docs/concepts/signals/traces/#spans) rastree la |
| 92 | +ejecución de una función completa. En ese caso, hay un decorador que puedes usar |
| 93 | +para reducir el código: |
| 94 | + |
| 95 | +```python |
| 96 | +@tracer.start_as_current_span("do_work") |
| 97 | +def do_work(): |
| 98 | + print("haciendo algún trabajo...") |
| 99 | +``` |
| 100 | + |
| 101 | +El uso del decorador es equivalente a crear el span dentro de `do_work()` y |
| 102 | +finalizarlo cuando `do_work()` termine. |
| 103 | + |
| 104 | +Para usar el decorador, debes tener una instancia de `tracer` disponible |
| 105 | +globalmente para la declaración de tu función. |
| 106 | + |
| 107 | +### Obtener el span actual |
| 108 | + |
| 109 | +A veces es útil acceder al span actual en un momento dado para poder |
| 110 | +enriquecerlo con más información. |
| 111 | + |
| 112 | +```python |
| 113 | +from opentelemetry import trace |
| 114 | + |
| 115 | +current_span = trace.get_current_span() |
| 116 | +# enriquecer 'current_span' con más información |
| 117 | +``` |
| 118 | + |
| 119 | +### Agregar atributos a un span |
| 120 | + |
| 121 | +Los [atributos](/docs/concepts/signals/traces/#attributes) te permiten adjuntar |
| 122 | +pares clave/valor a un [span](/docs/concepts/signals/traces/#spans) para que |
| 123 | +contenga más información sobre la operación actual que está rastreando. |
| 124 | + |
| 125 | +```python |
| 126 | +from opentelemetry import trace |
| 127 | + |
| 128 | +current_span = trace.get_current_span() |
| 129 | + |
| 130 | +current_span.set_attribute("operation.value", 1) |
| 131 | +current_span.set_attribute("operation.name", "¡Diciendo hola!") |
| 132 | +current_span.set_attribute("operation.other-stuff", [1, 2, 3]) |
| 133 | +``` |
| 134 | + |
| 135 | +### Agregar atributos semánticos |
| 136 | + |
| 137 | +Los [atributos semánticos](/docs/specs/semconv/general/trace/) son |
| 138 | +[atributos](/docs/concepts/signals/traces/#attributes) predefinidos que son |
| 139 | +convenciones de nombres bien conocidas para tipos comunes de datos. Usar |
| 140 | +atributos semánticos te permite normalizar este tipo de información en tus |
| 141 | +sistemas. |
| 142 | + |
| 143 | +Para usar los atributos semánticos en Python, asegúrate de tener instalado el |
| 144 | +paquete de convenciones semánticas: |
| 145 | + |
| 146 | +```shell |
| 147 | +pip install opentelemetry-semantic-conventions |
| 148 | +``` |
| 149 | + |
| 150 | +Luego puedes usarlos en el código: |
| 151 | + |
| 152 | +```python |
| 153 | +from opentelemetry import trace |
| 154 | +from opentelemetry.semconv.trace import SpanAttributes |
| 155 | + |
| 156 | +// ... |
| 157 | + |
| 158 | +current_span = trace.get_current_span() |
| 159 | +current_span.set_attribute(SpanAttributes.HTTP_METHOD, "GET") |
| 160 | +current_span.set_attribute(SpanAttributes.HTTP_URL, "https://opentelemetry.io/") |
| 161 | +``` |
| 162 | + |
| 163 | +### Agregar eventos |
| 164 | + |
| 165 | +Un [evento](/docs/concepts/signals/traces/#span-events) es un mensaje legible en |
| 166 | +un [span](/docs/concepts/signals/traces/#spans) que representa "algo que sucede" |
| 167 | +durante su vida útil. Puedes pensarlo como un registro o log primitivo. |
| 168 | + |
| 169 | +```python |
| 170 | +from opentelemetry import trace |
| 171 | + |
| 172 | +current_span = trace.get_current_span() |
| 173 | + |
| 174 | +current_span.add_event("¡Voy a intentarlo!") |
| 175 | + |
| 176 | +# Haz la cosa |
| 177 | + |
| 178 | +current_span.add_event("¡Lo hice!") |
| 179 | +``` |
| 180 | + |
| 181 | +### Agregar enlaces |
| 182 | + |
| 183 | +Un [span](/docs/concepts/signals/traces/#spans) se puede crear con uno o más |
| 184 | +[enlaces](/docs/concepts/signals/traces/#span-links) que lo vinculen causalmente |
| 185 | +con otro span. Un enlace necesita un contexto de span para ser creado. |
| 186 | + |
| 187 | +```python |
| 188 | +from opentelemetry import trace |
| 189 | + |
| 190 | +tracer = trace.get_tracer(__name__) |
| 191 | + |
| 192 | +with tracer.start_as_current_span("span-1"): |
| 193 | + # Hacer algo que 'span-1' rastrea. |
| 194 | + ctx = trace.get_current_span().get_span_context() |
| 195 | + link_from_span_1 = trace.Link(ctx) |
| 196 | + |
| 197 | +with tracer.start_as_current_span("span-2", links=[link_from_span_1]): |
| 198 | + # Hacer algo que 'span-2' rastrea. |
| 199 | + # El enlace en 'span-2' está causalmente asociado con 'span-1', |
| 200 | + # pero no es un span hijo. |
| 201 | + pass |
| 202 | +``` |
| 203 | + |
| 204 | +### Establecer el estado del span |
| 205 | + |
| 206 | +{{% docs/languages/span-status-preamble %}} |
| 207 | + |
| 208 | +```python |
| 209 | +from opentelemetry import trace |
| 210 | +from opentelemetry.trace import Status, StatusCode |
| 211 | + |
| 212 | +current_span = trace.get_current_span() |
| 213 | + |
| 214 | +try: |
| 215 | + # algo que podría fallar |
| 216 | +except: |
| 217 | + current_span.set_status(Status(StatusCode.ERROR)) |
| 218 | +``` |
| 219 | + |
| 220 | +### Registrar excepciones en spans |
| 221 | + |
| 222 | +Puede ser una buena idea registrar excepciones cuando ocurren. Se recomienda |
| 223 | +hacerlo a la vez que se establece el |
| 224 | +[estado del span](#establecer-el-estado-del-span). |
| 225 | + |
| 226 | +```python |
| 227 | +from opentelemetry import trace |
| 228 | +from opentelemetry.trace import Status, StatusCode |
| 229 | + |
| 230 | +current_span = trace.get_current_span() |
| 231 | + |
| 232 | +try: |
| 233 | + # algo que podría fallar |
| 234 | + |
| 235 | +# Considera capturar una excepción más específica en tu código |
| 236 | +except Exception as ex: |
| 237 | + current_span.set_status(Status(StatusCode.ERROR)) |
| 238 | + current_span.record_exception(ex) |
| 239 | +``` |
| 240 | + |
| 241 | +### Cambiar el formato de propagación predeterminado |
| 242 | + |
| 243 | +Por defecto, OpenTelemetry Python usa los siguientes formatos de propagación: |
| 244 | + |
| 245 | +- W3C Trace Context |
| 246 | +- W3C Baggage |
| 247 | + |
| 248 | +Si necesitas cambiar los valores predeterminados, puedes hacerlo a través de |
| 249 | +variables de entorno o en el código. |
| 250 | + |
| 251 | +#### Usando variables de entorno |
| 252 | + |
| 253 | +Puedes establecer la variable de entorno `OTEL_PROPAGATORS` con una lista |
| 254 | +separada por comas. Los valores aceptados son: |
| 255 | + |
| 256 | +- `"tracecontext"`: W3C Trace Context |
| 257 | +- `"baggage"`: W3C Baggage |
| 258 | +- `"b3"`: B3 Single |
| 259 | +- `"b3multi"`: B3 Multi |
| 260 | +- `"jaeger"`: Jaeger |
| 261 | +- `"xray"`: AWS X-Ray (tercero) |
| 262 | +- `"ottrace"`: OT Trace (tercero) |
| 263 | +- `"none"`: Sin propagador configurado automáticamente. |
| 264 | + |
| 265 | +La configuración predeterminada es equivalente a |
| 266 | +`OTEL_PROPAGATORS="tracecontext,baggage"`. |
| 267 | + |
| 268 | +#### Usando APIs del SDK |
| 269 | + |
| 270 | +Alternativamente, puedes cambiar el formato en el código. |
| 271 | + |
| 272 | +Por ejemplo, si necesitas usar el formato de propagación B3 de Zipkin, puedes |
| 273 | +instalar el paquete B3: |
| 274 | + |
| 275 | +```shell |
| 276 | +pip install opentelemetry-propagator-b3 |
| 277 | +``` |
| 278 | + |
| 279 | +Luego configura el propagador B3 en tu código de inicialización de trazado: |
| 280 | + |
| 281 | +```python |
| 282 | +from opentelemetry.propagate import set_global_textmap |
| 283 | +from opentelemetry.propagators.b3 import B3Format |
| 284 | + |
| 285 | +set_global_textmap(B3Format()) |
| 286 | +``` |
| 287 | + |
| 288 | +Nota que las variables de entorno anularán lo que esté configurado en el código. |
| 289 | + |
| 290 | +### Lectura adicional |
| 291 | + |
| 292 | +- [Conceptos de Trazas](/docs/concepts/signals/traces/) |
| 293 | +- [Especificación de Trazas](/docs/specs/otel/overview/#tracing-signal) |
| 294 | +- [Documentación de la API de Trazas de Python](https://opentelemetry-python.readthedocs.io/en/latest/api/trace.html) |
| 295 | +- [Documentación del SDK de Trazas de Python](https://opentelemetry-python.readthedocs.io/en/latest/sdk/trace.html) |
| 296 | + |
| 297 | +## Métricas |
| 298 | + |
| 299 | +Para comenzar a recopilar métricas, necesitarás inicializar un |
| 300 | +[`MeterProvider`](/docs/specs/otel/metrics/api/#meterprovider) y opcionalmente |
| 301 | +configurarlo como el proveedor global predeterminado. |
| 302 | + |
| 303 | +```python |
| 304 | +from opentelemetry import metrics |
| 305 | +from opentelemetry.sdk.metrics import MeterProvider |
| 306 | +from opentelemetry.sdk.metrics.export import ( |
| 307 | + ConsoleMetricExporter, |
| 308 | + PeriodicExportingMetricReader, |
| 309 | +) |
| 310 | + |
| 311 | +metric_reader = PeriodicExportingMetricReader(ConsoleMetricExporter()) |
| 312 | +provider = MeterProvider(metric_readers=[metric_reader]) |
| 313 | + |
| 314 | +# Establece el proveedor de medidores global predeterminado |
| 315 | +metrics.set_meter_provider(provider) |
| 316 | + |
| 317 | +# Crea un medidor a partir del proveedor de medidores global |
| 318 | +meter = metrics.get_meter("my.meter.name") |
| 319 | +``` |
| 320 | + |
| 321 | +### Crear y usar instrumentos síncronos |
| 322 | + |
| 323 | +Los instrumentos se utilizan para realizar mediciones de tu aplicación. |
| 324 | +[Los instrumentos síncronos](/docs/specs/otel/metrics/api/#synchronous-and-asynchronous-instruments) |
| 325 | +se usan en línea con la lógica de procesamiento de aplicaciones/negocios, como |
| 326 | +cuando se maneja una solicitud o se llama a otro servicio. |
| 327 | + |
| 328 | +Primero, crea tu instrumento. Los instrumentos generalmente se crean una vez al |
| 329 | +nivel del módulo o clase y luego se utilizan en línea con la lógica del negocio. |
| 330 | +Este ejemplo utiliza un [contador](/docs/specs/otel/metrics/api/#counter) para |
| 331 | +contar la cantidad de tareas de trabajo completadas: |
| 332 | + |
| 333 | +```python |
| 334 | +work_counter = meter.create_counter( |
| 335 | + "work.counter", unit="1", description="Cuenta la cantidad de trabajo realizado" |
| 336 | +) |
| 337 | +``` |
| 338 | + |
| 339 | +Usando la [operación de agregado](/docs/specs/otel/metrics/api/#add) del |
| 340 | +contador, el código a continuación incrementa el conteo en uno, utilizando el |
| 341 | +tipo de elemento de trabajo como un atributo. |
| 342 | + |
| 343 | +```python |
| 344 | +def do_work(work_item): |
| 345 | + # contar el trabajo que se está realizando |
| 346 | + work_counter.add(1, {"work.type": work_item.work_type}) |
| 347 | + print("haciendo algún trabajo...") |
| 348 | +``` |
| 349 | + |
| 350 | +### Crear y usar instrumentos asíncronos |
| 351 | + |
| 352 | +[Los instrumentos asíncronos](/docs/specs/otel/metrics/api/#synchronous-and-asynchronous-instruments) |
| 353 | +permiten al usuario registrar funciones de devolución de llamada (_callbacks_), |
| 354 | +que se invocan cuando sea necesario para realizar mediciones. Esto es útil para |
| 355 | +medir periódicamente un valor que no se puede instrumentar directamente. Los |
| 356 | +instrumentos asíncronos se crean con una o más callbacks que serán invocadas |
| 357 | +durante la recopilación de métricas. Cada callback acepta opciones del SDK y |
| 358 | +devuelve sus observaciones. |
| 359 | + |
| 360 | +Este ejemplo usa un |
| 361 | +[medidor asíncrono (_gauge_)](/docs/specs/otel/metrics/api/#asynchronous-gauge) |
| 362 | +para reportar la versión actual de la configuración proporcionada por un |
| 363 | +servidor de configuración al hacer scraping de un endpoint HTTP. Primero, |
| 364 | +escribe una callback para hacer observaciones: |
| 365 | + |
| 366 | +```python |
| 367 | +from typing import Iterable |
| 368 | +from opentelemetry.metrics import CallbackOptions, Observation |
| 369 | + |
| 370 | + |
| 371 | +def scrape_config_versions(options: CallbackOptions) -> Iterable[Observation]: |
| 372 | + r = requests.get( |
| 373 | + "http://configserver/version_metadata", timeout=options.timeout_millis / 10**3 |
| 374 | + ) |
| 375 | + for metadata in r.json(): |
| 376 | + yield Observation( |
| 377 | + metadata["version_num"], {"config.name": metadata["version_num"]} |
| 378 | + ) |
| 379 | +``` |
| 380 | + |
| 381 | +Nota que OpenTelemetry pasará opciones a tu callback que contienen un tiempo de |
| 382 | +espera. Las callbacks deben respetar este tiempo de espera para evitar |
| 383 | +bloquearse indefinidamente. Finalmente, crea el instrumento con la callback para |
| 384 | +registrarlo: |
| 385 | + |
| 386 | +```python |
| 387 | +meter.create_observable_gauge( |
| 388 | + "config.version", |
| 389 | + callbacks=[scrape_config_versions], |
| 390 | + description="La versión activa de la configuración para cada configuración", |
| 391 | +) |
| 392 | +``` |
| 393 | + |
| 394 | +### Lectura adicional |
| 395 | + |
| 396 | +- [Conceptos de métricas](/docs/concepts/signals/metrics/) |
| 397 | +- [Especificación de métricas](/docs/specs/otel/metrics/) |
| 398 | +- [Documentación de la API de métricas en Python](https://opentelemetry-python.readthedocs.io/en/latest/api/metrics.html) |
| 399 | +- [Documentación del SDK de métricas en Python](https://opentelemetry-python.readthedocs.io/en/latest/sdk/metrics.html) |
| 400 | + |
| 401 | +## Logs |
| 402 | + |
| 403 | +La API y SDK de logs están actualmente en desarrollo. |
| 404 | + |
| 405 | +## Próximos pasos |
| 406 | + |
| 407 | +Tal vez quieras configurar un exportador adecuado para |
| 408 | +[exportar tus datos de telemetría](/docs/languages/python/exporters) a uno o más |
| 409 | +backends de telemetría. |
0 commit comments