Metadata-Version: 2.4
Name: viclix-agent
Version: 0.3.5
Summary: Registro de tráfico (IPs, usuarios, sesiones, endpoints) para apps FastAPI, con visor incluido, listo para Viclix
License: MIT
Keywords: fastapi,asgi,middleware,logging,observability,viclix
Classifier: Framework :: FastAPI
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Logging
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100; extra == "fastapi"
Provides-Extra: dev
Requires-Dist: fastapi>=0.100; extra == "dev"
Requires-Dist: httpx>=0.24; extra == "dev"
Requires-Dist: pytest>=7; extra == "dev"

# viclix-agent

Registro de tráfico para apps **FastAPI**, listo para visualizar en **Viclix**.

Instala un middleware ASGI que registra **cada request** (IP, usuario, endpoint,
hora, duración, status…) en un archivo **JSONL dedicado**. La escritura ocurre en
un **hilo de fondo** con el archivo siempre abierto, así que el camino del request
nunca hace I/O de disco. Después, esos logs alimentan la visualización animada
de Viclix: quién entró, desde qué IP, a qué páginas y en qué orden.

## Instalación

```bash
pip install viclix-agent
```

## Uso mínimo

```python
from fastapi import FastAPI
from viclix_agent import MiddlewareLogger

app = FastAPI()
app.add_middleware(MiddlewareLogger)
```

Eso ya crea la carpeta `.viclix-agent/middleware/` y escribe ahí
`traffic-YYYY-MM-DD.jsonl`.

## Configuración

```python
app.add_middleware(
    MiddlewareLogger,
    log_path=".viclix-agent/middleware/traffic.jsonl",  # ruta base (se le añade la fecha)
    trust_proxy=True,                       # IP real desde X-Forwarded-For (PythonAnywhere)
    rotation="daily",                       # "daily" o None
    include_query=False,                    # incluir query string (ojo con datos sensibles)
    ignore_paths=["/static", "/health"],    # prefijos que no se registran
)
```

| Parámetro       | Default                  | Descripción                                             |
|-----------------|--------------------------|---------------------------------------------------------|
| `log_path`      | `.viclix-agent/middleware/traffic.jsonl` | Ruta base del log.                     |
| `trust_proxy`   | `True`                   | Lee la IP de `X-Forwarded-For` / `X-Real-IP`.          |
| `user_resolver` | lee `request.state.user` | `Callable[[scope], id]` para extraer el usuario.       |
| `rotation`      | `"daily"`                | Rotación diaria del archivo, o `None`.                 |
| `include_query` | `False`                  | Incluye el query string en el evento.                  |
| `ignore_paths`  | `[]`                     | Prefijos de path a ignorar.                            |
| `track_sessions`| `True`                   | Cookie de sesión anónima (`viclix_sid`) por visitante. |
| `session_cookie`| `"viclix_sid"`           | Nombre de la cookie de sesión.                         |
| `session_ttl_days` | `365`                 | Duración de la cookie de sesión.                       |

### Sesiones (trazar el flujo de un visitante)

Con `track_sessions=True` (por defecto), cada visitante recibe una cookie
anónima `viclix_sid` y cada evento lleva un campo `session`. Así puedes seguir la
secuencia completa de páginas de un mismo visitante **aunque no haya login** —
por ejemplo, para ver qué flujo llevó a un usuario a un error 4xx/5xx:

```
GET /            -> 200   sess=44ef64b0
GET /checkout    -> 200   sess=44ef64b0
GET /boom        -> 500   sess=44ef64b0   ← el flujo que terminó en error
```

### Identificar al usuario

Por defecto se lee `request.state.user` (lo que deje tu capa de auth). Si guardas
un objeto, se prueban `username`, `email`, `id`, `pk`. Para lógica propia:

```python
def resolver(scope):
    state = scope.get("state") or {}
    user = state.get("user")
    return getattr(user, "email", None)

app.add_middleware(MiddlewareLogger, user_resolver=resolver)
```

## Visor (CLI)

El paquete instala el comando `viclix-agent`. Al ejecutarlo en tu terminal:

```bash
viclix-agent
```

1. Lee los logs de `.viclix-agent/middleware/` (todos los días agregados). Si no
   existe esa carpeta, busca recursivamente (hasta 3 niveles) como respaldo.
2. Levanta un servidor local y abre el navegador con una visualización interactiva.
3. Muestra estadísticas, línea de tiempo por sesión/IP (con **animación** del
   tráfico), endpoints e IPs más activas, y una tabla filtrable por IP, path,
   usuario o clase de status.

### Mundo vivo (experimental)

En `/experimental` (enlace en el dashboard) hay una representación isométrica
donde **cada IP es una personita** que sale de la "entrada" y camina hacia el
endpoint que solicitó. Los endpoints se agrupan por clase (primer segmento del
path) en **distritos** — `/products`, `/products/42` → distrito *products* — y el
mapa **empieza en 0 y crece** a medida que se descubren IPs y endpoints. El color
del pulso indica la clase de status del último request (verde/amarillo/naranja/rojo).
Controles: reproducir, velocidad, scrub temporal, arrastrar para mover, rueda para
zoom, *Fit* para reencuadrar. El motor de personajes es el de POKER (`sprites.js`).

Esta vista es autocontenida y pública: es la base de lo que luego se mostrará en
Viclix.

Opciones:

```bash
viclix-agent [LOG]           # ruta a un .jsonl específico (opcional)
  --dir .                    # directorio raíz de búsqueda
  --depth 3                  # profundidad máxima de búsqueda
  --port 8787                # puerto del servidor local
  --all-days                 # agregar todos los archivos diarios de la misma base
  --no-browser               # no abrir el navegador automáticamente
```

## Formato del log (JSONL)

Una línea JSON por request:

```json
{"v":1,"ts":"2026-07-24T16:50:55.349029+00:00","ip":"1.2.3.4","method":"GET","path":"/dashboard","status":200,"duration_ms":3.06,"user":"jp@sizth.com","ua":"Mozilla/5.0","referer":null}
```

| Campo         | Descripción                                    |
|---------------|------------------------------------------------|
| `v`           | Versión del esquema.                           |
| `ts`          | Timestamp ISO-8601 en UTC.                     |
| `ip`          | IP del cliente.                                |
| `method`      | Método HTTP.                                   |
| `path`        | Ruta solicitada.                               |
| `status`      | Código de respuesta.                           |
| `duration_ms` | Duración del request en ms.                    |
| `user`        | Identificador de usuario (o `null`).           |
| `session`     | ID de sesión anónima (cookie `viclix_sid`).    |
| `ua`          | User-Agent.                                    |
| `referer`     | Referer.                                       |
| `query`       | Query string (solo si `include_query=True`).   |

## Notas de rendimiento

- Los eventos se encolan en memoria y los escribe un hilo daemon; el request no
  espera al disco.
- Si la cola se satura (`queue_maxsize`, 10k por defecto), los eventos nuevos se
  **descartan** en vez de bloquear la app. El writer lleva contadores `written`
  y `dropped`.
- El archivo se hace flush cada segundo y se cierra limpiamente al terminar el
  proceso (`atexit`).
