Ir al contenido

La fecha del punto

Un punto lleva la fecha en que ocurrió la cosa, no la fecha en que se recogió.

Esa es la única regla de la que se deriva todo lo demás. Una ejecución de workflow se sella cuando terminó. Una estrella se sella cuando se dio. Un día de tráfico se sella en la fecha de ese mismo día. Una pull request se sella cuando se cerró. Ninguno se sella en el instante en que el colector se enteró.

No todo lo que GitHub informa tiene fecha propia, así que hay tres tratamientos y cada medida declara cuál le corresponde.

TipoSellado enEjemplo
Fechadoel momento en que ocurrió la cosagh_star, gh_workflow_run, gh_traffic, gh_commit
Diarioel inicio del día UTCgh_traffic_referrer, gh_label, gh_milestone, gh_webhook
Ahorael instante de la pasadagh_repo, gh_actions_cache, gh_dependabot_alert

Diario es para una instantánea sin fecha propia. GitHub devuelve los diez primeros referrers de los catorce días anteriores como una lista sin día asociado, así que no es una serie. Sellarla en el instante de la pasada escribiría cuatro copias al día y cualquier consulta que las sumara informaría de cuatro veces el tráfico. Sellarla al inicio del día UTC hace que las pasadas de un día reescriban una sola fila.

Ahora es para algo que de verdad es un estado actual. El tamaño de la caché de Actions, el número de alertas abiertas, el inventario de workflows: ninguno ocurrió en un momento, así que fingir lo contrario sería una mentira con marca de tiempo.

Por qué existe la regla: volver a recoger tiene que converger

Sección titulada «Por qué existe la regla: volver a recoger tiene que converger»

InfluxDB indexa un punto por medida, conjunto de etiquetas y marca de tiempo. Tres campos, una fila. Escribe los mismos tres otra vez y la fila se reemplaza, no se suma.

Escrito del todo, dos pasadas separadas por seis horas ofrecen el mismo día dos veces, y la segunda reemplaza a la primera porque las tres claves son idénticas:

gh_traffic,owner=acme,repo=telemetry,kind=views count=220i,uniques=131i 1757203200000000000
gh_traffic,owner=acme,repo=telemetry,kind=views count=238i,uniques=140i 1757203200000000000
gh_traffic,owner=acme,repo=telemetry,kind=views count=238i,uniques=140i 1757203200000000000

Una fila, con el número más reciente que GitHub dio para ese día. Sella esas dos líneas en el momento de recogerlas y son dos filas, y toda suma sobre ellas está equivocada por tantas veces como pasadas hayan corrido.

Eso es lo que hace funcionar todo el diseño. La ventana de tráfico de GitHub es de catorce días, y el colector reescribe los catorce en cada pasada en vez de intentar averiguar qué día es nuevo:

Dos maneras de escribir los mismos catorce días Dos maneras de escribir la ventana de tráfico de 14 días de GitHub, una al lado de la otra. A la izquierda, el fechado tal como está hecho: 4 pasadas al día, cada 6 horas, releen la ventana entera y sellan cada día con su propia fecha, así que las 4 caen sobre las mismas 14 filas y el recuento más reciente sustituye al anterior. Al cabo de una semana el almacén tiene 14 filas por repositorio. A la derecha, las mismas pasadas selladas en el momento de recogerlas: cada una añade 14 filas en vez de sustituir 14, así que al cabo de una semana el almacén tiene 392 filas por repositorio, 28 copias de cada día, y sumarlas da 28 veces el tráfico. Fechado, tal como está hecho cada pasada relee la ventana entera de 14 días 4 pasadas al día, cada 6 horas 00:00 06:00 12:00 18:00 hace 14 días hoy 14 filas tras una semana, por repositorio Una fila por día. La pasada más reciente sustituye el día que releyó. Sellado al recoger cada pasada escribe otra vez lo que leyó 4 pasadas al día, cada 6 horas 00:00 +14 06:00 +14 12:00 +14 18:00 +14 hace 14 días hoy 392 filas tras una semana, por repositorio 28 copias de cada día. Sumar las visitas del mes da 28 veces el tráfico. una fila que se reescribe una fila que se añade
Dos maneras de escribir los mismos catorce días Dos maneras de escribir la ventana de tráfico de 14 días de GitHub, una al lado de la otra. A la izquierda, el fechado tal como está hecho: 4 pasadas al día, cada 6 horas, releen la ventana entera y sellan cada día con su propia fecha, así que las 4 caen sobre las mismas 14 filas y el recuento más reciente sustituye al anterior. Al cabo de una semana el almacén tiene 14 filas por repositorio. A la derecha, las mismas pasadas selladas en el momento de recogerlas: cada una añade 14 filas en vez de sustituir 14, así que al cabo de una semana el almacén tiene 392 filas por repositorio, 28 copias de cada día, y sumarlas da 28 veces el tráfico. Fechado, tal como está hecho cada pasada relee la ventana entera de 14 días 4 pasadas al día, cada 6 horas 00:00 06:00 12:00 18:00 hace 14 días hoy 14 filas tras una semana, por repositorio Una fila por día. La pasada más reciente sustituye el día que releyó. Sellado al recoger cada pasada escribe otra vez lo que leyó 4 pasadas al día, cada 6 horas 00:00 +14 06:00 +14 12:00 +14 18:00 +14 hace 14 días hoy 392 filas tras una semana, por repositorio 28 copias de cada día. Sumar las visitas del mes da 28 veces el tráfico. una fila que se reescribe una fila que se añade

