RousselTMLEARNING

Article · Alloy : de la découverte à l'expertise

Variables d'environnement et OpenTelemetry

1. L'essentiel : Alloy n'est pas un SDK #

Qui lit quelle variable, et pourquoi la confusion est fréquente.

Trois familles de variables à ne pas confondre #

Une idée reçue revient souvent : « Alloy est compatible OpenTelemetry, donc il suffit de définir les variables OTEL_* ». C'est faux. Ces variables sont définies par la spécification pour les SDK, c'est-à-dire les bibliothèques intégrées à vos applications. Alloy est un collecteur : il reçoit de l'OTLP, mais sa configuration passe par ses composants.

Qui lit quelle variable d'environnement entre l'application, Alloy et le backend

FamilleExemplesQui la lit ?
Variables natives d’AlloyGOMEMLIMIT, GOGC, HTTP_PROXYAlloy, automatiquement
Vos propres variablesTEMPO_ENDPOINT, CLUSTER_NAMEAlloy, seulement via sys.env()
Variables OpenTelemetryOTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINTLe SDK de l’application
L’exceptionOTEL_RESOURCE_ATTRIBUTESAlloy, via otelcol.processor.resourcedetection
Comment ces résultats ont été vérifiés : les comportements de cet article ont été testés le 4 novembre 2026 avec Grafana Alloy v1.21.3, en envoyant de vraies traces OTLP. La liste des variables évolue : consultez la documentation de votre version.

2. Les variables lues nativement par Alloy #

Mémoire, runtime Go, proxy et paquets Linux.

Mémoire et runtime Go #

Alloy étant écrit en Go, il respecte les variables du runtime. Ce sont les seules, avec celles du proxy, que la documentation d'Alloy liste comme lues automatiquement.

VariableRôleDéfaut
GOMEMLIMITLimite mémoire souple du ramasse-miettes (900MiB, 1GiB…)Calculée (voir ci-dessous)
AUTOMEMLIMITPart de la limite du conteneur utilisée pour calculer GOMEMLIMIT (0 à 1)0,9
AUTOMEMLIMIT_EXPERIMENTsystem : se baser sur la mémoire totale du système–
GOGCPourcentage cible du ramasse-miettes ; off le désactive100
GOMAXPROCSNombre de threads exécutant du code Go simultanémentNon précisé
GOTRACEBACKDétail des traces lors d’un panicNon précisé
GODEBUGOptions de débogage : x509usefallbackroots, netdns–
PPROF_MUTEX_PROFILING_PERCENTPart des mutex échantillonnés0,1 %
PPROF_BLOCK_PROFILING_RATEFréquence de suivi des blocages de goroutines10000
GOMEMLIMIT n'est pas une limite stricte : la documentation le rappelle explicitement. Gardez une marge sous la limite de votre conteneur, sinon le processus peut quand même être tué (OOM).

Proxy sortant #

VariableRôle
HTTP_PROXYProxy des requêtes HTTP
HTTPS_PROXYProxy des requêtes HTTPS
NO_PROXYExceptions séparées par des virgules : adresses IP, blocs CIDR, domaines ou *

Paquets Linux (systemd) #

Avec les paquets deb et rpm, le service lit ses réglages dans /etc/default/alloy (Debian, Ubuntu) ou /etc/sysconfig/alloy (RHEL, Fedora, SUSE). Après modification : sudo systemctl restart alloy.

VariableRôle
CONFIG_FILEFichier de configuration du moteur par défaut
CUSTOM_ARGSOptions supplémentaires, par exemple --server.http.listen-addr=0.0.0.0:12345
ALLOY_OTEL_MODEActive le moteur OpenTelemetry au lieu du moteur par défaut
OTEL_CONFIG_FILE, OTEL_CUSTOM_ARGSÉquivalents pour le moteur OpenTelemetry

3. Vos variables : sys.env() #

Lecture explicite, valeurs par défaut et pièges.

Lire une variable dans la configuration #

