---
title: "Traçabilité de bout en bout avec OpenTelemetry - API7.ai"
description: "Cet article explique comment commencer votre parcours dans l'observabilité et utiliser le traçage de bout en bout avec OpenTelemetry."
url: "https://api7.ai/fr/blog/end-to-end-tracing-opentelemetry"
---

[Blog](https://api7.ai/fr/blog)

[Products](https://api7.ai/fr/category/products)[Technology](https://api7.ai/fr/category/technology)[Ecosystem](https://api7.ai/fr/category/ecosystem)[Case Study](https://api7.ai/fr/category/usercase)[Team & Community](https://api7.ai/fr/category/community)

Search

⌘ + K

[Blog](https://api7.ai/blog)

Ecosystem

# Traçabilité de bout en bout avec OpenTelemetry

[![Nicolas Fränkel](https://avatars.githubusercontent.com/u/752258?v=4)](https://github.com/nfrankel)

[Nicolas Fränkel](https://github.com/nfrankel)

August 31, 2022

[Ecosystem](https://api7.ai/category/ecosystem)

Que vous implémentiez ou non des microservices (et vous ne devriez probablement pas), votre système est très probablement composé de plusieurs composants. Le système le plus simple est probablement constitué d'un proxy inverse, d'une application et d'une base de données. Dans ce cas, la surveillance n'est pas seulement une bonne idée ; c'est une nécessité. Plus le nombre de composants par lesquels une requête peut passer est élevé, plus cette nécessité est forte.

Cependant, la surveillance n'est que le début du voyage. Lorsque les requêtes commencent à échouer *en masse*, vous avez besoin d'une vue agrégée sur tous les composants. C'est ce qu'on appelle le **tracing**, et c'est l'un des piliers de l'*observabilité* ; les deux autres sont les métriques et les logs.

Dans cet article, je me concentrerai uniquement sur les traces et décrirai comment vous pouvez commencer votre voyage dans l'observabilité.

## La spécification W3C Trace Context

Une solution de tracing devrait fournir un format standard pour fonctionner à travers des piles technologiques hétérogènes. Un tel format doit adhérer à une spécification, qu'elle soit formelle ou *de facto*.

Il faut comprendre qu'une spécification n'apparaît rarement de nulle part. En général, le marché a déjà quelques implémentations distinctes. La plupart du temps, une nouvelle spécification conduit à une implémentation supplémentaire, comme le décrit la célèbre bande dessinée XKCD :

![la célèbre bande dessinée XKCD décrit](https://static.api7.ai/2022/10/03/633a3d1d1acbc.png?imageMogr2/format/webp)

Parfois, cependant, un miracle se produit : le marché adhère à la nouvelle spécification. Ici, Trace Context est une spécification W3C, et elle semble avoir fait l'affaire :

> Cette spécification définit des en-têtes HTTP standard et un format de valeur pour propager des informations de contexte qui permettent des scénarios de tracing distribué. La spécification standardise la manière dont les informations de contexte sont envoyées et modifiées entre les services. Les informations de contexte identifient de manière unique les requêtes individuelles dans un système distribué et définissent également un moyen d'ajouter et de propager des informations de contexte spécifiques au fournisseur. -- <https://www.w3.org/TR/trace-context/>

Deux concepts critiques émergent du document :

- Une **trace** suit le chemin d'une requête qui traverse plusieurs composants
- Un **span** est lié à un seul composant et relié à un autre span par une relation parent-enfant

!\[Traces et spans]\(<https://static-site.apiseven.com/wp-content/uploads/2022/08/trace-spans-1024x393.png> "Traces et spans" "Traces et span")

Au moment de la rédaction de cet article, la spécification est une recommandation W3C, qui est l'étape **finale**.

Trace Context a déjà [de nombreuses implémentations](https://github.com/w3c/trace-context/blob/main/implementations.md). L'une d'elles est OpenTelemetry.

## OpenTelemetry comme standard de référence

Plus vous êtes proche de la partie opérationnelle de l'informatique, plus vous avez de chances d'avoir entendu parler d'OpenTelemetry :

> OpenTelemetry est une collection d'outils, d'API et de SDK. Utilisez-le pour instrumenter, générer, collecter et exporter des données de télémétrie (métriques, logs et traces) pour vous aider à analyser les performances et le comportement de votre logiciel. OpenTelemetry est généralement disponible dans plusieurs langages et est prêt à l'emploi. -- <https://opentelemetry.io/>

OpenTelemetry est un projet géré par la CNCF. Avant OpenTelemetry, il y avait deux projets :

- OpenTracing, axé sur les traces comme son nom l'indique
- OpenCensus, dont l'objectif était de gérer les métriques et les traces

Les deux projets ont fusionné et ont ajouté les logs par-dessus. OpenTelemetry propose maintenant un ensemble de "couches" axées sur l'observabilité :

- Des API d'instrumentation dans une variété de langages
- Des implémentations canoniques, encore une fois dans différents langages
- Des composants d'infrastructure tels que des collecteurs
- Des formats d'interopérabilité, tels que le Trace Context du W3C

Notez que bien qu'OpenTelemetry soit une implémentation de Trace Context, il fait plus. Trace Context se limite à HTTP, tandis qu'OpenTelemetry permet aux spans de traverser des composants non web, tels que Kafka. Cela dépasse le cadre de cet article de blog.

## Le cas d'utilisation

Mon cas d'utilisation préféré est une boutique e-commerce, alors ne changeons pas. Dans ce cas, la boutique est conçue autour de microservices, chacun accessible via une API REST et protégé derrière une passerelle API. Pour simplifier l'architecture pour l'article de blog, je n'utiliserai que deux microservices : `catalog` gère les produits, et `pricing` gère le prix des produits.

Lorsqu'un utilisateur arrive sur l'application, la page d'accueil récupère tous les produits, obtient leur prix respectif et les affiche.

![Exemple de flux de requête à travers plusieurs composants](https://static.api7.ai/2022/10/03/633a3d1d29f7e.png?imageMogr2/format/webp)

Pour rendre les choses plus intéressantes, `catalog` est une application Spring Boot codée en Kotlin, tandis que `pricing` est une application Python Flask.

Le tracing devrait nous permettre de suivre le chemin d'une requête à travers la passerelle, les deux microservices et, si possible, les bases de données.

## Traces à la passerelle

Le point d'entrée est la partie la plus intéressante du tracing, car il devrait générer l'ID de trace : dans ce cas, le point d'entrée est la passerelle. J'utiliserai Apache APISIX pour implémenter la démo :

> Apache APISIX fournit des fonctionnalités riches de gestion du trafic comme l'équilibrage de charge, l'amont dynamique, la publication canari, la rupture de circuit, l'authentification, l'observabilité, etc. -- <https://apisix.apache.org/>

Apache APISIX est basé sur une architecture de plugins et propose un plugin OpenTelemetry :

> Le plugin `opentelemetry` peut être utilisé pour rapporter des données de tracing selon la spécification OpenTelemetry. Le plugin ne prend en charge que l'OLTP encodé en binaire sur HTTP. -- <https://apisix.apache.org/docs/apisix/plugins/opentelemetry/>

Configurons le plugin `opentelemetry` :

```
apisix:
  enable_admin: false #1
  config_center: yaml #1
plugins:
  - opentelemetry #2
plugin_attr:
  opentelemetry:
    resource:
      service.name: APISIX #3
    collector:
      address: jaeger:4318 #4
```

1. Exécutez Apache APISIX en mode autonome pour rendre la démo plus facile à suivre. C'est une bonne pratique en production de toute façon
2. Configurez `opentelemetry` comme un plugin global
3. Définissez le nom du service. C'est le nom qui apparaîtra dans le composant d'affichage des traces
4. Envoyez les traces au service `jaeger`. La section suivante le décrira.

Nous voulons tracer chaque route, donc au lieu d'ajouter le plugin à chaque route, nous devrions configurer le plugin comme un plugin global :

```
global_rules:
  - id: 1
    plugins:
      opentelemetry:
        sampler:
          name: always_on #1
```

1. Le tracing a un impact sur les performances. Plus nous traçons, plus nous avons d'impact. Par conséquent, nous devrions soigneusement équilibrer l'impact sur les performances par rapport aux avantages de l'observabilité. Pour la démo, cependant, nous voulons tracer chaque requête.

## Collecte, stockage et affichage des traces

Bien que Trace Context soit une spécification W3C et qu'OpenTelemetry soit un standard *de facto*, de nombreuses solutions existent sur le marché pour collecter, stocker et afficher les traces. Chaque solution peut fournir les trois capacités ou seulement une partie d'entre elles. Par exemple, la pile Elastic gère le stockage et l'affichage, mais vous devez vous appuyer sur autre chose pour la collecte. D'un autre côté, [Jaeger](https://www.jaegertracing.io/docs/1.18/opentelemetry/) et [Zipkin](https://zipkin.io/) fournissent une suite complète pour remplir les trois capacités.

Jaeger et Zipkin précèdent OpenTelemetry, donc chacun a son format de transport de traces. Ils fournissent cependant une intégration avec le format OpenTelemetry.

Dans le cadre de cet article de blog, la solution exacte n'est pas pertinente, car nous avons seulement besoin des capacités. J'ai choisi Jaeger car il fournit une image Docker tout-en-un : chaque capacité a son composant, mais ils sont tous intégrés dans la même image, ce qui rend la configuration beaucoup plus facile.

Les [ports pertinents](https://www.jaegertracing.io/docs/1.37/getting-started/#all-in-one) de l'image sont les suivants :

| Port    | Protocole | Composant | Fonction                                                      |
| ------- | --------- | --------- | ------------------------------------------------------------- |
| `16686` | HTTP      | query     | sert le frontend                                              |
| `4317`  | HTTP      | collector | accepte le protocole OpenTelemetry (OTLP) sur gRPC, si activé |
| `4318`  | HTTP      | collector | accepte le protocole OpenTelemetry (OTLP) sur HTTP, si activé |

La partie Docker Compose ressemble à ceci :

```
services:
  jaeger:
    image: jaegertracing/all-in-one:1.37 #1
    environment:
      - COLLECTOR_OTLP_ENABLED=true #2
    ports:
      - "16686:16686" #3
```

1. Utilisez l'image `all-in-one`
2. Très important : activez le collecteur au format OpenTelemetry
3. Exposez le port de l'interface utilisateur

Maintenant que nous avons mis en place l'infrastructure, nous pouvons nous concentrer sur l'activation des traces dans nos applications.

## Traces dans les applications Flask

Le service `pricing` est une simple application [Flask](https://flask.palletsprojects.com/). Il offre un seul point de terminaison pour récupérer le prix d'un seul produit à partir de la base de données.

```
@app.route('/price/<product_str>')                           #1-2
def price(product_str: str) -> Dict[str, object]:
    product_id = int(product_str)
    price: Price = Price.query.get(product_id)               #3
    if price is None:
        return jsonify({'error': 'Product not found'}), 404
    else:
        low: float = price.value - price.jitter              #4
        high: float = price.value + price.jitter             #4
        return {
            'product_id': product_id,
            'price': round(uniform(low, high), 2)            #4
        }
```

1. Point de terminaison
2. La route nécessite l'identifiant du produit
3. Récupère les données de la base de données en utilisant SQLAlchemy
4. Les moteurs de tarification réels ne renvoient jamais le même prix au fil du temps ; randomisons un peu le prix pour le plaisir

Avertissement : Récupérer un seul prix par appel est très inefficace. Cela nécessite autant d'appels que de produits, mais cela rend la trace plus intéressante. Dans la vraie vie, la route devrait être capable d'accepter plusieurs identifiants de produits et de récupérer tous les prix associés en une seule requête-réponse.

Il est maintenant temps d'instrumenter l'application. Deux options sont disponibles : l'instrumentation automatique et l'instrumentation manuelle. L'automatique est peu coûteuse et une victoire rapide ; la manuelle nécessite un temps de développement ciblé. Je conseille de commencer par l'automatique et de n'ajouter la manuelle que si nécessaire.

Nous devons ajouter quelques packages Python :

```
opentelemetry-distro[otlp]==0.33b0
opentelemetry-instrumentation
opentelemetry-instrumentation-flask
```

Nous devons configurer quelques paramètres :

```
pricing:
  build: ./pricing
  environment:
    OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1
    OTEL_RESOURCE_ATTRIBUTES: service.name=pricing #2
    OTEL_METRICS_EXPORTER: none #3
    OTEL_LOGS_EXPORTER: none #3
```

1. Envoyez les traces à Jaeger
2. Définissez le nom du service. C'est le nom qui apparaîtra dans le composant d'affichage des traces
3. Nous ne sommes intéressés ni par les logs ni par les métriques

Maintenant, au lieu d'utiliser la commande standard `flask run`, nous l'encadrons :

```
opentelemetry-instrument flask run
```

Avec cela seulement, nous collectons déjà des spans à partir des appels de méthode et des routes Flask.

Nous pouvons manuellement ajouter des spans supplémentaires si nécessaire, *par exemple* :

```
from opentelemetry import trace

@app.route('/price/<product_str>')
def price(product_str: str) -> Dict[str, object]:
    product_id = int(product_str)
    with tracer.start_as_current_span("SELECT * FROM PRICE WHERE ID=:id", attributes={":id": product_id}) as span: #1
        price: Price = Price.query.get(product_id)
    # ...
```

1. Ajoutez un span supplémentaire avec l'étiquette et l'attribut configurés

## Traces dans les applications Spring Boot

Le service `catalog` est une application [Spring Boot](https://spring.io/projects/spring-boot) Réactive développée en Kotlin. Il offre deux points de terminaison :

- Un pour récupérer un seul produit
- L'autre pour récupérer tous les produits

Les deux recherchent d'abord dans la base de données des produits, puis interrogent le service `pricing` ci-dessus pour le prix.

Comme pour Python, nous pouvons tirer parti de l'instrumentation automatique et manuelle. Commençons par les fruits à portée de main, l'instrumentation automatique. Sur la JVM, nous l'atteignons via un agent :

```
java -javaagent:opentelemetry-javaagent.jar -jar catalog.jar
```

Comme en Python, cela crée des spans pour chaque appel de méthode et point d'entrée HTTP. Il instrumente également les appels JDBC, mais nous avons une pile Réactive et utilisons donc R2DBC. Pour mémoire, un [problème GitHub](https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/2515) est ouvert pour ajouter le support.

Nous devons configurer le comportement par défaut :

```
catalog:
  build: ./catalog
  environment:
    APP_PRICING_ENDPOINT: http://pricing:5000/price
    OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1
    OTEL_RESOURCE_ATTRIBUTES: service.name=orders #2
    OTEL_METRICS_EXPORTER: none #3
    OTEL_LOGS_EXPORTER: none #3
```

1. Envoyez les traces à Jaeger
2. Définissez le nom du service. C'est le nom qui apparaîtra dans le composant d'affichage des traces
3. Nous ne sommes intéressés ni par les logs ni par les métriques

Comme pour Python, nous pouvons monter d'un cran en ajoutant une instrumentation manuelle. Deux options sont disponibles, programmatique et basée sur des annotations. La première est un peu complexe à moins que nous n'introduisions Spring Cloud Sleuth. Ajoutons des annotations.

Nous avons besoin d'une dépendance supplémentaire :

```
<dependency>
    <groupId>io.opentelemetry.instrumentation</groupId>
    <artifactId>opentelemetry-instrumentation-annotations</artifactId>
    <version>1.17.0-alpha</version>
</dependency>
```

Attention, l'artefact a été très récemment déplacé de `io.opentelemetry:opentelemetry-extension-annotations`.

Nous pouvons maintenant annoter notre code :

```
@WithSpan("ProductHandler.fetch")                                               //1
suspend fun fetch(@SpanAttribute("id") id: Long): Result<Product> {             //2
    val product = repository.findById(id)
    return if (product == null) Result.failure(IllegalArgumentException("Product $id not found"))
    else Result.success(product)
}
```

1. Ajoutez un span supplémentaire avec l'étiquette configurée
2. Utilisez le paramètre comme attribut, avec la clé définie sur `id` et la valeur la valeur du paramètre au moment de l'exécution

## Le résultat

Nous pouvons maintenant jouer avec notre simple démo pour voir le résultat :

```
curl localhost:9080/products
curl localhost:9080/products/1
```

Les réponses ne sont pas intéressantes, mais regardons l'interface utilisateur de Jaeger. Nous trouvons les deux traces, une par appel :

![Liste des traces dans l'interface utilisateur de Jaeger](https://static.api7.ai/2022/10/03/633a3b371df19.jpg?imageMogr2/format/webp)

Nous pouvons plonger dans les spans d'une seule trace :

![Tous les spans qui constituent une seule trace](https://static.api7.ai/2022/10/03/633a3d1cac655.jpg?imageMogr2/format/webp)

Notez que nous pouvons déduire le flux de séquence sans le diagramme UML ci-dessus. Encore mieux, la séquence affiche les appels internes à un composant.

Chaque span contient des attributs que l'instrumentation automatique a ajoutés et ceux que nous avons ajoutés manuellement :

![Attributs d'un span](https://static.api7.ai/uploads/2023/08/02/c9716Cc1_span-attributes.jpg?imageMogr2/format/webp)

## Conclusion

Dans cet article, j'ai présenté le tracing en suivant une requête à travers une passerelle API, deux applications basées sur des piles technologiques différentes et leurs bases de données respectives. J'ai effleuré seulement la surface du tracing : dans le monde réel, le tracing impliquerait probablement des composants sans rapport avec HTTP, tels que Kafka et les files d'attente de messages.

Cependant, la plupart des systèmes reposent sur HTTP d'une manière ou d'une autre. Bien que pas trivial à mettre en place, ce n'est pas trop difficile non plus. Tracer les requêtes HTTP à travers les composants est un bon début dans votre voyage vers l'observabilité de votre système.

Le code source complet de cet article peut être trouvé sur [GitHub](https://github.com/nfrankel/opentelemetry-tracing).

**Pour aller plus loin :**

- [Spécification W3C Trace Context](https://www.w3.org/TR/trace-context/)
- [Implémentations de Trace Context](https://github.com/w3c/trace-context/blob/main/implementations.md)
- [Un guide pour débutants sur OpenTelemetry](https://medium.com/@magstherdev/opentelemetry-d71d369c83d7)
- [Instrumentation automatique en Python](https://opentelemetry.io/docs/instrumentation/python/automatic/)
- [Distro Python](https://opentelemetry.io/docs/instrumentation/python/distro/)
- [Démarrage avec Jaeger](https://www.jaegertracing.io/docs/next-release/getting-started/)

Tags:

[OpenTelemetry](https://api7.ai/tags/opentelemetry)

[API Gateway Concept](https://api7.ai/tags/api-gateway-concept)

Share article link

Share

Related Posts

[![Comment intégrer API Gateway et Consul ?](https://static.api7.ai/apisix-webp/2022/blog/0818/ecosystem/HashiCorp%20Consul.webp)](https://api7.ai/blog/integrate-consul-kv-with-apache-apisix)

## [Comment intégrer API Gateway et Consul ?](https://api7.ai/blog/integrate-consul-kv-with-apache-apisix)

[![Une décision réelle de passerelle API : Au cœur du processus d'évaluation technique](https://static.api7.ai/uploads/2025/06/03/E7OqOddo_api-gateway-decision.webp)](https://api7.ai/blog/api-gateway-decision-inside-technical-evaluation)

## [Une décision réelle de passerelle API : Au cœur du processus d'évaluation technique](https://api7.ai/blog/api-gateway-decision-inside-technical-evaluation)

Table of Contents

- [La spécification W3C Trace Context](#la-sp%C3%A9cification-w3c-trace-context)
- [OpenTelemetry comme standard de référence](#opentelemetry-comme-standard-de-r%C3%A9f%C3%A9rence)
- [Le cas d'utilisation](#le-cas-dutilisation)
- [Traces à la passerelle](#traces-%C3%A0-la-passerelle)
- [Collecte, stockage et affichage des traces](#collecte-stockage-et-affichage-des-traces)
- [Traces dans les applications Flask](#traces-dans-les-applications-flask)
- [Traces dans les applications Spring Boot](#traces-dans-les-applications-spring-boot)
- [Le résultat](#le-r%C3%A9sultat)
- [Conclusion](#conclusion)

## Related Posts

[![Exploitez Amazon pour l'écosystème et la croissance d'Apache APISIX](https://static.api7.ai/uploads/2023/01/12/I6dWwBSn_aws.png)](https://api7.ai/fr/blog/leverage-amazon-for-apisix-ecosystem-and-growth)

Ecosystem

October 26, 2022

#### [Exploitez Amazon pour l'écosystème et la croissance d'Apache APISIX](https://api7.ai/fr/blog/leverage-amazon-for-apisix-ecosystem-and-growth)

Cet article présente Apache APISIX et ses plugins pour AWS, comment APISIX fonctionne avec les processeurs AWS, et comment API7 Cloud exploite Amazon pour atteindre une croissance rapide.

[APISIX Basics](https://api7.ai/tags/apisix-basics)

[API Gateway Concept](https://api7.ai/tags/api-gateway-concept)

[API7 Cloud](https://api7.ai/tags/api7-cloud)

[![Qu'est-ce que gRPC ? Comment travailler avec APISIX ?](https://static.api7.ai/uploads/2023/01/12/uMWcrTdz_grpc.png)](https://api7.ai/fr/blog/what-is-grpc-and-how-to-work-with-apisix)

Ecosystem

September 28, 2022

#### [Qu'est-ce que gRPC ? Comment travailler avec APISIX ?](https://api7.ai/fr/blog/what-is-grpc-and-how-to-work-with-apisix)

gRPC est un framework moderne, open-source et haute performance pour les appels de procédure distante (RPC) qui peut fonctionner dans n'importe quel environnement. Nous implémentons un client gRPC dans l'écosystème OpenResty.

[APISIX Basics](https://api7.ai/tags/apisix-basics)

[API Gateway Concept](https://api7.ai/tags/api-gateway-concept)

[gRPC](https://api7.ai/tags/grpc)

[![Comparaison des performances des serveurs basés sur ARM sur GCP, AWS et Azure](https://static.api7.ai/2022/11/18/6377328aa91b2.png)](https://api7.ai/fr/blog/arm-performance-google-aws-azure-with-apisix)

Ecosystem

August 12, 2022

#### [Comparaison des performances des serveurs basés sur ARM sur GCP, AWS et Azure](https://api7.ai/fr/blog/arm-performance-google-aws-azure-with-apisix)

Cet article utilise Apache APISIX pour comparer les performances des serveurs ARM de Google, AWS et Azure dans des scénarios intensifs en IO réseau.

[API Gateway Concept](https://api7.ai/tags/api-gateway-concept)

[Comparison to Competitors](https://api7.ai/tags/comparison-to-competitors)
