Logs techniques
Les logs techniques sont ce qu’écrivent l’API, les workers et le reverse proxy. Ils se lisent depuis la console d’administration, page Logs techniques. Ce qu’ils contiennent, et ce qui les distingue du journal métier, est décrit sur Traçabilité.
Le chemin d’une ligne
Section intitulée « Le chemin d’une ligne »flowchart LR
S["api, worker-outbox, worker-cleanup (stdout)"] --> AL["Alloy"]
CA["Caddy (fichiers d'accès)"] --> AL
AL --> L["Loki"]
L --> API["API : /v1/admin/logs"]
API --> CO["console-admin : /logs"]
Le navigateur n’interroge jamais Loki. Il envoie des critères à la console, qui les passe à l’API ;
c’est l’API qui compose la requête LogQL (api/src/infrastructure/logs/logql-builder.ts). Loki n’est
joignable que sur le réseau Docker interne.
Activer la collecte
Section intitulée « Activer la collecte »Sur le serveur :
tep obs on # mémorise l'activation (fichier .observability)tep up # démarre Prometheus, Loki, Alloy et node-exportertep obs status # cibles Prometheus, place occupée sur le disquetep obs off # arrête la collectetep obs on ajoute la surcouche deploy/docker-compose.observability.yml à la stack. C’est elle qui
pose LOKI_URL=http://loki:3100 sur le service api. La variable ne se pose pas à la main.
Sans LOKI_URL :
- les routes de logs répondent
503 LOGS_DISABLED; GET /v1/admin/logs/labelsrépond200avecenabled: false;- la page affiche « La collecte des logs n’est pas activée » ;
- l’onglet Trace reste utilisable : il montre le journal métier seul.
L’API de logs
Section intitulée « L’API de logs »Toutes les routes exigent la portée admin. Fichier : api/src/http/routes/admin-logs.routes.ts.
| Route | Rôle |
|---|---|
GET /v1/admin/logs |
Recherche de lignes, paginée |
GET /v1/admin/logs/histogram |
Volume par tranche de temps et par niveau, totaux par service |
GET /v1/admin/logs/labels |
Services connus sur 24 h, niveaux, types d’appel, collecte activée ou non |
GET /v1/admin/traces/:correlationId |
Trace d’une requête |
GET /v1/admin/sessions/:id/trace |
Trace d’un paiement entier |
Toutes sauf labels sont limitées à 120 requêtes par minute.
Critères
Section intitulée « Critères »Communs à la recherche et à l’histogramme. Le schéma est strict : un paramètre inconnu donne 400.
| Paramètre | Forme | Effet |
|---|---|---|
from, to |
Dates ISO 8601 | Plage. Absente : les 15 dernières minutes |
service |
Liste, 20 valeurs au plus | api, worker-outbox, worker-cleanup, caddy… |
level |
Liste | trace, debug, info, warn, error, fatal, unknown |
q |
Texte, 200 caractères au plus | Cherché dans la ligne, sans tenir compte de la casse |
correlationId, merchantId, legId |
Identifiant | La ligne porte ce champ avec cette valeur |
sessionId |
Identifiant | Cherché partout dans la ligne : l’adresse /v1/sessions/<id> compte aussi |
kind |
Liste | Types du journal d’appels (http_in, provider_call…) |
provider |
Liste | stripe, adyen, titreo, merchant, smtp |
probes |
true, false, 1, 0 |
true montre aussi le bruit de fond, écarté par défaut |
Une liste s’écrit ?service=a&service=b ou ?service=a,b. Un identifiant accepte 128 caractères au
plus parmi lettres, chiffres, _ . : -.
La recherche accepte en plus :
| Paramètre | Effet |
|---|---|
limit |
1 à 1000, 200 par défaut |
direction |
backward (défaut, de la plus récente à la plus ancienne) ou forward |
before |
Page suivante : la valeur nextBefore de la réponse précédente |
after |
Suivi en direct : la valeur newest de la réponse précédente. Force forward |
before et after sont des horodatages en nanosecondes. Ils priment sur from et to.
Le bruit écarté par défaut
Section intitulée « Le bruit écarté par défaut »Sondes de santé, relevé des métriques, fichiers statiques des consoles (/_next/static,
/_next/image, /favicon), et les requêtes de la page de logs elle-même (/v1/admin/logs,
/v1/admin/traces, /logs). probes=true les rend.
Réponses
Section intitulée « Réponses »Une ligne (LogLine, api/src/application/ports/log-store.ts) :
| Champ | Contenu |
|---|---|
id |
Horodatage en nanosecondes et empreinte : stable pour une ligne donnée |
ts, tsNs |
Instant en ISO 8601 et en nanosecondes |
service |
Étiquette service, à défaut le conteneur |
level |
Niveau normalisé. Les niveaux numériques de pino (30, 50) sont traduits |
message |
msg de la ligne, ou méthode et adresse pour une ligne d’accès |
fields |
Champs de la ligne si elle est en JSON, sinon null |
raw |
Ligne brute, bornée à 16 384 caractères |
Une trace rend des couloirs (lanes), des segments (spans), des repères (markers), les
corrélations et sessions rencontrées, des compteurs par issue et les lignes elles-mêmes. truncated
dit qu’il y en avait plus ; logsAvailable: false dit que seul le journal métier a répondu.
| Code | Statut | Cause |
|---|---|---|
LOGS_DISABLED |
503 | Aucun collecteur raccordé |
LOGS_UNAVAILABLE |
502 | Loki ne répond pas en 15 s, ou refuse la requête |
VALIDATION_ERROR |
400 | Paramètre inconnu, plage illisible, inversée ou de plus de 7 jours, curseur illisible |
La page de la console
Section intitulée « La page de la console »Adresse /logs, entrée « Logs techniques » du menu. Fichiers : console-admin/app/(wide)/logs/,
console-admin/components/logs/, console-admin/lib/logs/, actions serveur dans
console-admin/lib/actions/logs.ts.
Le groupe de routes (wide) reprend la console sans la colonne de lecture bornée : un journal se lit
en largeur. Deux vues, par onglet.
Explorateur
Section intitulée « Explorateur »| Élément | Comportement | Fichier |
|---|---|---|
| Plages | 15 min, 1 h, 6 h, 24 h, 7 j | LogsApp.tsx |
| Barre de requête | Ce qui est tapé devient des pastilles à la validation | QueryBar.tsx, lib/logs/query.ts |
| Histogramme | Volume par tranche, empilé par niveau. Glisser choisit une plage, cliquer une barre zoome sur sa tranche | Histogram.tsx |
| Facettes | Services et niveaux avec leurs compteurs, types d’appel, prestataires, et « Sondes et métriques » pour montrer le bruit | Facets.tsx |
| Liste | 500 lignes par page, de la plus récente à la plus ancienne ; « Charger les 500 lignes suivantes » | LogRows.tsx |
| Ligne ouverte | Ses champs, un clic sur une valeur pour filtrer dessus, « Trace de cette requête », « Trace du paiement », « Copier la ligne » | LogRows.tsx |
| Direct | Interroge toutes les 3 s ce qui est arrivé depuis la dernière ligne reçue | LogsApp.tsx |
Le suivi en direct garde 3 000 lignes au plus à l’écran, se met en pause quand l’onglet du navigateur est masqué, et s’arrête dès qu’une plage est choisie à la main. L’histogramme est rafraîchi un tour sur cinq.
Les filtres sont portés par l’adresse : un lien vers la page rouvre la même recherche.
Deux entrées : Paiement (session) ou Requête (corrélation). Des liens y mènent depuis la fiche
d’une transaction, depuis le journal métier et depuis une ligne de l’explorateur
(/logs?view=trace&session=…, /logs?view=trace&corr=…).
Une trace de paiement part du journal métier : il donne toutes les corrélations qui ont touché la
session, 20 au plus, et la fenêtre de temps à fouiller (api/src/application/logs/get-trace.ts).
| Élément | Comportement |
|---|---|
| Couloirs | Un par acteur : services (caddy, api, worker-outbox, worker-cleanup), prestataires, boutique du marchand, journal métier |
| Segments | Une ligne du journal d’appels, ou une ligne d’accès de Caddy. La ligne est écrite à la fin de l’appel : le début se déduit de la durée |
| Repères | Les autres lignes, et les faits du journal métier |
| Silences | Une pause de plus de 1,5 s entre deux périodes d’activité est repliée sur une largeur fixe, avec sa durée (lib/logs/scale.ts) |
| Résumé | Durée totale, appels, réussis, refusés, en échec, requêtes reliées |
| Détail | Cliquer un segment affiche son type, son statut, son issue, la référence du prestataire |
Une trace écarte ce que fait la console d’administration elle-même : l’adresse d’une page de trace contient l’identifiant cherché.
Échanges HTTP complets
Section intitulée « Échanges HTTP complets »Une ligne de log dit qu’un appel a eu lieu et comment il s’est terminé. L’échange dit ce qui a
été envoyé et ce qui a été répondu : en-têtes et corps, requête et réponse. Ouvrir une ligne qui
porte un exchangeId, ou cliquer un segment de trace, affiche le panneau Requête / Réponse,
avec « Copier le corps », « Copier l’échange » et « Copier en cURL » pour un appel sortant.
Ils ne sont pas dans les logs, et c’est voulu :
- un même corps figurerait trois ou quatre fois par paiement (requête reçue, opération, appel sortant, journal métier) ;
- Docker coupe les lignes au-delà de 16 Ko ;
- le Loki des logs peut être ouvert au Grafana du client (vhost
logs.), et une requête LogQL ne se filtre pas à l’entrée d’un proxy.
Les échanges vivent donc dans une seconde instance Loki, loki-exchanges, sans vhost ni
collecte Alloy, conservée 7 jours (deploy/observability/loki-exchanges.yml). L’API et les
workers y écrivent directement, par lots, en arrière-plan ; la console les lit par
GET /v1/admin/exchanges/:id, et chaque lecture est tracée dans le journal d’audit
(admin.exchange.read).
| Capturé | Où |
|---|---|
| Requêtes reçues : navigateur, CMS, SDK, webhooks PSP | api/src/http/plugins/call-log.ts |
| Appels à Titréo et à Stripe | observability/logged-fetch.ts, psp/stripe-logged-fetch.ts |
| Appels à Adyen | psp/adyen-logged-client.ts |
| Webhooks envoyés aux boutiques, réponse lue jusqu’à 64 Ko | webhooks/http-webhook-sender.ts |
Non capturés : les courriers (le corps porte des liens de vérification) et les lectures de logs par la console elle-même.
Politique de conservation
Section intitulée « Politique de conservation »EXCHANGE_CAPTURE, dans .env.prod :
| Valeur | En-têtes | Corps |
|---|---|---|
all |
toujours | toujours — préproduction |
errors (défaut) |
toujours | appels en échec, et tout appel d’un marchand en mode diagnostic — production |
off |
non | non |
Le mode diagnostic se pose sur la fiche du marchand dans la console d’administration, pour
1, 4 ou 24 h (PUT /v1/admin/merchants/:id/diagnostic, 24 h au plus, migration 027). Il est lu en
base au plus toutes les 15 s. Un corps absent dit pourquoi : appel réussi hors diagnostic, jeton,
binaire.
Expurgation
Section intitulée « Expurgation »- en-têtes : liste blanche d’en-têtes sans secret ; tout autre en-tête garde son nom, pas sa valeur
(
Authorization,Cookie, signatures…) ; - corps : carte cadeau réduite à ses quatre derniers caractères, CVV, clés, jetons,
client_secretcensurés, adresses e-mail masquées (j•••@exemple.fr), clés imbriquées des formulaires Stripe reconnues (card[number]), jetons repérés dans le texte libre ; - coordonnées de l’acheteur (
billing_details,shipping,address,shopper…) censurées, sauf le pays et les valeurs vides ; téléphone etreceipt_urlcensurés partout ; le numéro de commande reste lisible,numbern’étant masqué qu’à côté d’un CVC ou d’une expiration ; - adresse IP réduite à son réseau, IPv4 au /24 et IPv6 au /48 (
observability/ip.ts), dans les échanges, dans les ligneshttp_inet dans les journaux d’accès de Caddy (ip_mask) ; - la réponse d’
AuthTokenTitréo, qui est un jeton, n’est jamais conservée ; - corps plafonnés à
EXCHANGE_BODY_MAX_BYTES(32 Ko par défaut).
Code : api/src/infrastructure/observability/exchange.ts, api/src/infrastructure/exchanges/.
Si le stockage ne répond pas
Section intitulée « Si le stockage ne répond pas »Le lot en cours est perdu, compté, et signalé une fois par minute sur la sortie d’erreur du processus. Aucun appel de paiement n’attend l’enregistrement de son échange.
La barre de requête
Section intitulée « La barre de requête »clé:valeur filtre. Tout le reste est du texte cherché dans les lignes. Les clés s’écrivent en
français ou en anglais.
| Clé | Alias | Filtre | Valeurs |
|---|---|---|---|
service: |
services:, svc: |
Service | Liste séparée par des virgules |
niveau: |
level:, lvl: |
Niveau | Liste ; warn+ pour « ce niveau et les plus graves » |
type: |
kind: |
Type d’appel | http_in, http_out, provider_call, webhook_in, webhook_out, outbox, email_out |
prestataire: |
provider:, psp: |
Prestataire | stripe, adyen, titreo, merchant, smtp |
session: |
sessionid: |
Session | Un identifiant |
corr: |
correlation:, correlationid: |
Corrélation | Un identifiant |
marchand: |
merchant:, merchantid: |
Marchand | Un identifiant |
leg: |
legid: |
Moyen de paiement | Un identifiant |
client: |
cms:, extension: |
Extension appelante | prestashop, shopify, sdk-js, sdk-php |
Exemples :
service:api niveau:warn+type:http_out prestataire:titreosession:<identifiant> type:provider_call,outboxprestataire:titreo "Titreo HTTP"niveau:error timeoutRègles, telles que les applique applyQueryText :
- les guillemets gardent une expression entière, espaces compris ;
- un mot dont la clé est inconnue (
foo:bar) est cherché comme du texte ; - les listes s’ajoutent aux filtres déjà posés, un identifiant remplace le précédent ;
- une valeur hors de
[A-Za-z0-9_.:-]est ignorée ; - le texte est borné à 200 caractères ;
- retour arrière sur un champ vide retire la dernière pastille.
| Limite | Valeur | Où |
|---|---|---|
| Plage d’une recherche | 7 jours | api/src/application/logs/log-range.ts |
| Rétention des logs | 720 h (30 jours) | deploy/observability/loki.yml |
| Rétention des échanges | 168 h (7 jours) | deploy/observability/loki-exchanges.yml |
| Corps d’un échange | 32 Ko, puis tronqué | EXCHANGE_BODY_MAX_BYTES |
| Mode diagnostic | 24 h au plus | set-merchant-diagnostic.ts |
| Lignes par recherche | 1 000 | search-logs.ts |
| Lignes d’une trace | 1 000, au-delà truncated: true |
get-trace.ts |
| Faits métier d’une trace | 200 | get-trace.ts |
| Corrélations suivies par trace | 20 | get-trace.ts |
| Fenêtre d’une trace | De 5 min avant le premier fait à 48 h après le dernier, 7 jours au plus | get-trace.ts |
| Délai d’une requête à Loki | 15 s | loki-log-store.ts |
| Cadence | 120 requêtes par minute et par route | admin-logs.routes.ts |
À savoir :
- le
correlationIdn’est pas une étiquette Loki : ce serait une série par requête. Il est cherché dans le corps de la ligne (deploy/observability/commun.alloy) ; - une recherche en plein texte sur 7 jours parcourt beaucoup de données. Réduire la plage ou ajouter
un filtre
service:d’abord ; - sans collecte,
tep logs [service…]suit les journaux des conteneurs sur le serveur ; - la page est réservée à la console d’administration. La console marchand n’y a pas accès.
Voir aussi
Section intitulée « Voir aussi »- Traçabilité — ce que contient une ligne, et la rédaction.
- console-admin — le reste de la console.
- Exploitation & déploiement — la CLI
tepet la documentation du dépôtdeploy.