# Monitoramento em Tempo Real

O STA Connector fornece capacidades de monitoramento em tempo real atraves da API Admin e do Portal Admin React.

> **Nota:** A implementacao Go usa polling da API REST em vez de WebSockets. Para atualizacoes ao vivo, o Portal Admin usa polling periodico dos endpoints da API Admin.

## Dashboard do Portal Admin

O Portal Admin React fornece monitoramento em tempo real atraves de polling automatico da API Admin.

### Funcionalidades

- **Status de Saude** - Indicador de saude do sistema ao vivo
- **Dashboard de Metricas** - Metricas de processamento de arquivos em tempo real
- **Monitoramento de Arquivos** - Atualizacoes de status de arquivos ao vivo
- **Visualizador de Logs** - Entradas de log recentes

### Configuracao

O intervalo de polling do Portal Admin pode ser configurado:

```typescript
// Padrao: 5 segundos para metricas, 10 segundos para arquivos
const METRICS_POLL_INTERVAL = 5000;
const FILES_POLL_INTERVAL = 10000;
```

## Polling da API REST

Para integracoes customizadas, faca polling nos endpoints da API Admin:

### Polling de Metricas

```javascript
async function pollMetrics(interval = 5000) {
  const auth = btoa('admin:senha');

  while (true) {
    try {
      const response = await fetch('http://localhost:8081/admin/metrics', {
        headers: { 'Authorization': `Basic ${auth}` }
      });

      const metrics = await response.json();
      updateDashboard(metrics);
    } catch (error) {
      console.error('Falha no poll de metricas:', error);
    }

    await new Promise(resolve => setTimeout(resolve, interval));
  }
}
```

### Polling de Status de Arquivo

```javascript
async function pollFileStatus(fileId, onUpdate) {
  const auth = btoa('admin:senha');

  while (true) {
    const response = await fetch(
      `http://localhost:8081/admin/files?id=${fileId}`,
      { headers: { 'Authorization': `Basic ${auth}` } }
    );

    const data = await response.json();
    const file = data.files[0];

    onUpdate(file);

    // Para o polling quando o arquivo atinge status terminal
    if (['completed', 'failed'].includes(file.status)) {
      break;
    }

    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}
```

### Polling de Health Check

```javascript
async function monitorHealth(interval = 30000) {
  const auth = btoa('admin:senha');

  while (true) {
    try {
      const response = await fetch('http://localhost:8081/admin/health', {
        headers: { 'Authorization': `Basic ${auth}` }
      });

      const health = await response.json();

      if (health.status !== 'healthy') {
        sendAlert(`Sistema nao saudavel: ${JSON.stringify(health.checks)}`);
      }
    } catch (error) {
      sendAlert(`Falha no health check: ${error.message}`);
    }

    await new Promise(resolve => setTimeout(resolve, interval));
  }
}
```

## Integracao Orientada a Eventos

Para arquiteturas orientadas a eventos, considere estes padroes:

### Callbacks de Webhook

Configure callbacks de webhook ao enviar arquivos:

```bash
curl -X POST http://localhost:8080/api/v1/files \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "system": "CCS",
    "file_type": "ARQC001",
    "data": {
      "content": "conteudo-base64"
    },
    "destination": {
      "ispb": "00000000"
    },
    "callback": {
      "url": "https://sua-aplicacao.com/webhooks/sta",
      "headers": {
        "Authorization": "Bearer seu-token"
      }
    }
  }'
```

### Fila de Mensagens Externa

Integre com filas de mensagens para processamento assincrono:

```go
// Exemplo: Publicando eventos de arquivo no RabbitMQ
func publishFileEvent(event FileEvent) error {
    body, _ := json.Marshal(event)
    return channel.Publish(
        "sta-events",     // exchange
        event.Status,     // routing key
        false,            // mandatory
        false,            // immediate
        amqp.Publishing{
            ContentType: "application/json",
            Body:        body,
        },
    )
}
```

## Cliente de Monitoramento Python

```python
import requests
import time
from requests.auth import HTTPBasicAuth
from typing import Callable, Optional

class STAMonitor:
    def __init__(self, admin_url: str, username: str, password: str):
        self.admin_url = admin_url.rstrip('/')
        self.auth = HTTPBasicAuth(username, password)

    def get_metrics(self) -> dict:
        """Obter metricas atuais."""
        response = requests.get(
            f'{self.admin_url}/admin/metrics',
            auth=self.auth
        )
        response.raise_for_status()
        return response.json()

    def get_health(self) -> dict:
        """Obter status de saude."""
        response = requests.get(
            f'{self.admin_url}/admin/health',
            auth=self.auth
        )
        response.raise_for_status()
        return response.json()

    def list_files(
        self,
        status: Optional[str] = None,
        system: Optional[str] = None,
        limit: int = 100
    ) -> dict:
        """Listar arquivos com filtros opcionais."""
        params = {'limit': limit}
        if status:
            params['status'] = status
        if system:
            params['system'] = system

        response = requests.get(
            f'{self.admin_url}/admin/files',
            auth=self.auth,
            params=params
        )
        response.raise_for_status()
        return response.json()

    def watch_metrics(
        self,
        callback: Callable[[dict], None],
        interval: int = 5
    ):
        """Fazer polling continuo de metricas."""
        while True:
            try:
                metrics = self.get_metrics()
                callback(metrics)
            except Exception as e:
                print(f'Erro no poll de metricas: {e}')

            time.sleep(interval)

    def watch_file(
        self,
        file_id: str,
        callback: Callable[[dict], None],
        interval: int = 2
    ) -> dict:
        """Monitorar um arquivo ate atingir status terminal."""
        while True:
            files = self.list_files()
            file = next(
                (f for f in files['files'] if f['id'] == file_id),
                None
            )

            if file:
                callback(file)
                if file['status'] in ('completed', 'failed'):
                    return file

            time.sleep(interval)


