Le collecteur OpenTelemetry se trouve au centre de l'architecture OpenTelemetry mais n'est pas lié au contexte de trace du W3C. Dans ma démo de traçage , j'utilise Jaeger au lieu du Collector. Pourtant, c'est omniprésent, comme dans chaque article lié à OpenTelemetry. Je voulais l'explorer davantage.
Dans cet article, j'explore les différents aspects du Collector :
Il y a longtemps, l’observabilité telle que nous la connaissons n’existait pas ; ce que nous avions à la place, c'était la surveillance . À l’époque, la surveillance consistait en un groupe de personnes regardant des écrans affichant des tableaux de bord. Les tableaux de bord eux-mêmes étaient constitués de métriques et uniquement de métriques système : principalement l'utilisation du processeur, de la mémoire et du disque. Pour cette raison, nous commencerons par les métriques.
Prometheus est l'une des principales solutions de surveillance. Il fonctionne sur un modèle basé sur l'extraction : Prometheus récupère les points de terminaison compatibles de votre (vos) application (s) et les stocke en interne.
Nous utiliserons le collecteur OTEL pour récupérer un point de terminaison compatible Prometheus et imprimer le résultat dans la console. Grafana Labs propose un projet qui génère des métriques aléatoires avec lesquelles jouer. Par souci de simplicité, j'utiliserai Docker Compose ; la configuration ressemble à ce qui suit :
version: "3" services: fake-metrics: build: ./fake-metrics-generator #1 collector: image: otel/opentelemetry-collector:0.87.0 #2 environment: #3 - METRICS_HOST=fake-metrics - METRICS_PORT=5000 volumes: - ./config/collector/config.yml:/etc/otelcol/config.yaml:ro #4
Comme je l'ai mentionné ci-dessus, l'OTEL Collector peut faire beaucoup de choses. Par conséquent, la configuration est primordiale.
receivers: #1 prometheus: #2 config: scrape_configs: #3 - job_name: fake-metrics #4 scrape_interval: 3s static_configs: - targets: [ "${env:METRICS_HOST}:${env:METRICS_PORT}" ] exporters: #5 logging: #6 loglevel: debug service: pipelines: #7 metrics: #8 receivers: [ "prometheus" ] #9 exporters: [ "logging" ] #9
prometheus
prometheus
précédemment défini et les envoie à l'exportateur logging
, c'est-à-dire les imprime.
Voici un exemple du résultat :
2023-11-11 08:28:54 otel-collector-collector-1 | StartTimestamp: 1970-01-01 00:00:00 +0000 UTC 2023-11-11 08:28:54 otel-collector-collector-1 | Timestamp: 2023-11-11 07:28:54.14 +0000 UTC 2023-11-11 08:28:54 otel-collector-collector-1 | Value: 83.090000 2023-11-11 08:28:54 otel-collector-collector-1 | NumberDataPoints #1 2023-11-11 08:28:54 otel-collector-collector-1 | Data point attributes: 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__embrace_world_class_systems: Str(concept) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__exploit_magnetic_applications: Str(concept) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__facilitate_wireless_architectures: Str(extranet) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__grow_magnetic_communities: Str(challenge) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__reinvent_revolutionary_applications: Str(support) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__strategize_strategic_initiatives: Str(internet_solution) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__target_customized_eyeballs: Str(concept) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__transform_turn_key_technologies: Str(framework) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__whiteboard_innovative_partnerships: Str(matrices) 2023-11-11 08:28:54 otel-collector-collector-1 | StartTimestamp: 1970-01-01 00:00:00 +0000 UTC 2023-11-11 08:28:54 otel-collector-collector-1 | Timestamp: 2023-11-11 07:28:54.14 +0000 UTC 2023-11-11 08:28:54 otel-collector-collector-1 | Value: 53.090000 2023-11-11 08:28:54 otel-collector-collector-1 | NumberDataPoints #2 2023-11-11 08:28:54 otel-collector-collector-1 | Data point attributes: 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__expedite_distributed_partnerships: Str(approach) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__facilitate_wireless_architectures: Str(graphical_user_interface) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__grow_magnetic_communities: Str(policy) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__reinvent_revolutionary_applications: Str(algorithm) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__transform_turn_key_technologies: Str(framework) 2023-11-11 08:28:54 otel-collector-collector-1 | StartTimestamp: 1970-01-01 00:00:00 +0000 UTC 2023-11-11 08:28:54 otel-collector-collector-1 | Timestamp: 2023-11-11 07:28:54.14 +0000 UTC 2023-11-11 08:28:54 otel-collector-collector-1 | Value: 16.440000 2023-11-11 08:28:54 otel-collector-collector-1 | NumberDataPoints #3 2023-11-11 08:28:54 otel-collector-collector-1 | Data point attributes: 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__exploit_magnetic_applications: Str(concept) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__grow_magnetic_communities: Str(graphical_user_interface) 2023-11-11 08:28:54 otel-collector-collector-1 | -> fake__target_customized_eyeballs: Str(extranet)
Ce qui précède est une excellente première étape, mais il y a bien plus que l’impression sur la console. Nous exposerons les métriques à récupérer par une instance Prometheus standard ; nous pouvons ajouter un tableau de bord Grafana pour les visualiser. Même si cela peut sembler inutile, soyez patient, car ce n’est qu’une étape.
Pour réaliser ce qui précède, nous modifions uniquement la configuration du collecteur OTEL :
exporters: prometheus: #1 endpoint: ":${env:PROMETHEUS_PORT}" #2 service: pipelines: metrics: receivers: [ "prometheus" ] exporters: [ "prometheus" ] #3
prometheus
C'est ça. Le collecteur OTEL est très flexible.
Notez que le collecteur est multi-entrées, multi-sorties. Pour à la fois imprimer les données et les exposer via le point de terminaison, nous les ajoutons au pipeline :
exporters: prometheus: #1 endpoint: ":${env:PROMETHEUS_PORT}" logging: #2 loglevel: debug service: pipelines: metrics: receivers: [ "prometheus" ] exporters: [ "prometheus", "logging" ] #3
Avec l'exportateur Prometheus configuré, nous pouvons visualiser les métriques dans Grafana.
Notez que les destinataires et les exportateurs précisent leur type et que chacun d'entre eux doit être unique. Pour respecter cette dernière exigence, nous pouvons ajouter un qualificatif pour les distinguer, c'est-à-dire prometheus/foo
et prometheus/bar.
Une question valable serait de savoir pourquoi le collecteur OTEL est placé entre la source et Prometheus, car cela rend la conception globale plus fragile. À ce stade, nous pouvons exploiter la véritable puissance du collecteur OTEL : le traitement des données. Jusqu'à présent, nous avons ingéré des métriques brutes, mais le format source n'est peut-être pas adapté à la manière dont nous souhaitons visualiser les données. Par exemple, dans notre configuration, les métriques proviennent de notre faux générateur, « business », et de la plateforme NodeJS sous-jacente, « technique ». Cela se reflète dans le nom des métriques. Nous pourrions ajouter une étiquette source dédiée et supprimer le préfixe inutile pour filtrer plus efficacement.
Vous déclarez les sous-traitants dans la section processors
du fichier de configuration. Le collecteur les exécute dans l'ordre dans lequel ils sont déclarés. Implémentons la transformation ci-dessus.
La première étape vers notre objectif est de comprendre que le collectionneur a deux saveurs : une version « nue » et une version contrib qui s'appuie sur elle. Les processeurs inclus dans le premier sont limités, tant en nombre qu'en capacités ; par conséquent, nous devons changer la version de contrib.
collector: image: otel/opentelemetry-collector-contrib:0.87.0 #1 environment: - METRICS_HOST=fake-metrics - METRICS_PORT=5000 - PROMETHEUS_PORT=8889 volumes: - ./config/collector/config.yml:/etc/otelcol-contrib/config.yaml:ro #2
contrib
À ce stade, nous pouvons ajouter le processeur lui-même :
processors: metricstransform: #1 transforms: #2 - include: ^fake_(.*)$ #3 match_type: regexp #3 action: update operations: #4 - action: add_label #5 new_label: origin new_value: fake - include: ^fake_(.*)$ match_type: regexp action: update #6 new_name: $${1} #6-7 # Do the same with metrics generated by NodeJS
$${x}
Enfin, nous ajoutons le processeur défini au pipeline :
service: pipelines: metrics: receivers: [ "prometheus" ] processors: [ "metricstransform" ] exporters: [ "prometheus" ]
Voici les résultats:
Un connecteur est à la fois un récepteur et un exportateur et relie deux pipelines. L'exemple de la documentation reçoit le nombre de travées (traçage) et exporte le nombre, qui a une métrique. J'ai essayé de faire la même chose avec 500 erreurs - spoiler : cela ne fonctionne pas comme prévu.
Ajoutons d'abord un récepteur de journaux :
receivers: filelog: include: [ "/var/logs/generated.log" ]
Ensuite, on ajoute un connecteur :
connectors: count: requests.errors: description: Number of 500 errors condition: [ "status == 500 " ]
Enfin, nous connectons le récepteur de journaux et l'exportateur de métriques :
service: pipelines: logs: receivers: [ "filelog" ] exporters: [ "count" ] metrics: receivers: [ "prometheus", "count" ]
La métrique est nommée log_record_count_total
, mais sa valeur reste à 1.
Les processeurs permettent la manipulation des données ; les opérateurs sont des processeurs spécialisés qui travaillent sur les journaux. Si vous connaissez la pile Elasticsearch Logstash Kibana, elle est l'équivalent de Logstash.
Pour l’instant, l’horodatage du journal est l’horodatage de l’ingestion. Nous le remplacerons par l'horodatage de sa création.
receivers: filelog: include: [ "/var/logs/generated.log" ] operators: - type: json_parser #1 timestamp: #2 parse_from: attributes.datetime #3 layout: "%d/%b/%Y:%H:%M:%S %z" #4 severity: #2 parse_from: attributes.status #3 mapping: #5 error: 5xx #6 warn: 4xx info: 3xx debug: 2xx - id: remove_body #7 type: remove field: body - id: remove_datetime #7 type: remove field: attributes.datetime - id: remove_status #7 type: remove field: attributes.status
501-599
. L'opérateur a une valeur interprétée spéciale 5xx
(et similaire) pour les statuts HTTP.À ce stade, nous pouvons envoyer les journaux à n’importe quel composant d’agrégation de journaux. Nous resterons dans la sphère Grafana Labs et utiliserons Loki.
exporters: loki: endpoint: "http://loki:3100/loki/api/v1/push"
Nous pouvons également utiliser les logs du collecteur lui-même :
service: telemetry: logs:
Enfin, ajoutons un autre pipeline :
service: pipelines: logs: receivers: [ "filelog" ] exporters: [ "loki" ]
Grafana peut également visualiser les journaux. Choisissez Loki comme source de données.
Dans cet article, nous avons exploré le collecteur OpenTelemetry. Bien que ce ne soit pas une partie obligatoire de l'architecture OTEL, c'est un couteau suisse utile pour tous vos besoins en traitement de données. Si vous n'êtes pas limité à une pile spécifique ou si vous ne le souhaitez pas, c'est d'une aide précieuse.
Le code source complet de cet article peut être trouvé sur GitHub .
Pour aller plus loin:
Publié initialement sur A Java Geek le 12 novembre 2023