Ir al contenido

Grabar, marcar, dibujar

El colector mantiene un router vigilado; record es para la otra pregunta — estoy a punto de cambiar algo, ¿qué hace de verdad? Esta página responde cómo tomar una grabación desde tu máquina, qué contienen los cuatro ficheros que escribe, cómo entran los marcadores y en qué reloj, cómo el log del router pasa a formar parte de ella y qué dibuja plot.

Ventana de terminal
mikroscope record --for 5m --out cap # cap.jsonl, cap.csv, cap.markers.csv, cap.meta.json; escribe líneas para marcar
mikroscope mark --out cap "queue tree applied" # una nota sellada con la hora actual (ver abajo)
mikroscope mark --out cap --log-markers # las líneas del propio log del router, por la API
mikroscope plot --in cap # cap.svg, determinista

Los tres verbos comparten un mismo juego de opciones, así que cada uno acepta todas las opciones de abajo; las notas dicen sobre qué verbo actúa cada una.

Opción Por defecto Qué hace
--out capture-<UTC time> Prefijo de salida: <out>.jsonl, .csv, .markers.csv, .meta.json. mark necesita el prefijo de una grabación existente.
--for 0 record: para tras este tiempo. 0 graba hasta Ctrl-C.
--from-start desactivada record: rellena todo lo que guarda el anillo del agente antes de pasar a directo.
--poll 500ms Cada cuánto se tira del anillo del agente.
--batch 0 Muestras por petición. 0 es el doble de lo que produce un intervalo de --poll a la cadencia del agente, con un mínimo de 20; el relay limita una petición a 18.
--transport auto auto, direct (HTTP a la veth) o relay (/tool fetch por la API de RouterOS).
--log-markers desactivada record: añade las líneas del log del router de la ventana cuando termina la grabación. mark: añade las líneas del log de la ventana de la grabación.
--topics system,interface,container Temas del log que se conservan como marcadores; añade firewall o script cuando sus líneas son la historia.
--router-tz Local Zona IANA que muestra el reloj del router. Las horas del log de RouterOS no llevan zona.
--api MIKROSCOPE_API_ADDR host:port de la API de RouterOS, para el relay y para --log-markers.
--api-user MIKROSCOPE_API_USER El usuario de la API. La contraseña solo se lee de MIKROSCOPE_API_PASSWORD; no hay opción para ella.
--token MIKROSCOPE_TOKEN El token bearer del agente.
--port 9123 El puerto HTTP del agente.
--subnet MIKROSCOPE_SUBNET, si no 172.30.10.0/30 La /30 del agente; su dirección es la .2.
--in ninguno plot: un prefijo de grabación, o la ruta de un fichero .jsonl.
--svg <in>.svg plot: el fichero de salida.
--title el prefijo plot: el título del gráfico.

Lo que se ha medido que entrega una grabación

Sección titulada «Lo que se ha medido que entrega una grabación»

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 · · un record de 60 s a 10 Hz, 600 muestras en 59,9 s, un bucle de script de RouterOS lanzado por ssh y el log del router añadido como marcadores

Esa grabación dio exactamente 600 muestras, 0 huecos y un desfase de reloj de −7 ms. En ella, un bucle de RouterOS por script (:for … 400 000) se vio como la carga de un núcleo entero al 100 % de t = 21,0 a 25,8 s, con la muestra de 25,8 s marcando alrededor del 60 %, y el inicio y el final resueltos a 100 ms, y los marcadores del log del router explicaron una meseta de 2 s entre 15 y 17 s que nadie había provocado: el planificador ensure-ipv6-nd-prefix. Cinco minutos con un router recorre record y plot de principio a fin sobre otra captura: 70 s a 10 Hz con el router por lo demás en reposo, con tres notas escritas en el terminal de record.

--transport auto prueba primero el camino directo: un GET /healthz a http://<.2 de --subnet>:<--port>. Si no responde, abre la API de RouterOS y pide al router que haga él mismo la petición al agente. Si falta --api o --api-user, se detiene con un error que nombra --api, --api-user y MIKROSCOPE_API_PASSWORD y sugiere install --expose; si falta la contraseña, aparece en su lugar un error de inicio de sesión, api <host:port>: …. La sugerencia de --expose sirve a otros clientes HTTP, no a record: record siempre llama a la .2 de --subnet y no tiene opción para la dirección LAN del router. direct y relay fuerzan un camino y fallan en vez de recurrir al otro.

  • direct es HTTP plano de tu máquina a la veth. Envía --token como token bearer.
  • relay ejecuta /tool fetch output=user en el router por la API binaria, así que el usuario de la API necesita las políticas read,api,test. Cada llamada por relay tarda o unos 3 ms o alrededor de 1 s. Una respuesta está limitada a 64 512 B, así que una petición por relay pide como mucho 18 muestras, y una respuesta que llega al límite se rechaza en vez de analizarse truncada. La petición desde el router no lleva cabecera: un agente instalado con token solo se puede grabar por el camino directo.

