PostgreSQL: entenda log_directory, log_filename e log_file_mode antes de ir para produção
O autor do blog The Build mostra por que os defaults de logging do PostgreSQL servem para um notebook e falham num servidor, e como o desenho correto dos três GUCs decide auditoria, retenção e segurança.

Configurar logging no 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 → parece trivial até o momento em que alguém precisa de uma auditoria, o disco de dados enche por causa de um log_statement = 'all' esquecido, ou o log some de um relatório de incidente às três da manhã. No post "All Your GUCs in a Row: log_directory, log_filename, and log_file_mode", publicado no Planet PostgreSQL, o autor do blog The Build disseca os três parâmetros que descrevem os arquivos que o logging collector grava: onde ficam, como se chamam e quem pode lê-los. A tese central é direta: os defaults dos três são adequados para um notebook e errados para um servidor, e os motivos são mais mecânicos do que a documentação deixa transparecer.
Vale a ressalva que o próprio autor faz: os três parâmetros não fazem nada enquanto logging_collector estiver desligado. Eles só governam o comportamento do coletor. Sem coletor, não há arquivo para nomear, posicionar ou proteger.
log_directory: por que gravar fora do data directory
O default é log, contexto sighup. Um caminho relativo é resolvido em relação ao data directory, não ao diretório de onde o postmaster foi iniciado. Até a versão 10 o default era pg_log; o prefixo pg_ passou a ser reservado para o que é de fato parte do cluster.
O comportamento na recarga merece atenção. Ao mudar o valor com SIGHUP, o coletor força uma rotação, tenta um mkdir do novo diretório com as mesmas permissões do data directory (0700, ou 0750 se o cluster foi criado com acesso de grupo) e ignora falha na criação. O que ele não ignora é falha ao abrir arquivo lá dentro. O autor relata que apontar log_directory para /var/log/pgtest antes de o diretório existir produziu could not open log file ... No such file or directory, seguido de disabling automatic rotation (use SIGHUP to re-enable). O coletor então continuou gravando no arquivo antigo, com rotação desligada, até a próxima recarga. A consequência é traiçoeira: um erro de digitação nesse parâmetro não perde os logs, apenas para de rotacioná-los silenciosamente, e current_logfiles ainda aponta para o arquivo antigo, de modo que nada parece errado.
A pergunta real é: dentro ou fora do data directory? A resposta do autor é fora, por três razões que nada têm a ver com organização:
pg_basebackupcopia o diretório. A lista de exclusão do base backup (pg_dynshmem,pg_notify,pg_replslot,pg_stat_tmp,pgsql_tmpe afins) não incluilog. O backup do autor veio com 4,4 MB de logs. Uma réplica construída a partir de base backup nasce carregando os logs do primário, e todo restore arrasta os logs anteriores ao desastre junto. Opg_rewindusa o mesmo filtro.- Disco. Logs no data directory dividem filesystem com o heap e, em geral, com o WAL. Uma enxurrada de logs enche o disco de dados, e disco de dados cheio é servidor parado. Em filesystem próprio, a mesma enxurrada vira apenas uma indisponibilidade de logging: o coletor falha ao gravar, descarta mensagens, e o banco segue. Essa é a falha que se quer.
- Permissões. O diretório que o coletor cria é
0700, e nada emlog_file_modemuda isso. Se o engenheiro de plantão, o log shipper e o agente de monitoramento precisam ler os logs (e todos precisam), o diretório tem de ser criado manualmente, com o modo pretendido, o que significa fora do data directory.
Um detalhe operacional importante: o mkdir do coletor falha se o diretório-pai não for gravável pelo postgres, e /var/log não é. Portanto, crie o diretório antes de recarregar, não depois. Do lado das funções de leitura via servidor, a localização é indiferente: pg_ls_logdir() lista o que log_directory aponta, pg_current_logfile() reporta o caminho absoluto, e pg_read_file() aceita caminhos absolutos sob log_directory até para roles sem pg_read_server_files.
log_filename: o nome é a política de retenção
O default é postgresql-%Y-%m-%d_%H%M%S.log, contexto sighup. É um padrão strftime, renderizado pelo próprio strftime do PostgreSQL (apenas os escapes padrão, sem extensões da libc) no fuso de log_timezone. Para csvlog e jsonlog, o coletor troca um .log final por .csv ou .json; se o nome não termina em .log, ele acrescenta o sufixo. Assim, server_log.%H%M gera server_log.0244 e server_log.0244.json lado a lado.
O ponto crítico do artigo está aqui: o PostgreSQL nunca apaga um arquivo de log. As únicas chamadas a unlink do coletor são para seus próprios arquivos de metadados. A cada rotação, seja por idade, por tamanho ou por pg_rotate_logfile(), ele calcula um nome a partir do padrão e o abre. Se o nome é novo, há mais um arquivo, para sempre. Se o nome já existe, o coletor faz append, a menos que log_truncate_on_rotation esteja ligado e a rotação seja baseada em tempo, caso em que ele trunca. O autor verificou: um postgresql.log constante sobreviveu a duas rotações forçadas com tudo de antes e depois preservado.
O padrão de nome, portanto, escolhe entre dois regimes:
- Nome que muda a cada rotação (como o default): histórico completo e diretório ilimitado. Algo fora do PostgreSQL precisa comprimir e apagar.
- Nome cíclico, como
postgresql-%a.logcom truncamento ligado: sete arquivos limitados e um teto rígido de histórico. A terça-feira passada some quando a atual começa.
Não há terceira opção dentro do servidor, e o timestamp com granularidade de segundos no default é uma pista de que o projeto espera que o DBA escolha. A recomendação do autor é o primeiro regime: nomear por dia (postgresql-%Y-%m-%d.log) e rodar um job que comprime o de ontem e apaga o do mês passado. A ressalva: se houver rotação por tamanho (log_rotation_size), um nome que só muda por dia faz a rotação por tamanho reabrir o mesmo arquivo, então inclua %H%M nesse cenário.
log_file_mode: os logs são cópia dos dados sem os controles de acesso
O default é 0600, contexto sighup, e é um número octal: escreva com o zero à frente. Segundo o autor, 600 e 640 sem o zero são decimais, acima do teto 0777, e rejeitados na recarga (o que é o bom resultado); um decimal menor seria aceito e significaria algo não pretendido. O modo é aplicado via umask no instante em que o coletor cria o arquivo, então a mudança vale na próxima rotação e não altera arquivos existentes. O coletor força o bit de escrita do dono de volta em qualquer valor: 0000 resulta em 0200, write-only. É ignorado no Windows e nunca toca o diretório.
O argumento de segurança é o mais contundente do texto. 0600 significa que só o postgres lê o log. 0640 é o outro valor que vale a pena, para um grupo com as pessoas e agentes que precisam ler, e, como já dito, não adianta nada dentro de um diretório 0700. Não passe disso. Nas palavras do autor, um log legível por todos é "uma cópia dos dados mais interessantes do banco, sem nenhum dos controles de acesso do banco". O log contém toda instrução que deu erro, tudo que log_statement captura, a identidade de cada conexão e, se alguém foi generoso com log_min_duration_statement, os parâmetros com que essas instruções rodaram.
A configuração recomendada e o que fica para o DBA
Juntando os três, o autor propõe: um log_directory absoluto no filesystem de logs, criado por você, 0750, com grupo pertencente a quem embarca e lê os logs; log_filename = 'postgresql-%Y-%m-%d.log'; log_file_mode = 0640; e um job de cron que faça a exclusão que o servidor nunca fará.
Para o DBA brasileiro que opera bancos em produção, a lição estrutural é a de sempre: performance e segurança nascem do desenho correto, não de ajuste emergencial. Nenhum desses três parâmetros faz milagre isolado, mas errar qualquer um deles produz falhas silenciosas, o pior tipo de falha em produção: rotação desligada sem alarme, logs vazando para réplicas e backups, ou dados sensíveis expostos por um modo octal mal escrito. O ponto que o servidor deixa explícito, e que o texto reforça, é que a retenção e a exclusão são responsabilidade externa. Quem não montar o job de expurgo terá, mais cedo ou mais tarde, um diretório de logs sem teto.
Fonte 1: Planet PostgreSQL (https://postgr.es/p/9tq)
All Your GUCs in a Row: log_directory, log_filename, and log_file_mode — The Build
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?