1. Introducción

Última actualización: 05/03/2021
Observabilidad de la aplicación
Observabilidad y OpenTelemetry
Observabilidad es el término que se usa para describir un atributo de un sistema. Un sistema con observabilidad permite a los equipos depurar de forma activa su sistema. En ese contexto, los tres pilares de la observabilidad (registros, métricas y registros de seguimiento) son la instrumentación fundamental para que el sistema adquiera observabilidad.
OpenTelemetry es un conjunto de especificaciones y SDKs que aceleran la instrumentación y la exportación de datos de telemetría (registros, métricas y seguimientos) que requiere la observabilidad. OpenTelemetry es un estándar abierto y un proyecto impulsado por la comunidad bajo la CNCF. Al utilizar las bibliotecas que proporcionan el proyecto y su ecosistema, los desarrolladores pueden instrumentar sus aplicaciones de forma independiente del proveedor y en varias arquitecturas.
Registro de seguimiento distribuido
Entre los registros, las métricas y los registros de seguimiento, el registro de seguimiento es la telemetría que indica la latencia de una parte específica del proceso en el sistema. Especialmente en la era de los microservicios, el seguimiento distribuido es el principal factor para detectar los cuellos de botella de latencia en el sistema distribuido general.
Cuando se analizan los registros distribuidos, la visualización de los datos de registro es clave para comprender las latencias generales del sistema de un vistazo. En el registro de seguimiento distribuido, controlamos un conjunto de llamadas para procesar una sola solicitud al punto de entrada del sistema en forma de registro de seguimiento que contiene varios intervalos.
Un tramo representa una unidad de trabajo individual realizada en un sistema distribuido, y registra las horas de inicio y finalización. Los tramos suelen tener relaciones jerárquicas entre sí. En la siguiente imagen, todos los tramos más pequeños son tramos secundarios de un tramo /messages grande y se ensamblan en un solo registro de seguimiento que muestra la ruta de trabajo a través de un sistema.

Google Cloud Trace es una de las opciones para el backend de seguimiento distribuido y está bien integrado con otros productos de Google Cloud.
Qué compilarás
En este codelab, instrumentarás la información de seguimiento en los servicios llamados "Shakesapp" que se ejecutan en un clúster de Kubernetes que se ejecuta en Google Kubernetes Engine. La arquitectura de Shakesapp es la que se describe a continuación:

- Los clientes envían una cadena de consulta al servidor.
- El servidor acepta la consulta del cliente, recupera todas las obras de Shakespeare en formato de texto de Google Cloud Storage, busca las líneas que contienen la consulta y devuelve al cliente el número de la línea que coincidió.
Instrumentarás la información de seguimiento en toda la solicitud.
Qué aprenderás
- Cómo comenzar a usar las bibliotecas de OpenTelemetry Trace en un proyecto de Python
- Cómo crear un intervalo con la biblioteca
- Cómo propagar contextos de intervalo a través de la red entre componentes de la app
- Cómo enviar datos de seguimiento a Google Cloud Trace
- Cómo analizar el registro en Cloud Trace de Google Cloud
En este codelab, se explica cómo instrumentar tus microservicios. Para que sea fácil de entender, este ejemplo solo contiene 3 componentes (generador de carga, cliente y servidor), pero puedes aplicar el mismo proceso que se explica en este codelab a sistemas más complejos y grandes.
Requisitos
- Conocimiento de Python 3
2. Configuración y requisitos
Configuración del entorno de autoaprendizaje
Si aún no tienes una Cuenta de Google (Gmail o Google Apps), debes crear una. Accede a Google Cloud Platform Console (console.cloud.google.com) y crea un proyecto nuevo.
Si ya tienes un proyecto, haz clic en el menú desplegable de selección de proyectos en la parte superior izquierda de la Console:

y haz clic en el botón “PROYECTO NUEVO” en el diálogo resultante para crear un proyecto nuevo:

