Instrumentar informações de rastreamento usando o OpenTelemetry

1. Introdução

5af4a7e43b0feaab.png

Última atualização:05/03/2021

Observabilidade do aplicativo

Observabilidade e OpenTelemetry

Observabilidade é o termo usado para descrever um atributo de um sistema. Um sistema com observabilidade permite que as equipes depurem ativamente o sistema. Nesse contexto, três pilares da observabilidade (registros, métricas e rastreamentos) são a instrumentação fundamental para que o sistema adquira observabilidade.

O OpenTelemetry é um conjunto de especificações e SDKs que acelera a instrumentação e a exportação de dados de telemetria (registros, métricas e rastreamentos) necessários para a observabilidade. O OpenTelemetry é um padrão aberto e um projeto orientado pela comunidade da CNCF. Ao usar bibliotecas fornecidas pelo projeto e pelo ecossistema dele, os desenvolvedores podem instrumentar os aplicativos de maneira neutra em relação ao fornecedor e em várias arquiteturas.

Rastreamento distribuído

Entre registros, métricas e rastreamentos, o rastreamento é a telemetria que informa a latência de uma parte específica do processo no sistema. Principalmente na era dos microsserviços, o rastreamento distribuído é o principal fator para descobrir gargalos de latência no sistema distribuído geral.

Ao analisar rastreamentos distribuídos, a visualização de dados de rastreamento é fundamental para entender as latências gerais do sistema rapidamente. No rastreamento distribuído, processamos um conjunto de chamadas para processar uma única solicitação ao ponto de entrada do sistema na forma de um rastreamento que contém vários períodos.

Um intervalo representa uma unidade individual de trabalho realizada em um sistema distribuído, registrando horários de início e término. Os intervalos geralmente têm relações hierárquicas entre si. Na imagem abaixo, todos os intervalos menores são intervalos filhos de um intervalo grande /messages e são reunidos em um trace que mostra o caminho do trabalho em um sistema.

adbd3ecd69d410cb.png

O Google Cloud Trace é uma das opções de back-end de rastreamento distribuído e está bem integrado a outros produtos do Google Cloud.

O que você vai criar

Neste codelab, você vai instrumentar informações de rastreamento nos serviços chamados "Shakesapp", que são executados em um cluster do Kubernetes no Google Kubernetes Engine. A arquitetura do Shakesapp é descrita abaixo:

68873c018a7be7de.png

  • Os clientes enviam uma string de consulta ao servidor.
  • O servidor aceita a consulta do cliente, busca todas as obras de Shakespeare em formato de texto no Google Cloud Storage, pesquisa as linhas que contêm a consulta e retorna o número da linha correspondente ao cliente.

Você vai instrumentar as informações de rastreamento em toda a solicitação.

O que você vai aprender

  • Como começar a usar as bibliotecas de rastreamento do OpenTelemetry em um projeto Python
  • Como criar um intervalo com a biblioteca
  • Como propagar contextos de período pela rede entre componentes de apps
  • Como enviar dados de rastreamento para o Google Cloud Trace
  • Como analisar o rastreamento no Google Cloud Trace

Este codelab explica como instrumentar seus microsserviços. Para facilitar o entendimento, este exemplo contém apenas três componentes (gerador de carga, cliente e servidor), mas você pode aplicar o mesmo processo explicado neste codelab a sistemas maiores e mais complexos.

O que é necessário

  • Conhecimento sobre o Python 3

2. Configuração e requisitos

Configuração de ambiente autoguiada

Se você ainda não tem uma Conta do Google (Gmail ou Google Apps), crie uma. Faça login no Console do Google Cloud Platform ( console.cloud.google.com) e crie um novo projeto.

Se você já tiver um projeto, clique no menu suspenso de seleção no canto superior esquerdo do console:

15b8b6ac4d917005.png

e clique no botão "NEW PROJECT" na caixa de diálogo exibida para criar um novo projeto:

7136b3ee36ebaf89.png

Se você ainda não tiver um projeto, uma caixa de diálogo como esta será exibida para criar seu primeiro:

