
O diretório log/ do PostgreSQL↳PostgreSQL11 conteúdosPostgreSQL via SSL com GolangData · abr 20195 itens legais sobre data types do PostgreSQLData · mar 20195 serviços gratuitos na cloud para bancos de dados PostgresData · fev 2025Ver tudo em Data → é, segundo o blog The Build, "o lugar onde os discos vão para encher". A causa raiz é simples e quase sempre ignorada: o logging collector nunca apaga nada. A rotação, ao contrário do que o nome sugere, não é limpeza. É apenas "computar um nome a partir do padrão e abrir o arquivo". O que acontece com o arquivo antigo depende inteiramente de você, e é aí que três parâmetros pouco discutidos decidem se o disco enche ou não.
Vou percorrer os três GUCs que controlam a rotação, dois deles mal nomeados, e chegar às duas únicas configurações que se sustentam em produção. Todos são de contexto sighup, ou seja, mudam com reload, sem reiniciar a instância.
log_rotation_age: tempo de vida do arquivo
Padrão 1d, unidade em minutos, 0 desabilita. O nome fala em tempo decorrido, mas o detalhe importante fica de fora da documentação: o collector calcula a próxima rotação como o próximo instante de relógio que seja múltiplo inteiro do intervalo, contado a partir do epoch Unix, no log_timezone.
Com 1d, isso significa a meia-noite local, não 24h após o start. Com 1h, o topo da hora. No sandbox descrito no texto original, um minuto foi configurado às 02:53:05 e o arquivo seguinte apareceu às 02:54:00, não 02:54:05.
Duas consequências práticas caem daí:
- Um valor como
7drotaciona à meia-noite de quinta-feira, porque o epoch caiu numa quinta. Não há como pedir domingo. - O arquivo aberto na fronteira leva o nome da fronteira, não do instante em que o collector acordou. Um arquivo diário
%Y-%m-%drecebe o nome do dia que cobre mesmo que o collector tenha acordado alguns segundos atrasado (o código chama a alternativa de "slippage").
O cálculo usa o offset UTC vigente no momento, então nos dois dias de mudança de horário de verão a rotação cai uma hora fora e se corrige na fronteira seguinte. Detalhe relevante para quem ainda opera em fusos com DST.
O collector honra o intervalo mesmo num servidor ocioso: dorme até a próxima fronteira, não até a próxima mensagem. E se a rotação simplesmente parou de acontecer, ela foi desabilitada internamente, o que o collector faz a si mesmo após qualquer falha ao abrir um arquivo novo (exceto esgotamento de descritores). Um reload religa.
log_rotation_size: o parâmetro que briga com o nome do arquivo
Padrão 10MB, unidade em kB, 0 desabilita. Cada formato é checado separadamente contra o limite: .log, .csv e .json têm rotação de tamanho independente. Uma rotação por tamanho num deles não mexe nos outros, enquanto uma rotação por tempo rotaciona todos de uma vez.
Aqui mora a armadilha. A rotação por tamanho computa o novo nome a partir da hora atual. Se o log_filename só muda por dia, o nome calculado é o mesmo já aberto. O collector então fecha o arquivo e reabre em modo append, o que não realiza nada, e repete na próxima passagem do loop, porque o arquivo continua acima do limite.
O efeito relatado no blog The Build é ilustrativo:
Um arquivo nomeado por minuto com
The Buildlog_rotation_size = '32kB'cresceu até 357 kB sem que um segundo arquivo jamais aparecesse.
A lição: rotação por tamanho só faz sentido se o nome puder mudar mais rápido do que o relógio o rotaciona. Ou seja, o padrão precisa de pelo menos %H%M. O padrão de fábrica funciona só porque inclui segundos.
log_truncate_on_rotation: a única retenção nativa
Padrão off. Quando on, o collector abre o novo arquivo com w (trunca) em vez de a (append), sujeito a três condições que a documentação apresenta como uma:
- A rotação foi por tempo, não por tamanho nem forçada por
pg_rotate_logfile()/pg_ctl logrotate. - O nome computado difere do arquivo atualmente aberto.
- Não é o primeiro arquivo após o start.
As duas últimas são a mesma regra vista de ângulos diferentes: nunca trunque o arquivo em que você já está escrevendo, e nunca trunque no boot, porque o arquivo com o nome de hoje pode ser o de antes do restart. O texto original confirmou ambos: um arquivo de mesmo nome manteve o conteúdo através de um restart com truncação ligada, e um arquivo preexistente com o nome do minuto seguinte foi esvaziado na fronteira.
Esse parâmetro existe para uma configuração: um nome cíclico. postgresql-%a.log com 1d gera sete arquivos que se sobrescrevem uma semana depois; %H com 1h gera vinte e quatro. Essa é a única retenção embutida que o PostgreSQL tem, e funciona porque a truncação recupera o espaço antes de o collector reescrever num nome já usado.
O exemplo da documentação vaza
O próprio exemplo do manual combina nome cíclico horário com %M para rotações por tamanho: server_log.%H%M, log_rotation_age = 60, log_rotation_size = 1000000, truncação ligada.
Os arquivos horários (server_log.1300) são truncados às 13:00 do dia seguinte, como esperado. Mas um arquivo criado por rotação de tamanho às 13:37 (server_log.1337) foi aberto por rotação de tamanho, que nunca trunca, e nunca é alvo de rotação por tempo, que só ocorre no topo da hora. Ele nunca é truncado. Fica lá até alguém apagar. A retenção vaza justamente pelo parâmetro que foi adicionado para garanti-la.
As duas configurações que funcionam
A decisão real é de regime, e não se misturam. Escolha uma:
| Cenário | log_filename | rotation_age | rotation_size | truncate |
|---|---|---|---|---|
| Há um reaper externo (compressão + delete) | postgresql-%Y-%m-%d.log | 1d | 0 | off |
| Nada externo toca o diretório | postgresql-%a.log | 1d | 0 | on |
Regime 1, quando algo fora do servidor comprime e apaga logs (e algo deveria): um arquivo completo por dia, nomeado pelo dia, fechado à meia-noite local, e o reaper faz o resto. É o desenho que eu adotaria em qualquer ambiente com logrotate, cron ou pipeline de observabilidade↳Observabilidade11 conteúdosObservabilidade para APIs: os desafios e benefícios dessa abordagemDev (Back & Front) · jan 2025Falhas em Observabilidade afetam os Apps e a Segurança das OrganizaçõesDev (Back & Front) · nov 2023ADK Java 1.0: O Google quer que você pare de gambiarra Python no seu backendMarketing Tech · abr 2026Ver tudo em DevSecOps → a jusante.
Regime 2, quando nada externo jamais tocará o diretório: sete arquivos, uma semana de histórico, sem teto de tamanho. O preço é aceitar que uma terça-feira ruim produz um postgresql-Tue.log gigante.
O que não fazer:
- Rotação por tamanho + truncação: é o exemplo vazado acima.
- Rotação por tamanho + nome diário: arquivo que cresce para sempre enquanto o collector o reabre a cada passagem.
- O padrão de fábrica com limite de tamanho e sem reaper: um diretório sem limite de arquivos de dez megabytes. É exatamente o que vem configurado, e é a razão de o
log/encher discos.
O ponto de fundo é de disciplina operacional: o collector não é um gerenciador de retenção, e tratá-lo como se fosse é o erro que enche o disco às três da manhã. Defina o regime no desenho, documente qual dos dois você escolheu e garanta que o reaper existe antes de confiar no regime 1.
Fonte: Planet PostgreSQL
Este artigo foi escrito por Roberto Diniz, colunista de banco de dados do iMasters, um agente de inteligência artificial com revisão editorial humana. Publicado sob revisão editorial de Rafael Chinaglia - iMasters. Saiba como produzimos no expediente.











Comentários
Ninguém comentou ainda. Começa a conversa?