# Ejecutar el colector

Ejecuta mikroscope forward para traer la telemetría de kernel de un router MikroTik, unirla a la capa de la API de RouterOS, derivar valores y escribirla en once destinos.

Source: https://docs.jmrp.io/mikroscope/es/sinks/

_De dónde vienen los datos y a dónde van_ — El router ejecuta el agente en un contenedor que lee el kernel compartido y lo sirve por un veth. El colector de tu máquina tira de ahí, le une la capa de la API de RouterOS, deriva y escribe en cada destino que hayas nombrado.

`mikroscope forward` es el colector. Tira de la capa del kernel del agente en el
router, muestrea la capa de la API de RouterOS, marca las dos con el reloj del
agente, pasa la etapa de derivación sobre ellas y escribe la línea temporal
fusionada en cada destino que indiques.

```sh
mikroscope forward --prom :9124 --influx "$MIKROSCOPE_INFLUX_URL" --influx-db "$MIKROSCOPE_INFLUX_DB" --interfaces bridge,ether1
```

Indica al menos un destino: `--file`, `--prom`, `--influx`, `--loki`, `--otlp`,
`--graphite`, `--elastic`, `--sql`, `--postgres`, `--telegraf` o `--stdout`.
`forward` sin ninguno es un error, porque leería el router y tiraría los datos.
Lo normal es usar varios a la vez.

## Etapas de una ejecución

1. **Pide al agente su estado.** La respuesta trae el reloj de pared del agente, su
   cadencia, su número de secuencia más reciente y su hash de capacidades. La
   diferencia entre el reloj del agente y el del colector es el desfase; la cadencia
   dimensiona el lote de extracción y las referencias móviles de la etapa de derivación.

