
Logging não costuma ser tratado como assunto de arquitetura, mas em produção ele decide se um incidente é diagnosticável ou vira mistério. Christophe Pettus, na série "All Your GUCs in a Row" publicada no Planet 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 →, dedica um post inteiro a dois parâmetros que quase todo DBA configura no automático: log_destination e logging_collector. A tese central é direta e incômoda: você vai querer o collector ligado, e provavelmente vai descobrir isso num servidor de produção que já está rodando, quando já é tarde.
O mecanismo básico: tudo é stderr
A base do sistema de logging do PostgreSQL é mais simples do que a lista de duas dúzias de parâmetros log_ sugere. Salvo quando se pede syslog, toda mensagem que o PostgreSQL emite é uma escrita no standard error* do processo. Os demais parâmetros apenas refinam o que é escrito, em que formato e quem recolhe do outro lado.
log_destination é uma lista separada por vírgulas, com default stderr e contexto sighup (recarregável sem reinício). As opções são stderr, csvlog (desde a 8.3), jsonlog (desde a 15), syslog e, no Windows, eventlog.
logging_collector é um booleano, default off, contexto postmaster. Aqui está, segundo Pettus, o fato mais consequente do post inteiro: ligá-lo exige restart. Não é reload, não é SET. É parar e subir o servidor.
O que o collector realmente faz
Com o collector desligado, stderr aponta para onde quer que o processo que iniciou o postmaster tenha apontado: um arquivo via pg_ctl -l, o journal sob systemd, o stdout do container sob Docker↳Docker46 conteúdosE o Docker Swarm? Contextos e motivadores diáriosDevSecOps · ago 2024Automatizando o ambiente de desenvolvimento e testes com DockerDevSecOps · mai 2019MySQL + Adminer + Docker Compose: montando rapidamente um ambiente para usoData · abr 2019Ver tudo em DevSecOps →. Cada backend↳Back-end49 conteúdosIntegração front-end com backend: 7 decisões que evitam caos entre APIs, BFF e GraphQLDev (Back & Front) · abr 2026Como criar uma FAKE API REST para testes — JSONPlaceholderDev (Back & Front) · set 2025Construindo um aplicativo de bate-papo de IA simples com Spring AI e AngularDev (Back & Front) · jul 2025Ver tudo em Dev (Back & Front) → herda esse descritor e escreve cada mensagem com um único write(). Funciona, até certo ponto. Não há rotação, e em algumas plataformas escritores concorrentes no mesmo arquivo podem embaralhar linhas.
Com o collector ligado, o postmaster cria um pipe, aponta o próprio stderr para a ponta de escrita e cria um processo filho (postgres: logger no ps) que é dono da ponta de leitura e transforma o fluxo em arquivos. Todo filho subsequente já herda o stderr apontado para o pipe.
O detalhe de implementação que importa: os backends não jogam texto cru no pipe. Cada mensagem passa por um protocolo de chunking, com cabeçalho contendo PID, comprimento, formato de destino e uma flag de último pedaço, em blocos nunca maiores que PIPE_BUF (4096 bytes no Linux), para que cada escrita seja atômica. É por isso que o collector consegue remontar uma mensagem longa de um backend mesmo quando os pedaços de outro backend chegam no meio. Esse é o motivo concreto de a saída multilinha do auto_explain sair inteira, e não intercalada com a do vizinho.
A vantagem silenciosa sobre o syslog
Qualquer coisa que chegue ao pipe sem o cabeçalho é escrita direto no arquivo de log em formato texto. É ali que vai parar a reclamação de uma biblioteca compartilhada que grita no stderr, a saída do shell disparado por archive_command ou por COPY ... TO PROGRAM, sem timestamp e sem prefixo, porque não veio do código de logging do PostgreSQL.
Como Pettus resume, essa é a vantagem discreta do collector sobre o syslog: "o dynamic linker não sabe chamar syslog()". Ou seja, ruído de baixo nível que jamais passaria pelo syslog ainda assim é capturado.
Duas consequências práticas. Primeira: o arquivo .log em texto sempre existe com o collector ligado, independente do que log_destination diga, porque o postmaster o abre antes de forkar o logger (para provar que log_directory é gravável) e o texto de pass-through precisa de destino. Configure log_destination = 'csvlog' e você terá um .csv com as mensagens e um .log com a linha avisando que o logging migrou para csvlog, mais o que qualquer shell resolveu dizer.
Segunda: o logger só sobe depois de lidos os arquivos de config, checado o data directory e alocada a memória compartilhada. Falhas em qualquer dessas etapas são reportadas no stderr original, não em log_directory. Se o servidor não sobe, olhe no arquivo do -l do pg_ctl ou no journal antes de olhar em log/.
O logger é também o único filho que o postmaster não mata durante um ciclo de crash. Quando um backend morre por sinal e todo o resto é terminado e reinicializado, o logger mantém PID e arquivos, e é por isso que was terminated by signal 9 aparece de forma confiável no log. Complementam o quadro current_logfiles no data directory e a função pg_current_logfile() (ambos desde a 10), que apontam o arquivo em uso por formato, e ambos estão ausentes quando o collector está off.
O trade-off que de fato decide a configuração
Aqui está a parte que separa quem só liga o parâmetro de quem entende o que assinou. O pipe tem capacidade fixa, 64 kB por default no Linux. O collector foi projetado para nunca perder mensagem. Quando ele fica para trás, o pipe enche, e o próximo processo que tentar logar bloqueia em write() até o collector drenar. Todo processo.
Um log_directory em armazenamento lento, ou uma rajada de log_statement = 'all' num servidor movimentado, pode travar a instância inteira atrás do próprio arquivo de log. E o pior: apresenta-se como tudo ficando lento ao mesmo tempo, sem razão que o pg_stat_activity consiga mostrar, porque os backends estão em uma escrita de kernel, não num wait event.
O syslog resolve a mesma situação jogando mensagens fora. Nenhuma das escolhas é errada, mas você precisa saber qual fez. Resumindo o comportamento sob estresse:
- Disco lento: o collector trava a instância; o syslog nunca trava.
- Disco cheio: a escrita do collector falha, ele anota no stderr original e descarta a mensagem, sem bloquear backends; o syslog também descarta.
- Carga alta (rajada de logs): o collector bloqueia para não perder nada; o syslog descarta linhas.
O syslog ainda tem duas propriedades limitantes: quebra mensagens longas em 1024 bytes por default e descarta quando não dá conta.
Onde você provavelmente está hoje
Os defaults são a configuração menos interessante, porque quase ninguém os roda. Debian e Ubuntu deixam o collector desligado e sobem cada cluster com pg_ctl -l /var/log/postgresql/postgresql-18-main.log, rotacionando semanalmente via logrotate com copytruncate. É exatamente a configuração que a documentação classifica como adequada apenas para baixo volume, rodando numa fração enorme dos servidores PostgreSQL do mundo.
Funciona, mas por um motivo frágil: cada mensagem é um único write() num arquivo aberto em append, e o Linux, na prática, não intercala essas escritas. O que morde é o copytruncate: linhas escritas entre a cópia e o truncate são perdidas, e num servidor ocupado essa janela não é vazia.
Os RPMs do PGDG ligam o collector e rotacionam diariamente dentro de log/ no data directory. A imagem Docker oficial deixa desligado para que docker logs funcione; ligue dentro do container e os logs migram para o volume de dados, saindo do que sua plataforma coleta. Serviços gerenciados ligam e não perguntam.
A recomendação prática
Pettus fecha com uma receita objetiva: collector ligado, restart, log_destination = 'stderr', adicionando jsonlog (ou csvlog antes da 15) se algo que não seja humano lê os logs, mantendo stderr na lista para o texto de pass-through ter onde morar. A preferência por jsonlog sobre csvlog tem razão técnica: linhas CSV contêm quebras de linha embutidas nos campos de query e context, e cada parser "que lida com valores multilinha" lida de um jeito ligeiramente diferente.
Há ainda uma armadilha silenciosa documentada de forma incompleta: com o collector desligado, definir jsonlog ou csvlog simplesmente não faz nada, sem aviso. No teste de Pettus, log_destination = 'jsonlog' com collector off produziu texto comum no stderr, nenhum warning, e pg_current_logfile() retornou null. Se você configurou isso num Debian e o JSON sumiu, é aí que ele foi parar.
Use syslog apenas se todo o resto do host já passa por syslog e você fez as pazes com ele descartando linhas. E se você está no Debian e está funcionando, entenda que funciona por uma propriedade do kernel e uma aposta semanal, e ligue o collector antes que a aposta pare de pagar.
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?