El fichero y los demás destinos
Además de Prometheus e InfluxDB
3, forward escribe en ocho destinos más. Esta página
responde, para cada uno, qué partes de la línea temporal recibe, cómo se le entregan y qué
no te puede decir por culpa del protocolo del destino. La cola, la espera entre reintentos
y los contadores que comparten están en el colector.
Lo que recibe cada destino
Sección titulada «Lo que recibe cada destino»| Destino | Muestras del kernel | Texto del log del kernel | Capa de la API | Derivados y detecciones | Disparos, huecos, equipo |
|---|---|---|---|---|---|
| file | líneas del agente tal cual | dentro de las líneas de muestra | líneas {"api":…} |
{"derived":…}, {"detection":…} |
los tres, como líneas |
stdout json |
líneas del agente tal cual | dentro de las líneas de muestra | líneas {"api":…} |
como el fichero | los tres, como líneas |
stdout lp |
las medidas de InfluxDB | cuentas por nivel, puerto y tipo de evento | las medidas de InfluxDB | las medidas de InfluxDB | los tres |
| SQL | una tabla por fuente | filas mikroscope_event |
tablas, más mikroscope_api_error |
mikroscope_derived, mikroscope_detection |
los tres |
| Loki | no | una línea por registro | solo errores por orden | solo detecciones | los tres, como líneas |
| OTLP | sums y gauges | no | gauges, y una cuenta de errores | gauges, un sum de detecciones | los tres |
| Graphite | una ruta por valor | no | rutas | rutas | solo las partes numéricas |
| Elasticsearch | un documento por tick | un documento por registro | un documento por lectura, sin errores | en el documento del kernel, un documento por detección | los tres |
| Telegraf | las medidas de InfluxDB | cuentas por nivel, puerto y tipo de evento | las medidas de InfluxDB | las medidas de InfluxDB | los tres |
Desliza en horizontal para ver todas las columnas
Los registros del log del kernel solo existen cuando el contenedor corre con
privileged=yes; consulta lo que aporta privileged.
El fichero
Sección titulada «El fichero»mikroscope forward --file timeline.jsonlEl fichero se abre y se trunca, con modo 0600. Cada línea es un objeto JSON, y su
primera clave dice qué es:
- una muestra del kernel — la propia línea del agente, byte a byte, tal como la sirvió
/snapshot; {"trigger":…}— el marcador de captura del agente, también tal cual;{"derived":…}— los valores de la etapa de derivación, en la línea siguiente a la muestra a la que pertenecen, para que un lector que solo quiere muestras en bruto se salte ese tipo;{"detection":…},{"device":…},{"api":…}y{"gap":…}.
Las escrituras son síncronas a través de un búfer de 64 KiB, y los contadores van en eventos. Una escritura que el sistema de ficheros rechaza cuenta un error y un descarte.
Salida estándar
Sección titulada «Salida estándar»mikroscope forward --stdout=lp | telegraf --config …mikroscope forward --stdout=json | jq--stdout lp renderiza protocolo de líneas de InfluxDB con el propio codificador del
destino de InfluxDB, así que una tubería muestra exactamente lo que enviaría --influx.
--stdout json escribe los mismos tipos de línea que el fichero. Cualquier otro valor se
rechaza antes de que empiece la ejecución.
La salida estándar se puede atascar — un lector lento llena el búfer de la tubería y la
escritura se bloquea sin nada que la acote — así que este destino va en cola: un lote por
segundo, cada lote escrito en una sola llamada de líneas completas para que un lector nunca
vea un registro a medias, 64 KiB × --queue-seconds de presupuesto, descartando primero lo
más antiguo. Un lote que un lector atascado deja crecer por encima del presupuesto entero
se cierra antes. Ese presupuesto se dimensionó para una muestra en protocolo de líneas de
unos 1,2 KiB; no se ha medido para json, cuyas líneas llevan fuentes que el protocolo
de líneas omite y son más grandes.
- Una tubería rota no llega a los contadores: Go deja
SIGPIPEsin capturar en la salida estándar, así que el proceso termina. - Al cerrar, el destino espera como mucho 3 s a que el lector acepte el último lote, así
que un lector que dejó de leer no puede colgar
forward. forwardimprime también su resumen de salida por la salida estándar, así que una tubería haciatelegraftermina cada ejecución con líneas que el consumidor no puede interpretar.
SQL para PostgreSQL y TimescaleDB
Sección titulada «SQL para PostgreSQL y TimescaleDB»mikroscope forward --sql out.sql --for 10m && psql -f out.sqlmikroscope forward --sql - | psql # mira el aviso de abajo--sql escribe texto PostgreSQL — una cabecera DDL y luego un INSERT por fila — a un
fichero, o a la salida estándar con -. No usa driver a propósito: hablar el protocolo de
red de PostgreSQL necesita un driver de terceros, así que el texto SQL es la interfaz y
psql es dueño de la conexión. El coste es que el destino no puede saber si una fila se
guardó; cuenta los eventos que escribió.
La cabecera se puede aplicar por sí sola y es idempotente:
SET standard_— para que una barra invertida en un mensaje del kernel nunca se convierta en un escape y se trague las sentencias siguientes;conforming_ strings = on; CREATE TABLE IF NOT EXISTSpara cada tabla, cada una con una clave primaria que empieza portime, host;- con
--sql-hypertable, una llamadacreate_hypertablede TimescaleDB sobretimepara cada tabla, conif_not_exists => TRUE.
Cada INSERT termina en ON CONFLICT DO NOTHING, así que aplicar el mismo fichero dos
veces no hace nada en vez de abortar por clave duplicada. Una fila es un instante inmutable
de un delta de contador, nunca un total acumulado que un fichero posterior corrija.
| Tabla | Clave tras time, host |
Guarda |
|---|---|---|
mikroscope_cpu |
cpu |
user_ticks … steal_ticks, busy_ratio, dt_ns |
mikroscope_softnet |
cpu |
processed, dropped, time_squeeze |
mikroscope_irq |
irq |
name, count sumado sobre las CPU |
mikroscope_mem |
— | niveles: free_kb, available_kb, cached_kb, slab_kb, sunreclaim_kb |
mikroscope_load |
— | niveles: medias de carga, running, threads, procs_blocked |
mikroscope_stat |
— | deltas: ctxt, intr, forks, irq_total, irq_err, pgfault, pgmajfault |
mikroscope_self |
— | delta cpu_us; niveles rss, cgroup_mem; eventos de cgroup, NULL sin cgroup2; seq |
mikroscope_buddy |
node, zone, block_order |
free_blocks, una fila por zona y orden |
mikroscope_mtd |
device |
partition, contadores ECC tal como se leen, umbrales NULL donde no se publican |
mikroscope_psi |
— | microsegundos de bloqueo; ninguna fila donde el kernel no tiene PSI |
mikroscope_thermal |
zone |
celsius, critical_celsius |
mikroscope_slab |
cache |
active_objs, limit_objs (NULL para toda caché salvo nf_conntrack) |
mikroscope_disk |
device |
deltas de lectura y escritura, io_s; inflight es un nivel |
mikroscope_flash |
device |
deltas de desgaste; bad_blocks y free_chunks son niveles |
mikroscope_event |
kernel_seq |
un registro del log del kernel: level, facility, time_usec, message, y port, kind |
mikroscope_api_system |
— | cpu_load, memoria, free_hdd, uptime_s, version |
mikroscope_api_core |
cpu |
el porcentaje load, irq, disk de RouterOS |
mikroscope_api_health |
name |
value |
mikroscope_api_iface |
interface |
label, tasas, y cinco columnas de pérdidas que son NULL donde el router no devolvió la clave |
mikroscope_api_conntrack |
— | entries, el último valor repetido a la cadencia de la API |
mikroscope_api_ifinfo |
interface |
qué es cada interfaz: default_name, type, role, bridge, label, mtu |
mikroscope_api_ifcounter |
interface, counter |
value, en formato largo, con el nombre de contador del propio RouterOS |
mikroscope_api_error |
message |
una por cada orden de la API que falló |
mikroscope_gap |
seq_from, seq_to |
el rango perdido, con el reloj del colector |
mikroscope_trigger |
id |
cause, field, value, threshold, seq |
mikroscope_derived |
— | seq, mem_pressure, burst, suspect, valores por paquete NULL donde no se calcularon |
mikroscope_derived_iface |
interface |
los cuatro deltas de bytes y las dos proporciones del fast path |
mikroscope_detection |
rule, key |
seq, value, threshold, message |
mikroscope_device, mikroscope_, mikroscope_, mikroscope_ |
—, zone, cpu, source |
el flujo de datos del equipo |
Desliza en horizontal para ver todas las columnas
Las columnas nunca necesitan comillas: las columnas de ticks son user_ticks y compañía
porque user es una palabra reservada, y block_order porque order lo es. dt_ns va
solo en mikroscope_cpu, así que una tasa sobre cualquier otra tabla de deltas se une a
mikroscope_cpu por (time, host) para tener el intervalo real en vez de suponer el
periodo nominal.
mikroscope_api_ifinfo guarda una fila por interfaz, escrita al arrancar el colector y en
cada relectura de --labels-every (5 minutos por defecto), así que una consulta la une por
interface para darle a cualquier serie de interfaz un tipo, un rol y el comentario del
puerto. default_name es el nombre de fábrica de un puerto físico y está vacío para un
bridge, una VLAN o un túnel; mtu es el actual-mtu de RouterOS, NULL donde el router no
lo publica. En mikroscope_event, port es el puerto que nombra el registro — su nombre
actual en RouterOS cuando el inventario de la capa de la API lo da, y el nombre por defecto
de la placa si no — y kind es lo que le pasó: link-up, link-down, los estados
stp-*, own-address (el bridge recibió una trama con su propia MAC como origen, la firma
de un bucle de capa 2) u other. Ambas son NULL para un registro que no nombra ningún
puerto.
Una fuente que el despliegue no puede leer no emite ninguna fila. Un valor que no se midió
es NULL, nunca 0: RouterOS 7.24.2 no devuelve ninguna clave de errores de interfaz, y un 0
ahí afirmaría una medida que nunca se hizo. El texto se fuerza donde PostgreSQL lo
rechazaría — un byte NUL se elimina, el UTF-8 inválido pasa a U+FFFD — y un float NaN o
infinito pasa a NULL. TIMESTAMPTZ resuelve a 1 µs, así que dos muestras más cercanas que
eso chocarían en la clave primaria; a 10 Hz están a 100 ms.
Comparado con InfluxDB, el destino SQL lleva menos fuentes: no hay tablas de frecuencia de
CPU, PMU, softirq, niveles de /proc/vmstat, interrupciones por CPU ni cuentas del log del
kernel; no hay tabla de contadores de /proc/vmstat más allá de pgfault y pgmajfault (que
van en mikroscope_stat, así que faltan los deltas de pgscan_*, pgsteal_*, pgalloc,
pgfree, allocstall, compact_stall, oom_kill, pswpin y pswpout); no hay mikroscope_sample, y mikroscope_mem es más
estrecha. Lleva dos que InfluxDB no tiene: el texto del
log del kernel en mikroscope_event, y los errores de la capa de la API.
Tamaño, según el propio fixture de pruebas del destino el 2026-09-12 — dos núcleos, una cola softnet, una interrupción, sin fuentes privilegiadas — no según el equipo: un evento del kernel se renderiza en 1 375 B de SQL y un evento de la API en 1 138 B, así que 10 Hz más la capa de la API a 1 Hz son unos 14 KiB/s de fichero tras una cabecera de 5,6 KiB. Los mismos dos eventos en protocolo de líneas son 716 B y 608 B, unas 1,9× más pequeños, aunque parte de eso es contenido que las filas SQL llevan y el protocolo de líneas no. Con las fuentes privilegiadas presentes el evento del kernel crece hasta 2 749 B. Esa cabecera es la del fixture: la de las treinta y dos tablas que declara el destino, calculada a partir de las cadenas del esquema y no medida, son 7 757 B, unos 7,6 KiB.
export MIKROSCOPE_LOKI_URL=http://host:3100/loki/api/v1/pushmikroscope forward --loki "$MIKROSCOPE_LOKI_URL" --loki-tenant team-aLoki recibe los eventos de la línea temporal, no sus muestras. Una muestra es una
medida y pertenece a un almacén de métricas; 10 Hz de números en un almacén de logs son
una copia más lenta y más grande. Lo que llega es lo que pasó una vez, en un momento
conocido. Un token bearer sale de MIKROSCOPE_LOKI_TOKEN, y --loki-tenant
(MIKROSCOPE_LOKI_TENANT) fija X-Scope-OrgID para un Loki multi-tenant.
Los streams llevan tres etiquetas y ninguna más — host, source y level — porque Loki
indexa las etiquetas y la cardinalidad es un coste:
source |
level |
Una línea por |
|---|---|---|
kmsg |
el del propio registro: emerg … debug |
registro del log del kernel, marcado en su tick |
gap |
warn |
rango de secuencia perdido, marcado cuando el colector lo notó |
api |
err |
orden de la capa de la API que falló |
detection |
warn |
detección, en la muestra que la provocó |
trigger |
info |
disparo de captura, en el momento del disparo; la captura se queda en el agente |
device |
info |
registro de datos del equipo: board, kernel, cores, privileged, cgroup, sources, hash |
Desliza en horizontal para ver todas las columnas
La línea de un registro del kernel es el mensaje seguido de pares logfmt — level,
facility, prio, kseq, us (los microsegundos del propio kernel desde el arranque),
seq (la muestra) y, cuando el registro nombra un puerto, iface (el nombre del kernel),
ros_iface (el nombre en RouterOS), port_event (lo que pasó: link-up, link-down, un
estado stp-*, own-address u other), label (el comentario del puerto, entre
comillas) y role (sus listas de interfaces). ros_iface es el nombre actual del puerto
en RouterOS cuando el inventario de la capa de la API lo da, y el nombre por defecto de la
placa si no; label y role salen también de ese inventario, así que una ejecución sin
capa de la API no lleva ninguno de los dos. El puerto
va en la línea, no en una etiqueta, porque un stream por puerto multiplica el número de
streams por un campo que LogQL extrae bajo demanda:
{source="kmsg"} | logfmt | ros_iface="ether2"{source="kmsg"} | logfmt | port_event="own-address"Cada registro se marca con el reloj de pared de su tick, nunca con su propia marca desde el arranque, que lo fecharía en 1970 más el uptime y Loki lo rechazaría. Los registros de un mismo tick están separados 1 ns, en orden creciente, porque un stream de Loki se ordena solo por marca de tiempo y en el equipo de referencia una pareja «blocking state» y luego «learning state» llega dentro de un mismo tick de 100 ms con el mismo nivel: su orden es la señal. El desplazamiento es como mucho 63 ns, acotado por el límite del agente de 64 registros por tick.
Un push por segundo, 64 KiB × --queue-seconds de presupuesto. En el RB5009 (RouterOS
7.24.2, kernel 5.6.3, 2026-09-12) el log del kernel iba a 1,49 /s mientras el
reflejo de capa 2 estaba activo y a 0,03 /s después de arreglarlo, y una línea renderizada
mide unos 150 B con su envoltorio JSON, así que un segundo de presupuesto guarda horas de
ese tráfico. No medido durante una tormenta del log del kernel.
mikroscope forward --otlp http://collector:4318/v1/metrics--otlp envía métricas de OpenTelemetry a un receptor OTLP/HTTP en la codificación JSON,
una petición por segundo. Un token bearer sale de MIKROSCOPE_OTLP_TOKEN. JSON en vez de
protobuf es una decisión de dependencias: protobuf añadiría un generador de código y un
runtime, y todo receptor OTLP acepta application/json en el mismo endpoint. El recurso
lleva host.name (la etiqueta de host) y service.name=mikroscope; el scope lleva la
versión del colector.
El mapeo es la razón de que este destino sea barato de consumir. mikroscope envía deltas
en bruto, y OTLP tiene un sitio exacto para ellos: cada contador es un Sum con
AGGREGATION_ e isMonotonic=true. En los contadores de la muestra del
kernel, startTimeUnixNano = el reloj de pared de la muestra menos su intervalo real, y
timeUnixNano = su reloj de pared — así al receptor se le dice el intervalo que cubre cada
delta en vez de que adivine el nominal. Las demás sumas no llevan intervalo:
mikroscope.api.errors, mikroscope. y mikroscope. no
tienen hora de inicio, y mikroscope.trigger.fired y mikroscope.detection tienen una hora
de inicio igual a su hora. Cada nivel es un Gauge. De la capa del kernel no hay nada
dividido de antemano salvo mikroscope.; los gauges mikroscope.derived.* son
la etapa de derivación del colector.
| Tipo | Métrica | Atributos |
|---|---|---|
| Sum | mikroscope.cpu.ticks |
cpu, mode |
| Sum | mikroscope., mikroscope.interrupts, mikroscope.forks, mikroscope.self.cpu.time |
— |
| Sum | mikroscope., mikroscope., mikroscope. (solo con cgroup2) |
— |
| Sum | mikroscope.irq.count; mikroscope.irq.total, mikroscope.irq.errors |
irq, name; — |
| Sum | mikroscope.softnet; mikroscope.sched |
cpu, kind |
| Sum | mikroscope.softirq; mikroscope.vm.events |
kind |
| Sum | mikroscope.psi.stalled |
resource, scope |
| Sum | mikroscope.flash, mikroscope.disk; mikroscope.disk.io_time (ms) |
device, kind; device |
| Sum | mikroscope.api.errors; mikroscope., mikroscope. |
tier; — |
| Sum | mikroscope.trigger.fired; mikroscope.detection |
cause; rule |
| Gauge | mikroscope., mikroscope.cpu.frequency |
cpu |
| Gauge | mikroscope.sample.dt, mikroscope.sample.seq, mikroscope.threads, mikroscope.procs_blocked |
— |
| Gauge | mikroscope.memory (KiB), mikroscope.self.memory, mikroscope.vm.pages |
kind |
| Gauge | mikroscope.load |
window |
| Gauge | mikroscope. |
zone |
| Gauge | mikroscope.slab.objects, mikroscope.slab.limit |
cache |
| Gauge | mikroscope. |
node, zone, order |
| Gauge | mikroscope.mtd.ecc; mikroscope., mikroscope. |
device, partition, kind; device, partition |
| Gauge | mikroscope.flash.blocks; mikroscope. |
device, kind; device |
| Gauge | mikroscope.api.cpu_load, mikroscope.api.uptime; mikroscope.api.memory |
—; kind |
| Gauge | mikroscope.api.core; mikroscope.api.health |
cpu, kind; name |
| Gauge | mikroscope.api.interface |
interface, kind, y label, type, role donde el inventario los tiene |
| Gauge | mikroscope.; mikroscope. |
interface, counter, y label, type, role donde el inventario los tiene; — |
| Gauge | mikroscope., mikroscope., …., …., ….packets_per_irq |
— |
| Gauge | mikroscope. |
interface, direction |
| Gauge | mikroscope.device.cores; mikroscope., mikroscope. (s) |
board, kernel, hash; zone |
| Gauge | mikroscope., mikroscope.; mikroscope. |
cpu; source, reason |
Desliza en horizontal para ver todas las columnas
Los miembros de reclaim y swap de mikroscope.vm.events se omiten cuando valen cero: en
un Sum de deltas, un punto ausente y un punto a cero significan lo mismo. Los contadores
por puerto son gauges de un total acumulado, no Sums, porque el destino no tiene tiempo de
inicio para un contador que RouterOS lleva desde el arranque. Un gauge cuyo valor es NaN o
infinito se descarta. Los registros del log del kernel no se emiten: su sitio son los logs
OTLP en /v1/logs, que este destino no implementa.
Un éxito parcial de OTLP — un 2xx cuyo cuerpo rechaza algunos puntos — cuenta como escrito y se registra, no se reintenta. El rechazo es determinista (un receptor OTLP de Prometheus que rechaza un punto más antiguo que su ventana es el caso habitual), así que el mismo lote se rechazaría igual.
Tamaño, según un fixture de pruebas de dos núcleos el 2026-09-12 y no según el equipo: una muestra del kernel se renderiza en 8 132 B de JSON OTLP frente a 716 B de protocolo de líneas, unas 11×, el precio de repetir las claves de los atributos y de poner entre comillas cada entero de 64 bits. Un segundo de muestras a 10 Hz más una muestra de la API son 68 868 B, así que el presupuesto de 64 KiB por segundo guarda aproximadamente un segundo de atraso por segundo y los 60 s por defecto unos 57 lotes. El RB5009 de cuatro núcleos, con su top-K real de interrupciones, renderiza más; no medido.
Graphite
Sección titulada «Graphite»mikroscope forward --graphite carbon:2003 --graphite-prefix mikroscope--graphite (MIKROSCOPE_GRAPHITE_ADDR) escribe el protocolo de texto plano de carbon —
path value timestamp, una línea por valor — sobre una única conexión TCP persistente.
Graphite no tiene etiquetas, así que cada dimensión es un nodo de ruta bajo
<prefix>.<host>.; --graphite-prefix vale mikroscope por defecto. En un nodo solo
sobreviven letras ASCII, dígitos, _, - y :, cualquier otro byte pasa a _, y un
valor vacío pasa a none, así que la profundidad de una ruta nunca cambia.
| Rutas | De |
|---|---|
sample.{seq,dt_ns}, stat. |
la muestra |
cpu. |
/proc/stat, cpufreq |
softnet., irq.<id>.<name>.count, softirq.<kind>.count |
softnet, interrupts, softirqs |
mem., load. |
meminfo, loadavg |
vm., vmg. |
vmstat |
self. |
el coste propio del agente |
psi.*_us, sched. |
solo donde el kernel los tiene |
thermal.<index>.celsius, slab., buddy. |
thermal, slab, buddyinfo |
mtd.<dev>.<counter>, flash.<dev>.<counter>, disk. |
flash y dispositivos de bloques |
api.system.<field>, api., api.health.<name>, api.conntrack.entries |
la capa de la API |
api., api. |
la capa de la API y la etapa de derivación |
derived. |
la etapa de derivación |
trigger.<cause>, detection.<rule> — el valor 1 en cada evento |
disparos y detecciones |
device., device.thermal.<zone>.*, device.cpufreq.<n>.*, device. |
el flujo de datos del equipo |
collector. |
huecos, con el reloj del colector |
Desliza en horizontal para ver todas las columnas
Lo que el protocolo no puede prometer, dicho porque cada punto cambia lo que significa un panel de Graphite:
- Marcas de tiempo en segundos enteros. La retención más fina de Whisper es un
segundo, así que a 10 Hz nueve de cada diez muestras caen en una casilla que ya tiene
valor y carbon se queda con el último escrito. Es una lectura válida para un nivel
(
mem,load,thermal,freq_khz,slab,vmg) y se queda corta para un delta: una suma sobrecpu.0.userve más o menos una décima parte de los ticks que envió el agente. Sumar los deltas de cada segundo en el destino arreglaría las rutas de deltas y no las de niveles; ese intercambio no se ha hecho. Un consumidor que necesite cada tick tiene el destino de InfluxDB o el de fichero. - Sin respuesta.
writtencuenta lotes entregados al socket, no puntos que carbon guardó. Una escritura en un socket que carbon ya cerró funciona una vez y falla en la siguiente, así que el destino reintenta una vez con una conexión nueva; el lote que entró en el socket cerrado se pierde, uno por cada reinicio de carbon. - Zonas térmicas por índice, no por nombre, porque la cadena de tipo de una zona no es única; el nombre se conserva en los destinos de fichero e InfluxDB.
- Menos detalle: se descartan las cuentas de interrupciones por CPU, los softirqs se
suman sobre las CPU, no se emite
cpu.total(sumSeriessobrecpu.*.userlo da), se omitenpgalloc,pgfreey los contadores de swap, y se descartan los registros del log del kernel porque Graphite solo guarda números. Las cadenas de placa, kernel y governor no tienen forma en Graphite.
El presupuesto de bytes es de 256 KiB por segundo en cola, cuatro veces el de los demás: un tick con forma de RB5009 de cuatro núcleos con todas las fuentes presentes se renderiza en 6 411 B en 131 líneas en el fixture de pruebas del destino (máquina de desarrollo, 2026-09-12, no el equipo), así que 10 Hz son unos 63 KiB/s. No medido por encima de 10 Hz.
Elasticsearch y OpenSearch
Sección titulada «Elasticsearch y OpenSearch»export MIKROSCOPE_ELASTIC_AUTH=elastic:… # o una clave de APImikroscope forward --elastic http://opensearch:9200 --elastic-index 'mikroscope-%Y.%m.%d'--elastic (MIKROSCOPE_ELASTIC_URL) escribe a través de la API bulk que comparten los
dos productos. /_bulk se añade a la raíz de un clúster, conservando cualquier query
string. Un MIKROSCOPE_ELASTIC_AUTH con user:password se envía como autenticación
básica, y cualquier otra cosa como Authorization: ApiKey; las credenciales incrustadas en
la URL se ocultan en el nombre del destino que se imprime.
Un documento por evento, con kind para distinguirlos:
kernel— un tick del agente: ticks por CPU conbusyybusy_ratio,stat,mem,load,vm,self, cada fuente opcional solo cuando se leyó (sin clave, nunca un cero), y los valores de la etapa de derivación bajoderived;event— un registro del log del kernel:priority,level,facility,seq,time_usec,messagey, cuando el registro nombra un puerto,iface,ros_iface,port_event(lo que le pasó al puerto),labelyrole;api— una lectura de la API:system,cores,health,ifaces,iface_counters, el último número de conexiones, las proporciones del fast path bajofastpath, einventoryen las rondas que leen qué es cada interfaz. Cada entrada deifacesllevalabel,type,roleybridge, y cada entrada deiface_countersllevacomment,type,roleybridge, donde el inventario los tiene. Los errores por orden de la capa de la API no se escriben;gap(from,to,lost),device,detectionytrigger.
Cada documento lleva @timestamp con el reloj del agente (el del colector para huecos y
registros del equipo) y host. El nombre del índice expande %Y, %m y %d — solo esos
— contra esa marca de tiempo, así que un lote que queda en cola pasada la medianoche cae en
el día en que se muestreó, y se pasa a minúsculas porque el clúster rechaza la petición
entera si el nombre de índice tiene mayúsculas.
La acción es index con un _id construido a partir del tipo, el host, la marca de tiempo
del documento en nanosegundos y, donde existe, el número de secuencia que distingue
documentos del mismo instante, así que un lote que el clúster aplicó pero cuya respuesta se
perdió se reenvía sin duplicar nada. La marca de tiempo forma parte de la identidad porque
la secuencia del agente vuelve a empezar desde 1 en cada arranque: sin ella, las muestras de un
agente reiniciado sobrescribirían las anteriores del día, cada una con un 201.
Una petición bulk responde 200 aunque se hayan rechazado todos sus elementos. El destino
lee el veredicto de cada elemento, suma uno a dropped por cada documento rechazado, y
registra el primer motivo una vez por minuto — por separado de los fallos de entrega,
porque un conflicto de mapeo y un clúster inalcanzable piden acciones distintas. Los lotes
se cierran una vez por segundo o al llegar a 1 MiB, lo que ocurra primero.
Tamaño, según el fixture de dos núcleos del destino el 2026-09-12 y no según el equipo: 1 077 B de NDJSON para una muestra del kernel sin fuentes opcionales, 1 952 B repartidos en dos documentos con las fuentes opcionales y un registro del log del kernel. Una muestra de cuatro núcleos del RB5009 no se ha renderizado en este formato.
Telegraf
Sección titulada «Telegraf»mikroscope forward --telegraf http://host:8186/telegrafmikroscope forward --telegraf tcp://host:8094--telegraf (MIKROSCOPE_TELEGRAF_URL) envía los mismos registros de protocolo de líneas
que el destino de InfluxDB — llama a ese codificador en vez de copiarlo — para que las
propias salidas de Telegraf los repartan a sistemas para los que este repositorio no tiene
destino. Telegraf deja pasar la marca de tiempo sin cambiarla.
El esquema del endpoint elige el transporte:
http://ohttps://— envía a una entradahttp_listener_v2oinfluxdb_v2_listener. Unhost:portsin más se interpreta como HTTP, y a un endpoint HTTP sin ruta se le da/telegraf, el valor por defecto dehttp_listener_v2: un listener responde 404 en/y el cuerpo no dice por qué. UnMIKROSCOPE_conTELEGRAF_ TOKEN user:passwordse envía como autenticación básica, y cualquier otra cosa comoAuthorization: Token ….tcp://— registros delimitados por saltos de línea a unsocket_listener, con una conexión nueva por lote.udp://— datagramas de como mucho 1 432 bytes, cortados en los límites de registro para que ningún datagrama lleve media línea. No hay confirmación:writtencuenta lotes que aceptó el kernel local, un datagrama perdido por el camino es invisible, y un reintento tras un fallo a mitad de lote puede entregar algunos registros dos veces. Usahttp://otcp://para cualquier cosa que importe.
El presupuesto es el del destino de InfluxDB, 64 KiB por segundo en cola: a unos 1,2 KiB
por muestra a 10 Hz (RB5009, 2026-09-12), unos 5 minutos de atraso con los 60 s por
defecto. El codificador compartido escribe las lecturas de /system/health en el orden de
un map de Go, así que los registros dentro de un lote no tienen un orden estable — 12
renderizados de un map de 8 nombres dieron 7 órdenes (2026-09-12). Cada registro lleva su
propia marca de tiempo, así que no se pierde ni se desfasa nada.