← Voltar para o Blog

journalctl: filtrar log como gente grande

A maioria das pessoas usa três comandos do journalctl e sofre com o resto. Ele é um banco de dados indexado, não um arquivo de texto — e isso muda completamente o que dá para perguntar.

Equipe EasyOps Cloud · · 7 min de leitura

Quase todo mundo usa o journalctl de três formas: -u servico, -f para acompanhar, e | grep para o resto. Funciona, e desperdiça o que a ferramenta tem de melhor.

O journal não é um arquivo de texto — é um banco indexado, onde cada linha carrega dezenas de campos estruturados além da mensagem. Saber consultar esses campos muda a investigação de incidente de "procurar agulha no palheiro" para "perguntar exatamente o que interessa".

O que existe além da mensagem

Comece vendo tudo que uma linha carrega:

journalctl -u nginx -n 1 -o verbose

A saída traz campos como _PID, _UID, _SYSTEMD_UNIT, _HOSTNAME, _BOOT_ID, PRIORITY, _COMM, _EXE e _CMDLINE. Todos são consultáveis diretamente, sem grep:

journalctl _COMM=sshd
journalctl _UID=1001
journalctl _PID=21847
journalctl _EXE=/usr/sbin/nginx

Filtros com o mesmo campo são combinados com "ou"; campos diferentes, com "e":

# sshd OU sudo
journalctl _COMM=sshd _COMM=sudo

# do usuario 1001 E do processo sshd
journalctl _UID=1001 _COMM=sshd

A diferença em relação ao grep não é apenas elegância. O grep acerta a mensagem por texto e traz falso positivo — uma linha que menciona nginx no meio de outra coisa. O filtro por campo é exato, e usa índice em vez de varrer.

Tempo, que é o filtro mais usado

journalctl --since '2026-08-10 14:00' --until '2026-08-10 15:30'
journalctl --since '30 min ago'
journalctl --since yesterday --until today
journalctl --since '09:00'          # hoje, às 9h

Para investigar um incidente, a janela costuma ser o primeiro corte. Uma dica que economiza tempo: pegue alguns minutos antes do sintoma. A causa quase nunca está no instante em que o erro apareceu — está no que aconteceu logo antes.

Também dá para recortar por inicialização da máquina, o que é útil quando o problema é no boot:

journalctl --list-boots
journalctl -b            # o boot atual
journalctl -b -1         # o boot anterior
journalctl -b -1 -p err  # erros do boot anterior

O -b -1 é o comando que responde "por que a máquina caiu ontem?" — ele mostra o que foi registrado antes do desligamento, que se perde se você só olhar o boot atual.

Prioridade: separar ruído de problema

journalctl -p err                 # err e mais graves
journalctl -p warning..err        # faixa
journalctl -u meuapp -p err -b

Os níveis vão de emerg (0) a debug (7). Na prática, -p err é o corte que transforma milhares de linhas em algumas dezenas.

Vale saber que o nível depende de a aplicação registrar corretamente. Muito programa manda tudo para a saída padrão, e o journald classifica tudo como info — nesse caso o filtro por prioridade não ajuda, e a solução é a aplicação usar o nível certo.

Combinando janela, unidade e prioridade, chega-se rápido ao essencial:

journalctl -u meuapp --since '1 hour ago' -p warning --no-pager

O --no-pager evita o paginador quando você quer a saída direta, para canalizar para outro comando.

Seguir ao vivo, com filtro

journalctl -f -u meuapp
journalctl -f -u nginx -u php8.3-fpm     # duas unidades juntas
journalctl -f -p err                     # só erro, de tudo

Acompanhar duas unidades relacionadas ao mesmo tempo é subestimado. Ver nginx e php-fpm lado a lado mostra a sequência real — a requisição chegou, o backend demorou, o proxy desistiu — que fica invisível olhando um log de cada vez.

Para reproduzir um problema, o padrão que funciona é abrir o acompanhamento em uma sessão, disparar a ação em outra, e ler o que apareceu.

Saída estruturada, quando o olho não dá conta

journalctl -u meuapp -o json-pretty -n 5
journalctl -u meuapp -o json --since '1 hour ago' | \
  python3 -c "
import json,sys,collections
c=collections.Counter()
for l in sys.stdin:
    d=json.loads(l)
    c[d.get('MESSAGE','')[:60]] += 1
for m,n in c.most_common(15): print(f'{n:5}  {m}')
"

Esse agrupamento por mensagem é o mesmo raciocínio descrito no artigo sobre triagem de log com LLM: contar assinaturas revela padrão que a leitura linha a linha não revela, e custa nada.

Outros formatos úteis:

journalctl -o cat        # só a mensagem, sem prefixo
journalctl -o short-iso  # data em ISO, boa para ordenar