Llegar al agente explica qué camino permite una red. El usuario de la API se describe en su propia página.

Una vez conectado, record lee /healthz. El reloj de pared del agente menos el de tu máquina es el desfase de reloj, que se imprime por stderr junto con la versión del agente, la cadencia, el número de secuencia más reciente, el más antiguo que aún guarda el anillo y el transporte. La grabación empieza entonces en directo desde la muestra más reciente, o desde la más antigua que guarda el anillo con --from-start.

Cada --poll pide /snapshot?since=<last seq>&max=<batch>. Mientras una petición vuelve llena, vuelve a pedir, hasta 100 veces por intervalo, así que un anillo que se ha adelantado se vacía en vez de seguirse a ritmo fijo. Una petición que falla se registra como pull: … y la grabación continúa; la siguiente pide desde el mismo número de secuencia. Cuando vence --for o pulsas Ctrl-C, una última petición recoge lo que llegó entretanto, y record imprime cuántas muestras conservó, su rango de secuencia, los huecos, los marcadores, el transporte y los ficheros.

Cada fichero se crea con modo 0600, y un fichero existente con el mismo prefijo se sobrescribe.

  • <out>.jsonl — cada línea de muestra tal como la envió el agente: deltas crudos de ticks y contadores, con todas las fuentes que tiene el agente. Esta es la grabación; los demás ficheros son vistas de ella.
  • <out>.csv — una fila ancha por muestra, para una hoja de cálculo. El conjunto de columnas se dimensiona a partir de la primera muestra: un grupo por núcleo y uno por cola softnet.
  • <out>.markers.csvwall_ns,wall_utc,seq,kind,label, una fila por marcador.
  • <out>.meta.json — se escribe al principio, para que mark y plot puedan ejecutarse después: started_utc, skew_ns (reloj de pared del agente menos el del anfitrión), agent (su versión), rate_hz, transport y capabilities — lo que el agente estableció sobre la placa — cuando el transporte pudo obtenerlo.

El CSV guarda un subconjunto fijo de cada muestra. Todo lo demás que lleva una muestra — eventos del log del kernel, contadores PMU, temperaturas, interrupciones por línea y el resto — está solo en el .jsonl.

Columnas Contenido
seq, wall_ns, wall_utc, dt_ns El número de secuencia de la muestra, el reloj de pared del agente y el intervalo real.
busy_total La media de las proporciones de ocupación por núcleo, con tres decimales, calculada por la CLI a partir de los ticks.
c<N>_busy, c<N>_user, c<N>_nice, c<N>_system, c<N>_idle, c<N>_iowait, c<N>_irq, c<N>_softirq Por núcleo: la proporción de ocupación y después los deltas crudos de ticks.
ctxt, intr, irq_total Cambios de contexto e interrupciones de /proc/stat, y el delta sumado sobre todas las filas de /proc/interrupts.
softnet<N>_processed, softnet<N>_dropped, softnet<N>_time_squeeze Por cola softnet, los deltas del camino de recepción.
mem_free_kb, mem_available_kb, mem_cached_kb, mem_slab_kb Niveles de memoria, en kB.
load1, threads_running, threads_total Carga media y recuento de hilos.
pgfault, pgmajfault Deltas de fallos de página.
self_cpu_us, self_rss_bytes El tiempo de CPU propio del agente durante la muestra, en µs, y su memoria residente en ese momento, en bytes.

La proporción de ocupación del CSV es el único número que calcula la CLI, y hereda el suelo del kernel: un tick dura 10 ms, así que en una muestra de 100 ms un núcleo se resuelve en escalones del 10 %. El suelo de resolución explica por qué, y por qué la proporción está limitada a 1.

Un marcador es una fila de <out>.markers.csv de uno de tres tipos:

  • note — una línea de texto que añadiste tú. Mientras record corre en un terminal imprime type a line and press Enter to add a marker; Ctrl-C stops, y cada línea no vacía que escribes se convierte en una nota. Cuando la entrada estándar no es un terminal, no se lee nada de ella.
  • gap — se escribe cuando el agente informa de que unas muestras ya no estaban en su anillo, con la etiqueta samples <from>..<to> lost. Los mismos huecos aparecen en el resumen que imprime record al final.
  • log — una línea del propio log del router, añadida con --log-markers (abajo).

Las notas y los huecos llevan la hora de tu máquina más el desfase medido al principio, así que quedan sobre el eje de tiempo del agente, no del de tu máquina. mark --out cap "text" hace lo mismo con el desfase guardado en cap.meta.json: sella la hora actual en el reloj del agente, y ninguna opción fija otra. Sobre una grabación terminada, la nota cae por tanto después de la última muestra, y plot no la dibuja. mark necesita ese fichero y un cap.markers.csv existente, y su fila lleva seq 0.

