mirror of
https://github.com/hoshikawa2/compass_backoffice.git
synced 2026-07-09 13:54:20 +00:00
first commit
This commit is contained in:
3
docs_original_develop/README.md
Normal file
3
docs_original_develop/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Introduction
|
||||
Documentação relevante -- (txt)
|
||||
|
||||
137
docs_original_develop/api-clients.md
Normal file
137
docs_original_develop/api-clients.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Padrão de implementação para clients de API externa
|
||||
|
||||
Este documento define o padrão obrigatório para qualquer client novo
|
||||
que faça chamadas a APIs externas (HTTP ou outras). Ele garante que
|
||||
todas as requisições apareçam no Langfuse com endpoint, status code
|
||||
e response body, **sem que o dev precise escrever código de tracing
|
||||
manual**.
|
||||
|
||||
## 1. Use sempre `traced_async_client` / `traced_sync_client`
|
||||
|
||||
Nunca instancie `httpx.AsyncClient` (ou `httpx.Client`) diretamente
|
||||
em um client de API. Use os factories de [`src/utils/http.py`](../src/utils/http.py):
|
||||
|
||||
```python
|
||||
from src.utils.http import traced_async_client
|
||||
|
||||
async with traced_async_client(timeout=self.timeout) as client:
|
||||
response = await client.get(url, headers=headers)
|
||||
# ...
|
||||
```
|
||||
|
||||
O factory devolve um `httpx.AsyncClient` que automaticamente:
|
||||
|
||||
- registra o **endpoint real** (URL completa, com path e query string)
|
||||
da request realizada — não depende de `self.base_url` ou `self.url`;
|
||||
- registra o **status code** retornado;
|
||||
- registra o **response body** (JSON ou texto truncado em 2000 chars);
|
||||
- registra metadata também em **erros de rede** (timeout, connect error)
|
||||
com `status_code=None` e o erro como body.
|
||||
|
||||
Argumentos comuns aceitos: `timeout`, `verify_ssl` (default
|
||||
`settings.VERIFY_SSL`), `headers`, `base_url`, `response_sanitizer`,
|
||||
e qualquer outro kwarg de `httpx.AsyncClient`.
|
||||
|
||||
## 2. Decore os métodos públicos com `@trace_tool`
|
||||
|
||||
Aplique `@trace_tool` em todo método que faz chamada externa, incluindo
|
||||
helpers privados de autenticação (`_get_token`, `_refresh_xxx`). Cada
|
||||
método decorado vira um span filho próprio no Langfuse, com nome
|
||||
`NomeDaClasse.nome_do_metodo` — então uma classe com múltiplas APIs
|
||||
(ex: `SpeechAnalyticsClient._get_token` vs `.get_prediction` vs
|
||||
`.get_history`) não perde a granularidade.
|
||||
|
||||
```python
|
||||
from src.utils.observer import trace_tool
|
||||
|
||||
class MyClient:
|
||||
@trace_tool
|
||||
async def get_something(self, ...) -> ...:
|
||||
...
|
||||
```
|
||||
|
||||
## 3. Convenções de nomenclatura
|
||||
|
||||
- **Métodos** com verbo + recurso: `get_history`, `post_prediction`,
|
||||
`open_service_request`. O nome do método aparece no nome do span.
|
||||
- **`__init__`** não precisa expor `base_url` para fins de tracing —
|
||||
o endpoint real vem da request. Mantenha `self.base_url` apenas se
|
||||
o client realmente precisa dela para construir URLs.
|
||||
|
||||
## 4. Sanitização de payloads sensíveis
|
||||
|
||||
Quando a resposta contém credenciais, tokens ou dados sensíveis que
|
||||
não devem ir para o Langfuse, passe um `response_sanitizer` ao factory.
|
||||
A função recebe o body já parseado e devolve a versão filtrada:
|
||||
|
||||
```python
|
||||
def _sanitize_token_response(body):
|
||||
if not isinstance(body, dict):
|
||||
return body
|
||||
return {
|
||||
"expires_in": body.get("expires_in"),
|
||||
"status": body.get("status"),
|
||||
}
|
||||
|
||||
async with traced_async_client(
|
||||
timeout=settings.SPEECH_TIMEOUT,
|
||||
response_sanitizer=_sanitize_token_response,
|
||||
) as client:
|
||||
response = await client.post(url, data=...)
|
||||
```
|
||||
|
||||
Exemplo real: [`SpeechAnalyticsClient._get_token`](../src/components/clients/speech_analytics_client.py).
|
||||
|
||||
## 5. Clients que não usam HTTP
|
||||
|
||||
Para clients que não falam HTTP (ex: [`TaisKbClient`](../src/components/clients/tais_kb_client.py),
|
||||
que usa OCI SDK + oracledb), basta decorar o método público com
|
||||
`@trace_tool`. O decorator cai no fallback de logar o retorno da função
|
||||
como output do span. Não tente sintetizar um endpoint via
|
||||
`set_tool_call_metadata` — apenas adiciona ruído.
|
||||
|
||||
## 6. Exemplo mínimo
|
||||
|
||||
```python
|
||||
import httpx
|
||||
import logging
|
||||
from src.utils.observer import trace_tool
|
||||
from src.utils.http import traced_async_client
|
||||
from src.core.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FooClient:
|
||||
def __init__(self) -> None:
|
||||
self.base_url = settings.FOO_API_BASE_URL
|
||||
self.token = settings.FOO_API_TOKEN
|
||||
self.timeout = settings.FOO_API_TIMEOUT
|
||||
|
||||
@trace_tool
|
||||
async def get_foo(self, foo_id: str) -> dict:
|
||||
url = f"{self.base_url}/foo/{foo_id}"
|
||||
headers = {"Authorization": f"Bearer {self.token}"}
|
||||
try:
|
||||
async with traced_async_client(timeout=self.timeout) as client:
|
||||
response = await client.get(url, headers=headers)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPStatusError as exc:
|
||||
logger.error(f"Foo API HTTP error {exc.response.status_code}")
|
||||
raise
|
||||
```
|
||||
|
||||
Nada de `set_tool_call_metadata` espalhado pelo método. O span no
|
||||
Langfuse já vai conter `endpoint`, `status_code` e `response`
|
||||
automaticamente.
|
||||
|
||||
## Checklist de revisão
|
||||
|
||||
Ao revisar um PR de novo client, valide:
|
||||
|
||||
- [ ] Usa `traced_async_client` / `traced_sync_client` (não `httpx.AsyncClient` direto).
|
||||
- [ ] Métodos públicos têm `@trace_tool`.
|
||||
- [ ] Não há chamadas manuais a `set_tool_call_metadata`.
|
||||
- [ ] Respostas com dados sensíveis passam por `response_sanitizer`.
|
||||
- [ ] Nomes de método são `verbo_recurso` (legíveis como nome de span).
|
||||
119
docs_original_develop/ics.md
Normal file
119
docs_original_develop/ics.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Itens de Controle (IC's) - TIM
|
||||
|
||||
## Geral
|
||||
|
||||
1. Jornadas / Negócio — Exemplo: Prefixo AGC
|
||||
|
||||
Usado para marcar informações relacionadas ao negócio ou dados do cliente no agente de contas.
|
||||
|
||||
Exemplos de uso:
|
||||
|
||||
Tipo de cliente
|
||||
|
||||
Informações de entrada
|
||||
|
||||
Situação de dívida
|
||||
|
||||
Realização de promessa de pagamento
|
||||
|
||||
2. Infraestrutura / Motor — Prefixo LLM
|
||||
|
||||
Usado para eventos técnicos e de execução.
|
||||
|
||||
Exemplos de uso:
|
||||
|
||||
- Chamadas e respostas de APIs (sucesso ou falha)
|
||||
|
||||
- Erros de execução
|
||||
|
||||
- Acionamento de outros agentes
|
||||
|
||||
- Finalização anômala do agente
|
||||
|
||||
3. Contato com o Cliente — Prefixo CTT
|
||||
|
||||
Usado para interações relacionadas ao contato direto com o cliente.
|
||||
|
||||
Exemplos de uso:
|
||||
|
||||
- Dados provenientes do gerenciador de campanha
|
||||
|
||||
- Tipo de acionamento
|
||||
|
||||
4. GuardRails — Prefixo GRL
|
||||
|
||||
Usado quando existe intervenção ou bloqueio motivado por guardrails.
|
||||
|
||||
Exemplo:
|
||||
|
||||
- Acionamento de regra de segurança ou restrição operacional
|
||||
|
||||
###
|
||||
|
||||
---
|
||||
|
||||
# IC'S Específicos Agente Anatel (Feature 1366645)
|
||||
|
||||
|
||||
|
||||
|
||||
IC Descrição
|
||||
|
||||
**AGA.001** Entrada do Agente: Chamados Entrantes para Agente
|
||||
|
||||
**AGA.002** Resultado da validação do chamado = Cancelar
|
||||
|
||||
**AGA.003** Resultado da validação do chamado = Reclassificação
|
||||
|
||||
**AGA.004** Resultado da validação do chamado = Reencaminhamento
|
||||
|
||||
**AGA.005** Resultado da validação do chamado = Seguir via (LLM)
|
||||
|
||||
**AGA.006** Resultado da ação no chamado: Foi aberto no Siebel = sim
|
||||
|
||||
**AGA.007** Resultado da ação no chamado: Foi aberto no Siebel = não
|
||||
|
||||
**AGA.008** Resultado da ação no chamado: Teve Erro = sim
|
||||
|
||||
**AGA.009** Resultado da ação no chamado: Teve Erro = não
|
||||
|
||||
**AGA.010** Resultado consulta Speech
|
||||
|
||||
**AGA.011** Resultado IMDB
|
||||
|
||||
**AGA.012** Resultado Base de Conhecimento (TAIS - procedimentos)
|
||||
|
||||
**AGA.013** Registro resultado da busca de Agente Especializado (LLM)
|
||||
|
||||
**AGA.014** Houve acionamento do Agente Especializado (LLM) = sim
|
||||
|
||||
**AGA.015** Houve acionamento do Agente Especializado (LLM) = não
|
||||
|
||||
**AGA.016** Houve Criação de Chamado Siebel para Tratamento (quando enviado para SMART HUMAN ou
|
||||
Agente Especializado) = sim
|
||||
|
||||
**AGA.017** Houve Criação de Chamado Siebel para Tratamento (quando enviado para SMART HUMAN ou
|
||||
Agente Especializado) = não
|
||||
|
||||
**AGA.018** Houve retorno do resultado do Chamado (resultado do Agente ou Resultado do Smart
|
||||
Human)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**AGA.019** Registro da busca dos detalhes do chamado no Siebel para Resposta
|
||||
|
||||
**AGA.020** Registro da busca do template na Base de Conhecimento (TAIS)
|
||||
|
||||
**AGA.021** Registro da quantidade de template retornado na base de conhecimento (TAIS)
|
||||
|
||||
**AGA.022** Houve registro do envio de dados para resposta no Emulador = sim
|
||||
|
||||
**AGA.023** Houve registro do envio de dados para resposta no Emulador = não
|
||||
|
||||
**AGA.024** Registro da resposta (LLM) no Emulador
|
||||
|
||||
**AGA.025** Registro da ação do Agente Supervisor no Emulador
|
||||
|
||||
**AGA.026** Registro do retorno da Resposta Final no Emulador
|
||||
304
docs_original_develop/logging.md
Normal file
304
docs_original_develop/logging.md
Normal file
@@ -0,0 +1,304 @@
|
||||
# Logs de Aplicação
|
||||
|
||||
Este guia descreve como o logging está organizado, o que cada peça faz, e
|
||||
como adicionar logs em novas features de forma consistente com a política
|
||||
de monitoramento (doc interno 1330576 — *Monitoramento de Aplicação - OCI
|
||||
Logging*).
|
||||
|
||||
---
|
||||
|
||||
## Visão geral
|
||||
|
||||
- **Destino dos logs:** stdout (logs `< ERROR`) e stderr (logs `>= ERROR`). **A
|
||||
aplicação não envia logs diretamente para fora.**
|
||||
- **Formato em produção:** JSON (`LOG_FORMAT=json`).
|
||||
- **Enriquecimento automático:** todo log recebe `service`, `correlation`,
|
||||
`source_channel`, `conversation_start_time_ts`, `requesting_agent` e
|
||||
`user_id` automaticamente via *contextvars*
|
||||
|
||||
Arquivo central: [src/core/logging.py](../src/core/logging.py).
|
||||
|
||||
---
|
||||
|
||||
## Estrutura do JSON emitido
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-05-12T03:16:12.726Z",
|
||||
"level": "INFO",
|
||||
"logger": "src.agent.nodes.validation_node",
|
||||
"message": "process started",
|
||||
"source_channel": "ura",
|
||||
"conversation_start_time_ts": "2026-03-20T14:32:10Z",
|
||||
"requesting_agent": "agent_bo",
|
||||
"service": {
|
||||
"name": "Agent Microservice",
|
||||
"version": "0.4.0",
|
||||
"component": "validation_node",
|
||||
"agent_type": "backoffice"
|
||||
},
|
||||
"correlation": {
|
||||
"trace_id": "...",
|
||||
"request_id": "...",
|
||||
"span_id": "...",
|
||||
"session_id": "..."
|
||||
},
|
||||
"user_id": "...",
|
||||
"operation": {
|
||||
"name": "process",
|
||||
"status": "started",
|
||||
"execution_time": 0.001,
|
||||
"...": "campos custom adicionados via add_field"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `service.component` é derivado **automaticamente** do nome do logger
|
||||
(`record.name.rsplit(".", 1)[-1]`). Para sobrescrever, passe
|
||||
`extra={"component": "outro_nome"}` ou use o helper (`log_operation`).
|
||||
- O bloco `operation` só aparece quando você está dentro de um
|
||||
`log_operation(...)` ou passa `extra={"operation": {...}}` manualmente.
|
||||
- Em falhas, é adicionado o campo `exception` com o stacktrace.
|
||||
|
||||
---
|
||||
|
||||
## Quem popula os contextvars
|
||||
|
||||
| Contextvar | Quem seta | Onde |
|
||||
|---|---|---|
|
||||
| `request_id` | `LoggingMiddleware` (HTTP) ou `set_ticket_log_context` (consumer OCI) | [middleware/logging.py](../src/api/middleware/logging.py), [dependencies/logging_context.py](../src/api/dependencies/logging_context.py) |
|
||||
| `session_id` | `set_ticket_log_context` | idem |
|
||||
| `user_id` | `set_ticket_log_context` (Origin.submittedBy.userId) | idem |
|
||||
| `trace_id` | `set_ticket_log_context` (hoje = transaction_id; Fase 2 trocará para trace OTEL) | idem |
|
||||
| `source_channel` | `set_ticket_log_context` (Origin.sourceSystem) | idem |
|
||||
| `conversation_start_time_ts` | `set_ticket_log_context` (Complaint.openedAt) | idem |
|
||||
| `requesting_agent` | `set_ticket_log_context` (Origin.submittedBy.name) | idem |
|
||||
| `span_id` | (reservado — não populado hoje) | — |
|
||||
|
||||
Limpeza: `clear_context()` é chamado no `finally` do middleware HTTP e do
|
||||
consumer OCI para evitar vazamento entre requisições.
|
||||
|
||||
---
|
||||
|
||||
## API pública
|
||||
|
||||
```python
|
||||
from src.core.logging import (
|
||||
get_logger,
|
||||
log_operation, # context manager — preferido
|
||||
set_request_id,
|
||||
set_session_id,
|
||||
set_user_id,
|
||||
set_trace_id,
|
||||
set_span_id,
|
||||
set_source_channel,
|
||||
set_conversation_start_ts,
|
||||
set_requesting_agent,
|
||||
clear_context,
|
||||
MetricsLogger, # legado — prefira log_operation
|
||||
)
|
||||
```
|
||||
|
||||
### `get_logger(name)`
|
||||
|
||||
Wrapper sobre `logging.getLogger(name)`. Garante que o root logger está
|
||||
configurado. Convenção: `logger = get_logger(__name__)` no topo do módulo.
|
||||
|
||||
### `log_operation(name, *, component=None, logger=None, **fields)`
|
||||
|
||||
Context manager (funciona com `with` e `async with`) que emite:
|
||||
- `<name> started` no entry.
|
||||
- `<name> completed` no exit feliz, com `execution_time` em segundos.
|
||||
- `<name> failed: <exc>` no exit por exceção, com `exc_info` e
|
||||
`error_type` — a exceção é re-raised normalmente.
|
||||
|
||||
`component` quando omitido é derivado do nome do logger.
|
||||
|
||||
Métodos do objeto retornado:
|
||||
- `op.add_field(key, value)` — anexa um campo ao bloco `operation` que
|
||||
será emitido nos logs de success/failed (e em `op.event(...)`).
|
||||
- `op.event(message, level=INFO, **fields)` — emite um log
|
||||
*intermediário* dentro da operação (status `in_progress`), sem fechá-la.
|
||||
|
||||
---
|
||||
|
||||
## Guia de uso — quando e como logar
|
||||
|
||||
### Regra mental
|
||||
|
||||
1. **Operação clara com início e fim** (rota, node, chamada externa, job)
|
||||
→ use `log_operation`.
|
||||
2. **Evento pontual dentro de uma operação** (cache hit/miss, retry,
|
||||
decisão tomada) → `op.event(...)` ou `logger.info(...)` direto.
|
||||
3. **Diagnóstico técnico fino** → `logger.debug(...)`.
|
||||
4. **Algo inesperado mas não fatal** → `logger.warning(...)`.
|
||||
5. **Falha em bloco `except`** → `logger.error(msg, exc_info=True)` ou
|
||||
deixe `log_operation` propagar (já loga com `exc_info`).
|
||||
|
||||
### NUNCA
|
||||
|
||||
- Não passe `session_id`/`request_id`/`user_id` em `extra=` — eles já são
|
||||
injetados pelo `ContextFilter`. Adicionar manualmente só duplica.
|
||||
- Não use `logger.error(str(e))` sem `exc_info=True` em bloco `except` —
|
||||
perde o stacktrace.
|
||||
- Não use `logger.error(..., exc_info=True)` **fora** de bloco `except`
|
||||
— sem exceção ativa o campo `exception` vira `NoneType: None`.
|
||||
- Não logue payloads com PII (CPF, telefone, token, senha). Mascarar /
|
||||
anonimizar antes (política §2 do doc).
|
||||
- Não escreva em arquivo, não chame APIs externas para enviar logs —
|
||||
apenas stdout/stderr. Transporte é da infra.
|
||||
|
||||
### NÃO crie wrappers próprios
|
||||
|
||||
Se aparecer a tentação de criar um decorator/helper local para "padronizar
|
||||
log de início e fim", **pare**. Use `log_operation`. Múltiplos padrões na
|
||||
base é exatamente o que essa refatoração eliminou.
|
||||
|
||||
---
|
||||
|
||||
## Receitas
|
||||
|
||||
### 1. Rota HTTP / handler
|
||||
|
||||
O `LoggingMiddleware` já envolve toda requisição em
|
||||
`log_operation("http_request")`. Dentro da rota, **não precisa logar
|
||||
"recebi requisição" / "finalizei requisição"**. Logue apenas eventos de
|
||||
negócio relevantes.
|
||||
|
||||
### 2. Node do agente
|
||||
|
||||
**Não precisa fazer nada.** O decorator `@trace_node` em
|
||||
[src/utils/observer.py](../src/utils/observer.py) já envolve cada node
|
||||
com `log_operation(func_name, component=<node_name>)` e injeta
|
||||
`message_count` e `iteration_count` automaticamente.
|
||||
|
||||
Se quiser enriquecer com campos próprios do node, use `logger.info`
|
||||
dentro do node — o bloco `service` e a contextualização vêm de graça:
|
||||
|
||||
```python
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@trace_node
|
||||
async def process(state: AgentState) -> AgentState:
|
||||
# start/end são logados automaticamente pelo decorator
|
||||
logger.info(
|
||||
"Customer enriched from IMDB",
|
||||
extra={"payload": {"msisdn_masked": mask(msisdn), "cached": False}},
|
||||
)
|
||||
return state
|
||||
```
|
||||
|
||||
### 3. Cliente HTTP externo
|
||||
|
||||
Métodos decorados com `@trace_api` ou `@trace_tool` já estão envolvidos
|
||||
em `log_operation`. Para logar retries dentro do loop, **emita um log
|
||||
estruturado com o bloco `operation` em status `in_progress`**:
|
||||
|
||||
```python
|
||||
for attempt in range(max_retries + 1):
|
||||
try:
|
||||
return await call_api(...)
|
||||
except TransientError as exc:
|
||||
if attempt == max_retries:
|
||||
raise
|
||||
wait = backoff(attempt)
|
||||
logger.warning(
|
||||
"Cliente: tentativa falhou, repetindo",
|
||||
extra={
|
||||
"operation": {
|
||||
"name": "get_invoice_buffer",
|
||||
"status": "in_progress",
|
||||
"attempt": attempt + 1,
|
||||
"max_retries": max_retries,
|
||||
"backoff_seconds": round(wait, 3),
|
||||
"last_error": str(exc),
|
||||
},
|
||||
"component": "pdf_invoice_recover",
|
||||
},
|
||||
)
|
||||
await asyncio.sleep(wait)
|
||||
```
|
||||
|
||||
Para uma operação de API que **não** use `@trace_api`/`@trace_tool`
|
||||
(caso raro), envolva manualmente:
|
||||
|
||||
```python
|
||||
with log_operation(
|
||||
"get_invoice_buffer",
|
||||
component="pdf_invoice_recover",
|
||||
logger=logger,
|
||||
end_point_name="get_pdf",
|
||||
operacao_realizada="consulta",
|
||||
id_consulta=invoice_id,
|
||||
) as op:
|
||||
op.add_field("attempt", attempt)
|
||||
response = http_call(...)
|
||||
op.add_field("status_code", response.status_code)
|
||||
```
|
||||
|
||||
### 4. Job de background / consumer
|
||||
|
||||
Igual à rota: envolva o trabalho da unidade (uma mensagem consumida, um
|
||||
job rodado) em `log_operation`. Veja [src/api/main.py](../src/api/main.py)
|
||||
`process_incoming_ticket` como referência.
|
||||
|
||||
### 5. Cache / acesso a memória
|
||||
|
||||
Toda operação de I/O que possa falhar merece `log_operation`. Padrão usado
|
||||
no projeto:
|
||||
|
||||
```python
|
||||
try:
|
||||
async with log_operation("save_state_to_memory", component="memory", logger=logger):
|
||||
await save_state_to_memory(state)
|
||||
except Exception:
|
||||
# log_operation já emitiu failed com exc_info — silencie aqui
|
||||
# se o caminho feliz não depende do cache.
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Níveis de log — política
|
||||
|
||||
| Nível | Quando usar |
|
||||
|---|---|
|
||||
| `DEBUG` | Diagnóstico fino. Em produção fica desligado (LOG_LEVEL=INFO). |
|
||||
| `INFO` | Eventos de negócio e fluxo normal — início/fim de operação, decisão tomada, recurso criado. |
|
||||
| `WARNING` | Algo inesperado mas recuperável — fallback acionado, retry transitório, dado opcional ausente. |
|
||||
| `ERROR` | Falha de operação. Sempre **dentro de `except`** com `exc_info=True`. |
|
||||
| `CRITICAL` | Falha total / risco alto / corrupção de estado. |
|
||||
|
||||
Configuração por ambiente:
|
||||
- Produção: `LOG_LEVEL=INFO`, `LOG_FORMAT=json`.
|
||||
- Homologação/Dev: `LOG_LEVEL=DEBUG`, `LOG_FORMAT=text` (mais legível
|
||||
localmente; o split stdout/stderr funciona em ambos os formatos).
|
||||
- Loggers ruidosos (`httpx`, `urllib3`, `pymongo`, etc.) são silenciados
|
||||
para `WARNING` por padrão — ajuste via `LOG_NOISY_LEVEL`.
|
||||
|
||||
---
|
||||
|
||||
## Checklist para PR adicionando novos logs
|
||||
|
||||
- [ ] Usou `log_operation` para operações com início/fim claros?
|
||||
- [ ] Em bloco `except`, `logger.error(..., exc_info=True)`?
|
||||
- [ ] Não passou `session_id`/`request_id`/`user_id` redundantes em `extra`?
|
||||
- [ ] Não logou PII (CPF, telefone, token, payload bruto do cliente)?
|
||||
- [ ] Quando adicionou campos custom, encaixou no bloco `operation` ou em
|
||||
`payload` (não criou um nível superior novo)?
|
||||
- [ ] Se for um cliente HTTP com retry, registrou `attempt` e
|
||||
`max_retries` nos logs de retentativa?
|
||||
- [ ] Verificou localmente com `LOG_FORMAT=json` que o JSON contém os
|
||||
blocos esperados?
|
||||
|
||||
---
|
||||
|
||||
## Referências
|
||||
|
||||
- Política interna: doc 1330576 — *Monitoramento de Aplicação - OCI Logging*.
|
||||
- Implementação base: [src/core/logging.py](../src/core/logging.py).
|
||||
- Decorators que aplicam `log_operation` automaticamente:
|
||||
[src/utils/observer.py](../src/utils/observer.py) (`@trace_node`,
|
||||
`@trace_api`, `@trace_tool`).
|
||||
- Propagação do contexto da requisição:
|
||||
[src/api/dependencies/logging_context.py](../src/api/dependencies/logging_context.py).
|
||||
Reference in New Issue
Block a user