Skip to main content

botapp

PyPI Python Django License: MIT

botapp é um SDK + dashboard Django para observabilidade de automações RPA. Ele instrumenta seus bots com um único decorator, registra cada execução (sucesso, falha, duração, ambiente), expõe um painel web para acompanhamento e dispara alertas (Slack, Discord, e-mail) quando algo foge do esperado.


Sumário


Visão geral

Quando você mantém uma frota de bots RPA, a dor de cabeça não é escrever o bot — é saber quando ele parou de rodar, quando passou a falhar demais ou quando está mais lento do que deveria. O botapp resolve isso com três camadas acopladas:

  1. SDK (from botapp import BotApp) — um decorator @app.task que envolve suas funções e grava cada execução no banco automaticamente.
  2. Dashboard web — painel administrativo Django com listagens, detalhes de logs, exploração filtrada, exportação CSV/PDF e gestão de alertas.
  3. Motor de alertas — um scheduler que varre periodicamente o banco em busca de anomalias (silent_bot, error_spike, heartbeat_lost, duration_regression) e dispara notificações em Slack, Discord e e-mail.

Todos os três podem ser usados em conjunto ou separadamente.


Funcionalidades

Observabilidade

  • Decorator único para instrumentar tarefas (@app.task), com captura automática de:
    • host_name, host_ip, user_login, pid, bot_dir
    • os_platform, python_version, env (dev/staging/prod)
    • start_time, end_time, duration, status, exception_type, error_message, trigger_source.
  • Denormalização Bot.last_execution_at / Bot.last_status via post_save signal para listagens rápidas.
  • Função reconcile_bot_last_execution() para self-heal quando SDKs antigos escrevem logs sem disparar signals.

Dashboard

  • Lista de bots com status, última execução, contadores, filtros por departamento/status.
  • Detalhe do bot com histórico paginado de execuções, gráficos de taxa de erro e duração.
  • Página Dashboard global com contadores agregados (bots ativos, silenciosos, alertas críticos).
  • Explore — filtros combinados em TaskLog com exportação CSV.
  • Manutenção — ações de limpeza de órfãos e configuração em massa de thresholds por bot.
  • Tema responsivo, CSP opcional, rate limiting em rotas sensíveis.

Alertas

  • 4 regras de detecção prontas, todas com severidade graduada (low, medium, high, critical):
    • silent_bot — bot ativo sem execução há mais de N horas/minutos.
    • error_spike — pico de falhas em janela recente.
    • heartbeat_lost — log com status='started' que nunca fechou.
    • duration_regression — duração média recente acima do SLA da task.
  • Idempotência: não cria alerta duplicado se já existir um ativo do mesmo tipo para o mesmo bot.
  • Dispatcher multi-canal com fallback tolerante (Slack, Discord, e-mail).
  • Ações de acknowledge e resolve via UI ou REST.
  • Override de threshold por bot (silence_threshold_hours, silence_threshold_minutes).

API REST

  • DRF com ViewSets para Bot, Task, TaskLog.
  • Autenticação SessionAuthentication + BasicAuthentication.
  • Permissão padrão: IsAuthenticated.
  • Rate limiting em endpoints sensíveis via django-ratelimit.
  • Ingest de alertas externos (POST /api/alerts/ingest/): recebe alertas de um monitor de fora (ex.: webhook do Grafana/Alertmanager) e cria/resolve Alerts no painel. Máquina-a-máquina (Token/Basic, isento do rate-limit de login); um alerta ou um lote em {"alerts": [...]}; dedup idempotente por fingerprint; status firing/resolved. Ver a seção Sistema de alertas.

Operacional

  • Comandos de gerência para setup, scheduler, limpeza de órfãos e reconciliação.
  • Thread in-process opcional para dev (BOTAPP_ALERT_SCHEDULER_ENABLED).
  • Comando dedicado para produção multi-worker: botapp run_alert_scheduler.

Arquitetura — modos de uso

O botapp pode ser consumido de duas formas, detectadas automaticamente em botapp/__init__.py:

Modo standalone

Quando DJANGO_SETTINGS_MODULE não está definido, o pacote usa seu próprio botapp.settings. É assim que o dashboard é servido como serviço autônomo.

