Les Crash-Devs d'un Passionné

Mettre en place de l'observabilité

/Catégorie/python

Temps de lecture : 9 minutes

Pour suivre la santé de votre application il est primordiale de suivre les métriques les plus importantes. J'ai du implémenter ce mécanisme le mois dernier et je vais vous faire un retour sur son intégration dans Datadog puis Signoz.

Je vais utiliser un Application Performance Monitoring (APM) qui permet d'obtenir les erreurs HTTP, temps de réponse ou encore la consommation de ressource. On remonte les traces sur cet APM.

J'utiliserais également la remonté des logs qui est une autre fonctionnalité de Datadog et Signoz

Il y a 2 manières de configurer l'export des données :

  • via la modification du code de votre application (mode manuel ou code base)
  • via un outil qui wrappe le démarrage de l'application, sans modifier le code de prod (mode automatique ou no code)

On peut également choisir d'utiliser un middleware entre l'application et le serveur APM. Ce collecteur permet d'affiner un peu plus ce qui va être remonté dans l'outil, il portera la configuration ici au lieu dans l'application.

Après la lecture de cet article il vous restera à choisir l'observabilité qui vous convient le mieux.

Datadog

C'est le leader du marché pour mettre en place de l'observabilité, une solution performante mais aussi assez onéreuse. Une fois la période de 15 jours terminée, l'accès à l'APM et le log explorer n'est plus possible sans payer.

Datadog recommande de passer par leur agent (un service qui tourne à côté de votre application) qui est un intermédiaire entre l'application et le serveur datadog : je suis parti sur cette solution que je vais vous présenter.

L'avantage de cette solution est de passer par une seule librairie

ddtrace
,c'est une approche automatique c'est à dire que l'on ne modifie pas le code de production.

Il suffit d'aller préfixer l'exécution de votre serveur comme ceci

ddtrace-run uvicorn "src.main:app" --host=0.0.0.0 --port=8000

Comme nous passons par l'agent de Datadog il faut le lancer dans un container hérité de

gcr.io/datadoghq/agent:latest

Pour ma part j'utilise un sidecar sous GCP mais vous êtes libre de le faire autrement comme via un service docker-compose. Il faut penser à appliquer ces variables d'env

  • DD_SERVICE="myapp"
  • DD_ENV="PROD"
  • DD_SERVERLESS_LOG_PATH="/datadog/app.log"
  • DD_SITE="datadoghq.eu"
  • DD_API_KEY=<YOUR_DATADOG_API_KEY>

Vous avez surement remarqué que j'indique à Datadog où se situe les log puisque pour la rémonté des logs il faut mettre en place une écriture des logs dans un fichier qui sera configuré dans un handler de la librarie

logging

clipboard
Copier le code
1
2
3
4
5
6
7
"file": {
    "level": self.verbose_level,
    "class": "logging.handlers.RotatingFileHandler",
    "filename": "/datadog/app.log",
    "maxBytes": 50 * 1024 * 1024,
    "backupCount": 3,
 }

Il reste à configurer ce volume /datadog (ou un autre nom à votre convenance) qui sera partagé entre votre applicaton et l'agent Datadog.

Voici un exemple complet de configuration de mon agent sous GCP

clipboard
Copier le code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- name: datadog-agent
 image: gcr.io/datadoghq/agent:latest
 command: ["/bin/sh", "-c"]
 args:
 - >-
 for i in $(seq 1 150); do
   wget -q -O- http://127.0.0.1:8000/ >/dev/null 2>&1 && break;
   sleep 2;
 done;
 exec agent run
 env:
 - name: DD_SERVICE
 value: "myapp"
 - name: DD_ENV
 value: "PROD"
 - name: DD_SERVERLESS_LOG_PATH
 value: "/datadog/app.log"
 - name: DD_SITE
 value: "datadoghq.eu"
 - name: DD_API_KEY
 value: ${DATADOG_API_KEY}
 volumeMounts:
 - name: datadog
 mountPath: /datadog
 volumes:
 - name: datadog
 emptyDir: { }