90977ce514204b51.png

A caixa de diálogo de criação de projeto subsequente permite que você insira os detalhes do novo projeto:

6d9573e346e930b4.png

Lembre-se do código do projeto, um nome exclusivo em todos os projetos do Google Cloud. O nome acima já foi escolhido e não servirá para você. Ele será indicado mais adiante neste codelab como PROJECT_ID.

Em seguida, será preciso ativar o faturamento no Developers Console para usar os recursos do Google Cloud e ativar a API Cloud Trace, caso ainda não tenha feito isso.

eb5325f65619ad6a.png

A execução por meio deste codelab terá um custo baixo, mas poderá ser mais se você decidir usar mais recursos ou se deixá-los em execução. Consulte a seção "limpeza" no final deste documento. Os preços do Google Cloud Trace, do Google Kubernetes Engine e do Google Artifact Registry estão na documentação oficial.

Novos usuários do Google Cloud Platform estão qualificados para uma avaliação sem custo financeiro de US$300, o que torna este codelab totalmente sem custo financeiro.

Configuração do Google Cloud Shell

Embora o Google Cloud e o Google Cloud Trace possam ser operados remotamente do seu laptop, neste codelab usaremos o Google Cloud Shell, um ambiente de linha de comando executado no Cloud.

O Cloud Shell é uma máquina virtual com base em Debian que contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Isso significa que tudo que você precisa para este codelab é um navegador (sim, funciona em um Chromebook).

Para ativar o Cloud Shell no Console do Cloud, basta clicar em Ativar o Cloud Shell gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A. Leva apenas alguns instantes para provisionar e se conectar ao ambiente.

ff81d016724c4f67.png

fbe156ee6edfbb2e.png

Depois de se conectar ao Cloud Shell, você já estará autenticado e o projeto estará configurado com seu PROJECT_ID.

gcloud auth list

Resposta ao comando

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Resposta ao comando

[core]
project = <PROJECT_ID>

Se, por algum motivo, o projeto não estiver definido, basta emitir o seguinte comando:

gcloud config set project <PROJECT_ID>

Quer encontrar seu PROJECT_ID? Veja qual ID você usou nas etapas de configuração ou procure-o no painel do Console do Cloud:

a3e716fc9e7454e9.png

O Cloud Shell também define algumas variáveis de ambiente por padrão, o que pode ser útil ao executar comandos futuros.

echo $GOOGLE_CLOUD_PROJECT

Resposta ao comando

<PROJECT_ID>

Defina a zona padrão e a configuração do projeto:

gcloud config set compute/zone us-central1-f

É possível escolher uma variedade de zonas diferentes. Para mais informações, consulte Regiões e zonas.

Configuração do Python

Neste codelab, usamos "poetry" para gerenciar versões de pacotes de maneira estrita. Execute o comando a seguir no Cloud Shell:

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 -
source $HOME/.poetry/env

Configurar um cluster do Google Kubernetes

Neste codelab, você vai executar um cluster de microsserviços no Google Kubernetes Engine (GKE). O processo deste codelab é o seguinte:

  1. Baixar o projeto de linha de base no Cloud Shell
  2. Criar microsserviços em contêineres
  3. Fazer upload de contêineres para o Google Artifact Registry (GAR)
  4. Implantar contêineres no GKE
  5. Modificar o código-fonte dos serviços para instrumentação de rastreamento
  6. Acesse a etapa 2

Ativar o Kubernetes Engine

Primeiro, configuramos um cluster do Kubernetes em que o Shakesapp é executado no GKE. Portanto, precisamos ativar o GKE. Acesse o menu "Kubernetes Engine" e pressione o botão "ATIVAR".

56c680e93e169731.png

Agora você está pronto para criar um cluster do Kubernetes.

Criar cluster do Kubernetes

No Cloud Shell, execute o comando a seguir para criar um cluster do Kubernetes. Confirme se o valor da zona está na região que você usou para criar o repositório do Artifact Registry. Mude o valor da zona us-central1-f se a região do repositório não estiver cobrindo a zona.