from botapp import BotApp  # resolve para botapp.core.BotApp
app = BotApp('meu_banco')
  • Grava direto no Postgres usando os modelos Django.
  • Ideal para bots que rodam no mesmo host/rede do banco.

Modo plugin (REST client)

Quando o SDK é importado dentro de outro projeto Django (DJANGO_SETTINGS_MODULE definido e ROOT_URLCONF diferente de botapp.urls), BotApp é substituído por BotAppRestful, que fala com um dashboard remoto via HTTP.

# Em outro projeto Django, com BOTAPP_API_URL apontando para o dashboard remoto
from botapp import BotApp  # resolve para botapp.core_restful.BotAppRestful
app = BotApp()
  • Não exige acesso direto ao banco.
  • Perfeito para bots embarcados em aplicações maiores ou em redes segregadas.
  • Requer BOTAPP_API_URL, BOTAPP_API_USUARIO, BOTAPP_API_SENHA.

Instalação

Requisitos: Python 3.8+, Django 3.2+, Postgres 12+ (SQLite funciona para testes).

pip install botapp

Dependências instaladas automaticamente: Django, psycopg2-binary, djangorestframework, django-admin-rangefilter, django-ratelimit, whitenoise, python-dotenv, openpyxl, xhtml2pdf, requests.


Início rápido

1. Configure o ambiente

Crie um .env na raiz do projeto:

BOTAPP_DEBUG=True
BOTAPP_SECRET_KEY=troque-em-producao
BOTAPP_ALLOWED_HOSTS=*

# Postgres
PG_BOTAPP_SCHEMA=botapp_schema
PG_BOTAPP_DBNAME=botapp
PG_BOTAPP_USER=botapp
PG_BOTAPP_PASSWORD=senha
PG_BOTAPP_HOST=localhost
PG_BOTAPP_PORT=5432

# Superusuário inicial (criado pelo comando setup)
BOTAPP_SUPERUSER_USERNAME=admin
BOTAPP_SUPERUSER_EMAIL=admin@example.com
BOTAPP_SUPERUSER_PASSWORD=troque-em-producao

2. Inicialize o banco

botapp setup      # cria schema + roda migrations + cria superusuário

3. Suba o dashboard

botapp runserver 0.0.0.0:8000

Acesse http://localhost:8000/.

4. Instrumente um bot

from botapp import BotApp

app = BotApp('botapp')  # mesmo PG_BOTAPP_DBNAME
app.set_bot(
    bot_name='relatorio_diario',
    bot_description='Consolida vendas do dia',
    bot_version='1.0.0',
    bot_department='Financeiro',
)

@app.task
def gerar_relatorio():
    """Gera e envia o relatório diário."""
    # seu código aqui
    return 'ok'

gerar_relatorio()  # será registrada como TaskLog automaticamente

Modelo de dados

Bot
 ├── name, description, version, department
 ├── is_active
 ├── last_execution_at (denorm)      ← atualizado pelo signal em TaskLog
 ├── last_status (denorm)
 ├── silence_threshold_hours/minutes ← override por bot do limiar de silent_bot
 └── tasks (1:N)

Task
 ├── bot (FK)
 ├── name (__name__ da função decorada)
 ├── description (docstring)
 ├── expected_duration_seconds      ← SLA usado pelo detector de regressão
 └── logs (1:N)

TaskLog
 ├── task (FK)
 ├── status                         ← started | completed | failed
 ├── start_time / end_time / duration
 ├── result_data (JSON)             ← retorno da função serializado
 ├── error_message / exception_type ← traceback do erro, se houver
 ├── host_ip, host_name, pid, user_login, os_platform, python_version
 ├── bot_dir, env, trigger_source, manual_trigger
 └── indexes: -start_time, task+-start_time, status+-start_time, env+-start_time

Alert
 ├── type        ← silent_bot | error_spike | heartbeat_lost | duration_regression
 ├── severity    ← low | medium | high | critical
 ├── bot (FK, nullable)             ← null = alerta global
 ├── message, payload (JSON)
 ├── created_at / updated_at
 ├── acked_at, acked_by (FK User)   ← reconhecimento manual
 ├── resolved_at, resolved_by       ← resolução manual
 └── notified_at                    ← última vez que o dispatcher enviou

