Loki
El destino Loki envía a Grafana Loki, como líneas de log, la actividad de GitHub que es un evento y no un número (una estrella, una release, una ejecución fallida).
sinks: loki: url: http://loki:3100/loki/api/v1/push tenant_id: "" labels: job: ghchronicle max_age: 1h batch: 1000Medidas y eventos
Sección titulada «Medidas y eventos»Parte de lo que informa GitHub es una medida y parte es un evento. “El repositorio tiene 148 estrellas” es una medida. “Alguien le dio una estrella a las 03:03, se publicó esta release, aquel workflow falló en main, se abrió esta alerta” son eventos: cada uno ocurrió una vez, en un momento conocido, y lo que uno quiere después es leerlos en orden y buscarlos, no promediarlos.
Veintidós medidas tienen una representación de evento: estrellas en ambas direcciones, forks, releases, versiones de paquete publicadas, pull requests, revisiones, hilos de revisión, issues, commits, ejecuciones de workflows, logs de jobs, actividad del repositorio, alertas de Dependabot, análisis de code scanning, el feed de eventos, las notificaciones, las discusiones, las entregas de webhook, los despliegues, las versiones de ruleset y las contribuciones externas. Todo lo demás es un gauge disfrazado y no se envía.
Una medida sin representación se descarta en silencio, lo cual está bien para un
gauge y mal para un evento que nadie ha llegado a escribir: los despliegues y los
hilos de revisión fueron eventos fechados sin línea de log durante meses y nada
lo dijo. Por eso ahora toda medida fechada tiene que aparecer en una de las dos
tablas de internal/sink/loki.go, la de representaciones o la de rechazos, y
cada rechazo lleva el motivo por el que no es una línea de log. Una prueba falla
ante una medida fechada que no aparezca en ninguna de las dos.
En el registro de la pasada ya no se descarta en silencio. Este destino escribe
una fracción de lo que se le ofrece, así que la mayoría de sus líneas llevan
filtered y
points=0, que es lo que guardó y no lo que se le dio. Una entrada más vieja
que max_age, o demasiado atrasada respecto a la más reciente de su propio
flujo para que Loki la acepte, también se cuenta ahí y se informa en una línea
de entradas descartadas.
El formato de línea
Sección titulada «El formato de línea»Cada línea se lee primero como una frase y lleva detrás cada etiqueta y cada campo en logfmt, así que la misma línea es greppable en una terminal y consultable en Grafana sin mantener dos copias de los datos.
someone starred acme/telemetry full_name="acme/telemetry" user="someone" starred=1Dos representaciones cambiaron en 2.6.0, y una de ellas otra vez en 2.6.1. Una línea que ya está en Loki conserva el texto con el que se envió:
- Una contribución externa es una línea cuando el elemento se cierra, en el
momento en que se cerró, y dice qué le pasó al elemento y no quién lo hizo,
porque la fila no dice quién lo fusionó o lo cerró: una pull request dice
USER's pull request OWNER/REPO#N was mergedoUSER's pull request OWNER/REPO#N was closed without merging, y una issueUSER's issue OWNER/REPO#N was closed. Una fila cerrada cuyo estado y cuya marca de fusión no coinciden diceUSER's contribution OWNER/REPO#N. Un elemento todavía abierto no es ninguna línea desde 2.6.1: su fila se sella al principio de cada día en que se ve abierto, lo que es una lectura y no algo que ocurrió, y abrirlo ya es una línea del feed de eventos, conaction="opened". 2.6.0 enviaba esa fila como... is open, y solo el día en que una pasada deoutboundescribía en la primera hora del día UTC. Antes todas las líneas decíanUSER merged OWNER/REPO#N, issues abiertas incluidas. - Una release dice
published release TAG of OWNER/REPO, opublished prerelease TAG of OWNER/REPO, en el momento en que se publicó. Antes decíarelease TAG of OWNER/REPO, N downloads, así que una consulta que filtre pordownloadssolo encuentra las líneas antiguas.
batch es cuántas entradas van en un envío, 1000 salvo que se baje.
La etiqueta de stream es kind, que es por lo que se filtra primero.
{job="ghchronicle", kind="workflow_run"} |= "failure"{job="ghchronicle", kind="job_log"}max_age, y por qué la razón no es la obvia
Sección titulada «max_age, y por qué la razón no es la obvia»Loki rechaza un envío entero cuando una entrada es anterior a
reject_old_samples_max_age, una semana por omisión, y la mitad de lo que
produce este colector es más viejo que eso a propósito: una estrella de 2020, un
pull request de 2024.
Pero el límite que de verdad muerde es el otro. Loki también rechaza una entrada
que esté más atrasada que su ventana de desorden respecto a la entrada más nueva
que ya hay en ese stream, que es la mitad del max_chunk_age del ingester, una
hora por omisión.
Medido contra un Loki 3 real: una vez que el stream tenía una entrada de las 19:14, una de las 00:35 del mismo día volvió como “entry too far behind”. Contra Loki 3.7.7 con sus límites por omisión, un stream con una entrada de hace cinco minutos aceptó una de hace 55 minutos y rechazó una de hace 75.
Así que el horizonte se aplica de dos formas:
- contra el reloj de pared,
- contra la entrada más nueva que se ha enviado antes a ese stream.
Dentro de un mismo envío nada va atrasado, porque el destino envía cada stream de la más vieja a la más nueva y Loki juzga cada entrada contra la más nueva anterior a ella: un envío con entradas de hace 23 horas, 12 horas y un minuto a un stream vacío se aceptó entero.
Lo que cae fuera se deja fuera y se cuenta, a nivel de depuración, en vez de costar el envío entero.
max_age vale una hora por omisión, que es la ventana por defecto de Loki.
Súbelo solo si has subido a juego el max_chunk_age de Loki, ya que la ventana
es la mitad.
Una release es el evento que muestra lo que cuesta el horizonte, y uno de los
dos streams que miran más atrás. Su línea se genera a partir de
gh_release_published, en el momento en que se publicó la release. Antes salía
de gh_release, que se sella en la pasada porque sus descargas se mueven, así
que cada pasada de repositorios volvía a enviar todas las releases. Medido con
2.5.1 en producción, durante 30,9 horas y 27 pasadas de repo, fueron 4.313 de
las 10.467 líneas que envió el destino, un 41 por ciento, para las 2 releases
publicadas en esas horas. Fechada en la publicación, una release la ve primero la pasada de
repo siguiente, así que una publicada justo después de que una pasada leyera
su repositorio tiene una cadencia entera cuando escribe la siguiente pasada, más
lo que esa pasada se retrase: un tick que perdió, las familias más lentas que
corrieron antes, un reinicio. Con repo y max_age en su hora por omisión,
max_age por sí solo dejaba fuera esa release, y cada pasada posterior solo la
veía más vieja.
Así que el stream de releases mira atrás la cadencia de repo más max_age:
dos horas por omisión, siete con repo: 6h. Una contribución externa es el
otro stream que lo hace, por la misma razón: su línea se fecha cuando se cerró
el elemento, y la primera pasada que lo ve es la de outbound siguiente, así
que el stream mira atrás la cadencia de outbound más max_age, dos horas por
omisión. Antes de 2.6.1 tenía solo max_age, y un cierre se enviaba solo si la
pasada siguiente escribía dentro de la hora, cosa que una pasada horaria no
hace con un elemento cerrado en los segundos posteriores a que la anterior
leyera las búsquedas, ni, cuando se retrasa, con uno cerrado en los minutos que
lleva de retraso.
Cada mirada atrás tiene un tope de seis días, un día menos que la semana que
permite reject_old_samples_max_age, y nunca acorta max_age: uno fijado por
encima de seis días es el horizonte de estos streams igual que el de cualquier
otro. Loki solo rechaza una línea vieja por ir atrasada respecto a una más
nueva de su stream, que es lo que la segunda comprobación de arriba sigue
haciendo. Una release publicada en la hora anterior a una pasada la envía esa
pasada y otra vez la siguiente, la misma línea en el mismo instante, que Loki
guarda una sola vez. Una contribución se envía dos veces del mismo modo, y su
línea lleva el número de comentarios y el título del elemento, que pueden
moverse entre medias: medido contra Loki 3.7.7, una línea enviada otra vez con
comments pasado de 1 a 2 se guardó como una segunda línea en el mismo
instante. Con -once la cadencia que cuenta es la del calendario que lanza el
binario, así que pon every.families.repo y every.families.outbound a ese
valor. Las dos están en el almacén de métricas en cualquier caso.
Para qué no sirve Loki
Sección titulada «Para qué no sirve Loki»Para la historia fechada. De eso se encarga un almacén de métricas, y por eso los dos van juntos y no uno en lugar del otro. Un log responde “qué pasó recientemente, en orden”; una serie temporal responde “cuánto, en qué periodo”.
Los logs de jobs pertenecen aquí
Sección titulada «Los logs de jobs pertenecen aquí»La familia joblogs, apagada hasta que every.families.joblogs le da una
cadencia, recoge las últimas cuarenta líneas de cada job fallido de GitHub
Actions. Es texto y no una medida, así que el destino de InfluxDB lo excluye por
omisión y el exportador de Prometheus lo salta. Loki es donde le corresponde, y
la consulta es:
{job="ghchronicle", kind="job_log"}Los dashboards exportados no lo muestran, porque un dashboard atado a un
datasource no puede consultar dos y quien lo importa puede no tener Loki: llevan
un panel de texto, “Where failure output went”, con esa consulta. Publicar el
dashboard desde el colector cambia ese panel por las líneas, las más recientes
primero, filtradas por la variable de repositorio del dashboard allí donde la
variable del almacén se puede leer como expresión regular. Basta con un sink de
Loki cuya dirección termine en /loki/api/v1/push: se adopta un datasource de
Loki que Grafana ya tenga en esa dirección, sin la ruta, y si no lo hay el
datasource se crea a partir de ella. Uno que escriba en otro sitio lo dice y
toma un grafana.datasource.loki_uid en su lugar, y lo mismo un Grafana que
llega a Loki por otra dirección. Un token que no puede crear el datasource
cuesta este panel y nada más: la ejecución avisa una vez y publica todos los
dashboards con la nota.
Nada que migrar
Sección titulada «Nada que migrar»Un stream es su job, su tipo y las etiquetas configuradas, y las etiquetas de
un punto van dentro de la línea, así que una versión que mueve una etiqueta no
cambia ningún stream, y -migrate
no tiene nada que hacer aquí. Una línea es lo que se dijo cuando se dijo, y
Loki rechaza de todos modos las entradas más antiguas que su ventana.
Por dónde seguir
Sección titulada «Por dónde seguir»- Elegir almacén compara Loki 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.