Observabilidade¶
A camada de observabilidade / produção (Trilho O) dá ao seu app telemetry, logs estruturados, error boundary, feature flags e auth de cliente — tudo em Python tipado, idêntico nos dois modos. 📊
Em construção (Trilho O)
Esta camada é o Trilho O do roadmap. As fases O0–O4 estão detalhadas no plano de design. Esta página descreve a superfície planejada e o padrão adapter.
O padrão adapter¶
Todos os provedores seguem o mesmo princípio: uma interface mínima que você troca sem tocar no app. Você programa contra a API; o adapter decide para onde vai (console, Sentry, GrowthBook, …).
seu app ──chama──▶ Provider (API estável) ──delega──▶ Adapter (backend)
console / sentry / posthog / ...
Trocar backend não muda chamada
Migrar de console para sentry não altera nenhuma chamada track(). É
a mesma promessa do tempest-react-sdk, agora em Python tipado.
O0 — Telemetry¶
Instrumenta eventos do framework e do app (service worker, push, replay offline, erros) com provedor plugável.
from tempestweb.observability import telemetry
from tempestweb.observability.telemetry import ConsoleAdapter
telemetry.init(adapter=ConsoleAdapter())
telemetry.track("order_submitted", {"items": 3, "total": 99.9})
telemetry.identify("user-42")
Não vaze PII
Não coloque dados pessoais nos props e use amostragem para não inundar o
backend. A telemetria é diagnóstico, não um banco de dados de usuários.
O1 — Logger¶
Logging estruturado com sinks plugáveis e níveis tipados (LogLevel).
from tempestweb.observability import create_logger, console_sink
log = create_logger(sinks=[console_sink])
log.info("order created", order_id="o-1", total=99.9)
log.error("payment failed", order_id="o-1", reason="card_declined")
No Modo A o sink default é o console do browser
Sinks de rede (enviar logs a um servidor) devem ser async/não-bloqueantes — no Modo A um sink bloqueante trava a aba.
O2 — Error boundary¶
Captura erro de render → mostra um fallback visual + dispara um report, sem derrubar o app. O resto da árvore segue vivo.
from tempestweb.observability import error_boundary
from tempest_core import Text, Widget
@error_boundary(fallback=lambda err: Text(content=f"Algo quebrou: {err}"))
def risky_panel(app: object) -> Widget:
"""Render a panel that may raise during build.
Args:
app: The running app handle.
Returns:
The rendered panel widget.
"""
return build_dashboard(app.state) # se lançar, o fallback aparece
Erro de render ≠ erro de handler async
O boundary pega erros de render (durante o view()). Erros de handler
async vão para o tratamento do event loop. Em ambos os casos, reporte —
nunca engula o stack.
O3 — Feature flags¶
Liga/desliga features em runtime com rollout gradual. A interface do adapter é minúscula (~20 linhas para implementar uma nova).
from tempestweb.observability import feature_flags
from tempestweb.observability.feature_flags import InMemoryAdapter
feature_flags.init(adapter=InMemoryAdapter({"new_checkout": True}))
def view(app: object) -> object:
"""Render checkout, gated by a feature flag."""
if feature_flags.is_enabled("new_checkout"):
return new_checkout(app)
return legacy_checkout(app)
Flags não são segredo; tenha default seguro
Quando o backend de flags está fora, is_enabled deve cair num default
seguro — nunca quebrar o app. E nunca use flags para esconder segredos: elas
são visíveis no cliente.
O4 — Auth de cliente¶
Store de auth + guarda de rota + helpers de JWT + fila de refresh que serializa renovações concorrentes (uma renovação, várias esperas).
from tempestweb.observability import create_auth_store, create_refresh_queue
auth = create_auth_store()
refresh = create_refresh_queue(auth)
async def call_api(app: object) -> dict[str, object]:
"""Call a protected endpoint, refreshing the token once if needed.
Args:
app: The running app handle.
Returns:
The decoded JSON response.
"""
if auth.is_token_expired():
await refresh.run() # várias chamadas concorrentes => UM refresh
response = await app.native.http.request(
"GET", "/api/me", headers={"Authorization": f"Bearer {auth.token}"}
)
return response.json()
O token vive em lugares diferentes por modo
No Modo A o token vive no browser (storage) — trate XSS como risco
real. No Modo B ele vive na sessão do servidor, mais protegido. O servidor
reusa JWTUtils do tempest-fastapi-sdk.
Recap¶
- A observabilidade usa o padrão adapter: troca o backend sem mudar o app.
- Telemetry (O0), Logger (O1), Error boundary (O2), Feature flags (O3) e Auth (O4) são todos Python tipado, idênticos nos dois modos.
- Defaults seguros e cuidado com PII/tokens são parte do contrato.
Essa camada espelha os provedores do tempest-react-sdk. Para o detalhe
fase-a-fase, leia o
plano de design.
🚀