gcloud container clusters create otel-trace-codelab --zone us-central1-f \
--num-nodes 1 \
--machine-type e2-highcpu-4

Resposta ao 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

Configuração do Artifact Registry e do skaffold

Agora temos um cluster do Kubernetes pronto para implantação. Em seguida, preparamos um registro de contêiner para enviar e implantar contêineres. Para esta etapa, precisamos configurar o GAR e o Skaffold para usá-lo.

Configuração do Artifact Registry

Navegue até o menu "Artifact Registry" e pressione o botão "ATIVAR".

f7493243bae0cdf7.png

Depois de alguns instantes, o navegador de repositório do GAR vai aparecer. Clique no botão "CRIAR REPOSITÓRIO" e insira o nome do repositório.

f97f337f5476651.png

Neste codelab, vou chamar o novo repositório de trace-codelab. O formato do artefato é "Docker" e o tipo de local é "Região". Escolha a região próxima àquela que você definiu para a zona padrão do Google Compute Engine. Por exemplo, o exemplo acima escolheu "us-central1-f", então aqui escolhemos "us-central1 (Iowa)". Em seguida, clique no botão "CRIAR".

2f04143077ca56db.png

Agora você vai ver "trace-codelab" no navegador do repositório.

7a3c1f47346bea15.png

Vamos voltar aqui mais tarde para verificar o caminho do registro.

Configuração do Skaffold

O Skaffold é uma ferramenta útil quando você trabalha na criação de microsserviços executados no Kubernetes. Ele lida com o fluxo de trabalho de criação, envio e implantação de contêineres de aplicativos com um pequeno conjunto de comandos. Por padrão, o Skaffold usa o Docker Registry como registro de contêiner. Portanto, é necessário configurar o Skaffold para reconhecer o GAR ao enviar contêineres.

Abra o Cloud Shell novamente e confirme se o Skaffold está instalado. O Cloud Shell instala o Skaffold no ambiente por padrão. Execute o comando a seguir e confira a versão do skaffold.

skaffold version

Resposta ao comando

v1.20.0

Agora, você pode registrar o repositório padrão para o Skaffold usar. Para conseguir o caminho do registro, acesse o painel do Artifact Registry e clique no nome do repositório que você acabou de configurar na etapa anterior.

55173fe922f40327.png

Em seguida, você verá trilhas de navegação estrutural na parte de cima da página. Clique no ícone e157b1359c3edc06.png para copiar o caminho do registro para a área de transferência.

a9b0fa44c37e0178.png

Ao clicar no botão de cópia, você verá a caixa de diálogo na parte de baixo do navegador com a mensagem:

"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" foi copiado

Volte para o Cloud Shell. Execute o comando skaffold config set default-repo com o valor que você acabou de copiar do painel.

skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab

Resposta ao 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

Além disso, é necessário configurar o registro para a configuração do Docker. Execute este comando:

gcloud auth configure-docker us-central1-docker.pkg.dev --quiet

Resposta ao 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

Agora você está pronto para a próxima etapa, que é configurar um contêiner do Kubernetes no GKE.

Resumo

Nesta etapa, você vai configurar o ambiente do codelab:

  • Configurar o Cloud Shell
  • Criou um repositório do Artifact Registry para o registro de contêineres
  • Configurar o Skaffold para usar o Container Registry
  • Criar um cluster do Kubernetes em que os microsserviços do codelab são executados

A seguir

Na próxima etapa, você vai criar, enviar e implantar seus microsserviços no cluster.

3. Criar, enviar e implantar os microsserviços

Baixe o material do codelab

Na etapa anterior, configuramos todos os pré-requisitos para este codelab. Agora você já pode executar microsserviços inteiros neles. O material do codelab está hospedado no GitHub. Faça o download dele para o ambiente shell do Cloud Shell com o seguinte comando git.

cd ~
git clone https://github.com/GoogleCloudPlatform/opentelemetry-trace-codelab-python.git

