Plongez au cœur de votre code C++ : pourquoi l'observabilité n'est pas un luxe, mais une nécessité
\n\nImaginez : vous avez lancé un service à forte charge en C++. Une heure, deux heures, un jour — tout fonctionne parfaitement. Puis soudain, boum ! — les utilisateurs se plaignent de ralentissements, et vous êtes là à vous demander : où est le goulot d'étranglement ? Dans la mémoire ? Dans le réseau ? Ou quelqu'un a simplement oublié de libérer une ressource ? Sans système d'observabilité, vous êtes comme un capitaine de navire aux hublots obstrués. Vous sentez que quelque chose ne va pas, mais vous ne voyez pas quoi exactement.
\n\nL'observabilité en C++ — c'est votre ensemble de périscopes et de radars. Ce n'est pas seulement de la journalisation, ce sont trois piliers : le traçage, les métriques et les logs. Dans cet article, nous allons détailler chacun d'eux avec des exemples de code concrets, montrer comment faire cohabiter C++ avec OpenTelemetry et Prometheus, et vous donner des recettes prêtes pour la production. C'est parti !
\n\nLes trois piliers de l'observabilité : traçage, métriques, logs
\n\nAvant de plonger dans le code, définissons clairement en quoi ces concepts diffèrent et comment ils se complètent. Beaucoup confondent observabilité et simple journalisation — à tort. C'est comme comparer une lampe de poche à un projecteur.
\n\n- \n
- Les logs — ce sont des événements. "Que s'est-il passé ?" (par exemple, "Utilisateur connecté" ou "Erreur de connexion à la BDD"). Ils sont détaillés, mais sans contexte, ils peuvent être inutiles. \n
- Les métriques — ce sont des nombres. "Combien ?" (nombre de requêtes par seconde, utilisation du CPU, temps de réponse). Elles sont agrégées et montrent les tendances. \n
- Le traçage — c'est le chemin d'une requête. "Comment cela s'est-il produit exactement ?" (de l'entrée dans le service jusqu'à l'appel à la base de données et la réponse au client). C'est le lien entre les logs et les métriques. \n
L'observabilité idéale en C++ — c'est quand, en regardant un tableau de bord, vous pouvez comprendre en 10 secondes : où, quand et pourquoi une anomalie s'est produite. Sans cela, vous jouerez à deviner avec votre production.
\n\nTraçage en C++ : comment intégrer OpenTelemetry
\n\nCommençons par l'outil le plus puissant, mais aussi le plus complexe — le traçage. OpenTelemetry est le standard de facto pour la collecte de télémétrie. En C++, il n'est pas aussi richement supporté qu'en Go ou Java, mais il fonctionne de manière stable.
\n\nSupposons que nous ayons un simple serveur HTTP en C++ (nous utilisons une idée, pas une bibliothèque spécifique). Nous devons suivre combien de temps chaque requête prend à être traitée et quels appels se produisent à l'intérieur.
\n\nConfiguration d'OpenTelemetry en C++
\n\nD'abord, installons les dépendances. Dans CMakeLists.txt, ajoutez :
\n\nfind_package(opentelemetry-cpp REQUIRED)\ntarget_link_libraries(my_app PRIVATE opentelemetry::api opentelemetry::exporter_ostream)\n\nCréons maintenant un traceur et des spans (span — c'est une unité de travail). Voici un exemple minimal :
\n\n#include <opentelemetry/trace/provider.h>\n#include <opentelemetry/exporters/ostream/span_exporter.h>\n#include <opentelemetry/sdk/trace/tracer_provider.h>\n#include <opentelemetry/sdk/trace/simple_processor.h>\n\nnamespace trace_api = opentelemetry::trace;\nnamespace trace_sdk = opentelemetry::sdk::trace;\nnamespace trace_exporter = opentelemetry::exporter::trace;\n\nvoid init_tracer() {\n auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(\n new trace_exporter::OStreamSpanExporter(std::cout));\n auto processor = std::unique_ptr<trace_sdk::SpanProcessor>(\n new trace_sdk::SimpleSpanProcessor(std::move(exporter)));\n auto provider = std::make_shared<trace_sdk::TracerProvider>(std::move(processor));\n trace_api::Provider::SetTracerProvider(provider);\n}\n\nvoid process_request(const std::string& user_id) {\n auto tracer = trace_api::Provider::GetTracerProvider()->GetTracer("my_service");\n auto span = tracer->StartSpan("process_request");\n span->SetAttribute("user.id", user_id);\n\n // Simulation de travail\n std::this_thread::sleep_for(std::chrono::milliseconds(100));\n\n span->End();\n}\n\nint main