Migrations relevantes:

  • 0008_indexes_performance — índices de performance em TaskLog.
  • 0009_bot_last_execution_denorm — campos denormalizados em Bot.
  • 0010_alerts — tabela Alert.
  • 0011_task_expected_duration_seconds — SLA por task.
  • 0012_bot_silence_threshold_minutes — granularidade fina por bot.

SDK — instrumentando bots

BotApp (standalone)

from botapp import BotApp

app = BotApp(db_name='botapp')
app.set_bot(
    bot_name='meu_bot',           # normalizado: só alfanuméricos, capitalize
    bot_description='O que faz',
    bot_version='1.2.3',
    bot_department='TI',
)

@app.task
def minha_tarefa(arg1, arg2):
    """Docstring vira a description da Task."""
    return {'ok': True}

Comportamento do decorator:

  1. Se o bot estiver is_active=False, a execução é bloqueada com exceção.
  2. Cria/recupera a Task pelo func.__name__ e atualiza a description se a docstring mudou.
  3. Cria TaskLog(status='started') com snapshot do ambiente.
  4. Executa a função. Em caso de exceção, grava exception_type + error_message e re-lança.
  5. No finally, seta end_time e o status final.

BotAppRestful (modo plugin)

# Em outro projeto Django
from botapp import BotApp  # resolve para BotAppRestful se detectar host Django
app = BotApp()                         # usa BOTAPP_API_URL do env
app.set_bot('meu_bot', 'desc', '1.0', 'TI')

@app.task
def tarefa():
    ...

O fluxo é o mesmo, mas todas as operações batem na API REST do dashboard remoto via requests. Credenciais vêm de BOTAPP_API_USUARIO / BOTAPP_API_SENHA (HTTP Basic).


Dashboard web

Rotas principais (prefixadas por / quando em modo standalone):

Rota Descrição
/bots/ Lista de bots com filtros.
/bots/<id>/ Detalhe do bot: execuções, métricas, gráficos.
/bot/<id>/toggle-status/ Liga/desliga bot (POST).
/log/<id>/ Detalhe completo de um TaskLog.
/dashboard/ Painel agregado: bots ativos, silenciosos, alertas.
/alerts/ Lista de alertas (filtros: status, severity, type, bot).
/alerts/<id>/ack/ POST — ack um alerta.
/alerts/<id>/resolve/ POST — resolve um alerta.
/alerts/unread-count/ JSON para badge do menu (polling leve).
/maintenance/cleanup-orphans/ UI para acionar cleanup_orphans via HTTP.
/maintenance/silence-thresholds/ Edição em massa de thresholds de silent_bot.
/bots/bulk-silence-threshold/ Ação em massa dos thresholds.
/explore/ Filtros combinados em TaskLog.
/explore/export.csv Exporta o resultado filtrado como CSV.
/admin/ Django admin.
/api/ API REST (ver seção API REST).
/api/alerts/ingest/ POST — ingest de alertas de monitor externo (Token/Basic).
/accounts/login/ · /accounts/logout/ Autenticação.
/accounts/password_reset/… Fluxo completo de reset por e-mail.

Sistema de alertas

Regras

Tipo Dispara quando Severidade calculada em função de
silent_bot Bot is_active sem execução há mais de N horas (override por bot ok). horas_silencio / threshold
error_spike ≥ X falhas em janela deslizante de M minutos. falhas / threshold
heartbeat_lost Log com status='started' mais antigo que N horas. Severidade fixa por idade
duration_regression Média das últimas N execuções acima de expected_duration_seconds × k. duração_média / expected

Fechamento automático

Cada rodada de check_alerts fecha o alerta cuja condição já passou, antes de detectar de novo: bot que voltou a executar, execução travada que encerrou, janela do pico que passou, duração que voltou ao esperado. O alerta fechado assim recebe payload.fechado_por = "condicao_superada".

Ingest de alertas externos

Além das regras internas, um monitor de fora pode publicar alertas no painel via POST /api/alerts/ingest/ (autenticado por Token DRF ou Basic — máquina-a-máquina, isento do rate-limit de login). Aceita um único alerta ou um lote:

