Guide · SaaS & dev
Logs d’un SaaS : Railway et OpenTelemetry
Pages Logs Railway et signaux OpenTelemetry, relues le 2026-10-18. JSON sur une ligne, pas de drain, logs JS encore en développement. Non rejoué.
Deux pages, relues le 2026-10-18, ne décrivent pas le même objet. Logs dit ce que Railway garde quand le processus écrit sur stdout ou stderr. Logs décrit un enregistrement d’événement, et comment le relier à une trace. Connect a Third-Party Observability Tool dit comment sortir cette télémétrie de Railway. Aucune de ces pages n’a été exécutée ici. Pas de capture.
Gérer les logs d’un projet IA choisit les signaux d’un agent, les alertes et la rétention des prompts. Ce guide-ci ne le refait pas. Si le SaaS est un agent, lisez celui-là pour le contrat d’événements, et celui-ci pour le tuyau Railway et le modèle OpenTelemetry.
Ce que Railway capture
Toute ligne de build ou de déploiement écrite sur la sortie standard ou d’erreur est gardée. console.log est l’exemple de la page. Trois endroits pour les lire :
- Panneau build / deploy : clic sur un déploiement dans la fenêtre du service. L’onglet Build Logs est à part, une fois le déploiement ouvert.
- Log Explorer : bouton Observability dans la navigation du haut. Toute l’environnement, avec une plage de dates et des colonnes.
- CLI :
railway logs, pour le dernier déploiement.
Nous n’avons pas lancé la CLI.
Le filtre est le même esprit partout, avec des attributs selon le type de log. Une chaîne filtre en sous-chaîne. @attribute:value filtre un champ. AND, OR, et - pour nier. Des parenthèses groupent. Les comparaisons numériques (>, >=, <, <=, ..) valent pour les logs de déploiement en JSON, et pour des attributs HTTP nommés sur la page (@httpStatus, @responseTime, et d’autres).
Pour voir les lignes autour d’un hit : clic droit, View in Context.
Les logs HTTP et DNS ont leurs attributs. Les logs DNS sont sous l’onglet Network d’un déploiement, vue DNS, sans config, d’après la page. Ce n’est pas le journal applicatif. Ne les confondez pas avec un console.log.
Une ligne JSON, sinon ce n’est pas un champ
La page appelle « structured logs » un JSON. Le champ message est requis dans l’exemple. level prend debug, info, warn, error. Un champ en plus, par exemple orderId, se requête en @orderId:valeur.
Le JSON entier doit tenir sur une ligne. Un pretty-print casse le parse. La page le dit en note, et montre pourtant un exemple indenté plus bas. Suivez la note, pas l’exemple indenté, si vous voulez des attributs requêtables.
stderr est converti en level.error. stdout sans level devient level.info. log.msg est renommé message. Les levels sont passés en minuscules et ramenés au plus proche de debug, info, warn, error.
Winston est cité comme bibliothèque dont le JSON par défaut a la forme attendue. La page ne donne pas la version. Ne l’inventez pas.
Plafond, rétention, pas de tarif ici
La page fixe 500 lignes par seconde et par réplique, sur tous les plans. Au-delà, les lignes tombent, et un avertissement s’affiche avec le nombre écarté. Elle propose de baisser la verbosité, d’éviter le pretty-print, d’échantillonner les événements fréquents, de couper le verbeux hors prod, et de fusionner des lignes liées.
La rétention dépend du plan. Le tableau est sur la page. Cet article ne le recopie pas : ce n’est pas un argument de free tier, et la colonne peut changer. Une phrase de la page reste utile sans chiffres : passer à un plan supérieur restaure tout de suite des logs qui étaient sortis de la fenêtre précédente. Nous ne l’avons pas constaté sur un compte.
Free Trial et Pricing Plans listent crédits et prix. Pas de montant ici. Le plafond de 500 lignes n’est pas un prix. C’est une limite de collecte, identique d’un plan à l’autre d’après la page Logs.
OpenTelemetry, dans l’ordre de la page concept
Un log, sur cette page, est un texte horodaté, structuré de préférence, avec des métadonnées optionnelles. OpenTelemetry ne remplace pas votre bibliothèque. Il fournit une API, un SDK, et des ponts. Les événements sont un type de logs. L’inverse n’est pas vrai.
Pour une app, la page dit d’écrire avec la bibliothèque que vous avez déjà. L’auto-instrumentation ou le SDK, une fois actifs, corrèle ces logs avec la trace et le span en cours. Le premier pas fréquent, côté collecte, est un Collector, pas une réécriture de chaque log().
Statut des logs par langage, tableau relu le 2026-10-18 : C++, C#/.NET, Java et PHP stables. Go en release candidate. Rust en bêta. JavaScript, Python, Ruby, Swift, Erlang/Elixir en développement. La page JavaScript confirme : traces et métriques stables, logs en développement. Ne documentez pas un SDK de logs JS comme s’il était stable. Pour Node, la page tierce Railway montre l’auto-instrumentation par NODE_OPTIONS=--require @opentelemetry/auto-instrumentations-node/register. Cette ligne est sur la page tierce, pas une preuve que les logs JS sont exportés.
Un JSON n’est pas « structuré » au sens de la page s’il n’a pas un schéma stable. Un blob dont les champs changent d’une ligne à l’autre est semi-structuré. Les logs non structurés se lisent, et s’analysent mal. La page déconseille d’appeler logger.Enabled avant chaque ligne : l’appel de log est déjà léger quand le logger est off, et le résultat de Enabled peut changer. Ne le mettez pas en cache.
L’auteur d’une app n’appelle pas la Logs Bridge API. Il configure un appender sur sa bibliothèque. Le Logger Provider et le Logger de cette API sont pour les auteurs de bibliothèques de log. L’exporteur envoie vers stdout, un Collector, ou un backend. Un log record a, entre autres, Timestamp, TraceId, SpanId, SeverityText, Body, Resource, Attributes, EventName. La liste complète est sur la page. C’est elle qui permet de joindre une ligne Railway à une trace, si vous exportez les deux.
Le guide IA déjà cité choisit quels événements émettre (tool.denied, durée, version). Ici, le point est ailleurs : ces champs doivent tenir dans le message et les attributs d’une seule ligne JSON si vous restez sur l’explorateur Railway, ou dans les attributs du log record si vous exportez en OTLP.
Sortir les logs de Railway
La page tierce le dit sans détour : Railway n’a pas de réglage de log drain. stdout ne se forward pas vers une URL d’intake par une case à cocher. Deux voies :
- SDK du vendeur (Datadog, New Relic, Sentry dans le tableau). Complexité basse, d’après la page. Les variables système
RAILWAY_SERVICE_NAME,RAILWAY_DEPLOYMENT_ID,RAILWAY_ENVIRONMENT_NAME,RAILWAY_REPLICA_IDse mappent aux noms du vendeur. L’exemple Datadog est sur la page. Les autres vendeurs ont d’autres noms. Ne recopiez pasDD_*pour New Relic. - OpenTelemetry OTLP, si vous voulez changer de backend sans réinstrumenter. La page demande
OTEL_SERVICE_NAME,OTEL_RESOURCE_ATTRIBUTES,OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf, et un en-tête d’autorisation. Elle préfère HTTP protobuf, port 4318, à gRPC 4317, à cause des proxys. Le jeton ne se commite pas. La page écrit<token>comme placeholder.
Railway envoie SIGTERM à l’ancien déploiement quand le nouveau prend la place. Les SDK OpenTelemetry ne flushent pas tout seuls. La page dit d’appeler shutdown() dans le handler, sinon le dernier lot de spans tombe. Les SDK vendeurs, eux, flushent seuls. Le snippet de la page est un NodeSDK. Nous ne l’avons pas branché.
Pour forwarder stdout sans instrumenter l’app, la page dit de lancer Vector ou Fluent Bit comme service Railway à part. Ce n’est pas configuré ici.
Le réseau privé Railway est en IPv6. Un exporteur vers un collector du même projet doit parler IPv6. La page renvoie au guide de config des bibliothèques. Nous ne l’avons pas retesté.
Ce qu’il ne faut pas logger
La page concept OpenTelemetry montre un exemple de log de login avec un champ mot de passe masqué par des astérisques, et un autre exemple où un jeton apparaît en clair dans le corps. Traitez le second comme un exemple de format, pas comme un modèle. Un Price ID Stripe, un DATABASE_URL, un jeton de bot ou une clé secrète n’ont rien à faire dans message. Le guide des secrets et le guide des logs IA couvrent le masquage. Pas la peine de le réécrire.
La page Logs ne dit pas à quel moment le plafond arrive. Elle dit quoi faire si l’avertissement s’affiche : moins de verbosité, pas de pretty-print, échantillonnage, verbeux coupé hors prod. Un corps de requête dans chaque ligne remplit ce quota plus vite qu’une erreur avec un identifiant. Ça, c’est une lecture du quota, pas une mesure.
Sources
- Logs Railway : stdout/stderr, trois vues, filtre, JSON une ligne, 500 lignes/s/réplique, rétention par plan non recopiée.
- Logs OpenTelemetry : modèle, statuts de langage, pont plutôt que Bridge API applicative.
- JavaScript OpenTelemetry : logs encore en développement le 2026-10-18.
- Connect a Third-Party Observability Tool : pas de log drain, SDK vendeur ou OTLP,
SIGTERM. - Free Trial et Pricing Plans : tarifs non recopiés.
Sources recontrôlées le 2026-10-19. railway logs n’a pas été lancé. Aucun exporteur n’a été configuré.