Ir al contenido

Prometheus

El destino Prometheus es un exportador que sirve el valor actual de cada métrica de GitHub para que Prometheus lo recoja.

sinks:
prometheus:
listen: 127.0.0.1:9605
path: /metrics

Un exportador, no un emisor: apúntale un scrape. Es el único destino del proyecto que no es saliente, y existe porque Prometheus insiste en tirar de los datos.

Los nombres de métrica son github_<medida>_<campo>, con las etiquetas como labels.

github_repo_stars{repo="ghchronicle",language="Go",visibility="public"} 283
github_workflow_runs_count{repo="ghchronicle",conclusion="success"} 412

No, y no por elección: no puede servir la historia fechada. Prometheus sella una muestra en el instante del scrape y rechaza cualquier cosa apreciablemente más vieja: medido contra Prometheus 3.14 con --web.enable-otlp-receiver y una ventana de desorden de treinta minutos, una muestra fechada dos días atrás vuelve como HTTP 400.

A través de este destino, la ventana de tráfico de catorce días de GitHub se colapsa a su día más reciente, y la historia de estrellas al total actual. Eso merece decirse claro en vez de esconderse. Úsalo junto a un almacén de historia, no en su lugar; ambos pueden correr a la vez y la recolección ocurre una sola vez.

Antes de servir, Summarize reduce cada medida según una regla.

ReglaQué sobrevive
keepLastEl valor más reciente de cada conjunto de etiquetas. Instantáneas
sumLas filas sumadas. Ventanas, como las visitas de los catorce días
countUn recuento más la media de cada campo numérico. Elementos fechados
skipNada

Una medida sin regla se salta, así que un colector nuevo no puede inundar en silencio el exportador con una serie por estrella.

El lote se lee tal como lo guardan los almacenes. Un punto con la misma medida, las mismas etiquetas y la misma hora que otro anterior es la misma fila, así que se suma, se cuenta y se promedia una vez, igual que los almacenes de historia lo guardan una vez; la fecha del punto dice qué campos suyos conserva cada almacén. Un precio es el único número que un sum no suma: la factura repite el precio de un SKU en cada fila, una por repositorio y día, así que github_billing_usage_price_per_unit es el más alto de ellos, el MAX(price_per_unit) de los dashboards SQL, y no el precio multiplicado por los días facturados.

Cada media es sobre los elementos que traían el campo, no sobre el recuento. Un colector omite un campo cuando no tiene un valor honesto para él: un job sin hora de inicio no tiene queued_seconds, y un job del que GitHub ya no lista los pasos no tiene steps. Contados como ceros, una pasada en la que la mitad de los jobs hubiera perdido sus pasos dejaría github_workflow_jobs_steps_mean en la mitad. Tres campos son la excepción, porque omitirlos ya es la respuesta: merged en una contribución externa solo se escribe al fusionarse, advanced en un fork solo cuando tiene fecha de push, y pull_requests en una ejecución solo cuando se lanzó por alguno. Cada uno de ellos se promedia sobre todos los elementos, así que la media de merged es la proporción de contribuciones fusionadas y no 1.

El reductor publica además total, un recuento acumulado de elementos distintos por serie. Eso es lo que permite que un dashboard de Prometheus diga “por día” mediante increase(), ya que no tiene filas que contar.

El punch card de commits es una serie por repositorio, día de la semana y hora, y los ficheros de release una por cada fichero publicado alguna vez. Medido, juntas eran cuatro quintas partes de toda la salida del exportador. Ambas se dibujan bien en el dashboard de InfluxDB.

Otras diez se saltan por un motivo distinto del tamaño, nueve por ser historia y una por ser texto, así que doce medidas en total no llegan nunca al exportador. La lista, con el motivo de cada una, está en la fecha del punto.

El exportador solo tiene lo que recogió la última pasada, y para las ejecuciones de workflows eso son las treinta más nuevas por repositorio entre builds: una pasada ordinaria lee la lista de ejecuciones en páginas de treinta, y solo pasa de página mientras una página venga llena de ejecuciones más nuevas que su ventana de dos horas. Los almacenes guardan cada ejecución que el recorrido vio alguna vez; este es el único sitio donde la página más pequeña se nota.

Los jobs de workflow son el otro: una pasada lleva los jobs de las ejecuciones que listó por primera vez, así que gh_workflow_jobs cuenta los jobs nuevos para este proceso y no los de las veinte ejecuciones más nuevas, y una pasada en el que no terminó ninguna ejecución no lleva ninguno, con lo que el último recuento se mantiene hasta que caduca un día después. El total de al lado no cambia, porque cuenta cada job distinto que el proceso ha visto alguna vez; los almacenes tampoco, porque un job se escribe una vez y se fecha cuando terminó.

scrape_configs:
- job_name: ghchronicle
static_configs:
- targets: ["127.0.0.1:9605"]

El exportador guarda sus muestras en memoria, así que un reinicio lo vacía. Por eso la primera pasada tras el arranque corre todas las familias activas diga lo que diga el fichero de estado: sin ella, una familia de doce horas dejaría sus paneles a cero medio día.

sinks:
prometheus:
listen: 0.0.0.0:9605
path: /metrics
no_prime: true # deja la primera pasada en su horario normal

no_prime: true apaga esa pasada de cebado, para una cuenta con la cuota tan justa que una pasada completa en cada reinicio no salga a cuenta. El precio es exactamente el comportamiento que el cebado existe para evitar: hasta que a cada familia le toque su cadencia, los paneles que la leen no tienen nada, y en una familia de doce horas eso es medio día de ceros. Los almacenes no se ven afectados en ningún caso, porque conservan lo que se recogió antes del reinicio.

La pasada de cebado anota como hechas solo las familias a las que les tocaba, y las demás vuelven a correr cuando lo habrían hecho sin el reinicio. Anotadas todas a la vez, las familias de seis horas o más tocarían juntas un día después y se turnarían, y la última pasaría del día tras el cual el exportador descarta una serie.

Una serie que lleva 24 horas sin reescribirse se descarta, para que un repositorio que sale de la pasada deje de informarse como si siguiera ahí. El horizonte no se configura.

prometheus exporter: listen tcp :9605: bind: address already in use

Se informa al arrancar el proceso en vez de quedar sepultado en una goroutine de fondo, para que un choque de puerto no te deje con un colector corriendo y un exportador ausente en silencio.

El ejemplo escucha en 127.0.0.1, que dentro de un contenedor es el loopback del propio contenedor e inalcanzable desde la máquina anfitriona. Ahí usa 0.0.0.0:9605 y deja que la publicación del puerto decida quién llega.

El exportador guarda en memoria los valores de hoy, y un reinicio con la versión nueva los sirve con su forma, así que -migrate no tiene nada que hacer aquí. El servidor de Prometheus conserva las series antiguas hasta su retención, y terminan donde empiezan las nuevas, así que ninguna consulta cuenta un elemento dos veces.

  • Elegir almacén compara Prometheus con los demás, y lleva el registro de escrituras que todos comparten.
  • Los dashboards dice cuál de los cinco se dibuja contra cada almacén, y en qué se convierte un panel que un almacén no puede responder.