{
  "alerts": [
    {
      "status": "firing",            // firing (default) | resolved
      "type": "host_disk",           // slug livre, ≤30 chars
      "severity": "critical",        // low | medium | high | critical (default medium)
      "message": "Disco cheio em docker01 (92%)",
      "fingerprint": "grafana-abc123", // chave de dedup (opcional)
      "bot_name": "bot_x",           // associa a um Bot se existir (opcional)
      "payload": { "host": "docker01" } // contexto livre (opcional)
    }
  ]
}
  • firing cria o alerta, a menos que já exista um ativo com a mesma chave — fingerprint se informado (guardado em payload.fingerprint), senão type + message. É idempotente: um monitor que reenvia enquanto a condição persiste não duplica.
  • resolved fecha os alertas ativos que casam com a chave.
  • Não dispara notificações (Slack/Discord/e-mail) — o alerta aparecer no painel é a entrega. A resposta traz {created, resolved, deduped} (e errors + HTTP 207 se algum item do lote for inválido).

Também aceita o formato nativo do webhook do Grafana/Alertmanager (itens com labels/annotations): type ← labels.type|alertname (truncado a 30), severity normalizada de critical|warning|info|critico|aviso|…, message ← annotations.summary|description, fingerprint ← fingerprint, status ← status, resto no payload. Assim o Grafana aponta o webhook direto para cá sem template de payload — basta a URL e o header Authorization: Token <chave>.

Isso não é só limpeza de painel. A deduplicação de cada regra é contra alerta aberto do mesmo tipo para o mesmo bot — então um alerta que nunca fecha cega aquele tipo para aquele bot, e a próxima ocorrência real não gera alerta nenhum.

O fechamento é conservador: só fecha o que consegue julgar como normal agora. Sem como julgar (bot ausente, amostra insuficiente de duração), o alerta fica aberto. --dry-run não fecha nada.

Antes de tudo isso, cada rodada encerra execução morta: TaskLog preso em started por mais de BOTAPP_ORPHAN_TASKLOG_HOURS (default 24) vira failed com exception_type='ProcessoMorto'. O @task fecha o log no finally até quando a task levanta exceção — log eternamente em started significa que o processo morreu sem passar por ali (container derrubado, OOM, compose down, job cancelado). Sem esse encerramento o heartbeat_lost daquele bot nunca se resolve e, pela deduplicação, tampa o próximo alerta do mesmo tipo. O limiar é deliberadamente maior que o do heartbeat_lost (6h): na janela entre os dois o alerta deve aparecer, porque ali ainda pode ser job de verdade travado. end_time fica nulo — a hora da morte é desconhecida, e gravar now inflaria a duração com o tempo que o registro passou órfão.

Os alertas de CI seguem a mesma ideia, em ci_sync: pipeline_failed e pipeline_masked_error fecham quando um pipeline posterior do mesmo projeto passa (resolver_alertas_obsoletos), e schedule_without_run / project_never_ran fecham quando o projeto volta a executar dentro do intervalo do cron (resolver_agendamentos_em_dia, payload.fechado_por = "agendamento_em_dia").

Dispatcher (notifiers.py)

Ao criar um alerta, check_alerts chama dispatch_alert(alert) que envia para todos os canais configurados. Cada canal é opt-in: se a env var correspondente não estiver definida, o canal é silenciosamente ignorado. Uma falha em um canal não bloqueia os outros.

  • Slack: webhook com attachment colorido por severidade.
  • Discord: embed com cor hex equivalente.
  • E-mail: usa settings.EMAIL_* (SMTP do Django) com lista de destinatários em BOTAPP_ALERT_EMAIL_RECIPIENTS.

Se qualquer canal teve sucesso, alert.notified_at é atualizado — assim, executar check_alerts em intervalo curto não re-dispara notificações a cada rodada.

Como rodar o detector

Desenvolvimento (thread in-process, single worker):

BOTAPP_ALERT_SCHEDULER_ENABLED=true
BOTAPP_ALERT_SCHEDULER_INTERVAL_SECONDS=60

Ao subir o Django, o AppConfig.ready() inicia uma thread daemon que loopa check_alerts a cada intervalo. Não use em produção com múltiplos workers — N workers × N schedulers gera concorrência e alertas duplicados.

Produção (processo dedicado):

botapp run_alert_scheduler --interval 60

Ou em container:

services:
  botapp_scheduler:
    image: meu-registry/botapp
    environment:
      BOTAPP_ROLE: scheduler
    command: botapp run_alert_scheduler

