1. Ingestion des Traces #
Ingestion via OTLP ou protocoles tiers (Jaeger, Zipkin).
Recevoir les traces #
Disponible dans : ✓ OSS ✓ Enterprise ✓ Cloud
Les applications instrumentées envoient leurs traces à Alloy, qui les traite puis les transmet à Tempo ou à un autre backend. Les ports standard de l'OTLP sont 4317 (gRPC) et 4318 (HTTP).
otelcol.receiver.otlp "default" {
grpc {
endpoint = "0.0.0.0:4317"
}
http {
endpoint = "0.0.0.0:4318"
}
output {
traces = [otelcol.processor.memory_limiter.default.input]
}
}
otelcol.processor.memory_limiter "default" {
check_interval = "1s"
limit_percentage = 80
spike_limit_percentage = 20
output {
traces = [otelcol.processor.batch.default.input]
}
}
otelcol.processor.batch "default" {
output {
traces = [otelcol.exporter.otlp.tempo.input]
}
}
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo:4317"
tls {
insecure = true
}
}
}L'ordre recommandé #
| Étape | Composant | Pourquoi |
|---|---|---|
| 1 | memory_limiter | En premier : refuse les données avant que le processus ne manque de mémoire |
| 2 | Traitements | Attributs, transformations, échantillonnage |
| 3 | batch | Juste avant l’envoi : regroupe et réduit le nombre de requêtes |
| 4 | otelcol.exporter.otlp | Envoi |
Erreur rencontrée :limit_percentageseul est refusé au démarrage (« limit_percentage and spike_limit_percentage must be greater than 0 »). Indiquez les deux : c'est pourquoi l'exemple précise aussispike_limit_percentage.
Réglage de batch | Défaut |
|---|---|
timeout | 200ms |
send_batch_size | 2000 |
send_batch_max_size | 3000 |
Accepter les anciens formats #
Pendant une migration, Alloy reçoit aussi Jaeger et Zipkin, puis convertit tout vers le même pipeline. Les applications existantes n'ont donc rien à changer.
otelcol.receiver.jaeger "historique" {
protocols {
grpc {}
}
output {
traces = [otelcol.processor.batch.default.input]
}
}
otelcol.receiver.zipkin "historique" {
output {
traces = [otelcol.processor.batch.default.input]
}
}
otelcol.processor.batch "default" {
output {
traces = []
}
}Vérifier #
Branchez temporairement otelcol.exporter.debug en sortie : il affiche chaque span dans les journaux d'Alloy. Ce composant est expérimental : lancez Alloy avec --stability.level=experimental. Les métriques otelcol_receiver_accepted_spans_total et otelcol_exporter_sent_spans_total permettent ensuite de comparer l'entrée et la sortie.
0.0.0.0:4318rend le récepteur accessible aux autres machines. Sur un hôte partagé, limitez l'accès, ou ajoutez l'authentification avecotelcol.auth.*.
2. Transformation et Échantillonnage #
Adaptation des spans et échantillonnage (sampling).
Nettoyer les attributs #
Une trace peut contenir des données sensibles. otelcol.processor.attributes les retire ou les masque avant qu'elles ne quittent votre réseau.
otelcol.processor.attributes "nettoyage" {
action {
key = "http.request.header.authorization"
action = "delete"
}
action {
key = "user.email"
action = "hash"
}
action {
key = "deployment.environment.name"
value = "prod"
action = "upsert"
}
output {
traces = []
}
}| Attribut reçu | Attribut envoyé (mesuré) |
|---|---|
http.request.header.authorization: Bearer secret | Supprimé |
user.email: alice@exemple.fr | 182e2bdf10871ea9… (haché) |
| Absent | deployment.environment.name: prod |
Le hachage garde une valeur stable : vous pouvez toujours compter les utilisateurs touchés, sans connaître leur adresse.
Normaliser avec OTTL #
otelcol.processor.transform exécute des instructions en OTTL. Ici, on regroupe GET /produits/42, GET /produits/43… sous un seul nom : sans cela, chaque identifiant crée une opération distincte, et les tableaux de bord deviennent illisibles.
otelcol.processor.transform "noms" {
error_mode = "ignore"
trace_statements {
context = "span"
statements = [
`set(attributes["http.route"], "/produits/{id}") where IsMatch(name, "^GET /produits/[0-9]+$")`,
`set(name, "GET /produits/{id}") where IsMatch(name, "^GET /produits/[0-9]+$")`,
]
}
output {
traces = []
}
}Résultat constaté : le span s'appelle GET /produits/{id} et porte http.route=/produits/{id}. L'ordre compte : on écrit l'attribut avant de renommer, sinon la condition ne correspond plus.
Échantillonner intelligemment #
Garder toutes les traces coûte cher. Il existe deux approches :
En tête (probabilistic_sampler) | En queue (tail_sampling) | |
|---|---|---|
| Décision | Dès le premier span | Après avoir vu la trace |
| Garde les erreurs ? | Non, c’est le hasard | Oui |
| Coût | Très faible | Mémoire : les traces sont retenues |
otelcol.processor.tail_sampling "decision" {
decision_wait = "30s"
num_traces = 50000
policy {
name = "garder-les-erreurs"
type = "status_code"
status_code {
status_codes = ["ERROR"]
}
}
policy {
name = "garder-les-lentes"
type = "latency"
latency {
threshold_ms = 1000
}
}
policy {
name = "echantillon-du-reste"
type = "probabilistic"
probabilistic {
sampling_percentage = 5
}
}
output {
traces = []
}
}Une trace est gardée dès qu'une politique l'accepte. Nous avons testé erreurs et lenteur (avec decision_wait réduit à 5 s) sur 3 traces :
| Trace | Résultat |
|---|---|
GET /produits/42 en erreur, 20 ms | Gardée |
GET /sante réussie, 10 ms | Écartée |
POST /payer réussie, 2500 ms | Gardée |
otelcol_receiver_accepted_spans_total valait 3, et otelcol_exporter_sent_spans_total 2.
En cas de plusieurs instances : tous les spans d'une trace doivent arriver sur la même instance. Devant plusieurs Alloy, ajoutezotelcol.exporter.loadbalancingavecrouting_key = "traceID".decision_wait(30 s par défaut) etnum_traces(50000) déterminent la mémoire nécessaire.
Produire des métriques à partir des traces #
Pour ne pas perdre les taux réels malgré l'échantillonnage, générez les métriques avant celui-ci : forward les traces reçues à la fois vers ce connecteur et vers le pipeline.
otelcol.connector.spanmetrics "red" {
histogram {
explicit {
buckets = ["100ms", "500ms", "2s"]
}
}
output {
metrics = [otelcol.exporter.prometheus.vers_prom.input]
}
}
otelcol.exporter.prometheus "vers_prom" {
forward_to = [prometheus.remote_write.mimir.receiver]
}
prometheus.remote_write "mimir" {
endpoint {
url = "http://mimir:9009/api/v1/push"
}
}