Si aún no tienes un proyecto, deberías ver un cuadro de diálogo como este para crear el primero:

El cuadro de diálogo de creación posterior del proyecto te permite ingresar los detalles de tu proyecto nuevo:

Recuerda el ID del proyecto, que es un nombre único en todos los proyectos de Google Cloud (el nombre anterior ya se encuentra en uso y no lo podrá usar). Se hará referencia a él más adelante en este codelab como PROJECT_ID.
A continuación, si aún no lo has hecho, deberás habilitar la facturación en Developers Console para usar los recursos de Google Cloud y habilitar la API de Cloud Trace.

Ejecutar este codelab debería costar solo unos pocos dólares, pero su costo podría aumentar si decides usar más recursos o si los dejas en ejecución (consulta la sección “Limpiar” al final de este documento). Los precios de Google Cloud Trace, Google Kubernetes Engine y Google Artifact Registry se indican en la documentación oficial.
- Precios de Google Cloud Observability
- Precios | Documentación de Kubernetes Engine
- Precios de Artifact Registry | Documentación de Artifact Registry
Los usuarios nuevos de Google Cloud Platform están aptas para obtener una prueba gratuita de $300, por lo que este codelab es completamente gratuito.
Configuración de Google Cloud Shell
Si bien Google Cloud y Google Cloud Trace se pueden operar de manera remota desde tu laptop, en este codelab usaremos Google Cloud Shell, un entorno de línea de comandos que se ejecuta en la nube.
Esta máquina virtual basada en Debian está cargada con todas las herramientas de desarrollo que necesitarás. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Esto significa que todo lo que necesitarás para este Codelab es un navegador (sí, funciona en una Chromebook).
Para activar Cloud Shell desde la consola de Cloud, solo haz clic en Activar Cloud Shell
(el aprovisionamiento y la conexión al entorno debería llevar solo unos minutos).


Una vez conectado a Cloud Shell, debería ver que ya se autenticó y que el proyecto ya se configuró con tu PROJECT_ID:
gcloud auth list
Resultado del comando
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Resultado del comando
[core] project = <PROJECT_ID>
Si, por algún motivo, el proyecto no está configurado, solo emite el siguiente comando:
gcloud config set project <PROJECT_ID>
Si no conoce su PROJECT_ID, Observa el ID que usaste en los pasos de configuración o búscalo en el panel de la consola de Cloud:

Cloud Shell también configura algunas variables de entorno de forma predeterminada, lo que puede resultar útil cuando ejecutas comandos futuros.
echo $GOOGLE_CLOUD_PROJECT
Resultado del comando
<PROJECT_ID>
Establece la zona predeterminada y la configuración del proyecto.
gcloud config set compute/zone us-central1-f
Puedes elegir una variedad de zonas diferentes. Para obtener más información, consulta Regiones y zonas.
Configuración de Python
En este codelab, usamos "poetry" para administrar las versiones de los paquetes de forma estricta. Ejecuta el siguiente comando en Cloud Shell:
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - source $HOME/.poetry/env
Configura un clúster de Google Kubernetes
En este codelab, ejecutarás un clúster de microservicios en Google Kubernetes Engine (GKE). El proceso de este codelab es el siguiente:
- Descarga el proyecto de referencia en Cloud Shell
- Compila microservicios en contenedores
- Sube contenedores a Google Artifact Registry (GAR).
- Implementa contenedores en GKE
- Modifica el código fuente de los servicios para la instrumentación de seguimiento
- Ir al paso 2
Habilita Kubernetes Engine
Primero, configuramos un clúster de Kubernetes en el que se ejecuta Shakesapp en GKE, por lo que debemos habilitar GKE. Navega al menú "Kubernetes Engine" y presiona el botón HABILITAR.

