Configurer le plug-in OpenTelemetry de base dans gRPC Python

1. Introduction

Dans cet atelier de programmation, vous allez utiliser gRPC pour créer un client et un serveur qui constituent la base d'une application de cartographie d'itinéraire écrite en Python.

À la fin de ce tutoriel, vous disposerez d'une application gRPC HelloWorld simple instrumentée avec le plug-in gRPC OpenTelemetry. Vous pourrez également consulter les métriques d'observabilité exportées dans Prometheus.

Points abordés

  • Configurer le plug-in OpenTelemetry pour une application Python gRPC existante
  • Exécuter une instance Prometheus locale
  • Exporter des métriques vers Prometheus
  • Afficher les métriques du tableau de bord Prometheus

2. Avant de commencer

Prérequis

  • git
  • curl
  • build-essential
  • Python 3.9 ou version ultérieure. Pour obtenir des instructions d'installation de Python spécifiques à une plate-forme, consultez Configuration et utilisation de Python. Vous pouvez également installer un Python non système à l'aide d'outils tels que uv ou pyenv.
  • pip version 9.0.1 ou ultérieure pour installer les packages Python.
  • venv pour créer des environnements virtuels Python.

Installez les prérequis :

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

Obtenir le code

Pour faciliter votre apprentissage, cet atelier de programmation propose une structure de code source prédéfinie pour vous aider à démarrer. Les étapes suivantes vous guideront dans l'instrumentation du plug-in gRPC OpenTelemetry dans une application.

grpc-codelabs

Le code source du canevas pour cet atelier de programmation est disponible dans ce répertoire GitHub. Si vous préférez ne pas implémenter le code vous-même, le code source complet est disponible dans le répertoire completed.

Commencez par cloner le dépôt de l'atelier de programmation gRPC et accédez au dossier grpc-python-opentelemetry :

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

Vous pouvez également télécharger le fichier .zip contenant uniquement le répertoire de l'atelier de programmation et le décompresser manuellement.

Commençons par créer un environnement virtuel Python (venv) pour isoler les dépendances de votre projet des packages système :

python3 -m venv --upgrade-deps .venv

Pour activer l'environnement virtuel dans le shell bash/zsh :

source .venv/bin/activate

Pour Windows et les shells non standards, consultez le tableau à l'adresse https://docs.python.org/3/library/venv.html#how-venvs-work.

Ensuite, installez les dépendances dans l'environnement à l'aide de la commande suivante :

python -m pip install -r requirements.txt

3. Enregistrer le plug-in OpenTelemetry

Nous avons besoin d'une application gRPC pour ajouter le plug-in gRPC OpenTelemetry. Dans cet atelier de programmation, nous allons utiliser un client et un serveur HelloWorld gRPC simples que nous instrumenterons avec le plug-in OpenTelemetry gRPC.

La première étape consiste à enregistrer le plug-in OpenTelemetry configuré avec un exportateur Prometheus dans le client. Ouvrez start_here/observability_greeter_client.py avec l'éditeur de votre choix. Commencez par ajouter les dépendances et les macros associées pour obtenir le résultat suivant :

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

Transformez ensuite run() pour qu'il ressemble à :

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

L'étape suivante consiste à ajouter le plug-in OpenTelemetry au serveur. Ouvrez start_here/observability_greeter_server.py et ajoutez les dépendances et les macros associées pour obtenir le résultat suivant :

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

Transformez ensuite run() pour qu'il ressemble à :

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. Exécuter l'exemple et afficher les métriques

Pour exécuter le serveur, exécutez la commande suivante :

cd start_here
python -m observability_greeter_server

Si la configuration réussit, le résultat suivant s'affiche pour le serveur :

Server started, listening on 50051

Pendant que le serveur est en cours d'exécution, exécutez le client sur un autre terminal :

# 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

Une exécution réussie se présente comme suit :

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

Étant donné que nous avons configuré le plug-in gRPC OpenTelemetry pour exporter les métriques à l'aide de Prometheus. Ces métriques seront disponibles sur localhost:9464 pour le serveur et sur localhost:9465 pour le client.

Pour afficher les métriques client :

curl localhost:9465/metrics

Le résultat doit respecter le format suivant :

# 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

De même, pour les métriques côté serveur :

curl localhost:9464/metrics

5. Afficher les métriques sur Prometheus

Ici, nous allons configurer une instance Prometheus qui extraira notre exemple de client et de serveur gRPC exportant des métriques à l'aide de Prometheus.

Téléchargez la dernière version de Prometheus pour votre plate-forme à l'aide du lien fourni ou de la commande suivante :

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

Extrayez-le et exécutez-le à l'aide de la commande suivante :

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

Créez un fichier de configuration Prometheus avec les éléments suivants :

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

Démarrez Prometheus avec la nouvelle configuration :

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

Cela configurera les métriques des processus de l'atelier de programmation client et serveur pour qu'elles soient récupérées toutes les cinq secondes.

Accédez à http://localhost:9090/graph pour afficher les métriques. Par exemple, la requête

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

affichera un graphique avec la latence médiane des tentatives, en utilisant une fenêtre temporelle d'une minute pour le calcul du quantile.

Taux de requêtes :

increase(grpc_client_attempt_duration_seconds_bucket[1m])

6. (Facultatif) Exercice pour l'utilisateur

Dans les tableaux de bord Prometheus, vous remarquerez que le QPS est faible. Essayez d'identifier dans l'exemple de code un code suspect qui limite les requêtes par seconde.

Pour les enthousiastes, le code client se limite à n'avoir qu'un seul RPC en attente à un moment donné. Vous pouvez modifier cette valeur pour que le client envoie davantage de RPC sans attendre que les précédents se terminent. (La solution n'a pas été fournie.)