Configura il plug-in OpenTelemetry di base in gRPC Python

1. Introduzione

In questo codelab, utilizzerai gRPC per creare un client e un server che costituiscono la base di un'applicazione di mappatura delle route scritta in Python.

Al termine del tutorial, avrai una semplice applicazione gRPC HelloWorld instrumentata con il plug-in gRPC OpenTelemetry e potrai visualizzare le metriche di osservabilità esportate in Prometheus.

Obiettivi didattici

  • Come configurare il plug-in OpenTelemetry per un'applicazione gRPC Python esistente
  • Esecuzione di un'istanza Prometheus locale
  • Esportazione delle metriche in Prometheus
  • Visualizzazione delle metriche dalla dashboard di Prometheus

2. Prima di iniziare

Che cosa ti serve

  • git
  • curl
  • build-essential
  • Python 3.9 o versioni successive. Per istruzioni sull'installazione di Python specifiche per la piattaforma, consulta Configurazione e utilizzo di Python. In alternativa, installa una versione di Python non di sistema utilizzando strumenti come uv o pyenv.
  • pip versione 9.0.1 o successive per installare i pacchetti Python.
  • venv per creare ambienti virtuali Python.

Installa i prerequisiti:

sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl build-essential clang
sudo apt install python3
sudo apt install python3-pip python3-venv

Ottieni il codice

Per semplificare l'apprendimento, questo codelab offre uno scaffold di codice sorgente precompilato per aiutarti a iniziare. I passaggi seguenti ti guideranno nell'instrumentazione del plug-in gRPC OpenTelemetry in un'applicazione.

grpc-codelabs

Il codice sorgente dello scaffold per questo codelab è disponibile in questa directory di GitHub . Se preferisci non implementare il codice autonomamente, il codice sorgente completato è disponibile nella directory completed.

Innanzitutto, clona il repository del codelab gRPC e passa alla cartella grpc-python-opentelemetry:

git clone -b v1 https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-python-opentelemetry/

In alternativa, puoi scaricare il file .zip contenente solo la directory del codelab ed estrarlo manualmente.

Creiamo innanzitutto un nuovo ambiente virtuale Python (venv) per isolare le dipendenze del progetto dai pacchetti di sistema:

python3 -m venv --upgrade-deps .venv

Per attivare l'ambiente virtuale nella shell bash/zsh:

source .venv/bin/activate

Per Windows e le shell non standard, consulta la tabella all'indirizzo https://docs.python.org/3/library/venv.html#how-venvs-work.

Poi, installa le dipendenze nell'ambiente utilizzando:

python -m pip install -r requirements.txt

3. Registra il plug-in OpenTelemetry

Abbiamo bisogno di un'applicazione gRPC per aggiungere il plug-in gRPC OpenTelemetry. In questo codelab, utilizzeremo un semplice client e server gRPC HelloWorld che instrumenteremo con il plug-in gRPC OpenTelemetry.

Il primo passo consiste nel registrare il plug-in OpenTelemetry configurato con un esportatore Prometheus nel client. Apri start_here/observability_greeter_client.py con il tuo editor preferito. Innanzitutto, aggiungi le dipendenze e le macro correlate in modo che abbiano questo aspetto:

import logging
import time

import grpc
import grpc_observability
import helloworld_pb2
import helloworld_pb2_grpc
from opentelemetry.exporter.prometheus import PrometheusMetricReader
from opentelemetry.sdk.metrics import MeterProvider
from prometheus_client import start_http_server

_SERVER_PORT = "50051"
_PROMETHEUS_PORT = 9465

Poi trasforma run() in modo che abbia questo aspetto:

def run():
    # Start Prometheus client
    start_http_server(port=_PROMETHEUS_PORT, addr="0.0.0.0")
    meter_provider = MeterProvider(metric_readers=[PrometheusMetricReader()])

    otel_plugin = grpc_observability.OpenTelemetryPlugin(
        meter_provider=meter_provider
    )
    otel_plugin.register_global()

    with grpc.insecure_channel(target=f"localhost:{_SERVER_PORT}") as channel:
        stub = helloworld_pb2_grpc.GreeterStub(channel)
        # Continuously send RPCs every second.
        while True:
            try:
                response = stub.SayHello(helloworld_pb2.HelloRequest(name="You"))
                print(f"Greeter client received: {response.message}")
                time.sleep(1)
            except grpc.RpcError as rpc_error:
                print("Call failed with code: ", rpc_error.code())

    # Deregister is not called in this example, but this is required to clean up.
    otel_plugin.deregister_global()

Il passaggio successivo consiste nell'aggiungere il plug-in OpenTelemetry al server. Apri start_here/observability_greeter_server.py e aggiungi le dipendenze e le macro correlate in modo che abbiano questo aspetto:

from concurrent import futures
import logging
import time

import grpc
import grpc_observability
import helloworld_pb2
import helloworld_pb2_grpc
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.exporter.prometheus import PrometheusMetricReader
from prometheus_client import start_http_server

_SERVER_PORT = "50051"
_PROMETHEUS_PORT = 9464

Poi trasforma run() in modo che abbia questo aspetto:

def serve():
    # Start Prometheus client
    start_http_server(port=_PROMETHEUS_PORT, addr="0.0.0.0")

    meter_provider = MeterProvider(metric_readers=[PrometheusMetricReader()])

    otel_plugin = grpc_observability.OpenTelemetryPlugin(
        meter_provider=meter_provider
    )
    otel_plugin.register_global()

    server = grpc.server(
        thread_pool=futures.ThreadPoolExecutor(max_workers=10),
    )
    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port("[::]:" + _SERVER_PORT)
    server.start()
    print("Server started, listening on " + _SERVER_PORT)

    server.wait_for_termination()

    # Deregister is not called in this example, but this is required to clean up.
    otel_plugin.deregister_global()