Ya puedes crear un clúster de Kubernetes.
Crea un clúster de Kubernetes
En Cloud Shell, ejecuta el siguiente comando para crear un clúster de Kubernetes. Confirma que el valor de la zona esté dentro de la región que usaste para crear el repositorio de Artifact Registry. Cambia el valor de la zona us-central1-f si la región de tu repositorio no abarca la zona.
gcloud container clusters create otel-trace-codelab --zone us-central1-f \ --num-nodes 1 \ --machine-type e2-highcpu-4
Resultado del comando
Creating cluster otel-trace-codelab in us-central1-f... Cluster is being health-checked (master is healthy)...done. Created [https://container.googleapis.com/v1/projects/psychic-order-307806/zones/us-central1-f/clusters/otel-trace-codelab]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab?project=psychic-order-307806 kubeconfig entry generated for otel-trace-codelab. NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS otel-trace-codelab us-central1-f 1.18.12-gke.1210 104.154.162.176 e2-medium 1.18.12-gke.1210 3 RUNNING
Configuración de Artifact Registry y Skaffold
Ahora tenemos un clúster de Kubernetes listo para la implementación. A continuación, preparamos un registro de contenedores para enviar e implementar contenedores. Para estos pasos, debemos configurar GAR y Skaffold para que lo usen.
Configuración de Artifact Registry
Navega al menú de "Artifact Registry" y presiona el botón HABILITAR.

Después de unos instantes, verás el navegador de repositorios de GAR. Haz clic en el botón "CREATE REPOSITORY" y, luego, ingresa el nombre del repositorio.

En este codelab, llamo al nuevo repositorio trace-codelab. El formato del artefacto es "Docker" y el tipo de ubicación es "Región". Elige la región cercana a la que configuraste para la zona predeterminada de Google Compute Engine. Por ejemplo, en el ejemplo anterior, se eligió "us-central1-f", por lo que aquí elegimos "us-central1 (Iowa)". Luego, haz clic en el botón "CREAR".

Ahora verás "trace-codelab" en el navegador de repositorios.

Volveremos aquí más tarde para verificar la ruta del registro.
Configuración de Skaffold
Skaffold es una herramienta útil cuando trabajas en la compilación de microservicios que se ejecutan en Kubernetes. Controla el flujo de trabajo de compilación, envío e implementación de contenedores de aplicaciones con un pequeño conjunto de comandos. De forma predeterminada, Skaffold usa Docker Registry como registro de contenedores, por lo que debes configurar Skaffold para que reconozca GAR cuando envíes contenedores.
Abre Cloud Shell nuevamente y confirma si Skaffold está instalado. (Cloud Shell instala Skaffold en el entorno de forma predeterminada). Ejecuta el siguiente comando y observa la versión de Skaffold.
skaffold version
Resultado del comando
v1.20.0
Ahora puedes registrar el repositorio predeterminado para que lo use Skaffold. Para obtener la ruta de acceso del registro, navega al panel de Artifact Registry y haz clic en el nombre del repositorio que acabas de configurar en el paso anterior.

Luego, verás rutas de navegación en la parte superior de la página. Haz clic en el ícono de
para copiar la ruta de registro en el portapapeles.

Cuando haces clic en el botón de copiar, ves el diálogo en la parte inferior del navegador con el siguiente mensaje:
Se copió "us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab"
Regresa a Cloud Shell. Ejecuta el comando skaffold config set default-repo con el valor que acabas de copiar del panel.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
Resultado del comando
set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox
Además, debes configurar el registro en la configuración de Docker. Ejecuta el siguiente comando:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Resultado del comando
{
"credHelpers": {
"gcr.io": "gcloud",
"us.gcr.io": "gcloud",
"eu.gcr.io": "gcloud",
"asia.gcr.io": "gcloud",
"staging-k8s.gcr.io": "gcloud",
"marketplace.gcr.io": "gcloud",
"us-central1-docker.pkg.dev": "gcloud"
}
}
Adding credentials for: us-central1-docker.pkg.dev
Ahora puedes continuar con el siguiente paso para configurar un contenedor de Kubernetes en GKE.
Resumen
En este paso, configurarás tu entorno de codelab:
- Configura Cloud Shell
- Creaste un repositorio de Artifact Registry para el registro de contenedores.
- Configura Skaffold para usar el registro de contenedores
- Creaste un clúster de Kubernetes en el que se ejecutan los microservicios del codelab
Cuál es el próximo paso
En el siguiente paso, compilarás, enviarás e implementarás tus microservicios en el clúster.
3. Compila, envía e implementa los microservicios
Descarga el material del codelab
En el paso anterior, configuramos todos los requisitos previos para este codelab. Ahora puedes ejecutar microservicios completos sobre ellos. El material del codelab está alojado en GitHub, por lo que debes descargarlo en el entorno de Cloud Shell con el siguiente comando de git.
cd ~ git clone https://github.com/GoogleCloudPlatform/opentelemetry-trace-codelab-python.git
La estructura de directorios del proyecto es la siguiente:
shakesapp-python
├── LICENSE
├── manifests
│ ├── client.yaml
│ ├── loadgen.yaml
│ └── server.yaml
├── proto
│ └── shakesapp.proto
├── skaffold.yaml
└── src
├── client
├── loadgen
└── server
- manifiestos: Archivos de manifiesto de Kubernetes
- proto: Definición de .proto para la comunicación entre el cliente y el servidor
- src: directorios para el código fuente de cada servicio
- skaffold.yaml: Archivo de configuración de Skaffold
Ejecuta el comando skaffold
Por último, ya puedes compilar, enviar e implementar todo el contenido en el clúster de Kubernetes que acabas de crear. Esto parece contener varios pasos, pero, en realidad, Skaffold lo hace todo por ti. Probemos con el siguiente comando:
cd shakesapp-python skaffold run --tail
En cuanto ejecutes el comando, verás el resultado del registro de docker build y podrás confirmar que se enviaron correctamente al registro.
Resultado del comando
... ---> Running in c39b3ea8692b ---> 90932a583ab6 Successfully built 90932a583ab6 Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1 The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice] cc8f5a05df4a: Preparing 5bf719419ee2: Preparing 2901929ad341: Preparing 88d9943798ba: Preparing b0fdf826a39a: Preparing 3c9c1e0b1647: Preparing f3427ce9393d: Preparing 14a1ca976738: Preparing f3427ce9393d: Waiting 14a1ca976738: Waiting 3c9c1e0b1647: Waiting b0fdf826a39a: Layer already exists 88d9943798ba: Layer already exists f3427ce9393d: Layer already exists 3c9c1e0b1647: Layer already exists 14a1ca976738: Layer already exists 2901929ad341: Pushed 5bf719419ee2: Pushed cc8f5a05df4a: Pushed step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001
Después de la inserción de todos los contenedores de servicio, las implementaciones de Kubernetes se inician automáticamente.
Resultado del comando
sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997 Tags used in deployment: - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a Starting deploy... - deployment.apps/clientservice created - service/clientservice created - deployment.apps/loadgen created - deployment.apps/serverservice created - service/serverservice created
Precaución: Si recibes un error como "No push access to specified image repository", verifica si el comando de Skaffold intenta enviar imágenes a Docker Hub (docker.io) independientemente de tu configuración en el repo predeterminado en Skaffold. En ese caso, intenta agregar la opción "–default-repo" a "skaffold run" como se muestra a continuación.
$ skaffold run –tail –default-repo=us-central1-docker.pkg.dev/[ID del proyecto]/[nombre del repositorio]
Después de la implementación, verás los registros reales de la aplicación emitidos en stdout en cada contenedor de la siguiente manera:
Resultado del comando
[server] {"event": "starting server: 0.0.0.0:5050", "severity": "info", "timestamp": "2021-03-17T05:25:56.758575Z"}
[client] [2021-03-17 05:25:54 +0000] [1] [INFO] Starting gunicorn 20.0.4
[client] [2021-03-17 05:25:54 +0000] [1] [INFO] Listening at: http://0.0.0.0:8080 (1)
[client] [2021-03-17 05:25:54 +0000] [1] [INFO] Using worker: threads
[client] [2021-03-17 05:25:54 +0000] [7] [INFO] Booting worker with pid: 7
[client] {"event": "server address is serverservice:5050", "severity": "info", "timestamp": "2021-03-17T05:25:54.888627Z"}
[client] {"event": "request to server with query: world", "severity": "info", "timestamp": "2021-03-17T05:26:11.550923Z"}
[server] {"event": "query: world", "severity": "info", "timestamp": "2021-03-17T05:26:11.567048Z"}
[loadgen] {"event": "check connectivity: http://clientservice:8080/_healthz", "severity": "info", "timestamp": "2021-03-17T05:26:11.533605Z"}
[loadgen] {"event": "/_healthz response: ok", "severity": "info", "timestamp": "2021-03-17T05:26:11.544267Z"}
[loadgen] {"event": "confirmed connection ot clientservice", "severity": "info", "timestamp": "2021-03-17T05:26:11.544527Z"}
Por último, ya puedes comenzar a instrumentar tu aplicación con OpenTelemetry para el seguimiento distribuido de los servicios.
Resumen
En este paso, preparaste el material del codelab en tu entorno y confirmaste que Skaffold se ejecuta según lo previsto.
Cuál es el próximo paso
En el siguiente paso, modificarás el código fuente del servicio de loadgen para instrumentar la información de seguimiento.
4. Instrumentación para HTTP
Concepto de instrumentación y propagación de registros
Antes de editar el código fuente, permítanme explicar brevemente cómo funcionan los registros distribuidos en un diagrama simple.