Flags úteis:

  • --interval N — sobrescreve BOTAPP_ALERT_SCHEDULER_INTERVAL_SECONDS.
  • --once — roda uma vez e sai (útil para cron externo).
  • check_alerts --dry-run — só loga o que faria.
  • check_alerts --no-notify — cria alertas mas não envia webhooks.

API REST

Base: /api/ · Autenticação: Session ou Basic · Permissão: IsAuthenticated.

Método · Rota Descrição
GET /api/bots/ Lista bots (parametros: search).
POST /api/bots/ Cria bot.
GET /api/bots/{id}/ Detalhe.
PATCH /api/bots/{id}/ Atualização parcial.
DELETE /api/bots/{id}/ Remove.
GET /api/tasks/ Lista tasks (?bot=<id>&name=<str>).
POST /api/tasks/ Cria task.
GET /api/tasklog/ Lista logs.
POST /api/tasklog/ Cria log (usado pelo BotAppRestful).
PATCH /api/tasklog/{id}/ Atualiza log (status, end_time, duration…).

Exemplo:

curl -u admin:senha http://localhost:8000/api/bots/?search=relatorio

Comandos de gerência

Disponíveis via entry point botapp (equivalente a python manage.py):

Comando Uso
botapp setup Cria schema + roda migrations + cria superusuário.
botapp migrate [--noinput] Aplica migrations.
botapp collectstatic [--noinput] Coleta estáticos (whitenoise em produção).
botapp runserver [host:port] Servidor dev.
botapp check_alerts [--dry-run] [--no-notify] Roda o motor de alertas uma vez.
botapp run_alert_scheduler [--interval N] [--once] Loop blocante do motor (para processo dedicado).
botapp cleanup_orphans [--threshold-hours N] [--bot-id ID] [--dry-run] [--batch-size N] [--sleep-ms N] Fecha logs travados.
botapp reconcile_bot_denorm Reconcilia Bot.last_execution_at com o TaskLog real mais recente.

Variáveis de ambiente

Essenciais

Variável Default Descrição
DJANGO_SETTINGS_MODULE botapp.settings (standalone) Aponta para seu settings em modo plugin.
BOTAPP_DEBUG False Modo debug do Django.
BOTAPP_SECRET_KEY obrigatório em prod Secret key. Default de dev não é aceito com DEBUG=False.
BOTAPP_ALLOWED_HOSTS * Lista separada por vírgula.
BOTAPP_CSRF_TRUSTED_ORIGINS * (quando DEBUG=False) Lista separada por vírgula.
BOTAPP_PORT_ADMIN 8000 Porta usada por app.open_admin().
BOTAPP_LANGUAGE_CODE pt-br
BOTAPP_TIME_ZONE America/Cuiaba Fuso padrão.
BOTAPP_USE_I18N True
BOTAPP_USE_TZ True Mantenha True para datetimes aware (exigido pelos notifiers).
BOTAPP_DEPLOY_ENV dev Gravado em TaskLog.env.
BOTAPP_LOGGING_LEVEL INFO Nível do logger botapp.
BOTAPP_DJANGO_LOG_LEVEL WARNING Nível do logger django.

Banco de dados (Postgres)

Variável Descrição
BOTAPP_DATABASES (opcional) JSON com o dict DATABASES completo. Sobrescreve as demais.
PG_BOTAPP_SCHEMA Schema das tabelas (default botapp_schema).
PG_BOTAPP_DBNAME Nome do banco.
PG_BOTAPP_USER Usuário.
PG_BOTAPP_PASSWORD Senha.
PG_BOTAPP_HOST Host.
PG_BOTAPP_PORT Porta (default 5432).

Superusuário inicial (usado por botapp setup)

Variável Default
BOTAPP_SUPERUSER_USERNAME admin
BOTAPP_SUPERUSER_EMAIL admin@example.com
BOTAPP_SUPERUSER_PASSWORD admin123 (proibido em prod)

Cache / Redis

Variável Default
BOTAPP_CACHES JSON com o dict CACHES. Se ausente em prod, usa Redis.
BOTAPP_REDIS_URL redis://botapp_redis:6379/1

E-mail (SMTP)

Variável Default
BOTAPP_EMAIL_HOST —
BOTAPP_EMAIL_PORT 587
BOTAPP_EMAIL_USER —
BOTAPP_EMAIL_PASSWORD —
BOTAPP_EMAIL_USE_TLS True
BOTAPP_DEFAULT_FROM_EMAIL BOTAPP_EMAIL_USER