APM avec agent

Signoz

C'est une alternative open source à Datadog que j'avais envie de tester. En effet comme vu aupravant Datadog sur sa version free ne permet pas de tester son APM (après avoir terminé la version d'essai).

Pour simplifier ma configuration je suis parti sur un accès direct à l'exporter de signoz sans passer par l'exporter OTLP proposé par open telemetry (la solution évoquée avec Datadog juste avant reposait sur un exporter OTLP que Datadog nomme agent).

APM sans agent

L'approche no code

On va commencer par installer la librairie

opentelemetry-distro
qui permet de mettre en place de l'instrumentation.

Il suffit d'aller préfixer l'exécution de votre serveur comme ceci

opentelemetry-instrument uvicorn "src.main:app" --host=0.0.0.0 --port=8000

Dans mon

Dockerfile
je précise toute la mécanique d'auto configuration via

RUN opentelemetry-bootstrap --action=install

La seconde librairie

opentelemetry-exporter-otlp
permet d'aller configurer l'exporteur, simplement en passant par des variables d'environnements :

  • OTEL_EXPORTER_OTLP_PROTOCOL=grpc
  • OTEL_EXPORTER_OTLP_ENDPOINT=ngest.eu.signoz.cloud:443
  • OTEL_EXPORTER_OTLP_HEADERS=signoz-access-token=${SIGNOZ_TOKEN}
  • OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED="true
  • OTEL_RESOURCE_ATTRIBUTES="deployment.environment=prod,service.version=${CI_COMMIT_SHA}"
  • OTEL_SERVICE_NAME=myapp

trace_apm_signoz

Un point qui n'est pas précisé dans la documentation de signoz c'est que la collecte des logs nécessite un handler particulier. Contrairement au trace qui utilise le monkey patching, pour les logs avec la librairie

logging
il faut préciser à OTEL où se connecter.

Vous devrez ajouter ce handler dans votre configuration d'application

clipboard
Copier le code
1
2
3
4
"otel": {
 "class": "opentelemetry.sdk._logs.LoggingHandler",
 "level": "INFO",
},

log_apm_signoz

L'approche code base

Si vous vous êtes intéressé à mettre en place de l'observabilité dans FastApi vous êtes surement tombé sur cette librairie

opentelemetry-instrumentation-fastapi

C'est un outil qui récolte les informations (trace) dans les profondeurs du framework. Il se comporte comme un middleware et doit être appelé après l'initialisation du framework.

clipboard
Copier le code
1
2
app = FastAPI()
FastAPIInstrumentor.instrument_app(app)

Comme vous le remarquez il est nécessaire de modifier son code de production.

Avec cette librairie on a mis en place la collecte des informations mais cela n'est pas suffisant. Il faut également mettre en place :

  • la collecte des logs avec
    opentelemetry-instrumentation-logging
  • la mécanique de l'observabilité avec
    opentelemetry-sdk
  • l'exporteur de données (trace + log) avec
    opentelemetry-exporter-otlp

Je ne vais pas rentrer dans le détail de son implémentation car cela est fastidieux. Il faut refaire la mécanique de

opentelemetry-distro
, certaines fois cela peut être intéressant si vous avez besoin de finesse dans votre observabilité.

Conclusion

La simplicité de datadog, qui ne nécessite pas autant de paramètres que signoz, le rend plus vite configurable.

Le choix entre une instrumentation manuelle (modification du code de prod) ou automatique (via un wrapper de lib) dépend de votre contexte. Le mode automatique est idéal, si vous n'avez pas la main sur la gestion du serveur d'application ou si vous ne voulez pas que votre instrumentation "pollue" le code métier par exemple.

Le mode manuel est privilégié si vous voulez garder la main sur ce que vous voulez remonté et maitriser la mécanique de récolte d'information plus finement.

Et voila 2 techiques pour mettre en place une observabilité sur votre application python.