4. Esecuzione dell'esempio e visualizzazione delle metriche

Per eseguire il server, esegui questo comando:

cd start_here
python -m observability_greeter_server

Se la configurazione è andata a buon fine, vedrai il seguente output per il server:

Server started, listening on 50051

Mentre il server è in esecuzione, in un altro terminale esegui il client:

# Run the below commands to cd to the working directory and activate virtual environment in the new terminal
cd grpc-codelabs/codelabs/grpc-python-opentelemetry/
source .venv/bin/activate

cd start_here
python -m observability_greeter_client

Un'esecuzione riuscita avrà questo aspetto:

Greeter client received: Hello You
Greeter client received: Hello You
Greeter client received: Hello You

Abbiamo configurato il plug-in gRPC OpenTelemetry per esportare le metriche utilizzando Prometheus. Queste metriche saranno disponibili su localhost:9464 per il server e localhost:9465 per il client.

Per visualizzare le metriche del client:

curl localhost:9465/metrics

Il risultato sarà del modulo:

# HELP python_gc_objects_collected_total Objects collected during gc
# TYPE python_gc_objects_collected_total counter
python_gc_objects_collected_total{generation="0"} 241.0
python_gc_objects_collected_total{generation="1"} 163.0
python_gc_objects_collected_total{generation="2"} 0.0
# HELP python_gc_objects_uncollectable_total Uncollectable objects found during GC
# TYPE python_gc_objects_uncollectable_total counter
python_gc_objects_uncollectable_total{generation="0"} 0.0
python_gc_objects_uncollectable_total{generation="1"} 0.0
python_gc_objects_uncollectable_total{generation="2"} 0.0
# HELP python_gc_collections_total Number of times this generation was collected
# TYPE python_gc_collections_total counter
python_gc_collections_total{generation="0"} 78.0
python_gc_collections_total{generation="1"} 7.0
python_gc_collections_total{generation="2"} 0.0
# HELP python_info Python platform information
# TYPE python_info gauge
python_info{implementation="CPython",major="3",minor="10",patchlevel="9",version="3.10.9"} 1.0
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 1.868988416e+09
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 4.1680896e+07
# TYPE process_resident_memory_bytes gauge                                                                                                                                                                                                                                                                21:20:16 [154/966]
process_resident_memory_bytes 4.1680896e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.72375679833e+09
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.38
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 9.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 4096.0
# HELP target_info Target metadata
# TYPE target_info gauge
target_info{service_name="unknown_service",telemetry_sdk_language="python",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="1.26.0"} 1.0
# HELP grpc_client_attempt_started_total Number of client call attempts started
# TYPE grpc_client_attempt_started_total counter
grpc_client_attempt_started_total{grpc_method="other",grpc_target="localhost:50051"} 18.0
# HELP grpc_client_attempt_sent_total_compressed_message_size_bytes Compressed message bytes sent per client call attempt
# TYPE grpc_client_attempt_sent_total_compressed_message_size_bytes histogram
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="0.0"} 0.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="5.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="10.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="25.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="50.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="75.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="100.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="250.0"} 18.0

Allo stesso modo, per le metriche lato server:

curl localhost:9464/metrics

5. Visualizzazione delle metriche in Prometheus

Qui configureremo un'istanza Prometheus che eseguirà lo scraping del nostro client e server di esempio gRPC che esportano le metriche utilizzando Prometheus.

Scarica l'ultima release di Prometheus per la tua piattaforma utilizzando il link fornito o il seguente comando:

curl -sLO https://github.com/prometheus/prometheus/releases/download/v3.7.3/prometheus-3.7.3.linux-amd64.tar.gz

Poi estrailo ed eseguilo utilizzando il seguente comando:

tar xvfz prometheus-*.tar.gz
cd prometheus-*

Crea un file di configurazione di Prometheus con i seguenti contenuti:

cat > grpc_otel_python_prometheus.yml <<EOF
scrape_configs:
  - job_name: "prometheus"
    scrape_interval: 5s
    static_configs:
      - targets: ["localhost:9090"]
  - job_name: "grpc-otel-python"
    scrape_interval: 5s
    static_configs:
      - targets: ["localhost:9464", "localhost:9465"]
EOF

Avvia Prometheus con la nuova configurazione:

./prometheus --config.file=grpc_otel_python_prometheus.yml

In questo modo, le metriche dei processi del codelab client e server verranno sottoposte a scraping ogni 5 secondi.

Vai all'indirizzo http://localhost:9090/graph per visualizzare le metriche. Ad esempio, la query:

histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))

mostrerà un grafico con la latenza mediana dei tentativi utilizzando 1 minuto come finestra temporale per il calcolo dei quantili.

Frequenza delle query:

increase(grpc_client_attempt_duration_seconds_bucket[1m])

6. (Facoltativo) Esercizio per l'utente

Nelle dashboard di Prometheus, noterai che le QPS sono basse. Prova a identificare del codice sospetto nell'esempio che limita le QPS.

Per i più entusiasti, il codice client si limita ad avere una sola RPC in attesa in un determinato momento. Questa impostazione può essere modificata in modo che il client invii più RPC senza attendere il completamento delle precedenti. La soluzione non è stata fornita.