1

Quando logs TRACE viram escrita constante no SSD

Hoje eu fui investigar uma suspeita simples: o arquivo ~/.codex/logs_2.sqlite parecia estar sendo escrito sem parar.

A hipótese era que algum log em nível TRACE estava despejando eventos demais no SQLite. Não era uma suspeita absurda. O arquivo já estava grande, havia um -wal ativo, e o horário de modificação mudava o tempo todo.

Então fui medir.

Primeiro olhei os arquivos:

logs_2.sqlite      417 MB
logs_2.sqlite-wal   10 MB

Depois fiz uma amostragem curta do mtime e do tamanho do WAL. O resultado foi claro: o WAL era atualizado várias vezes por segundo.

Abrindo o SQLite em modo somente leitura, a tabela era simples:

logs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  ts INTEGER NOT NULL,
  level TEXT NOT NULL,
  target TEXT NOT NULL,
  feedback_log_body TEXT,
  module_path TEXT,
  process_uuid TEXT,
  estimated_bytes INTEGER NOT NULL DEFAULT 0
)

A distribuição recente confirmou o problema. Em uma janela curta, quase tudo era TRACE.

Alguns exemplos dos alvos mais barulhentos:

codex_api::endpoint::responses_websocket
codex_api::sse::responses
tokio-tungstenite
hyper_util

E os corpos dos logs mostravam atividade de WebSocket em baixo nível:

WebSocketStream
Stream.poll_next
Read.read
WouldBlock
received frame
Opcode: Control(Pong)

Ou seja: não era um log ocasional de aplicação. Era ruído de transporte em nível TRACE.

O processo principal era o codex.exe app-server do Codex Desktop.

A intervenção

Antes de mexer em qualquer coisa, fiz backup:

  • backup lógico consistente via API do SQLite
  • cópia bruta de logs_2.sqlite
  • cópia de logs_2.sqlite-wal
  • cópia de logs_2.sqlite-shm

Depois instalei um trigger para interceptar novas escritas na tabela logs:

CREATE TRIGGER codex_block_logs_insert
BEFORE INSERT ON logs
BEGIN
  SELECT RAISE(IGNORE);
END;

Esse trigger não apaga logs antigos. Ele só ignora novos inserts na tabela.

Em seguida rodei:

PRAGMA wal_checkpoint(TRUNCATE);

O WAL caiu para 0 bytes.

O resultado

Amostrei por 30 segundos depois da mudança.

Resultado:

MAX(id): estável
count(*): estável
logs_2.sqlite-wal: 0 bytes
mtime do WAL: sem mudança

Antes, em 20 segundos, apareceram 300 novas linhas TRACE.

Depois do trigger, nada novo entrou na tabela.

Isso estava destruindo o SSD?

Provavelmente não.

SSD moderno aguenta muito mais escrita do que algumas dezenas de KB/s em janelas curtas. Não era um cenário de "meu disco vai morrer amanhã".

Mas era escrita desnecessária, contínua e silenciosa. E isso importa.

Não só por desgaste. Também por:

  • crescimento de arquivo sem valor prático
  • atividade constante de disco
  • WAL sempre ativo
  • ruído em backup, indexação e antivírus
  • dificuldade de separar logs úteis de ruído

Então a resposta equilibrada é: não parecia uma emergência de hardware, mas fazia sentido cessar a escrita.

A ressalva

Isso não "conserta" a origem do log TRACE.

O processo ainda pode tentar emitir esses eventos. O trigger só impede que eles sejam persistidos na tabela logs.

Também não bloqueia outras escritas normais do Codex, como estado, sessão, cache ou outros bancos SQLite. Ele atua apenas sobre a tabela logs de logs_2.sqlite.

Para desfazer:

import sqlite3, os

p = os.path.expanduser(r"~/.codex/logs_2.sqlite")
conn = sqlite3.connect(p)
conn.execute("DROP TRIGGER IF EXISTS codex_block_logs_insert")
conn.commit()
print(conn.execute("PRAGMA wal_checkpoint(TRUNCATE)").fetchall())
conn.close()

O problema era real: havia escrita contínua em logs_2.sqlite, dominada por logs TRACE de WebSocket/transporte.

A mitigação com trigger funcionou: novas linhas deixaram de entrar, o WAL foi truncado e parou de crescer durante a amostragem.

Não é a solução ideal de produto. A solução ideal seria o próprio aplicativo respeitar um nível de log menos verboso ou não persistir esse tipo de TRACE por padrão.

Mas como mitigação local, reversível e com backup, resolveu o sintoma mais incômodo: escrita constante e inútil no SSD.

Carregando publicação patrocinada...