# Exemplo de uso
if __name__ == '__main__':
    monitor = STAMonitor(
        admin_url='http://localhost:8081',
        username='admin',
        password='senha'
    )

    def on_metrics(metrics):
        print(f"Processados: {metrics['inbound']['files_processed']}")
        print(f"Pendentes: {metrics['inbound']['files_pending']}")

    def on_file_update(file):
        print(f"Arquivo {file['id']}: {file['status']}")

    # Monitorar metricas
    # monitor.watch_metrics(on_metrics, interval=5)

    # Monitorar arquivo especifico
    # final = monitor.watch_file('file-id', on_file_update)
```

## Cliente de Monitoramento Node.js

```javascript
const axios = require('axios');

class STAMonitor {
  constructor(adminUrl, username, password) {
    this.client = axios.create({
      baseURL: adminUrl,
      auth: { username, password }
    });
  }

  async getMetrics() {
    const response = await this.client.get('/admin/metrics');
    return response.data;
  }

  async getHealth() {
    const response = await this.client.get('/admin/health');
    return response.data;
  }

  async listFiles({ status, system, limit = 100 } = {}) {
    const response = await this.client.get('/admin/files', {
      params: { status, system, limit }
    });
    return response.data;
  }

  async watchMetrics(callback, interval = 5000) {
    const poll = async () => {
      try {
        const metrics = await this.getMetrics();
        callback(null, metrics);
      } catch (error) {
        callback(error, null);
      }
    };

    await poll();
    return setInterval(poll, interval);
  }

  async watchFile(fileId, callback, interval = 2000) {
    return new Promise((resolve, reject) => {
      const poll = async () => {
        try {
          const data = await this.listFiles();
          const file = data.files.find(f => f.id === fileId);

          if (file) {
            callback(null, file);

            if (['completed', 'failed'].includes(file.status)) {
              clearInterval(timer);
              resolve(file);
            }
          }
        } catch (error) {
          callback(error, null);
        }
      };

      poll();
      const timer = setInterval(poll, interval);
    });
  }
}

// Exemplo de uso
async function main() {
  const monitor = new STAMonitor(
    'http://localhost:8081',
    'admin',
    'senha'
  );

  // Obter metricas atuais
  const metrics = await monitor.getMetrics();
  console.log('Processados:', metrics.inbound.files_processed);

  // Monitorar metricas
  const metricsTimer = await monitor.watchMetrics((err, metrics) => {
    if (err) {
      console.error('Erro de metricas:', err);
      return;
    }
    console.log('Arquivos pendentes:', metrics.inbound.files_pending);
  });

  // Parar de monitorar apos 1 minuto
  setTimeout(() => clearInterval(metricsTimer), 60000);
}

main().catch(console.error);
```

## Alertas

Configure alertas baseados em limites de metricas:

```python
def check_alerts(metrics: dict) -> list:
    alerts = []

    # Alta contagem de arquivos pendentes
    if metrics['inbound']['files_pending'] > 100:
        alerts.append({
            'severity': 'warning',
            'metric': 'inbound.files_pending',
            'value': metrics['inbound']['files_pending'],
            'threshold': 100,
            'message': 'Alta contagem de arquivos pendentes'
        })

    # Alta taxa de falhas
    total = metrics['inbound']['files_processed']
    failed = metrics['inbound']['files_failed']
    if total > 0 and (failed / total) > 0.05:
        alerts.append({
            'severity': 'critical',
            'metric': 'inbound.failure_rate',
            'value': failed / total,
            'threshold': 0.05,
            'message': 'Alta taxa de falhas (>5%)'
        })

    # Limite de taxa STA baixo
    if metrics['sta_client']['rate_limit_remaining'] < 10:
        alerts.append({
            'severity': 'warning',
            'metric': 'sta_client.rate_limit_remaining',
            'value': metrics['sta_client']['rate_limit_remaining'],
            'threshold': 10,
            'message': 'Limite de taxa STA quase esgotado'
        })

    return alerts
```

## Proximos Passos

- [API Admin](/pt/api/admin) - Referencia completa da API
- [Guia de Tempo Real](/pt/guide/realtime) - Padroes de integracao
- [Solucao de Problemas](/pt/troubleshooting) - Problemas comuns