Modo plugin (REST client)

Variável Default Descrição
BOTAPP_API_URL — URL do dashboard remoto. Obrigatório no modo plugin.
BOTAPP_API_USUARIO — HTTP Basic user.
BOTAPP_API_SENHA — HTTP Basic password.
BOTAPP_API_TIMEOUT 10 Timeout (s) das chamadas HTTP.

Scheduler / alertas

Variável Default
BOTAPP_ALERT_SCHEDULER_ENABLED false (não inicia thread in-process)
BOTAPP_ALERT_SCHEDULER_INTERVAL_SECONDS 60
BOTAPP_SILENT_BOT_THRESHOLD_HOURS 24
BOTAPP_ERROR_SPIKE_WINDOW_MINUTES 60
BOTAPP_ERROR_SPIKE_THRESHOLD 5
BOTAPP_HEARTBEAT_LOST_THRESHOLD_HOURS 6
BOTAPP_DURATION_REGRESSION_MULTIPLIER 1.5
BOTAPP_DURATION_REGRESSION_WINDOW 20 (últimas N execuções)

Canais de notificação

Variável Default Efeito
BOTAPP_SLACK_WEBHOOK_URL — Se definida, envia para Slack.
BOTAPP_DISCORD_WEBHOOK_URL — Se definida, envia para Discord.
BOTAPP_ALERT_EMAIL_RECIPIENTS — Lista separada por vírgula. Se vazia, não envia.
BOTAPP_DASHBOARD_URL — Base usada para gerar link nas notificações.
BOTAPP_NOTIFIER_TIMEOUT 5 Timeout (s) das chamadas aos webhooks.

Limpeza de órfãos

Variável Default
BOTAPP_ORPHAN_THRESHOLD_HOURS 24
BOTAPP_ORPHAN_BATCH_SIZE 500
BOTAPP_ORPHAN_SLEEP_MS 100
BOTAPP_ORPHAN_HTTP_MAX 5000

Export

Variável Default Descrição
BOTAPP_CSV_MAX_ROWS 0 0 = ilimitado. Teto opcional para /explore/export.csv.

Deploy em produção

Topologia recomendada:

┌──────────────┐   ┌────────────────────┐   ┌─────────────────────┐
│  Bots (SDK)  │──▶│  web (gunicorn)    │──▶│  Postgres + Redis   │
└──────────────┘   │  BOTAPP_ROLE=web   │   └─────────────────────┘
                   │  N workers         │
                   └────────────────────┘
                           │
                   ┌────────────────────┐
                   │  scheduler         │  (um único processo)
                   │  BOTAPP_ROLE=      │
                   │     scheduler      │
                   └────────────────────┘

Pontos importantes:

  1. Nunca deixe BOTAPP_ALERT_SCHEDULER_ENABLED=true no container web com múltiplos workers — use um container scheduler dedicado.
  2. Rode botapp migrate antes do primeiro start (ou no entrypoint do serviço web).
  3. Configure BOTAPP_SECRET_KEY, BOTAPP_ALLOWED_HOSTS, BOTAPP_CSRF_TRUSTED_ORIGINS explicitamente.
  4. HTTPS reverse proxy na frente do gunicorn; o settings já ativa SECURE_SSL_REDIRECT, HSTS e cookies seguros quando DEBUG=False.
  5. BOTAPP_DASHBOARD_URL deve apontar para a URL pública do dashboard — usado nos links das notificações.

Exemplo de docker-compose mínimo:

services:
  web:
    image: botapp:latest
    environment:
      BOTAPP_ROLE: web
      BOTAPP_ALERT_SCHEDULER_ENABLED: "false"
    env_file: .env.prod
    ports: ["8000:8000"]

  scheduler:
    image: botapp:latest
    environment:
      BOTAPP_ROLE: scheduler
      BOTAPP_ALERT_SCHEDULER_ENABLED: "true"
    env_file: .env.prod
    command: botapp run_alert_scheduler
    depends_on: [web]

  redis:
    image: redis:alpine

Troubleshooting