En este ejemplo, instrumentamos el código para exportar información de Trace y Span a Cloud Trace, y propagar el contexto de seguimiento en la solicitud desde el servicio de loadgen al servicio de servidor.
La aplicación debe enviar metadatos de Trace, como el ID de Trace y el ID de Span, para que Cloud Trace pueda ensamblar todos los intervalos que tienen el mismo ID de Trace en un solo registro de seguimiento. Además, la aplicación debe propagar los contextos de seguimiento (la combinación del ID de seguimiento y el ID del intervalo principal) cuando solicita servicios downstream, de modo que estos puedan saber qué contexto de seguimiento están controlando.
OpenTelemetry te ayuda a hacer lo siguiente:
- Generar un ID de seguimiento y un ID de intervalo únicos
- Exportar el ID de seguimiento y el ID de tramo al backend
- para propagar contextos de seguimiento a otros servicios
Instrumenta el primer intervalo
Instrumenta el servicio del generador de carga
Presiona el botón
en la parte superior derecha de Cloud Shell para abrir el editor de Cloud Shell. Abre src/loadgen/loadgen.py desde el explorador en el panel izquierdo y busca la función main.
src/loadgen/loadgen.py
def main():
...
# start request loop to client service
logger.info("start client request loop")
addr = f"http://{target}"
while True:
logger.info("start request to client")
call_client(addr)
logger.info("end request to client")
time.sleep(2.0)
En la función main, verás el bucle que llama a la función call_client. En la implementación actual, la sección tiene 2 líneas de registro que registran el inicio y el final de la llamada a la función. Ahora, instrumentemos la información del intervalo para hacer un seguimiento de la latencia de la llamada a la función.
Primero, debes crear un intervalo con un ID de seguimiento y un ID de intervalo únicos. OpenTelemetry proporciona una biblioteca útil para ello. Agrega las siguientes líneas para importar las bibliotecas de OpenTelemetry a tu código.
import structlog
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.instrumentation.requests import RequestsInstrumentor
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
Dado que el generador de carga llama a la aplicación cliente en HTTP a través del módulo requests, usamos el paquete de extensión para requests y habilitamos la instrumentación.
from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
+
+RequestsInstrumentor().instrument()
Luego, configura la instancia de Tracer que controla la configuración del contexto y el exportador de Trace.
target = os.environ.get("CLIENT_ADDR", "0.0.0.0:8080")
+ exporter = CloudTraceSpanExporter()
+ trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(exporter))
+ tracer = trace.get_tracer(__name__)
+ propagate.set_global_textmap(CloudTraceFormatPropagator())
+ trace.set_tracer_provider(TracerProvider())
+
# connectivity check to client service
healthz = f"http://{target}/_healthz"
logger.info(f"check connectivity: {healthz}")
Ten en cuenta que, como este es un codelab para comprender cómo funciona la instrumentación de seguimiento, configuramos el objeto Tracer para que registre cada solicitud y la envíe al backend. (SimpleSpanProcessor()) Esto no es adecuado para los entornos de producción, así que asegúrate de cambiar esta parte cuando instrumentes tu aplicación de producción.
Ahora puedes instrumentar intervalos con el objeto Tracer. El punto aquí es que lo que necesitas hacer es generar un Span de forma explícita, y eso es todo. Si bien hay dos líneas que agregan metadatos de eventos a Span, no es necesario que generes manualmente un ID de seguimiento y un ID de Span únicos, ni que los incorpores a Span.
logger.info("start client request loop")
addr = f"http://{target}"
while True:
- logger.info("start request to client")
- call_client(addr)
- logger.info("end request to client")
+ with tracer.start_as_current_span("loadgen") as root_span:
+ root_span.add_event(name="request_start")
+ logger.info("start request to client")
+ call_client(addr)
+ root_span.add_event(name="request_end")
+ logger.info("end request to client")
time.sleep(2.0)
Para que la compilación de Docker recupere los paquetes de OpenTelemetry necesarios, ejecuta el siguiente comando:
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-requests=^0.20b0"
Puedes confirmar que la descripción de la dependencia correspondiente está escrita en pyproject.toml.
Servicio de instrumentos para clientes
En la sección anterior, instrumentamos la parte encerrada en el rectángulo rojo del siguiente dibujo. Se instrumentó la información de intervalos en el servicio del generador de carga. De manera similar al servicio de generador de carga, ahora debemos instrumentar el servicio del cliente. La diferencia con el servicio de generador de carga es que el servicio de cliente debe extraer la información del ID de seguimiento propagada desde el servicio de generador de carga en el encabezado HTTP y usar el ID para generar intervalos.