A estrutura de diretórios do projeto é a seguinte:

shakesapp-python
├── LICENSE
├── manifests
│   ├── client.yaml
│   ├── loadgen.yaml
│   └── server.yaml
├── proto
│   └── shakesapp.proto
├── skaffold.yaml
└── src
    ├── client
    ├── loadgen
    └── server
  • manifests: arquivos de manifesto do Kubernetes
  • proto: definição proto para a comunicação entre cliente e servidor
  • src: diretórios para o código-fonte de cada serviço
  • skaffold.yaml: arquivo de configuração do skaffold

Executar o comando skaffold

Por fim, você está pronto para criar, enviar e implantar todo o conteúdo no cluster do Kubernetes que acabou de criar. Isso parece conter várias etapas, mas o skaffold faz tudo por você. Vamos tentar com o seguinte comando:

cd shakesapp-python
skaffold run --tail

Assim que você executar o comando, vai ver a saída de registro de docker build e poderá confirmar que eles foram enviados ao registro.

Resposta ao 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

Depois do push de todos os contêineres de serviço, as implantações do Kubernetes começam automaticamente.

Resposta ao 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

Atenção: se você receber um erro como "No push access to specified image repository", verifique se o comando skaffold está tentando enviar imagens para o Docker Hub (docker.io) independente da sua configuração no repositório padrão do skaffold. Nesse caso, tente adicionar a opção "–default-repo" a "skaffold run" como abaixo.

$ skaffold run –tail –default-repo=us-central1-docker.pkg.dev/[ID do projeto]/[nome do repositório]

Após a implantação, você verá os registros reais do aplicativo emitidos para stdout em cada contêiner, assim:

Resposta ao 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 fim, você está pronto para começar a instrumentar seu aplicativo com o OpenTelemetry para rastreamento distribuído dos serviços.

Resumo

Nesta etapa, você preparou o material do codelab no seu ambiente e confirmou que o Skaffold é executado conforme o esperado.

A seguir

Na próxima etapa, você vai modificar o código-fonte do serviço loadgen para instrumentar as informações de rastreamento.

4. Instrumentação para HTTP

Conceito de instrumentação e propagação de rastreamento

Antes de editar o código-fonte, vou explicar brevemente como os rastreamentos distribuídos funcionam em um diagrama simples.

c8c659deaa9c9091.png

Neste exemplo, instrumentamos o código para exportar informações de rastreamento e intervalo para o Cloud Trace e propagar o contexto de rastreamento na solicitação do serviço loadgen para o serviço de servidor.

O aplicativo precisa enviar metadados de trace, como ID do trace e ID do período, para que o Cloud Trace reúna todos os períodos com o mesmo ID do trace em um só trace. Além disso, o aplicativo precisa propagar contextos de rastreamento (a combinação de ID de rastreamento e ID de período do período pai) ao solicitar serviços downstream para que eles saibam qual contexto de rastreamento estão processando.

O OpenTelemetry ajuda você a:

  • para gerar um ID de trace e um ID de período exclusivos
  • para exportar o ID do trace e o ID do período para o back-end
  • para propagar contextos de rastreamento para outros serviços

Instrumentar o primeiro período

Instrumentar o serviço de gerador de carga

Abra o Editor do Cloud Shell pressionando o botão 776a11bfb2122549.png no canto superior direito do Cloud Shell. Abra src/loadgen/loadgen.py no explorador do painel esquerdo e encontre a função 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)

Na função main, você vê o loop chamando a função call_client. Na implementação atual, a seção tem duas linhas de registro que registram o início e o fim da chamada de função. Agora vamos instrumentar as informações de período para rastrear a latência da chamada de função.

Primeiro, crie um período com um ID de rastreamento e um ID de período exclusivos. O OpenTelemetry oferece uma biblioteca útil para isso. Adicione as linhas a seguir para importar as bibliotecas do OpenTelemetry ao seu 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

Como o gerador de carga está chamando o aplicativo cliente em HTTP pelo módulo requests, usamos o pacote de extensão para requests e ativamos a instrumentação.

 from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
