Esplorare il Collector di OpenTelemetry

L’OpenTelemetry Collector si trova al centro dell’architettura di OpenTelemetry ma non è correlato al W3C Trace Context. Nel mio demo di tracing, uso Jaeger invece del Collector. Tuttavia, è onnipresente, come in ogni post relativo a OpenTelemetry. Volevo esplorarlo ulteriormente.

In questo post, esploro gli aspetti diversi del Collector:

  • Il tipo di dati: log, metriche e tracce
  • Modelli push e pull
  • Operazioni: letture, trasformazioni e scritture

Primi passi

A long time ago, observability as we know it didn’t exist; what we had instead was monitoring. Back then, monitoring was a bunch of people looking at screens displaying dashboards. Dashboards themselves consisted of metrics and only system metrics, mainly CPU, memory, and disk usage. For this reason, we will start with metrics.

Prometheus è una delle principali soluzioni di monitoraggio. Funziona con un modello basato su pull: Prometheus esegue scraping degli endpoint compatibili del tuo applicativo(i) e li memorizza internamente.

Utilizzeremo l’OTEL Collector per eseguire lo scraping di un endpoint compatibile con Prometheus e stampare il risultato nella console. Grafana Labs offre un progetto che genera metriche casuali con cui giocare. Per semplicità, userò Docker Compose; la configurazione è simile alla seguente:

YAML

 

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

  1. Non è disponibile un’immagine Docker per il progetto delle metriche false; pertanto, dobbiamo compilarla
  2. Versione più recente dell’OTEL Collector al momento della stesura di questo articolo
  3. Parametrizzare il seguente file di configurazione
  4. Tutto accade qui

Come ho detto sopra, l’OTEL Collector può fare molto. Quindi, la configurazione è tutto.

YAML

 

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" ]                                              #10

  1. Elenco dei ricevitori. Un ricevitore legge i dati; può essere di tipo push-based o pull-based.
  2. Utilizziamo il ricevitore predefinito prometheus
  3. Definire i job di pull
  4. Configurazione del job
  5. Elenco degli esportatori. Al contrario dei ricevitori, un esportatore scrive dati.
  6. L’esportatore più semplice è quello di scrivere dati sull’uscita standard
  7. I pipeline assemblano ricevitori ed esportatori
  8. Definire un pipeline relativo alle metriche
  9. Il pipeline ottiene dati dal ricevitore prometheus precedentemente definito e li invia all’esportatore logging, cioè, li stampa

Ecco un esempio del risultato:

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)

Oltre la Stampa

Il passo precedente è ottimo per iniziare, ma c’è più che stampare a video. Esamineremo come rendere le metriche disponibili per essere raccolte da un’istanza di Prometheus regolare; possiamo aggiungere un dashboard Grafana per visualizzarle. Anche se potrebbe sembrare inutile, abbiate pazienza, poiché è solo un gradino.

Per realizzare quanto sopra, basta modificare la configurazione del Collector OTEL:

YAML

 

exporters:
  prometheus:                                                               #1
    endpoint: ":${env:PROMETHEUS_PORT}"                                     #2

service:
  pipelines:
    metrics:
      receivers: [ "prometheus" ]
      exporters: [ "prometheus" ]                                           #3

  1. Aggiungere un esportatore prometheus
  2. Esporre un endpoint conforme a Prometheus
  3. Sostituire la stampa con l’esposizione

Ecco tutto. Il Collector OTEL è molto flessibile.

Si noti che il Collector è multi-input, multi-output. Per stampare i dati e contemporaneamente esporli tramite l’endpoint, li aggiungiamo al pipeline:

YAML

 

exporters:
  prometheus:                                                               #1
    endpoint: ":${env:PROMETHEUS_PORT}"
  logging:                                                                  #2
    loglevel: debug

service:
  pipelines:
    metrics:
      receivers: [ "prometheus" ]
      exporters: [ "prometheus", "logging" ]                                #3

  1. Esporre dati
  2. Stampare dati
  3. Il pipeline stamperà sia i dati che li esporrà

Con l’esportatore Prometheus configurato, possiamo visualizzare le metriche in Grafana.

Si noti che ricevitori ed esportatori specificano il loro tipo e ognuno di essi deve essere unico. Per rispettare l’ultima richiesta, possiamo aggiungere un qualificatore per distinguerli, cioè, prometheus/foo e prometheus/bar.

Elaborazione dei Dati Intermedi