La misma propiedad es la que hace seguro ejecutar dos veces un relleno histórico, y la que permite borrar el fichero de estado sin corromper nada: volver a recoger reescribe filas que ya había escrito.

Lo que Prometheus no puede sostener por construcción

Sección titulada «Lo que Prometheus no puede sostener por construcción»

Prometheus sella una muestra en el instante del scrape. No toma una marca de tiempo del productor, y rechaza cualquier cosa apreciablemente más vieja que ahora.

Esto se midió, no se supuso. Contra Prometheus 3.14, con --web.enable-otlp-receiver y out_of_order_time_window: 30m, una muestra fechada dos días atrás vuelve como HTTP 400.

La mitad de lo que esto recoge es más viejo que eso a propósito: una estrella de 2020, una pull request fusionada en julio, el tráfico de ayer. Así que no hay configuración de Prometheus en la que sobreviva la historia fechada. Ensanchar la ventana de desorden mueve la frontera; no la elimina.

Como el almacén no puede sostener la historia, la reducción ocurre antes de que Prometheus o un backend OTLP con raw: false vean los datos. Summarize da a cada medida una de cuatro reglas.

ReglaQué haceSe usa para
keepLastGana el punto más reciente de cada conjunto de etiquetasInstantáneas: gh_repo, gh_account, gh_release
sumSe suman todos los puntos del loteVentanas: las visitas de los catorce días
countLos puntos pasan a ser un recuento más la media de cada campo numéricoElementos fechados: las pull requests pasan a ser “cuántas se fusionaron” y “cuánto tardaron”
skipNo se sirve nadaHistoria sin valor actual honesto

Una medida sin regla se salta en vez de adivinarse. Ese es el valor por defecto seguro, y es deliberado: sin él, un colector nuevo podría inundar en silencio un exportador con una serie por estrella.

count promedia cada uno de sus números excepto los identificadores. Un campo que une una fila con otra, run_id, workflow_id, pull_request, number, stack y los demás, es un nombre y no una cantidad: promediado sobre una cuenta se convierte en un número con la forma exacta del identificador del que está hecho y que no pertenece a nada, y gh_deployment publicó run_id_mean así. Esos campos quedan fuera de la reducción, y también las marcas que un punto lleva solo para tener algún campo, cuya media es 1,0 para siempre.

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

Diez de las medidas llevan skip, así que un exportador de Prometheus y un backend OTLP con raw: false no las ven nunca. Siete son historia, dos son tamaño y una es texto:

MedidaPor qué
gh_artifactHistoria. Una fila por artefacto de siempre, y ninguna se vuelve a mover
gh_commit_punchcardTamaño. Una serie por repositorio, día de la semana y hora
gh_commits_weekHistoria. La serie semanal de commits
gh_contribution_dayHistoria. El calendario verde, una fila por día
gh_contribution_day_repoHistoria. El mismo calendario partido por repositorio, que acuñaría una serie por día
gh_job_logTexto, no un número. Su sitio es un almacén de logs
gh_package_versionHistoria. La fecha de publicación de cada tag; su recuento ya es un campo de gh_package
gh_release_assetTamaño. Una serie por cada fichero publicado alguna vez
gh_traffic_pathHistoria. Las rutas por día
gh_workflow_stepHistoria. Los tiempos por paso

Las dos que se saltan por tamaño son las que conviene conocer, porque son números de verdad y no historia: medido, juntas eran cuatro quintas partes de toda la salida del exportador. Ambas se dibujan bien en el dashboard de InfluxDB, y gh_release guarda las descargas por release, que es para lo que se leían los ficheros.

AlmacénLa historia fechadaPor qué
InfluxDB, PostgreSQL, Graphite, ElasticsearchLa marca de tiempo es parte de la identidad de una fila
Telegrafhasta donde permitan sus salidasReenvía las marcas de tiempo sin tocarlas; una salida que sella al recibir las pierde
Fichero y stdoutLa marca de tiempo va en la línea
Lokisolo eventos recientesLoki rechaza una entrada demasiado atrasada respecto a la más nueva de su stream. Ver Loki
OpenTelemetrylo decide el backendLos puntos OTLP llevan una marca de tiempo explícita; que se respete no depende de esta herramienta
PrometheusnoSolo valores actuales, según las reglas de arriba

Una etiqueta es una serie, un campo es un valor. Todo lo no acotado va en un campo. El nombre del runner de Actions parece una buena etiqueta hasta que uno se fija en que un runner alojado se nombra de forma única en cada ejecución (GitHub Actions 1000163135), lo que crearía una serie por cada job ejecutado alguna vez. Es un campo.

Las filas semanales se anclan a la semana, no a hoy. gh_commits_week se sella en el domingo con el que empieza cada semana. Una pasada del martes y otra del viernes tienen que caer en la misma fila, o cada relectura escribe una segunda copia del año.

Prometheus reserva algunos nombres de etiqueta. Una etiqueta llamada job o instance choca con las etiquetas del scrape, y el receptor OTLP la sobrescribe con el nombre del servicio. Por eso los jobs de workflow se etiquetan job_name.