+
+RequestsInstrumentor().instrument()

Em seguida, configure a instância do rastreador que processa o contexto de rastreamento e as configurações do exportador.

     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}")

Como este é um codelab para entender como funciona a instrumentação de trace, configuramos o Tracer para gravar todas as solicitações e enviá-las ao back-end. (SimpleSpanProcessor()) Isso não é adequado para ambientes de produção. Portanto, mude essa parte ao instrumentar seu aplicativo de produção.

Agora é possível instrumentar intervalos com o rastreador. O ponto aqui é que você precisa gerar um intervalo de maneira explícita, e é isso! Embora haja duas linhas que adicionam metadados de eventos ao período, não é necessário gerar um ID de trace e um ID de período exclusivos manualmente e incorporá-los ao período.

     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 o build do Docker busque os pacotes necessários do OpenTelemetry, execute o seguinte 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"

Confirme se a descrição da dependência correspondente está escrita em pyproject.toml.

Instrumentar o atendimento ao cliente

Na seção anterior, instrumentamos a parte envolvida no retângulo vermelho no desenho abaixo. Implementamos informações de extensão no serviço de gerador de carga. Assim como o serviço de gerador de carga, agora precisamos instrumentar o serviço do cliente. A diferença do serviço de gerador de carga é que o serviço de cliente precisa extrair as informações do ID de rastreamento propagadas do serviço de gerador de carga no cabeçalho HTTP e usar o ID para gerar intervalos.

ae074d4513c9931f.png

Abra o editor do Cloud Shell e adicione os módulos necessários, como fizemos para o serviço de gerador 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

Você percebe que acabou de importar FlaskInstrumentor, que permite a instrumentação automática para o aplicativo Flask em nome dos usuários para extrair cabeçalhos HTTP e obter contextos de rastreamento com uma única linha de código. A comunidade OpenTelemetry oferece integrações úteis semelhantes com outras bibliotecas importantes. Para mais informações, consulte a documentação oficial.

 app = flask.Flask(__name__)
+FlaskInstrumentor().instrument_app(app)

Antes de iniciar a instrumentação, prepare a instância do Tracer da mesma forma que fizemos no serviço de gerador 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():
    ....

Agora está tudo pronto para adicionar instrumentação ao gerenciador. Encontre main_handler() e modifique a parte que envia a solicitação gRPC para o serviço do 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

Assim como no serviço de gerador de carga, adicione os pacotes necessários ao pyproject.toml com o seguinte 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"

Em seguida, tente iniciar o aplicativo com o comando skaffold run e confira o que o painel do Cloud Trace mostra:

skaffold run --tail

Depois de ver algumas mensagens de build, push e implantação, você vai encontrar registros de aplicativos em formatos JSON. Acesse Cloud Trace > Lista de traces para verificar se você recebe as informações de trace. Como o serviço de geração de carga envia solicitações ao serviço do cliente periodicamente e você ativou os rastreamentos para todas as solicitações, muitos pontos vão aparecer na lista de rastreamentos.

f7440360551980e.png

Ao clicar em um deles, você vai ver um gráfico em cascata como o abaixo, que explica a latência de cada parte durante o processo de solicitação e resposta. Encontre a caixa de seleção ao lado de "Mostrar eventos" para ver as anotações no gráfico de cascata. Essas anotações são as que você instrumentou no código pelo método span.add_event().

67596a4a313738.png

Talvez você note que os intervalos do serviço de servidor não aparecem. Isso está correto porque não instrumentamos intervalos no serviço do servidor.

Resumo

Nesta etapa, você instrumentou o serviço de gerador de carga e o serviço de cliente e confirmou que foi possível propagar o contexto de rastreamento entre os serviços e exportar informações de intervalo dos dois serviços para o Cloud Trace.

A seguir

Na próxima etapa, você vai instrumentar o serviço de cliente e o serviço de servidor para confirmar como propagar o contexto de rastreamento via gRPC.

5. Instrumentação para gRPC