2. **Entrega a cada destino el flujo de datos del equipo.** Las `/capabilities` del
   agente — placa, kernel, techos, cadencias — salen al arrancar como registro
   propio, de nuevo cuando cambia el hash de capacidades y, si no, cada cinco
   minutos, para que los paneles del equipo tengan una fila dentro de cualquier
   ventana. Consulta [Datos del equipo](https://docs.jmrp.io/mikroscope/es/sinks/device-info/).

3. **Tira del anillo cada `--poll`.** La primera extracción empieza después de la
   muestra más reciente del agente: `forward` no reproduce lo que el anillo tenía
   antes de arrancar, y rechaza `--from-start` como opción desconocida (solo
   `record` recupera el anillo). Cada extracción pide las muestras posteriores al
   último número de secuencia visto. Un marcador de disparo viaja entre las
   muestras en orden de secuencia y se reenvía como anotación, nunca se decodifica
   como muestra.

4. **Deriva y luego reparte.** Cada muestra del kernel pasa por [la etapa de
   derivación](https://docs.jmrp.io/mikroscope/es/sinks/derive/), y la muestra, sus valores derivados y
   cualquier [detección](https://docs.jmrp.io/mikroscope/es/sinks/detections/) que haya provocado van a
   cada destino en el mismo orden.

5. **Muestrea la capa de la API cada `--api-every`** (1 s por defecto) cuando hay
   credenciales de la API configuradas. Consulta [Capa de la API de
   RouterOS](https://docs.jmrp.io/mikroscope/es/sinks/api-tier/).

6. **Vuelve a medir el desfase cada minuto.** Un salto de más de 50 ms — un paso
   del reloj del router, una corrección de NTP — se registra y se cuenta como
   salto de desfase. La misma lectura de estado vuelve a comprobar el hash de
   capacidades.

7. **Con Ctrl-C o al final de `--for`**, extrae una última vez, cierra cada destino con
   un vaciado final e imprime lo que hizo cada uno.

En ese bucle no hay interpolación en ningún sitio: cada consumidor ve la cadencia que
tiene de verdad cada fuente.

## Cadencia de sondeo y lote

| Opción    | Por defecto | Qué ajusta                                                                                                                                                                    |
| --------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--poll`  | `500ms`     | Cada cuánto se tira del anillo.                                                                                                                                               |
| `--batch` | `0`         | Muestras que pide una extracción. `0` es el doble de lo que produce un intervalo de sondeo a la cadencia del agente, nunca menos de 20, para que un agente a 50 Hz no quede limitado a 40 Hz. |

- Una extracción se repite mientras vuelva llena, hasta 100 veces, para que el
  cursor se ponga al día dentro de un sondeo en vez de avanzar un lote por
  sondeo. Una respuesta corta es el borde del anillo.
- El transporte por relay limita una extracción a 13
  líneas. El límite se calcula a partir de los 64 512 B
  que devuelve como mucho `/tool fetch`, de una línea del anillo que se cobra a la
  clase de tamaño del asignador de 3 456 B (los
  medidos 3 230 B, redondeados) y de un 134 % de margen
  para líneas por encima de la media: unos 45 kB. Una respuesta que aun así llega al límite de fetch se
  rechaza con `relay reply hit the 64512-byte fetch limit; lower the batch` en
  vez de analizarse truncada.
- `forward` calcula lo que el lote efectivo permite por cada `--poll` y avisa al
  arrancar cuando queda por debajo de la cadencia del agente. Para el relay
  contra un agente a 100 Hz, 13 muestras por sondeo de 500 ms dan:

```text
warning: at most 13 samples per pull every 500ms is 26/s, below the agent's 100 Hz; the collector will fall behind and report gaps. Raise --batch, lower --poll, or use the direct transport
```

Un colector que se queda más atrás que el anillo del agente (60 s por defecto) recibe
una línea de hueco en vez de las muestras, y cada destino registra el hueco.

## Marcas de tiempo

| Registro                              | Marca de tiempo                                                               |
| ------------------------------------- | ----------------------------------------------------------------------------- |
| Muestra del kernel, valores derivados | el propio reloj de pared del agente, tal como lo lleva la muestra             |
| Detección                             | el reloj de pared de la muestra que la provocó                                |
| Marcador de disparo                   | el reloj de pared del agente en el momento del disparo                        |
| Muestra de la capa de la API          | el reloj del colector más el desfase medido                                   |
| Hueco                                 | el reloj del colector cuando volvió la extracción que lo encontró             |
| Registro de datos del equipo          | el reloj del colector: los datos de la placa no tienen marca de tiempo propia |

## Elegir un destino

`forward` escribe en once destinos. Casi todas las
instalaciones necesitan una de las dos primeras filas; las demás existen para que
mikroscope encaje con lo que ya tienes.

| Si…                                                          | Usa            | Lleva                                             | [Dashboard](https://docs.jmrp.io/mikroscope/es/sinks/#dashboard-en-grafana) |
| -------------------------------------------------------------- | -------------- | -------------------------------------------------- | --------- |
| quieres todo, con los dashboards, y no tienes nada montado    | `--influx`     | todas las medidas, como protocolo de línea          | **sí**, generado |
| ya tienes Prometheus                                          | `--prom`       | todas las familias, recalculadas de las muestras    | **sí**, generado |
| quieres capturar una ventana y mirarla después                | `--file`       | la línea temporal unida como JSONL, sin instalar nada | no      |
| guardas datos a largo plazo en PostgreSQL o TimescaleDB       | `--sql`        | DDL e INSERTs para `psql`, sin driver               | **sí**, generado, sobre una fuente de datos que creas tú |
| quieres escribir directamente en un PostgreSQL en marcha      | `--postgres`   | las sentencias de `--sql`, por una conexión         | **sí**, generado |
| quieres el registro del kernel y las detecciones con tus logs | `--loki`       | **solo eventos**: kmsg, detecciones, huecos, disparos, errores de la API, registros del equipo | no |
| ya tienes una tubería de OpenTelemetry                        | `--otlp`       | métricas como OTLP/HTTP                             | no        |
| ya tienes Graphite o Elasticsearch                            | `--graphite`, `--elastic` | todas las medidas, con la forma de ese producto | **sí**, uno más pequeño |
| ya tienes Telegraf                                            | `--telegraf`   | todas las medidas, como protocolo de línea          | no        |
| quieres canalizarlo hacia algo tuyo                           | `--stdout`     | protocolo de línea o NDJSON por la salida estándar  | no        |

- Nombra varios a la vez: `--file` junto a un almacén te deja una captura a la
  que volver, y `--loki` junto a `--influx` pone el registro del kernel donde
  puede alcanzarlo una consulta de logs mientras los números van al almacén que
  leen los dashboards.
- **Loki recibe eventos, no métricas** —los registros del kernel, las
  detecciones, los huecos, los disparos, los errores de la capa de la API y los
  registros del equipo—, así que una ejecución solo con Loki no tiene ni un
  número de CPU o memoria.
- **`--prom` se consulta, no se envía**: `forward` sirve `/metrics` y
  Prometheus viene a por él, así que el colector tiene que ser alcanzable desde
  la máquina de Prometheus.

## Dashboard en Grafana

Seis destinos alimentan los cinco dashboards: `--influx`, `--prom`, `--postgres` y `--sql` (que
comparten el de PostgreSQL), `--graphite` y `--elastic`. Añade `--grafana <url>` y pon un token de cuenta de servicio de
Grafana, con el rol Admin, en `GRAFANA_TOKEN`: en cada arranque, antes de llegar al router, el
colector crea o corrige una fuente de datos y publica el dashboard de cada uno de ellos en el que
escribe:

```sh
export GRAFANA_TOKEN=…
mikroscope forward --influx http://influx:8181 --influx-db mikroscope --grafana http://grafana:3000
```

- **Tres describen su propia fuente de datos.** `--influx`, `--elastic` y `--postgres` escriben
  en el servidor al que pregunta Grafana, así que la fuente de datos se construye con sus opciones,
  en la dirección que usa el colector. Cuando Grafana llega a ese almacén por otra dirección,
  pásala en `--grafana-datasource-url`.
- **A los otros tres hay que decírselo.** A `--prom` lo consulta Prometheus y `--graphite`
  escribe en el puerto de ingesta de carbon, así que cada uno necesita en
  `--grafana-datasource-url` la dirección a la que pregunta Grafana, o en
  `--grafana-datasource-uid` una fuente de datos que ya tengas. `--sql` nunca se conecta, así que
  solo admite `--grafana-datasource-uid`.
- **Un almacén por ejecución con esas dos opciones.** Cada una nombra una sola fuente de datos,
  así que una ejecución que escribe en dos almacenes con dashboard y fija cualquiera de ellas se
  rechaza antes de escribir nada. Quítalas del colector, que entonces publica los almacenes que se
  describen solos y avisa de los demás, y publica cada uno de los demás una vez con
  `mikroscope dashboards publish`, con la opción de destino de ese almacén y su propio valor.
- **Un fallo no detiene el colector.** Imprime
  `grafana: could not publish, carrying on without it: <motivo>`, una línea por fallo, y sigue
  recogiendo.
- **El Grafana sale de `--grafana` o de `MIKROSCOPE_GRAFANA_URL`**, nunca de `GRAFANA_URL`,
  que pueden fijar otras herramientas de Grafana
  ([Token de Grafana](https://docs.jmrp.io/mikroscope/es/dashboards/import-and-check/#token-de-grafana)).

Los otros cinco destinos no tienen dashboard. `mikroscope dashboards publish`, con las mismas
opciones de destino y `--grafana`, publica una sola vez sin recoger.
[Configurar en Grafana](https://docs.jmrp.io/mikroscope/es/dashboards/import-and-check/) tiene lo que crea, los otros
caminos y la comprobación.

## Destinos

| Opción                          | Destino                                             | URL o credencial desde el entorno                                        | Forma      | Página                                                                  |
| ------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------ | ---------- | ----------------------------------------------------------------------- |
| `--file path.jsonl`             | fichero JSONL                                       | —                                                                        | síncrono   | [el fichero](https://docs.jmrp.io/mikroscope/es/sinks/other/#el-fichero)                    |
| `--prom :9124`                  | `/metrics` de Prometheus en la máquina del colector | —                                                                        | en memoria | [Prometheus](https://docs.jmrp.io/mikroscope/es/sinks/prometheus/)                          |
| `--influx URL`, `--influx-db DB` | protocolo de líneas de InfluxDB 3                  | `MIKROSCOPE_INFLUX_URL`, `MIKROSCOPE_INFLUX_DB`, `MIKROSCOPE_INFLUX_TOKEN` | en cola    | [InfluxDB 3](https://docs.jmrp.io/mikroscope/es/sinks/influxdb/)                            |
| `--sql path` o `--sql -`        | sentencias PostgreSQL / TimescaleDB, para `psql`    | —                                                                        | síncrono   | [SQL](https://docs.jmrp.io/mikroscope/es/sinks/other/#sql-para-postgresql-y-timescaledb)    |
| `--postgres DSN`                | las mismas sentencias, a un PostgreSQL en marcha    | `MIKROSCOPE_POSTGRES_DSN`                                                | en cola    | [`--postgres`](https://docs.jmrp.io/mikroscope/es/sinks/other/#--postgres-las-mismas-sentencias-por-una-conexión) |
| `--stdout lp` o `--stdout json` | salida estándar                                     | —                                                                        | en cola    | [stdout](https://docs.jmrp.io/mikroscope/es/sinks/other/#salida-estándar)                   |
| `--loki URL`                    | API push de Loki: eventos, no métricas              | `MIKROSCOPE_LOKI_URL`, `MIKROSCOPE_LOKI_TOKEN`, `MIKROSCOPE_LOKI_TENANT` | en cola    | [Loki](https://docs.jmrp.io/mikroscope/es/sinks/other/#loki)                                |
| `--otlp URL`                    | métricas OTLP/HTTP, codificación JSON               | `MIKROSCOPE_OTLP_URL`, `MIKROSCOPE_OTLP_TOKEN`                           | en cola    | [OTLP](https://docs.jmrp.io/mikroscope/es/sinks/other/#otlp)                                |
| `--graphite host:port`          | texto plano de carbon sobre TCP                     | `MIKROSCOPE_GRAPHITE_ADDR`                                               | en cola    | [Graphite](https://docs.jmrp.io/mikroscope/es/sinks/other/#graphite)                        |
| `--elastic URL`                 | `_bulk` de Elasticsearch u OpenSearch               | `MIKROSCOPE_ELASTIC_URL`, `MIKROSCOPE_ELASTIC_AUTH`                      | en cola    | [Elasticsearch](https://docs.jmrp.io/mikroscope/es/sinks/other/#elasticsearch-y-opensearch) |
| `--telegraf URL`                | un listener de Telegraf por HTTP, TCP o UDP         | `MIKROSCOPE_TELEGRAF_URL`, `MIKROSCOPE_TELEGRAF_TOKEN`                   | en cola    | [Telegraf](https://docs.jmrp.io/mikroscope/es/sinks/other/#telegraf)                        |

- Las credenciales de los destinos nunca vienen de una opción: una opción se ve
  en `ps` y en el historial del shell. Cada token de un destino se lee solo de su
  variable `MIKROSCOPE_*`. El token bearer del propio agente es la excepción:
  `forward` lo toma como `--token`, con `MIKROSCOPE_TOKEN` por defecto.
- `--host-tag` (`MIKROSCOPE_HOST_TAG`, `router` por defecto) pone la misma
  etiqueta de host en cada punto de cada destino.
- Un destino que se pidió y no se puede construir — un puerto ya ocupado, un
  fichero que no se puede abrir — hace fallar la ejecución en vez de quedar
  ausente en silencio.

Las ejecuciones que ha hecho el colector contra un router y los destinos que ha
alimentado están en la [página de pruebas](https://docs.jmrp.io/mikroscope/es/about/status/#campaign-rates-2026-09-15),
y los almacenes contra los que se prueba cada destino, en las baterías de [pruebas](https://docs.jmrp.io/mikroscope/es/about/status/#las-baterías-de-pruebas).

## Colas y descartes

El bucle de extracción nunca espera a un destino. Cada destino que habla con un
remoto renderiza en memoria y entrega los bytes a una cola acotada que vacía una
goroutine propia una vez por segundo:

- La cola guarda `--queue-seconds` (60 por defecto) segundos de un presupuesto de bytes:
  64 KiB por segundo para InfluxDB, PostgreSQL (`--postgres`), Loki, OTLP,
  Elasticsearch, Telegraf y stdout, y 256 KiB por segundo para Graphite, cuyo formato
  de una línea por valor ocupa más.
- Pasado el presupuesto se expulsa el lote **más antiguo** y se cuenta; el más nuevo se
  conserva siempre, porque la telemetría fresca vale más que la rancia.
- Una entrega fallida espera 2 s, doblando hasta 60 s, y registra como mucho una línea
  por minuto. Todo lo demás está en los contadores.
- Cada POST HTTP lleva un tiempo de espera de 10 s, y una conexión reutilizada muerta es
  un error que se reintenta y se cuenta, no un reenvío silencioso. `--postgres` envía
  cada lote como una sola transacción con un tiempo de espera de 30 s.

Tres destinos no van en cola. Los destinos de fichero y SQL escriben de forma síncrona a
través de un búfer de 64 KiB, porque un fichero local no se atasca como un remoto; un
error de escritura cuenta un error y un descarte. El destino de Prometheus actualiza un
estado en memoria bajo un cerrojo y lo sirve en cada scrape.

> **Una tubería hacia psql puede bloquear el colector**
>
> El destino SQL no tiene cola, así que con `--sql -` alimentando `| psql`, un `psql` que se retrasa
> llena la tubería y la siguiente escritura bloquea el bucle de extracción en vez de descartar. Cada
> `INSERT` es su propia transacción, que es la forma realista de que `psql` se quede atrás frente a
> un agente a 10 Hz ([sin medir](https://docs.jmrp.io/mikroscope/es/about/status/#not-tested)). Escribe a un fichero y
> aplícalo después.

### Contadores de entrega

`forward` imprime `written`, `dropped` y `errors` por destino, y la unidad depende de la
forma:

- **Los destinos en cola cuentan lotes.** `written` es un lote que el destino aceptó,
  `dropped` un lote expulsado por el presupuesto de bytes, `errors` un intento fallido —
  un lote que falla tres veces y luego llega son 3 errores y 1 escrito. Elasticsearch
  suma un `dropped` por cada documento que el clúster rechazó dentro de una respuesta 200.
- **Fichero, SQL y Prometheus cuentan eventos**: uno por muestra, disparo, lectura de la
  API, hueco, detección o registro del equipo aceptado.

## Salida en consola

Al arrancar, por la salida de error: con `--grafana`, primero las líneas `grafana:` de la
publicación ([Dashboard en Grafana](https://docs.jmrp.io/mikroscope/es/sinks/#dashboard-en-grafana)); después una línea `sink: <name>` por
destino, la configuración de la capa de la API, y la versión, cadencia, número de secuencia,
desfase, transporte y lote efectivo del agente. Cada minuto, por la salida de error, un
informe en curso:

```text
forwarded <n> kernel, <n> api, <n> gap(s), <n> trigger(s), <n> detection(s), <n> agent restart(s), last seq <n>; <sink>: <n> written, <n> dropped, <n> errors
```

Al salir, por la **salida estándar**, los totales y una línea por destino:

```text
forwarded <n> kernel samples, <n> api samples, <n> gap(s), <n> skew jump(s)
  <sink>: <n> written, <n> dropped, <n> errors
```

> **Dos cosas que saber antes de canalizarla**
>
> El resumen de salida va al mismo flujo en el que escribe el destino `--stdout`, así que
> `forward --stdout=lp | telegraf` termina cada ejecución con líneas que el consumidor no puede
> interpretar. Y un `--token` erróneo se registra en cada extracción como `401 Unauthorized`,
> mientras la ejecución termina igualmente en su plazo `--for` con código de salida 0 y
> `forwarded 0 kernel samples`.

## Nombres de etiquetas

Un procesador es `cpu` en todas partes — etiqueta de InfluxDB, columna SQL, etiqueta de
Prometheus, atributo OTLP — nunca `core`. El cable lleva la unidad del propio kernel y la
nombra en el campo (`_khz`, `_kb`, `_ticks`, `_pages`, `_sectors`); cada destino convierte
una sola vez, a la convención de ese almacén, y convierte un valor y su techo de la misma
manera. Por eso la temperatura es `celsius` junto a `critical_celsius`, y el tiempo
ocupado de un dispositivo de bloques es `io_s`.

## Véase también

- [Prometheus](https://docs.jmrp.io/mikroscope/es/sinks/prometheus/): el `/metrics` del colector y el trabajo de
  scrape que espera el panel.
- [InfluxDB 3](https://docs.jmrp.io/mikroscope/es/sinks/influxdb/): la URL de escritura, las medidas y lo que rechaza
  InfluxDB 3 Core.
- [Configurar en Grafana](https://docs.jmrp.io/mikroscope/es/dashboards/import-and-check/): el dashboard de cada
  almacén, desde el colector o importado.
- [Capa de la API de RouterOS](https://docs.jmrp.io/mikroscope/es/sinks/api-tier/): lo que el colector sigue
  preguntando al router, y cómo preguntar menos.
- [Acceso por red](https://docs.jmrp.io/mikroscope/es/install/reaching-the-agent/): los transportes directo y por relay
  sobre los que va la extracción.
