Appearance
Observabilite et logging
Le service produit un document JSON par ligne sur stdout. Ce format est le contrat d'ingestion du flux OpenObserve service_base = 'tvcast-intercopartnerapi'.
Champs communs
| Champ | Description |
|---|---|
timestamp | Horodatage ISO 8601 UTC |
level | fatal, error, warn, info, debug ou trace |
severity_number | Niveau Pino numerique |
service | Nom runtime du service |
service_base | Identifiant stable OpenObserve |
service_version | Version de l'application |
deployment_environment | Environnement d'execution |
log_schema_version | Version du contrat de log |
event | Nom stable et requetable de l'evenement |
request_id | Identifiant de correlation HTTP |
component | Composant non vide obligatoire, present exactement une fois a la racine de tout evenement |
error_code | Code stable et requetable de l'echec ; ne pas utiliser msg comme identifiant |
http_route | Patron de route Fastify, par exemple /v1/areas/:areaExternalId/ |
http_path | Chemin concret appele, sans query string, par exemple /v1/areas/area-123/ |
client_address | Adresse cliente resolue depuis la chaine de proxies de confiance |
client_address_chain | Adresses validees, de la plus proche a la plus distante |
client_socket_address | Adresse du pair TCP direct, generalement Traefik dans Dokploy |
Les query strings ne sont jamais incluses dans http_path, car elles peuvent contenir des secrets. Les secrets connus sont remplaces par [Redacted]. Une erreur est stockee dans l'objet err; sa stack reste dans le document JSON et ne cree jamais de lignes brutes supplementaires.
Contrat des evenements
Les noms suivent domaine.action.resultat, en minuscules et separes par des points, par exemple partner.auth.failed. Le niveau decrit l'impact :
| Niveau | Usage |
|---|---|
debug | Diagnostic detaille, normalement filtre en production |
info | Cycle normal du service ou requete reussie |
warn | Echec attendu ou recuperable, notamment une reponse HTTP 4xx |
error | Defaillance technique, appel downstream en echec ou reponse HTTP 5xx |
fatal | Le service ne peut pas demarrer ou continuer |
Les evenements de frontiere HTTP contiennent le contexte reseau complet. Les evenements metier lies a une requete conservent request_id, event, component, error_code et les identifiants metier utiles ; leur correlation avec http.request.completed se fait par request_id, sans recopier les adresses IP. Les evenements globaux, tels que server.started, ne portent que le contexte du service. Les evenements http.request.* utilisent le composant httpLifecycle, les evenements server.* utilisent server, et les rares logs sans contexte plus precis utilisent le fallback application.
Lorsqu'un payload structure ou un message entierement constitue d'un objet JSON contient un component, le logger le promeut au niveau racine sans modifier msg. Un component racine explicite reste toujours prioritaire.
error_code constitue l'identifiant stable utilise dans les requetes et alertes. msg reste une description lisible et err contient l'exception serialisee. Les messages d'erreur variables et le champ historique reason ne doivent pas servir de contrat.
Les headers d'authentification, cookies, tokens, query strings et payloads bruts ne doivent jamais etre journalises. Les diagnostics doivent exposer uniquement des champs explicitement choisis, des identifiants externes non secrets et, si necessaire, des nombres d'elements.
Evenements principaux
| Evenement | Niveau | Usage |
|---|---|---|
http.request.received | info | Debut d'une requete HTTP |
http.request.completed | info, warn ou error | Fin, statut et duree d'une requete |
http.request.failed | error | Exception non geree par une route |
facility.lookup.failed | warn ou error | Echec de resolution d'une facility |
facility.list.failed | error | Echec technique de lecture des facilities accessibles |
partner.auth.failed | error | Defaillance technique de validation du partenaire |
cms.request.started | debug | Diagnostic d'un appel CMS sans URL, filtre ou payload |
remote.request.failed | error | Echec d'un appel au service de controle distant |
server.started | info | Service pret a recevoir du trafic |
server.start.failed | fatal | Echec du demarrage |
facility.lookup.failed expose error_code, facility_external_id et downstream_service. Une facility inconnue porte error_code = 'FACILITY_NOT_FOUND'.
Les appels historiques non encore migres conservent temporairement legacy.console.*. Ils restent au niveau debug pour console.log et sont migres par domaine vers des evenements nommes. Aucun nouveau console.* direct n'est autorise hors de l'adaptateur createLegacyConsoleLogger.
Health check des orchestrateurs
Le service expose GET /health sans authentification. Cette route operationnelle est non versionnee : elle reste donc /health, quelle que soit la valeur de APIVER, et n'appartient ni a l'API v0 ni a l'API v1.
Une reponse 200 avec le corps JSON exact {"status":"ok"} indique que Fastify a termine son initialisation et peut traiter des requetes. Ce controle est destine aux orchestrateurs, notamment Dokploy/Docker Swarm, ainsi qu'aux load balancers. Il ne contacte ni Directus, ni le CMS, ni l'API distante, et ne garantit donc pas la disponibilite de ces services externes.
Les appels a /health sont exclus des evenements HTTP ordinaires http.request.received et http.request.completed afin que les sondes periodiques ne polluent pas les logs de production au niveau info. Les autres routes restent journalisees normalement.
La route operationnelle est volontairement exclue des documents OpenAPI partenaires versionnes /docs/openapi-v0.json et /docs/openapi-v1.json.
IP cliente derriere Dokploy
Fastify ignore X-Forwarded-For par defaut. Configurer TRUST_PROXY avec le CIDR du reseau par lequel Traefik joint le conteneur :
env
TRUST_PROXY=10.0.0.0/24La valeur accepte aussi une liste separee par des virgules ou un nombre de sauts. TRUST_PROXY=true fait confiance a toute la chaine et ne doit etre utilise que si le port applicatif est strictement inaccessible sans passer par Traefik et si chaque proxy remplace les headers X-Forwarded-* recus. Un CIDR ou un nombre de sauts borne evite de faire confiance a une adresse ajoutee par le client. Ces adresses sont destinees a l'observabilite et ne doivent pas servir a une decision d'autorisation.
Requetes OpenObserve
Facilities inconnues :
sql
SELECT timestamp, request_id, facility_external_id, http_route
FROM "default"
WHERE service_base = 'tvcast-intercopartnerapi'
AND event = 'facility.lookup.failed'
AND error_code = 'FACILITY_NOT_FOUND'
ORDER BY timestamp DESC;Erreurs HTTP sur les quinze dernieres minutes :
sql
SELECT timestamp, request_id, http_method, http_route, http_path, client_address,
http_status_code, duration_ms
FROM "default"
WHERE service_base = 'tvcast-intercopartnerapi'
AND event = 'http.request.completed'
AND http_status_code >= 500
ORDER BY timestamp DESC;Remplacer "default" par le nom du stream configure dans OpenObserve.