Na etapa anterior, instrumentamos a primeira metade da solicitação nesses microsserviços. Nesta etapa, tentamos instrumentar a comunicação gRPC entre o serviço do cliente e o serviço do servidor. (Retângulo verde e roxo na imagem abaixo)

c4dec3e741c3ab4f.png

Instrumentação automática para cliente gRPC

O ecossistema do OpenTelemetry oferece muitas bibliotecas úteis que ajudam os desenvolvedores a instrumentar aplicativos. Na etapa anterior, usamos a instrumentação automática para o módulo "requests". Nesta etapa, como estamos tentando propagar o contexto de rastreamento pelo gRPC, usamos a biblioteca para isso.

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()

Para o serviço de cliente, o que precisamos fazer para a instrumentação é bem pequeno. O que queremos fazer é propagar o contexto de trace, que é a combinação do ID do trace e do ID do período do período atual via gRPC. Então, chamamos GrpcInstrumentatorClient.instrument() para que o cliente gRPC na função de manipulador possa incorporar o contexto de rastreamento no cabeçalho HTTP abaixo.

Adicione novas dependências a pyproject.toml com o comando poetry add:

poetry add "opentelemetry-instrumentation-grpc=^0.20b0"

Instrumentação automática para servidor gRPC

Assim como fizemos para o cliente gRPC, chamamos a instrumentação automática para o servidor gRPC. Adicione importações como as seguintes e chame GrpcInstrumentationServer().instrument() na parte de cima do arquivo.

Atenção: ligue para

GrpcInstrumentationServe() 

nesta etapa, não

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()
+

Em seguida, você vai adicionar o exportador para enviar informações de rastreamento ao back-end do Cloud Trace. Adicione o seguinte código à função 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)

Adicione os pacotes recém-incluídos no serviço do 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"

Executar o microsserviço e confirmar o rastreamento

Em seguida, execute o código modificado com o comando skaffold.

skaffold run --tail

Agora, você vê vários traces na página "Lista de traces" do Cloud Trace. Clique em um dos rastreamentos e veja que os períodos abrangem a solicitação do serviço de gerador de carga para o serviço de servidor.

141cb620245b689d.png

Resumo

Nesta etapa, você instrumentou a comunicação baseada em gRPC com o suporte das bibliotecas do ecossistema OpenTelemetry. Além disso, você confirmou que o contexto de rastreamento gerado no serviço de gerador de carga foi entregue com sucesso ao serviço de servidor.

6. Parabéns

Você criou rastreamentos distribuídos com o OpenTelemetry e confirmou as latências de solicitação no microsserviço no Google Cloud Trace.

Para exercícios mais longos, você pode tentar os seguintes tópicos por conta própria.

  • A implementação atual envia todos os períodos gerados pela verificação de integridade. Como você filtra esses períodos do Cloud Trace? A dica está aqui.
  • Correlacione registros de eventos com períodos e saiba como isso funciona no Google Cloud Trace e no Google Cloud Logging. A dica está aqui.
  • Substitua um serviço por outro em um idioma diferente e tente instrumentá-lo com o OpenTelemetry para esse idioma.

Atenção: o Google Kubernetes Engine e o Google Artifact Registry consomem o recurso constantemente.

Limpeza

Depois deste codelab, pare o cluster do Kubernetes e exclua o projeto para evitar cobranças inesperadas no Google Kubernetes Engine, no Google Cloud Trace e no Google Artifact Registry.

Primeiro, exclua o cluster com o seguinte comando:

skaffold delete

Resposta ao comando

Cleaning up...
 - deployment.apps "clientservice" deleted
 - service "clientservice" deleted
 - deployment.apps "loadgen" deleted
 - deployment.apps "serverservice" deleted
 - service "serverservice" deleted

Depois de excluir o cluster, no painel de menu, selecione "IAM e administrador" > "Configurações" e clique no botão "ENCERRAR".

578ca2b72a161e9d.png

Em seguida, insira o ID do projeto (e não o nome) no formulário da caixa de diálogo e confirme o encerramento.