Toute autre variable doit être lue explicitement avec sys.env(). Si elle n'existe pas, la fonction renvoie une chaîne vide, sans erreur : c'est pourquoi on l'associe à coalesce() pour prévoir une valeur par défaut.

otelcol.exporter.otlp "tempo" {
  client {
    // host:port pour cet exportateur gRPC ; valeur par défaut si la variable est absente
    endpoint = coalesce(sys.env("TEMPO_ENDPOINT"), "tempo:4317")
    headers  = { "X-Scope-OrgID" = coalesce(sys.env("TEMPO_TENANT"), "anonymous") }
    tls {
      insecure = true
    }
  }
}
Piège : sans valeur par défaut, l'échec survient plus loin. Avec endpoint = sys.env("ABSENTE") sur otelcol.exporter.otlphttp, alloy run s'arrête sur « at least one endpoint must be specified ». Le message ne cite pas la variable : pensez à elle en premier.

Une variable d'environnement n'est lue qu'au démarrage du processus : la changer impose de redémarrer Alloy. Pour une valeur qui doit pouvoir changer à chaud, utilisez local.file ou remote.http. Les secrets sont traités dans la leçon Gestion des secrets.

4. OTEL_RESOURCE_ATTRIBUTES : la variable que l'on peut lire #

Le détecteur env, l'option override et son piège.

Le composant resourcedetection #

Le composant otelcol.processor.resourcedetection possède un détecteur env, activé par défaut (detectors = ["env"]). Il lit OTEL_RESOURCE_ATTRIBUTES au format cle1=valeur1,cle2=valeur2 et ajoute ces attributs à toutes les données qui le traversent. C'est le moyen d'indiquer l'environnement ou le cluster une seule fois, au niveau du collecteur.

Effet mesuré de OTEL_RESOURCE_ATTRIBUTES selon la configuration d'Alloy

Le piège d'override #

Ces quatre résultats ont été mesurés avec une même trace envoyée par une application nommée from-app. Trois enseignements :

  • Sans le composant, la variable n'a aucun effet. La définir pour Alloy ne suffit pas.
  • override vaut true par défaut : un attribut déjà présent est remplacé. Si la variable contient service.name, toutes les applications qui passent par cet Alloy prennent ce nom. Vos services fusionnent alors dans Tempo.
  • OTEL_SERVICE_NAME est ignorée par ce détecteur, contrairement à un SDK où elle a priorité.
Bonne pratique : sur un Alloy qui reçoit plusieurs applications, utilisez override = false et limitez la variable aux attributs du site : deployment.environment.name, k8s.cluster.name, cloud.region. Ne mettez jamais service.name.

5. Les variables OTEL_* côté application #

Pointer un SDK vers Alloy avec les variables standard.

Variables générales du SDK #

VariableRôleDéfaut (spécification)
OTEL_SERVICE_NAMENom du service ; prioritaire sur le service.name de OTEL_RESOURCE_ATTRIBUTES–
OTEL_RESOURCE_ATTRIBUTESAttributs de ressource : cle=valeur,cle2=valeur2–
OTEL_SDK_DISABLEDDésactive le SDKfalse
OTEL_LOG_LEVELNiveau de journalisation du SDKinfo
OTEL_PROPAGATORSPropagation du contextetracecontext,baggage
OTEL_TRACES_SAMPLERÉchantillonneurparentbased_always_on
OTEL_TRACES_SAMPLER_ARGArgument de l’échantillonneur (ex. 0.1)–
OTEL_TRACES_EXPORTER, OTEL_METRICS_EXPORTER, OTEL_LOGS_EXPORTERExportateur de chaque signalotlp

Variables de l'exportateur OTLP #

Chacune existe aussi par signal, par exemple OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, qui l'emporte alors sur la variable générale.