Alertas não estão sendo criados. Verifique nessa ordem: (1) a migration 0010_alerts rodou (\dt botapp_alert no psql); (2) o scheduler está rodando (botapp run_alert_scheduler em container dedicado ou BOTAPP_ALERT_SCHEDULER_ENABLED=true em dev); (3) existem bots com is_active=True e últimos logs fora do threshold. Rode botapp check_alerts --dry-run para ver o que seria criado sem tocar no banco.

Alertas criados mas sem notificação. Nenhuma das envs de canal foi definida — o dispatcher pula canais sem configuração. Defina pelo menos uma entre BOTAPP_SLACK_WEBHOOK_URL, BOTAPP_DISCORD_WEBHOOK_URL, BOTAPP_ALERT_EMAIL_RECIPIENTS. Verifique o log do scheduler por notifier.slack: falha / notifier.discord: falha / notifier.email: falha.

Bot.last_execution_at desatualizado. SDK antigo (sem o signal post_save) está escrevendo TaskLog direto no banco. Rode botapp reconcile_bot_denorm manualmente ou aguarde o check_alerts (ele chama a reconciliação a cada rodada).

Muitos alertas heartbeat_lost. Crashes deixaram logs em status='started'. Rode botapp cleanup_orphans --threshold-hours 24 para fechá-los retroativamente como failed/orphan_heartbeat.

ProgrammingError: relation "botapp_alert" does not exist. As migrations não rodaram no ambiente. Execute botapp migrate --noinput.

Unknown command: 'check_alerts'. Você está em uma versão < 0.3.1, que foi publicada sem o diretório management/. Atualize para 0.3.1+.


Desenvolvimento local

git clone https://github.com/botlorien/botapp
cd botapp
python -m venv .venv && source .venv/bin/activate
pip install -e .
pip install build twine

# Configure .env como na seção "Início rápido"
botapp setup
botapp runserver

Para testar o SDK contra o banco local, use example.py como referência.

Publicando uma nova versão