A valid question would be why the OTEL Collector is set between the source and Prometheus, as it makes the overall design more fragile. At this stage, we can leverage the true power of the OTEL Collector: data processing. So far, we have ingested raw metrics, but the source format may not be adapted to how we want to visualize data. For example, in our setup, metrics come from our fake generator, “business,” and the underlying NodeJS platform, “technical.” It is reflected in the metrics’ name. We could add a dedicated source label and remove the unnecessary prefix to filter more efficiently.

Si dichiarano i processori di dati nella sezione processors del file di configurazione. Il collector li esegue nell’ordine in cui sono dichiarati. Implementiamo la trasformazione sopra descritta.

Il primo passo verso il nostro obiettivo è capire che il collector ha due varianti: una “nuda” e una contrib che si basa su di essa. I processori inclusi nella prima sono limitati, sia in numero che in capacità; pertanto, dobbiamo passare alla versione contrib.

YAML

 

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

  1. Utilizzare il sapore contrib
  2. Per maggiore divertimento, il file di configurazione si trova in un altro percorso

A questo punto, possiamo aggiungere il processore stesso:

YAML

 

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
# Fai lo stesso con le metriche generate da NodeJS

  1. Invoca il processore di trasformazione delle metriche
  2. Elenco delle trasformazioni applicate in ordine
  3. Corrisponde a tutte le metriche con la regexp definita
  4. Elenco delle operazioni applicate in ordine
  5. Aggiungi il label
  6. Rinomina la metrica rimuovendo il prefisso del gruppo regexp
  7. Roba da divertirsi: la sintassi è $${x}

Infine, aggiungiamo il processore definito al pipeline:

YAML

 

service:
  pipelines:
    metrics:
      receivers: [ "prometheus" ]
      processors: [ "metricstransform" ]
      exporters: [ "prometheus" ]

Ecco i risultati:

Collegamento di Ricevitori ed Esportatori

A connector is both a receiver and an exporter and connects two pipelines. The example from the documentation receives the number of spans (tracing) and exports the count, which has a metric. I tried to achieve the same with 500 errors — spoiler: it doesn’t work as intended.

Iniziamo aggiungendo un ricevitore di log:

YAML

 

receivers:
  filelog:
    include: [ "/var/logs/generated.log" ]

Quindi, aggiungiamo un connettore:

YAML

 

connectors:
  count:
    requests.errors:
      description: Number of 500 errors
      condition: [ "status == 500 " ]

Infine, colleghiamo il ricevitore di log e l’esportatore di metriche:

YAML

 

service:
   pipelines:
     logs:
       receivers: [ "filelog" ]
       exporters: [ "count" ]
     metrics:
       receivers: [ "prometheus", "count" ]

La metrica è denominata log_record_count_total, ma il suo valore rimane a 1.

Manipolazione dei Log

I processori consentono la manipolazione dei dati; gli operatori sono processori specializzati che lavorano sui log. Se hai familiarità con lo stack ELK, sono l’equivalente di Logstash.

Finora, l’ora del log è l’ora di inserimento. Cambieremo questo invece con l’ora di creazione del log.

YAML

 

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

  1. Il log è in formato JSON; possiamo utilizzare il parser JSON fornito
  2. Attributi di metadati da impostare
  3. Campi da leggere
  4. Pattern di parsing
  5. Tabella di mappatura
  6. Accetta un intervallo, ad esempio, 501-599. L’operatore ha un valore interpretato speciale 5xx (e simili) per i codici di stato HTTP.
  7. Rimuovi dati duplicati

Log

A questo punto, possiamo inviare i log a qualsiasi componente di aggregazione dei log. Rimarremo nell’ambito di Grafana Labs e utilizzeremo Loki.

YAML

 

exporters:
  loki:
    endpoint: "http://loki:3100/loki/api/v1/push"

Possiamo anche utilizzare i log dal collector stesso:

YAML

 

service:
  telemetry:
    logs:

Infine, aggiungiamo un’altra pipeline:

YAML

 

service:
  pipelines:
    logs:
      receivers: [ "filelog" ]
      exporters: [ "loki" ]

Grafana può anche visualizzare i log. Scegli Loki come datasource.

Conclusione

In questo post, abbiamo approfondito il raccoltore OpenTelemetry. Nonostante non sia parte obbligatoria dell’architettura OTEL, è un’utile coltellino svizzero per tutte le tue esigenze di elaborazione dei dati. Nel caso in cui non ti sei attaccato a una specifica pila o non vuoi farlo, è di grande aiuto.

Il codice sorgente completo per questo post è disponibile su GitHub.

Per andare oltre

Source:
https://dzone.com/articles/exploring-the-opentelemetry-collector