Skip to main content

OpenTelemetry Collector

El Collector es un componente del backend.

Es responsable de ingerir los datos de telemetría, todos los registros, traces y métricas, y todas las demás cosas que serán implementadas en el futuro. Primeramente recoge todo y después hace algún procesamiento, si es necesario, y por fin hace el export.

Es bastante similar al SDK en algunas partes, pero no necesariamente genera los datos, recibe los datos.

  • SDK

    • Genera datos
    • Procesa datos
    • Exporta los datos
    • Exclusivo de la aplicación
  • Collector

    • Recibe los datos
    • Procesa los datos (puede hacer, no es obligatorio)
    • Exporta los datos
    • Puede ser escalado para recibir varios registros de varias fuentes
    • Sirve como puente entre el vendor y la infraestructura local

Si todas las aplicaciones envían el dato al collector tendremos una configuración centralizada para donde vamos a almacenar los datos. Vamos a imaginar que hoy estamos usando Datadog, pero dentro de un tiempo vamos a pasar a Dynatrace, solo el cambio de configuración en el collector sería necesario si todas las aplicaciones utilizasen el collector, de lo contrario sería necesario cambiar el exporter de todas ellas.

Un collector tiene la función de separar los datos de métrica, logs y traces y enviarlos a diferentes vendors.

Trace pipeline: receiver>>>>processor>>>>exporter
Metric pipeline: receiver>>>>processor>>>>exporter
Logs pipeline: receiver>>>>processor>>>>exporter

El vendor para métricas puede ser diferente del vendor para traces y para logs. Podríamos usar Elasticsearch para trace, Prometheus para métricas y Grafana Loki para logs.

Vamos a analizar lo que teníamos hasta ahora.

El SDK de cada aplicación envía los datos a Jaeger y expone el /metric para que Prometheus vaya a buscar las métricas y para eso configuramos Prometheus con los targets de esas aplicaciones.

alt text

¿Qué queremos? Que las aplicaciones envíen todo al collector y él distribuya a los lugares correctos. Prometheus ahora hará el scrape en el collector.

alt text

Para ello vamos a configurar un collector que en realidad es una configuración yaml simple.

Vamos a añadir el collector al docker-compose

##código...
collector:
image: otel/opentelemetry-collector-contrib
command:
- '--config=/etc/collector/collector.yaml'
ports:
- 8889:8889
- 4317:4317
- 4318:4318
volumes:
- ./collector:/etc/collector
depends_on:
- prometheus
- jaeger

Básicamente necesitamos exponer los puertos que usaremos y pasar el archivo de configuración.

Ahora necesitamos definir el archivo de configuración del collector.

Ahora vamos a ver ese archivo de configuración.

# Configuraciones de receivers
receivers:
otlp: # Vamos a usar referenciar esta configuración en services.
protocols:
http:
endpoint: 0.0.0.0:4318
cors:
allowed_origins: ["*"]
grpc:
endpoint: 0.0.0.0:4317

# Configuraciones de processors
processors:

# Configuraciones de exporters
exporters:
# Prometheus hará el scrape en nuestro collector en lugar de hacerlo en la aplicación, por lo que es necesario cambiar las configuraciones en él.
prometheus:
endpoint: 0.0.0.0:8889
send_timestamps: true
namespace: otel
const_labels:
via: collector

otlphttp: ## Para exportar a jaeger usando otlp con http
endpoint: "http://jaeger:4318"
tls:
insecure: true

# Configuraciones de extensions hablaremos más tarde
extensions:
health_check:

# Configuraciones de services
service:
extensions:
- health_check
pipelines: # Tendremos dos pipelines en nuestro escenario
# Cada uno de estos pipelines tiene sus receivers, processors y exporters
traces:
# Aquí estamos diciendo cómo vamos a ingerir los datos, podría ser en formatos diferentes,
# con niveles diferentes de seguridad, con diferentes encodings, etc
# en nuestro caso vamos a usar el receiver con el nombre otlp que definimos arriba que acepta http y grpc
receivers: # podemos ingerir datos de varios lugares por eso es un array
- otlp
processors:
# podríamos exportar a varios lugares al mismo tiempo en nuestro caso solo jaeger para traces
exporters:
- otlphttp
metrics:
receivers:
- otlp
processors:
# podríamos exportar a varios lugares al mismo tiempo en nuestro caso solo prometheus para métricas
exporters:
- prometheus

Como mencionado arriba necesitamos cambiar el target de Prometheus en el archivo prometheus.yaml para hacer el scrape del collector en lugar de nuestras aplicaciones.

global:
scrape_interval: "5s"

scrape_configs:
- job_name: 'opentelemetry'
metrics_path: /metrics
scheme: http
static_configs:
- targets:
# - todo:9464
# - auth:9464
- collector:8889

También será necesario cambiar la configuración del sdk de nuestra aplicación. El nuevo código estará en la branch collector incluyendo todos los archivos aquí mencionados.

En nuestro instrumentation.ts vamos a hacer las siguientes alteraciones

import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-proto";
//Código....

function start(serviceName: string) {
//Código....

// YA NO VAMOS A EXPONER LOS DATOS EN UN ENDPOINT, NECESITAMOS HACER EL PUSH DE LOS DATOS AL COLLECTOR.
// const prometheusExporter = new PrometheusExporter(
// {
// port: PrometheusExporter.DEFAULT_OPTIONS.port,
// endpoint: PrometheusExporter.DEFAULT_OPTIONS.endpoint,
// },
// () => {
// console.log(
// `prometheus scrape endpoint: http://localhost:${PrometheusExporter.DEFAULT_OPTIONS.port}${PrometheusExporter.DEFAULT_OPTIONS.endpoint}`
// );
// }
// );

// VAMOS A USAR AHORA EL OTLPMetricExporter

const metricReader = new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({
url: "http://collector:4318/v1/metrics",
}),
});

const meterProvider = new MeterProvider({
resource,
// readers: [prometheusExporter],
readers: [metricReader],
});

const traceExporter = new OTLPTraceExporter({
// url: "http://jaeger:4318/v1/traces",
// En lugar de enviar a jaeger vamos a enviar al collector.
url: "http://collector:4318/v1/traces",
});
//Código....
}

Eso es todo... si verificas verás que tenemos todo funcionando. Ejecuta el compose nuevamente, verifica jaeger y prometheus con las métricas.