VariableRôleDéfaut
OTEL_EXPORTER_OTLP_ENDPOINTURL de destinationgRPC http://localhost:4317, HTTP http://localhost:4318
OTEL_EXPORTER_OTLP_PROTOCOLgrpc, http/protobuf ou http/jsonhttp/protobuf
OTEL_EXPORTER_OTLP_HEADERSEn-têtes : cle=valeur,cle2=valeur2–
OTEL_EXPORTER_OTLP_TIMEOUTDélai maximal d’un envoi, nouvelles tentatives comprises10s
OTEL_EXPORTER_OTLP_COMPRESSIONgzip ou noneChoix du SDK
OTEL_EXPORTER_OTLP_CERTIFICATECertificat de confiance TLS–
Le piège du chemin : avec OTEL_EXPORTER_OTLP_ENDPOINT=http://alloy:4318, le SDK ajoute /v1/traces. Avec la variable par signal OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, l'URL est utilisée telle quelle : indiquez alors http://alloy:4318/v1/traces. Autre erreur fréquente : envoyer du http/protobuf (protocole par défaut) sur le port gRPC 4317.

Exemple complet : une application et Alloy #

L'application reçoit ses variables standard ; Alloy reçoit celles qui concernent le site. Sa configuration, validée avec alloy validate et testée de bout en bout, reprend explicitement la destination :

otelcol.receiver.otlp "default" {
  grpc {
    endpoint = "0.0.0.0:4317"
  }
  http {
    endpoint = "0.0.0.0:4318"
  }
  output {
    traces  = [otelcol.processor.resourcedetection.env.input]
    metrics = [otelcol.processor.resourcedetection.env.input]
    logs    = [otelcol.processor.resourcedetection.env.input]
  }
}