python setup.py sdist bdist_wheel
twine upload dist/*

Antes de publicar, verifique que find_packages() detecta todos os subpacotes (em particular botapp.management e botapp.management.commands, que precisam de __init__.py):

python -c "from setuptools import find_packages; print(find_packages())"

Integração com CI (GitLab)

A partir da 0.6.0 o painel também lê o servidor de CI, e não só o que o bot conta sobre si mesmo. Isso cobre três pontos cegos da instrumentação:

  1. Bot que morre antes de instrumentar — falha de credencial, dependência ausente, imagem quebrada: o SDK nunca é chamado e o painel não mostra nada.
  2. Bot que nunca instrumentou — sem o SDK configurado, ele roda, falha e ninguém vê.
  3. Verde que mente — pipeline com status de sucesso cujo log tem Traceback: a exceção foi engolida e o processo saiu com código 0.

A feature nasce desligada. Para ligar, no mínimo:

BOTAPP_CI_ENABLED=true
BOTAPP_CI_BASE_URL=https://seu-gitlab            # sem default de propósito
BOTAPP_CI_NAMESPACE=seu-grupo                     # path ou id numérico
BOTAPP_CI_TOKEN=<token de LEITURA>
python manage.py sync_ci --bootstrap --discovery   # cria a conexão e descobre
python manage.py run_ci_scheduler                  # loop (container separado)

As telas ficam em /ci/ (visão geral), /ci/projects/ e /ci/connections/.

Segurança do token

O token de leitura de API dá acesso a código-fonte e logs de build de todo o namespace. Recomendações que o próprio código impõe:

  • use um token de grupo/serviço somente-leitura, nunca um token pessoal de administrador;
  • por padrão o token não vai para o banco: o registro guarda só o nome da variável de ambiente (token_source="env"), então um dump de backup não contém credencial;
  • o modo token_source="db" exige BOTAPP_CI_TOKEN_KEY (Fernet, extra pip install "botapp[ci-db-token]") e é recusado sem a chave, em vez de gravar em texto puro;
  • a tela mostra no máximo uma impressão digital do token; a API nunca o serializa; o cliente HTTP mascara o valor em qualquer mensagem de erro;
  • o log de job é proxeado pelo servidor — o navegador nunca recebe o token — e servido como text/plain com nosniff, porque log é conteúdo não confiável.

Variáveis

variável default função
BOTAPP_CI_ENABLED false liga a integração
BOTAPP_CI_BASE_URL — URL do servidor de CI
BOTAPP_CI_NAMESPACE — grupo/organização a sincronizar
BOTAPP_CI_TOKEN — token de leitura
BOTAPP_CI_TOKEN_KEY — chave Fernet (só p/ token_source="db")
BOTAPP_CI_DISCOVERY_INTERVAL_MINUTES 1440 refresh de projetos/agendamentos
BOTAPP_CI_POLL_INTERVAL_MINUTES 15 busca de pipelines
BOTAPP_CI_ERROR_PATTERNS Traceback (most recent call last), CRITICAL, FATAL padrões de erro no log (separados por |)
BOTAPP_CI_IGNORE_PATTERNS vazio ruídos a ignorar antes de casar padrão
BOTAPP_CI_LOG_TAIL_BYTES 65536 tamanho máx. da cauda persistida
BOTAPP_CI_ALERT_MAX_AGE_DAYS 7 não alerta sobre execução mais antiga que isso — a carga inicial importa histórico, e falha de meses atrás não é acionável
BOTAPP_CI_STORE_TRIGGERED_BY true grava quem disparou o pipeline (dado pessoal — desligue se o seu regime tratar isso como monitoramento de pessoa)
BOTAPP_CI_ALLOW_INSECURE false permite http:// na base_url
BOTAPP_CI_TIMEOUT_SECONDS 30 timeout por chamada

Projetos inativos

Projeto arquivado no servidor de CI é detectado na redescoberta e marcado como inativo: a consulta traz os arquivados de propósito, porque filtrá-los criaria um ponto cego permanente — um projeto arquivado depois da primeira importação sumiria do resultado, o painel nunca saberia, e seguiria sincronizando e alertando um repositório que ninguém mantém.

Também dá para arquivar no painel um projeto que segue ativo no CI mas está dormente (/ci/projects/<id>/ › Arquivar no painel). Em ambos os casos o projeto deixa de ser sincronizado, deixa de gerar alerta, e os alertas abertos dele são fechados. Ele some da listagem por padrão — o checkbox incluir inativos o traz de volta.

O painel não arquiva no servidor de CI: o cliente é somente-leitura por desenho. A tela oferece o link direto das configurações do projeto para quem tem permissão de escrita fazer isso lá.

Em lote: python manage.py archive_dormant_ci_projects --days 60 --dry-run.

Detecção de "verde que mente"

É opt-in por projeto (scan_logs), porque custa uma chamada de log por job bem-sucedido — ligar para tudo multiplica o tráfego. Quando liga, use BOTAPP_CI_IGNORE_PATTERNS para os ruídos conhecidos da sua stack; sem isso a detecção vira alarme constante e alguém a desliga.

Detalhes de arquitetura em docs/ci-integration-design.md.


Licença

MIT — ver LICENSE.

Metadata

Release files for botapp 0.6.22

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for botapp 0.6.22
File Size Uploaded
botapp-0.6.22.tar.gz 184.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for botapp 0.6.22
File Interpreter ABI Platform
botapp-0.6.22-py3-none-any.whl Python 3 none any Details

Total release size: 384.8 kB

Release files / botapp-0.6.22.tar.gz

Download URL botapp-0.6.22.tar.gz
Size 184.8 kB
Tags Source
SHA-256 checksum
How to use checksums
ab98761c13890385112c763a6b1cd3b3faa19d411cac03831a4dd1a0c756250b
BLAKE2b-256 checksum
How to use checksums
8e2e4d9cfb7a2a661dec0a51c345a2240acd09895a0d9d09968e69c13c3e4e1e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / botapp-0.6.22-py3-none-any.whl

Download URL botapp-0.6.22-py3-none-any.whl
Size 199.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e4a8067ff37641b8f9f5e154a556a118eb5d18866b2178c519a71ccacd91cba0
BLAKE2b-256 checksum
How to use checksums
3b1f19e844a25b5f10b474bcac6a5851d1c5c04be63b759d08e18d6251c48397
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release history Release notifications | RSS feed

0.6.25

2 release files

0.6.24

2 release files

0.6.23

2 release files

This release

0.6.22 This release

2 release files

0.6.21

2 release files

0.6.20

2 release files

0.6.19

2 release files

0.6.18

2 release files

0.6.17

2 release files

0.6.16

2 release files

0.6.15

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.3

1 release file

0.4.2

1 release file

0.4.1

1 release file

0.4.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page