O -o cat é o que você quer ao canalizar para outra ferramenta, porque remove timestamp e nome de unidade que atrapalhariam a análise.

Investigar um incidente, na prática

Uma sequência que funciona bem quando algo aconteceu e você não sabe o quê:

# 1. Panorama de erros na janela
journalctl --since '14:00' --until '15:00' -p err --no-pager | head -50

# 2. O que reiniciou nesse período
journalctl --since '14:00' -u '*' -p notice --no-pager | grep -i -E 'start|stop'

# 3. O kernel viu alguma coisa?
journalctl -k --since '14:00' --no-pager

# 4. Alguém entrou ou executou sudo
journalctl --since '14:00' _COMM=sshd _COMM=sudo --no-pager

O passo 3 é o mais esquecido e o que mais explica sumiço inesperado: OOM killer, disco com erro e problema de rede aparecem no log do kernel, não no da aplicação. O artigo sobre o OOM killer detalha como ler essas mensagens.

O passo 4 responde a pergunta desconfortável mas necessária: alguém mexeu?

Espaço e retenção

O journal tem limite próprio e o padrão é generoso demais — até 10% do disco:

journalctl --disk-usage
# /etc/systemd/journald.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
MaxRetentionSec=30day
sudo systemctl restart systemd-journald

O Storage=persistent merece atenção: sem ele, em algumas configurações o journal fica só em memória e some no reinício — justamente quando você precisa saber o que aconteceu antes da máquina cair. Confira se /var/log/journal existe:

ls -d /var/log/journal 2>/dev/null || \
  echo "journal volátil — cria o diretório para persistir"

Para corte imediato quando o disco apertar:

sudo journalctl --vacuum-size=500M
sudo journalctl --vacuum-time=14d

O tema completo de espaço está no artigo sobre disco cheio — journal sem limite é uma das causas recorrentes.

Exportar para levar embora

Quando o log precisa sair da máquina — para anexar em chamado, ou analisar com calma:

journalctl -u meuapp --since '2 hours ago' -o short-iso > /tmp/meuapp.log

# Ou o formato nativo, que preserva todos os campos
journalctl -u meuapp --since '2 hours ago' -o export | \
  gzip > /tmp/meuapp.journal.gz

Antes de enviar para qualquer lugar, vale lembrar que log costuma conter dado sensível — token em URL, e-mail, IP de usuário. Filtrar antes de compartilhar é parte da higiene, e o artigo sobre segredos no servidor traz os comandos para achar o que vazou.

Os comandos que valem memorizar

journalctl -u SERVICO -f                       # acompanhar
journalctl -u SERVICO -p err --since '1h ago'  # o que deu errado
journalctl -b -1 -p err                        # por que caiu
journalctl -k --since '30 min ago'             # o kernel viu?
journalctl _COMM=sudo --since today            # quem mexeu
journalctl --disk-usage                        # quanto ocupa

Seis comandos cobrem a maior parte das investigações. O que muda o resultado não é conhecer opções exóticas — é lembrar de olhar o log do kernel e o boot anterior, que são justamente os dois lugares onde a resposta costuma estar e que quase ninguém consulta.

Correlacionar com o que não está no journal

O journal cobre serviços do systemd e o kernel. Fica de fora o que grava em arquivo próprio — nginx, muitas aplicações, e ferramentas antigas.

Numa investigação isso importa, porque a sequência real de eventos está espalhada. Uma forma prática de juntar é normalizar o formato de tempo e mesclar por ordem:

journalctl -u meuapp --since '14:00' --until '15:00' -o short-iso --no-pager \
  > /tmp/a.log
sudo awk '{print}' /var/log/nginx/error.log > /tmp/b.log
sort -m /tmp/a.log /tmp/b.log | less

Vale um investimento maior quando isso se repete: fazer a aplicação registrar no journal em vez de em arquivo. Basta escrever na saída padrão e deixar o systemd capturar — o que já acontece automaticamente com uma unit bem escrita.

O ganho é ter tudo no mesmo lugar, com os mesmos filtros e a mesma retenção. E some uma categoria inteira de problema: log de aplicação sem rotação, que é uma das formas mais comuns de encher disco.

Se a aplicação usa formato estruturado, o journald preserva os campos quando o texto é JSON com os nomes esperados — o que permite filtrar por campo próprio da aplicação, como identificador de requisição, exatamente como se filtra por _PID.

Vale um último hábito que muda a qualidade de toda investigação futura: quando encontrar a linha que explicou um incidente, anote o comando que a encontrou. Uma lista curta de consultas que já funcionaram no seu ambiente vale mais que qualquer manual, porque ela é específica dos serviços que você opera e dos erros que eles de fato produzem.

Suba um servidor em minutos

Preço em real, suporte em português e dados no Brasil.

Criar conta