// Ajoute les attributs de OTEL_RESOURCE_ATTRIBUTES sans écraser ceux des applications
otelcol.processor.resourcedetection "env" {
  detectors = ["env"]
  override  = false
  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

otelcol.processor.batch "default" {
  output {
    traces  = [otelcol.exporter.otlphttp.backend.input]
    metrics = [otelcol.exporter.otlphttp.backend.input]
    logs    = [otelcol.exporter.otlphttp.backend.input]
  }
}

// Reprend explicitement la variable standard : sans sys.env, elle ne serait pas lue
otelcol.exporter.otlphttp "backend" {
  client {
    endpoint = sys.env("OTEL_EXPORTER_OTLP_ENDPOINT")
    headers  = { "X-Scope-OrgID" = coalesce(sys.env("BACKEND_TENANT"), "anonymous") }
  }
}
services:
  alloy:
    image: grafana/alloy:latest
    command: run /etc/alloy/config.alloy --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data
    volumes:
      - ./config.alloy:/etc/alloy/config.alloy:ro
    environment:
      OTEL_EXPORTER_OTLP_ENDPOINT: http://tempo:4318
      OTEL_RESOURCE_ATTRIBUTES: deployment.environment.name=prod,k8s.cluster.name=eu-west
      GOMEMLIMIT: 900MiB
    deploy:
      resources:
        limits:
          memory: 1G

  app:
    image: mon-registre/commandes:1.4.0
    environment:
      OTEL_SERVICE_NAME: commandes
      OTEL_RESOURCE_ATTRIBUTES: service.version=1.4.0,team=paiements
      OTEL_EXPORTER_OTLP_ENDPOINT: http://alloy:4318
      OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
      OTEL_TRACES_SAMPLER: parentbased_traceidratio
      OTEL_TRACES_SAMPLER_ARG: "0.1"

À l'essai, la trace arrive bien sur /v1/traces du backend : otelcol.exporter.otlphttp ajoute le chemin de chaque signal, comme un SDK avec la variable générale.

Correspondance : otelcol.exporter.otlphttp attend une URL (http://tempo:4318) et otelcol.exporter.otlp, en gRPC, un host:port (tempo:4317). Sans endpoint, ce dernier est refusé au chargement (« missing required attribute endpoint »), même si OTEL_EXPORTER_OTLP_ENDPOINT est définie.

6. Le moteur OpenTelemetry : alloy otel #

La syntaxe ${env:VAR} du Collector, en préversion publique.

Une configuration YAML du Collector #

Le binaire d'Alloy embarque aussi un moteur OpenTelemetry, lancé avec alloy otel --config=otel.yaml. Il lit un fichier YAML au format du Collector : on y retrouve la syntaxe ${env:VARIABLE}, au lieu de sys.env(). Nous avons vérifié cette substitution et le détecteur env sur Alloy v1.21.3.

receivers:
  otlp:
    protocols:
      http:
        endpoint: ${env:RECEIVER_ENDPOINT}
processors:
  resourcedetection:
    detectors: [env]
exporters:
  otlphttp:
    endpoint: ${env:OTEL_EXPORTER_OTLP_ENDPOINT}
service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [resourcedetection]
      exporters: [otlphttp]
Ce moteur est en préversion publique : la documentation prévient que des changements incompatibles sont possibles. Pour la production, le moteur par défaut (alloy run) reste le choix stable.

7. Kubernetes et bonnes pratiques #

Helm, Beyla, erreurs courantes et commandes.

Sur Kubernetes #

# values.yaml du chart Helm grafana/alloy
alloy:
  extraEnv:
    - name: OTEL_RESOURCE_ATTRIBUTES
      value: "deployment.environment.name=prod,k8s.cluster.name=eu-west"
    - name: GOMEMLIMIT
      value: "900MiB"
  resources:
    limits:
      memory: 1Gi

Cas particulier de Beyla : le composant beyla.ebpf peut reprendre, via extra_resource_labels, des attributs fournis par la variable OTEL_RESOURCE_ATTRIBUTES du service observé. C'est la variable de l'application qui compte, pas celle d'Alloy.

À retenir #

  • Définir OTEL_* pour Alloy ne configure pas Alloy, sauf OTEL_RESOURCE_ATTRIBUTES avec resourcedetection.
  • Lisez vos valeurs avec sys.env(), et prévoyez une valeur par défaut avec coalesce().
  • Utilisez override = false sur un Alloy partagé, et jamais service.name dans sa variable.
  • Réservez OTEL_SERVICE_NAME et OTEL_EXPORTER_OTLP_* aux applications.
  • Fixez GOMEMLIMIT sous la limite mémoire du conteneur.

Commandes à connaître #

# Vérifier la configuration avec les variables de l'environnement courant
TEMPO_ENDPOINT=tempo:4317 alloy validate config.alloy

# Valider un fichier sans le lancer, puis le démarrer
alloy fmt config.alloy
alloy run config.alloy --server.http.listen-addr=127.0.0.1:12345

# Voir les variables réellement reçues par le processus
docker compose exec alloy env | grep -E 'OTEL_|GOMEM'

# Tester le pipeline avec une trace minimale (OTLP/HTTP)
curl -X POST -H 'Content-Type: application/json' -d @trace.json http://localhost:4318/v1/traces

# Moteur OpenTelemetry (préversion publique)
alloy otel --config=otel.yaml

Sources officielles #

📄 Variables d'environnement de Grafana Alloy : GOMEMLIMIT, sys.env et OTEL_RESOURCE_ATTRIBUTES →

Mon suivi

  • ⏱ Durée estimée : ≈ 23 min

Connectez-vous pour suivre votre progression et prendre des notes. Se connecter

💬 Poser une question

Glossaire de la formation

Observabilité

La capacité à connaître l'état interne d'un système à partir des données qu'il émet.Ces données sont classées en 3 piliers : logsmétriquestracesprofil...

Traces distribuées

Technique (issue du pilier des Traces) permettant de suivre le cheminement complet d'une requête à travers de multiples micro-services pour identifier...

Métriques

Mesures numériques collectées à intervalles réguliers (ex: CPU, RAM, temps de réponse) utilisées pour évaluer l'état de santé global d'un système au f...

Profilage en continu (Continuous Profiling)

Analyse constante de l'exécution du code en production pour identifier avec précision quelles lignes de code ou fonctions consomment le plus de ressou...

Access Log

Fichier de journalisation enregistrant les requêtes traitées par un serveur web (Apache, Nginx, Lighttpd, etc.). Il permet de tracer l'activité du ser...

Client IP

L'adresse IP de l'utilisateur effectuant la requête vers le serveur web. Lorsqu'un utilisateur passe par un Load Balancer ou un proxy (ex: Cloudflare)...

Timestamp

La date et l'heure exactes auxquelles la requête a été reçue par le serveur.Configuration : %t dans Apache, $time_local ou $time_iso8601 dans Nginx.

Request

La ligne de requête initiale du client. Elle comprend généralement la méthode HTTP (ex: GET), l'URL demandée et la version du protocole HTTP.Configura...

Status Code

Le code de statut HTTP final renvoyé par le serveur au client (ex : 200 pour un succès, 404 pour ressource non trouvée).Configuration : %>s dans Apach...

Size

Le volume des données renvoyées au client, mesuré en octets (généralement sans les en-têtes HTTP).Configuration : %b ou %O dans Apache, $body_bytes_se...

Referrer

L'URL de la page web depuis laquelle le client a cliqué ou suivi un lien pour accéder à la ressource actuelle.Configuration : %{Referer}i dans Apache,...

User-Agent

Les informations d'identification fournies par le client concernant son navigateur, son système d'exploitation et son appareil. Sa structure standard ...

Response Time

La durée totale prise par le serveur pour traiter la requête et renvoyer la réponse au client.Configuration : %D (microsecondes) ou %T (secondes) dans...

Grafana Alloy

Collecteur de télémétrie open source et flexible, successeur de Grafana Agent. Il est conçu pour collecter, transformer et exporter des logs, métrique...

River

Langage de configuration déclaratif utilisé par Grafana Alloy, inspiré de HCL (Terraform). Il permet de définir des pipelines de télémétrie complexes ...

Grafana Loki

Système de journalisation (logs) multi-tenant, hautement disponible et inspiré de Prometheus. Il est conçu pour être très économe en ressources en n'i...

Articles recommandés

Envoyer des traces vers Tempo : instrumentation OpenTelemetry et Alloy

Produire et acheminer des traces vers Tempo : auto-instrumentation Python/Java/Node, SDK manuel, ...

Configuration de Grafana Alloy : syntaxe, ports et premiers composants

Dans le cadre d'une formation Grafana ou formation observabilité, maîtrisez la syntaxe déclarativ...

OpenTelemetry : Instrumentation Automatique vs Manuelle

Comprenez les différences entre l'instrumentation automatique et manuelle avec OpenTelemetry, leu...

Instrumenter ses applications pour Jaeger avec OpenTelemetry

Envoyer des traces à Jaeger avec OpenTelemetry : auto-instrumentation (Java, Python, Node.js), SD...

Bonnes Pratiques Grafana Alloy : Optimiser sa Collecte de Télémétrie

Découvrez les règles d'or pour configurer Grafana Alloy de manière robuste : modularité, gestion ...

Grafana Alloy : Collecter les métriques système et les logs locaux

Découvrez comment configurer Grafana Alloy pour superviser le serveur sur lequel il s'exécute, av...

Grafana Alloy et les traces : OTLP, Jaeger et Zipkin vers Tempo

Plongez dans le traitement des traces distribuées. Apprenez à ingérer des traces OTLP, Jaeger ou ...

Grafana Alloy vs OpenTelemetry Collector : Lequel choisir ?

Comparaison détaillée entre Grafana Alloy et l'OpenTelemetry Collector. Découvrez les avantages, ...

Grafana Alloy : Collecte et Transformation de Télémétrie

Apprenez à utiliser Grafana Alloy pour collecter, transformer et acheminer logs, métriques et tra...

Soutenir

♥ SOUTENIR

Soutenez RousselTM Learning

Les formations, articles, TP et attestations restent gratuits et sans publicité intrusive. Une contribution libre, du montant de votre choix, finance l’hébergement, les environnements de TP et l’écriture de nouveaux contenus.

Contribuer avec PayPal Montant libre · carte bancaire ou compte PayPalEn savoir plus
QR code PayPal
Ou scannez ce QR code avec votre téléphone

Merci, chaque contribution compte !