Tracing de bout en bout dans les fintech : du frontend au collecteur OpenTelemetry
Dans les systèmes fintech distribués, des journaux sans traceId ne permettent pas de relier une erreur 500 à l’action de l’utilisateur. OpenTelemetry permet un tracing de bout en bout — depuis le frontend d’une application monopage (SPA) jusqu’aux services backend — via le collecteur OpenTelemetry. Notre implémentation TypeScript repose sur un CompositeLogger et un fetch modifié pour préserver la hiérarchie des spans dans les flux critiques, comme les virements bancaires.
Concepts fondamentaux d’OpenTelemetry pour développeurs frontend
OpenTelemetry normalise la collecte des données d’observabilité : traces, spans, événements et attributs.
- Trace — structure racine identifiée par un
traceId, utilisée pour regrouper des spans liées. - Span — opération temporelle avec horodatages de début et de fin ; elle supporte l’imbrication pour refléter la hiérarchie des appels.
- Événement — occurrence horodatée liée à une span, accompagnée d’attributs personnalisés.
- Attribut — métadonnée sous forme clé-valeur, permettant le filtrage, la recherche et l’enrichissement contextuel.
Ces primitives combinées vous permettent de suivre un clic utilisateur jusqu’aux intégrations backend sous-jacentes.
Aperçu de l’architecture d’observabilité
Le frontend envoie les traces via un microservice d’audit au collecteur OpenTelemetry. Les services backend — équipes produit et plateforme — acheminent leurs métriques vers Jaeger (traces), Prometheus (métriques) et Kibana (journaux). Grafana fournit des tableaux de bord unifiés.
Principaux avantages de cette architecture :
- Ingestion centralisée — aucun accès direct du frontend à l’infrastructure interne d’observabilité.
- Déploiement progressif par microservice, limitant les risques.
- L’obfuscation des données sensibles est obligatoire — jamais optionnelle.
Implémentation frontend : l’interface Logger
L’abstraction fondamentale est une interface Logger, garantissant une journalisation cohérente et multiplateforme.
export interface Logger {
readonly name: string;
init?(options?: CompositeInitOptions | SentryInitOptions | AuditInitOptions): void;
logError(error: Error, context?: ErrorContextType | ErrorContextType[]): void;
logMessage?(message: string, context?: Record<string, unknown>): void;
}
CompositeLogger implémente le patron Composite, redirigeant les événements vers plusieurs loggers sous-jacents (OpenTelemetry, Sentry, Audit).
export class CompositeLogger implements Logger {
public readonly name = "composite";
constructor(private readonly loggers: Logger[]) {}
init(options?: CompositeInitOptions): void {
this.loggers.forEach((logger) => {
logger.init?.(options?.[logger.name as keyof CompositeInitOptions]);
});
}
logError(error: Error, context?: ErrorContextType[]): void {
this.loggers.forEach((logger) => {
logger.logError(error, context);
});
}
logMessage(message: string, context?: Record<string, unknown>): void {
this.loggers.forEach((logger) => {
logger.logMessage?.(message, context);
});
}
startBusinessProcess(name: string, attributes?: Attributes): void {
this.loggers.forEach((logger) => {
if (logger.name === "otlp") {
(logger as OtlpLogger).startBusinessProcess(name, attributes);
}
});
}
addEvent(name: string, attributes?: Attributes): void {
this.loggers.forEach((logger) => {
if (logger.name === "otlp") {
(logger as OtlpLogger).addEvent(name, attributes);
}
});
}
}
Intégration React via Context
LoggerProvider et useLogger offrent un accès transparent au logger dans toute l’arborescence des composants.
import React, { createContext, useContext } from "react";
import { CompositeLogger } from "./composite-logger";
const LoggerContext = createContext<CompositeLogger | null>(null);
export const LoggerProvider: React.FC<{
logger: CompositeLogger;
children: React.ReactNode;
}> = ({ logger, children }) => (
<LoggerContext.Provider value={logger}>{children}</LoggerContext.Provider>
);
export const useLogger = (): CompositeLogger => {
const logger = useContext(LoggerContext);
if (!logger) {
throw new Error("Logger introuvable dans le contexte");
}
return logger;
};
OtlpLogger : modification de fetch et utilisation de StackContextManager
OtlpLogger initialise le WebTracerProvider, modifie fetch pour propager automatiquement les spans parentes, et exploite StackContextManager afin de résoudre la perte de contexte asynchrone dans les navigateurs — garantissant que les spans enfants s’attachent correctement aux processus métier sans passage manuel de contexte.
Exemple : flux de virement bancaire :
startBusinessProcess('virement-bancaire')addEvent('etape-formulaire-1', {montant: 1000})- Appel
fetchvers le backend — hérite automatiquement du contexte de la span courante logErroren cas d’échec d’intégration, préservant toute la lignée de la trace
Avantages de cette implémentation
- Réduction du MTTR de 10× ou plus, grâce au filtrage instantané basé sur
traceIdsur les journaux frontend et backend. - Extensibilité : de nouveaux loggers (ex. Datadog, Honeycomb) s’intègrent via npm — aucune modification du code applicatif requise.
- Corrélation structurée : des attributs cohérents permettent une correspondance précise entre événements frontend et backend.
Les visualisations Jaeger montrent le parcours complet : clic utilisateur → appel API → Kafka → backend plateforme.
Points clés à retenir
- Le tracing de bout en bout unifie les journaux frontend et backend en faisant du
traceIdla seule source de vérité. - Le
CompositeLoggerprotège les développeurs de la complexité tout en supportant une télémétrie multi-destinations. - Le
fetchmodifié assure une hiérarchie de spans fiable — même lors d’appels réseau asynchrones. - Le
StackContextManagerélimine le code répétitif lié au tracing côté client dans les frameworks JavaScript modernes. - L’obfuscation des données est indispensable pour répondre aux exigences réglementaires dans le secteur fintech.
— Editorial Team
Aucun commentaire pour le moment.