Abre el editor de Cloud Shell y agrega los módulos necesarios, como lo hicimos para el servicio de generador de carga.
src/client/client.py
import flask
import grpc
import structlog
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.instrumentation.flask import FlaskInstrumentor
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import \
+ CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
Observa que acabas de importar FlaskInstrumentor, que habilita la instrumentación automática para la aplicación de Flask en nombre de los usuarios para extraer encabezados HTTP y obtener contextos de seguimiento con una sola línea de código. La comunidad de OpenTelemetry proporciona integraciones útiles similares con otras bibliotecas importantes. Para obtener más información, consulta la documentación oficial.
app = flask.Flask(__name__)
+FlaskInstrumentor().instrument_app(app)
Antes de comenzar la instrumentación, debes preparar la instancia de Tracer de manera similar a lo que hicimos en el servicio del generador de carga.
logger.info(f"server address is {SERVER_ADDR}")
+exporter = CloudTraceSpanExporter()
+trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(exporter))
+propagate.set_global_textmap(CloudTraceFormatPropagator())
+trace.set_tracer_provider(TracerProvider())
@app.route("/")
def main_handler():
....
Ahora está listo para agregar la instrumentación en el controlador. Busca main_handler() y modifica la parte que arroja la solicitud de gRPC al servicio del servidor.
@app.route("/")
def main_handler():
q, count = random.choice(list(queries.items()))
# get Tracer
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("client") as cur_span:
channel = grpc.insecure_channel(SERVER_ADDR)
stub = shakesapp_pb2_grpc.ShakespeareServiceStub(channel)
logger.info(f"request to server with query: {q}")
cur_span.add_event("server_call_start")
resp = stub.GetMatchCount(shakesapp_pb2.ShakespeareRequest(query=q))
cur_span.add_event("server_call_end")
if count != resp.match_count:
raise UnexpectedResultError(
f"The expected count for '{q}' was {count}, but result was {resp.match_count } obtained"
)
result = str(resp.match_count)
logger.info(f"matched count for '{q}' is {result}")
return result
De manera similar al servicio de generador de carga, agrega los paquetes necesarios a pyproject.toml con el siguiente comando.
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-flask=^0.20b0"
Luego, intenta iniciar la aplicación con el comando skaffold run y observa lo que muestra el panel de Cloud Trace:
skaffold run --tail
Después de ver algunos mensajes de compilación, envío y también de implementación, verás los registros de la aplicación en formato JSON. Navega a Cloud Trace > Lista de seguimientos para verificar si obtienes la información de seguimiento. Dado que el servicio de generador de carga envía solicitudes al servicio del cliente de forma periódica y habilitaste los registros para todas las solicitudes, comenzarás a ver muchos puntos en la lista de registros.

