FastApi & Open Telemetry
Découvrez comment intégrer Open Telemetry avec FastAPI pour surveiller et tracer les performances de vos applications Python.
15 août 2023
Published
Hugo Mufraggi
Author

FastApi & Open Telemetry page
Récemment, chez Invyo j’ai eu à développer un micro service en python avec fastapi. Dans cette série d’articles, je vous partagerai deux trois de mes découvertes sur des sujets QA. Aujourd’hui, nous nous intéresserons à la telemetry.
Stack technique:
- FastApi
- Pydentic
- Pytest
- OpenTelemetry
- Jaeger
Telemetry et open telemetry
On peut définir la telemetry comme une suite de process permettant de monitorer des applications. De mon expérience, je l’ai toujours vu du côté d’un backend, d’après chatgpt, c’est possible de monitorer une app front. Si jamais les dev fronts qui me lisent, vous avez des avis ou des retours d’experiences, je suis preneur.
La telemetry est un procédé vieux de plusieurs dizaines d’années. En 2019, plusieurs acteurs opensource ont travaillé à la definition d’un protocole standard pour la collecte de données de telemetry dans les environnements informatiques modernes.
Grace à cette standardisation des solutions privées ont vu le jour pour proposer des interfaces graphiques afin d’exploiter toute la donnée récoltée. Pour cet article nous allons utiliser Jaeger qui est un projet opensourcé par les équipes d’uber.
Les datas remontées par l’open-telemetry sont de 3 types :
- Traces : Enregistre le cheminement des transactions à travers différents composants d’une application, révélant les délais, les goulots d’étranglement et les itinéraires des données. Cela permet d’identifier les problèmes et d’optimiser les performances.
- Métriques : Mesure des performances de l’application, telles que le temps de réponse, l’utilisation de la mémoire et la charge du système. Ces indicateurs surveillent la santé générale de l’application et détectent les tendances anormales.
- Logs : Enregistre les événements et les erreurs dans l’application, offrant des détails précis sur ce qui s’est produit. Bien qu’accessoire, OpenTelemetry peut aider à agréger et à analyser les logs.
Selon les langages, les implémentations sont plus ou moins abouties. Dans notre cas en python on en est là : https://opentelemetry.io/docs/instrumentation/python/
- Traces: stable
- Metrics: stable
- Logs: experimental
Python Implementation
Nous allons à présent créer un projet fastApi et le monitorer. Le code python sera très simple, le but étant d’avoir plusieurs scénarii. Attention ! le code produit a été créé juste pour l’exemple.
Initialisation du projet
Première chose, vous allez avoir besoin d’avoir Python3 installé. Je vous laisse voir comment l’installer.
On va partir du principe que nous sommes dans un dossier vide. Nous allons commencer par créer un virtuel environnement, il contiendra nos packages installés.
python -m venv venv
source venv/bin/activate # Sur Windows : venv\\Scripts\\activate
On va installer fastAPI et Uvicorn. FastAPI est le framework, et Uvicorn est un serveur ASGI pour le déployer.
pip install fastapi uvicorn
Créer un fichier main.py et y coller notre serveur.
from typing import List
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
def fibonacci(n):
fib_sequence = [0, 1]
for i in range(2, n):
next_fib = fib_sequence[i - 1] + fib_sequence[i - 2]
fib_sequence.append(next_fib)
return fib_sequence
class InputBook(BaseModel):
title: str
author: str
published_year: int
class OutputBooks(BaseModel):
books: List[InputBook]
books = []
@app.post("/books/", tags=['books'])
async def create_book(book: InputBook):
books.append(book)
return {"message": "Book created successfully", "book": book}
@app.get("/books/", response_model=OutputBooks, tags=['books'])
async def get_books():
return OutputBooks(books=books)
@app.get("/fibonacci/{num}")
async def get_fibonacci_sequence(num: int):
if num <= 0:
raise HTTPException(status_code=400,
detail="Input should be a positive integer")
fib_sequence = fibonacci(num)
return {"fibonacci_sequence": fib_sequence}
Ajout de l’open telemetry
On va commencer par lancer un Jaeger en local sur notre machine à l’aide de ce docker.
docker run -d --name jaeger \\
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \\
-e COLLECTOR_OTLP_ENABLED=true \\
-p 6831:6831/udp \\
-p 6832:6832/udp \\
-p 5778:5778 \\
-p 16686:16686 \\
-p 4317:4317 \\
-p 4318:4318 \\
-p 14250:14250 \\
-p 14268:14268 \\
-p 14269:14269 \\
-p 9411:9411 \\
jaegertracing/all-in-one:latest
Une fois lancé, vous pouvez vous rendre sur le port : http://localhost:16686 pour accéder à l’interface graphique.
On va commencer par installer ces paquets. Vous retrouverez ici la doc.
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
Puis on pourra lancer notre app et monitorer notre backend à ce moment là.
opentelemetry-instrument \\
--traces_exporter console,otlp \\
--metrics_exporter console \\
--service_name article-service \\
--exporter_otlp_endpoint <http://localhost:4317> \\
uvicorn main:app --host 0.0.0.0 --port 8000
Maintenant je vais utiliser le swagger qui est dispo sur l’url suivante http://localhost:8000/docs. Je vais jouer quelques query pour remplir notre jaeger.
Jaeger
On va jouer deux fois le endpoint de fib une fois avec 15000 et une fois avec 0. Le but est d’avoir une trace un peu longue et l’autre d’avoir une erreur 400.

Service sélecteur(Vert): Permet de choisir quel service vous allez observer. Dans ce jaeger je centralise 3 services distincts.
Opération sélecteur(Bleu): Permet de choisir quel endpoint on veut voir.
Les tags(Orange): C’est un moteur de query permettant par exemple de faire remonter toutes les traces avec un status_code=400.
Le Graph des traces(Rose): Permet d’afficher les traces en fonction du temps qu’elles ont pris et de l’heure. Cela peut être pratique lors de remontées de bug en prod pour pouvoir investiguer le pourquoi et le comment, ou pouvoir mettre une durée sur une query trop longue en db.
En cliquant sur une trace on arrive sur une nouvelle page avec toute l’information sur la trace.

Premier encart (Bleu): On va y retrouver de manière graphique tous les calls de fonction et les temps qui leurs sont liés.
Second encart(Orange): On y retrouve précisément chaque span et leurs temps. Si vous réalisez des calls db selon la prise en charge des langages, vous pouvez y retrouver la query que vous avez jouée.
Dans la vraie vie, cette page peut permettre de débusquer des lenteurs de manière précise dans votre code. Imaginons que dans notre endpoint on va avoir un call une db puis un call à micro service tiers et que le endpoint retourne la donnée quand le microservice répond.
Cette vue va permettre de savoir si c’est la db, le micro service externe ou les deux qui ralentissent le code. Cela permet de poser un diagnostic et de guider les devs pour fixer le endpoint.