El log explica a menudo un transitorio que no provocaste tú: ejecuciones del planificador, errores, eventos de interfaz. --log-markers convierte las líneas del log de la ventana de la grabación en marcadores log, con la etiqueta <topics>: <message>.

Ventana de terminal
export MIKROSCOPE_API_ADDR=192.168.88.1:8728 MIKROSCOPE_API_USER=mikroscope MIKROSCOPE_API_PASSWORD=
mikroscope record --for 60s --out burst
mikroscope mark --out burst --log-markers --router-tz Europe/Madrid
  • mark --log-markers usa la ventana desde started_utc del fichero meta, desplazado por su skew_ns al reloj del agente, hasta la última muestra del .jsonl, e imprime cuántas líneas añadió, la ventana y los temas. started_utc se guarda al segundo. Añade sin comprobar lo que ya hay: ejecutarlo dos veces vuelve a añadir las mismas líneas.
  • record --log-markers pide el log cuando la grabación se ha detenido, para la ventana desde su inicio hasta su final en el reloj del agente, y añade las líneas por el mismo camino que usa mark, así que acaban en <out>.markers.csv y el total de marcadores del resumen cuenta lo que contiene el fichero. Si la propia petición del log falla, record imprime log markers: … y conserva la grabación.

La CLI pide al router solo la ventana, con una consulta ?>time= que empieza un segundo antes, y solo los campos time, topics y message: el RB5009 tenía 66 217 filas de log, porque su tema dns registra a disco. Después conserva las líneas dentro de la ventana cuyos temas incluyen alguno de --topics.

Un router con varias acciones de registro sobre un mismo tema lleva cada evento una vez por acción, precedido del nombre de la acción ([INFO]: …, [SYSTEM]: …); el prefijo se elimina y los duplicados se conservan una sola vez.

Las horas del log de RouterOS no llevan zona. RouterOS 7.24.2 imprime la fecha completa por la API; el analizador acepta también las formas más cortas, sin año o sin fecha, y las completa a partir del final de la ventana. Se leen en --router-tz y se sellan como reloj de pared del agente — el propio reloj del router — así que no se les aplica desfase. El valor por defecto Local es la zona de tu máquina: si la del router es distinta, pásala, o cada marcador de log caerá desplazado en esa diferencia. Las horas del log tienen resolución de un segundo, así que un marcador de log sitúa su evento al segundo, no a la muestra.

plot --in cap lee cap.jsonl, y cap.markers.csv cuando existe, y escribe cap.svg (o --svg). Imprime el nombre del fichero con sus recuentos de muestras y marcadores. La misma entrada produce siempre los mismos bytes.

El gráfico mide 1 200 unidades de ancho, con un título (--title, o el prefijo) y una línea con el número de muestras, la duración y el número de núcleos. Tres paneles comparten un eje de tiempo, en segundos desde que empezó la grabación:

  1. CPU busy per core, % — de 0 a 100, una línea por núcleo, cada una etiquetada en su extremo. La paleta tiene ocho colores, así que se dibujan los ocho primeros núcleos.
  2. softnet per second, all CPUsdropped y time_squeeze, sumados sobre todas las colas y agrupados en segundos enteros. Los descartes se dibujan en rojo.
  3. memory available, MiBMemAvailable por muestra, con el eje y ajustado a los datos.

Cada marcador es una línea vertical discontinua que cruza los tres paneles, gris para notas y líneas de log y roja para huecos, con una etiqueta encima del primer panel. Las etiquetas se reparten en hasta seis filas para separarlas; una etiqueta de más de 40 caracteres se acorta. Los marcadores de log consecutivos, en orden de tiempo, que caen en el mismo segundo se pliegan en una sola etiqueta, <count>× <topics>: <first message>, para que un planificador parlanchín no entierre el gráfico; una nota o un hueco entre ellos corta el pliegue, y las notas y los huecos nunca se pliegan. Los marcadores fuera del intervalo de tiempo de la grabación no se dibujan. Con una sola muestra, el SVG dice not enough samples to draw; sin ninguna, plot se detiene con record: no samples y no escribe SVG.

La paleta es propia del gráfico, validada para su fondo claro: ΔE entre pares adyacentes con deficiencia de visión del color 9,1, con visión normal 22,9. No hay variante oscura.

plot también lee una captura que el agente guardó por un disparo: guarda GET /captures/<id> en un fichero .jsonl y pásalo a --in. La línea de cabecera de la captura no lleva número de secuencia y se salta.

Cuando salta un disparador en el agente, una línea {"trigger":{…}} viaja en la misma petición que las muestras, justo antes de la muestra en la que saltó. El colector la reconoce; record no.

Captura por disparo explica qué salta y cómo traer la ventana a cadencia completa que el agente guardó a su alrededor.