Si haces clic en una de ellas, verás un gráfico de cascada como el que se muestra a continuación, que explica la latencia de cada parte durante el proceso de solicitud y respuesta. Busca la casilla de verificación junto a "Mostrar eventos" y, luego, verás las anotaciones dentro del gráfico de cascada. Estas anotaciones son las que instrumentaste en el código con el método span.add_event().

Es posible que notes que no ves los tramos del servicio del servidor. Es correcta porque no instrumentamos los tramos en el servicio del servidor.
Resumen
En este paso, instrumentaste el servicio del generador de carga y el servicio del cliente, y confirmaste que pudiste propagar correctamente el contexto de seguimiento entre los servicios y exportar la información del intervalo de ambos servicios a Cloud Trace.
Cuál es el próximo paso
En el siguiente paso, instrumentarás el servicio del cliente y el servicio del servidor para confirmar cómo propagar el contexto de seguimiento a través de gRPC.
5. Instrumentación para gRPC
En el paso anterior, instrumentamos la primera mitad de la solicitud en estos microservicios. En este paso, intentaremos instrumentar la comunicación de gRPC entre el servicio del cliente y el servicio del servidor. (Rectángulo verde y violeta en la siguiente imagen)

Instrumentación automática para el cliente de gRPC
El ecosistema de OpenTelemetry ofrece muchas bibliotecas útiles que ayudan a los desarrolladores a instrumentar aplicaciones. En el paso anterior, usamos la instrumentación automática para el módulo "requests". En este paso, como intentamos propagar el contexto de seguimiento a través de gRPC, usamos la biblioteca para ello.
src/client/client.py
import flask
import grpc
import structlog
from opentelemetry import propagate, trace
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
+from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.propagators.cloud_trace_propagator import \
CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
app = flask.Flask(__name__)
FlaskInstrumentor().instrument_app(app)
+GrpcInstrumentorClient().instrument()
En cuanto a la atención al cliente, lo que debemos hacer para la instrumentación es bastante pequeño. Lo que queremos hacer es propagar el contexto de seguimiento, que es la combinación del ID de seguimiento y el ID de intervalo del intervalo actual a través de gRPC. Por lo tanto, llamamos a GrpcInstrumentatorClient.instrument() para que el cliente de gRPC en la función de controlador pueda incorporar el contexto de seguimiento en el encabezado HTTP subyacente.
Asegúrate de agregar dependencias nuevas a pyproject.toml con el comando poetry add:
poetry add "opentelemetry-instrumentation-grpc=^0.20b0"
Instrumentación automática para el servidor de gRPC
Al igual que lo hicimos para el cliente de gRPC, llamamos a la instrumentación automática para el servidor de gRPC. Agrega importaciones como las siguientes y llama a GrpcInstrumentationServer().instrument() en la parte superior del archivo.
Precaución: Asegúrate de llamar
GrpcInstrumentationServe()
en este paso, no
GrpcInstrumentationClient()
.
src/server/server.py
import grpc
import structlog
from google.cloud import storage
from grpc_health.v1 import health_pb2, health_pb2_grpc
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.instrumentation.grpc import GrpcInstrumentorServer
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
BUCKET_NAME = "dataflow-samples"
BUCKET_PREFIX = "shakespeare/"
+# enable auto gRPC server trace instrumentation
+GrpcInstrumentorServer().instrument()
+
A continuación, agregarás el exportador para enviar información de seguimiento al backend de Cloud Trace. Agrega el siguiente código en la función serve().
def serve():
+ # start trace exporter
+ trace.set_tracer_provider(TracerProvider())
+ trace.get_tracer_provider().add_span_processor(
+ SimpleSpanProcessor(CloudTraceSpanExporter())
+ )
+ propagators.set_global_textmap(CloudTraceFormatPropagator())
+
+ # add gRPC services to server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
service = ShakesappService()
shakesapp_pb2_grpc.add_ShakespeareServiceServicer_to_server(service, server)
health_pb2_grpc.add_HealthServicer_to_server(service, server)
Asegúrate de agregar los paquetes recién agregados en el servicio del servidor.
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-instrumentation-grpc=^0.20b0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation=^0.20b0"
Ejecuta el microservicio y confirma el registro
Luego, ejecuta el código modificado con el comando de Skaffold.
skaffold run --tail
Ahora, nuevamente, verás varios registros en la página Lista de registros de Cloud Trace. Haz clic en uno de los registros y verás que abarca la solicitud desde el servicio del generador de carga hasta el servicio del servidor.

Resumen
En este paso, instrumentaste la comunicación basada en gRPC con la ayuda de las bibliotecas del ecosistema de OpenTelemetry. También confirmaste que el contexto de seguimiento generado en el servicio del generador de carga se entregó correctamente al servicio del servidor.
6. Felicitaciones
Creaste correctamente seguimientos distribuidos con OpenTelemetry y confirmaste las latencias de las solicitudes en el microservicio en Cloud Trace de Google Cloud.
En el caso de los ejercicios extendidos, puedes probar los siguientes temas por tu cuenta.
- La implementación actual envía todos los intervalos generados por la verificación de estado. ¿Cómo se filtran esos intervalos de Cloud Trace? La pista está aquí.
- Correlaciona los registros de eventos con los intervalos y observa cómo funciona en Google Cloud Trace y Google Cloud Logging. La pista está aquí.
- Reemplaza algún servicio por uno en otro idioma y trata de instrumentarlo con OpenTelemetry para ese idioma.
Precaución: Google Kubernetes Engine y Google Artifact Registry consumen el recurso de forma constante.
Realiza una limpieza
Después de este codelab, detén el clúster de Kubernetes y asegúrate de borrar el proyecto para que no se te cobren cargos inesperados en Google Kubernetes Engine, Google Cloud Trace ni Google Artifact Registry.
Primero, borra el clúster con el siguiente comando:
skaffold delete
Resultado del comando
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Después de borrar el clúster, en el panel del menú, selecciona "IAM y administración" > "Configuración" y, luego, haz clic en el botón "APAGAR".

Luego, ingresa el ID del proyecto (no el nombre) en el formulario del diálogo y confirma el cierre.