Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

01 - journalctl (filtros, desde, seguir)

video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

1. Arquitetura de Acesso e Leitura Mapeada (mmap)

O journalctl distingue-se dos leitores de texto clássicos (como less, grep ou tail) por não realizar operações de leitura sequencial ingênua (read() tradicional) sobre arquivos de texto.

Quando o administrador executa o journalctl, o utilitário invoca internamente a API sd-journal fornecida pela biblioteca libsystemd. O processo de acesso aos dados ocorre em dois modos de operação, definidos pelo nível de privilégio da chamada:

  1. Acesso Direto por Mapeamento de Memória (mmap): Se o usuário possui privilégios de leitura direta sobre os arquivos contidos em /var/log/journal/<machine-id>/ ou /run/log/journal/<machine-id>/ (seja como root ou membro do grupo systemd-journal), o journalctl mapeia os arquivos binários .journal diretamente no espaço de endereçamento virtual do processo via chamada de sistema mmap(). Isso permite navegar pelas árvores B+ internas e tabelas de hash do arquivo sem incorrer na sobrecarga de copiar blocos de dados do espaço de kernel para o espaço de usuário através de chamadas I/O convencionais.
  2. Acesso Intermediado por IPC (D-Bus): Se executado por um usuário sem permissões de leitura direta no sistema de arquivos, mas autorizado pelas políticas do Polkit, o journalctl estabelece uma conexão via D-Bus com o systemd-journald para solicitar as entradas de log serializadas, atuando como um cliente RPC (Remote Procedure Call).

Como o arquivo binário do journal mantém índices em tabela de hash ordenados temporal e semanticamente, o journalctl pode saltar diretamente para a posição exata de uma entrada de log em tempo constante $O(1)$ ou logarítmico $O(\log N)$, sem precisar descompactar ou parsear o arquivo desde a primeira linha.


2. O Motor de Filtragem por Campos (Field Matching) e Álgebra Booleana

A filtragem no journalctl opera sobre o dicionário de chaves e valores (Key-Value Pair) gravado nativamente em cada entrada do banco de dados binário. A sintaxe de linha de comando implementa uma álgebra booleana estrita para combinar predicados de busca.

2.1. Injeção de Predicados e Igualdade

Qualquer argumento passado na forma CAMPO=valor instrui a API sd-journal a consultar as tabelas de hash de índice associadas àquele campo específico.

Exemplo de campos estruturados de alta cardinalidade:

  • _SYSTEMD_UNIT=nome.service: Restringe a busca às entradas originadas pelo cgroup atrelado àquela unidade.
  • _PID=1234: Filtra eventos produzidos estritamente pelo PID 1234.
  • _UID=1000: Filtra eventos de processos executados pelo UID de usuário 1000.
  • _COMM=sshd: Filtra pelo nome do processo no espaço do kernel (campo comm do objeto task_struct).
  • PRIORITY=3: Filtra mensagens pelo nível de severidade Syslog (0=Emergência, 3=Erro, 6=Info, 7=Debug).
  • SYSLOG_FACILITY=4: Filtra pela facilidade de origem (ex: 4 = auth/security).

2.2. Lógica Combinatória (AND vs OR)

A combinação de múltiplos argumentos de filtragem obedece às seguintes regras lógicas de ordenamento:

  • Operação AND (Conjunção Implícita): A inclusão de campos distintos na mesma linha de comando é processada como um AND lógico.
journalctl _SYSTEMD_UNIT=sshd.service _UID=0 PRIORITY=3

Resultado: Retorna apenas logs gerados pelo sshd.service E disparados pelo usuário root (UID 0) E com prioridade de erro (3).
* Operação OR (Disjunção Explícita via Operador +): Para realizar uniões lógicas entre campos ou valores diferentes, utiliza-se o caractere + isolado como delimitador.

journalctl _SYSTEMD_UNIT=httpd.service + _SYSTEMD_UNIT=nginx.service

Resultado: Retorna entradas onde a unidade é httpd.service OU nginx.service.
* Expressões Mistas: É possível compor grupos complexos combinando conjuntos interseccionados.

journalctl _SYSTEMD_UNIT=nginx.service _PID=5000 + _SYSTEMD_UNIT=php-fpm.service

Resultado: (Nginx AND PID 5000) OR (PHP-FPM).

2.3. Atalhos Sintáticos (-u, -g, -p)

O journalctl provê flags utilitárias que envelopam pesquisas de campos comuns:

  • -u nginx.service (ou --unit=): Abreviação para _SYSTEMD_UNIT=nginx.service.
  • -p err (ou --priority=): Filtra por prioridade. Permite passar nomes ou números, suportando faixas (ex: -p warning..err busca entre o nível 4 e 3).
  • -g "expressao" (ou --grep=): Aplica um mecanismo de busca por expressão regular (PCRE2) sobre o campo MESSAGE=. Nota de Desempenho: Ao contrário dos filtros de campo indexados que usam a tabela de hash, o --grep exige que o journalctl descompacte a string de mensagem de cada entrada que já passou pelos filtros de campo, revertendo parcialmente a busca para $O(N)$ sobre o subconjunto filtrado.

3. Delimitação Temporal e Paginação Robusta por Cursores

A navegação no tempo é um dos pilares do journalctl. Como o journal armazena internamente dois timestamps distintos para cada mensagem — o Realtime Clock (Wall Clock) e o Monotonic Clock do kernel —, o utilitário oferece precisão absoluta mesmo em cenários onde o relógio da máquina sofreu saltos drásticos por sincronização NTP ou alteração manual.

3.1. Filtros de Intervalo Temporal (--since e --until)

As flags -S (--since) e -U (--until) aceitam especificadores de tempo em múltiplos formatos:

  1. Formatos Absolutos (ISO 8601):
    journalctl --since "2026-10-14 08:00:00" --until "2026-10-14 10:30:00"
  2. Formatos Relativos:
    journalctl --since "1 hour ago" ou journalctl --since "2 days ago"
  3. Marcadores de Sistema:
    journalctl --since "yesterday" ou journalctl --since "today"

3.2. Escopo por Ciclo de Inicialização (-b / --boot)

Em vez de depender de datas, o administrador pode restringir a busca a um ciclo de execução específico do sistema operacional utilizando o campo _BOOT_ID.

  • journalctl -b: Exibe logs do boot atual (equivalente a filtrar pelo _BOOT_ID corrente).
  • journalctl -b -1: Exibe logs do boot imediatamente anterior.
  • journalctl -b -2: Exibe logs de dois reboots atrás.
  • journalctl -b 8f5a4e3...: Exibe logs de um _BOOT_ID específico de 128 bits.

3.3. Paginação Imutável baseada em Cursores (--cursor)

A navegação por número de linha (ex: OFFSET 100) é inerentemente instável em um banco de dados de logs concorrente de alta gravação, pois novos registros alteram os índices numéricos continuamente. O systemd-journald resolve isso emitindo uma string opaca denominada Cursor para cada registro individual.

Um cursor é gerado concatenando a assinatura do registro:
s=3f1b2c...;i=2c4;b=8f5a...;m=1a2b...;t=5c3d...;x=8e7f...

Essa estrutura encapsula:

  • s (Sequential Number): O número de sequência global da mensagem.
  • i (Inode / Entry Array Index): O índice interno dentro do arquivo .journal.
  • b (Boot ID): O UUID do boot.
  • m (Monotonic Timestamp): O tempo em microssegundos desde o início do boot.
  • t (Realtime Timestamp): O tempo em microssegundos desde a Época Unix.

O uso da flag --cursor="s=..." instrui o journalctl a buscar a posição exata daquela estrutura de dados na árvore do arquivo, independente do relógio ter sido alterado. As aplicações de monitoramento de terceiros gravam a string do último cursor processado em disco (--cursor-file=arquivo.txt) para garantir a retoma da leitura sem perda nem duplicidade de eventos caso o processo coletor seja interrompido subitamente.


4. Acompanhamento de Fluxo em Tempo Real via Kernel Inotify (--follow)

A funcionalidade de acompanhamento contínuo da cauda do log (journalctl -f ou --follow) replica o comportamento histórico do tail -f, mas opera sobre o ecossistema de eventos do kernel Linux.

Mecânica Interna da Flag -f:

  1. Posicionamento Inicial: O journalctl lê os últimos 10 registros (ou o valor especificado pela flag -n / --lines=) navegando retrogradamente a partir do final da árvore do arquivo.
  2. Registro de Evento inotify: O processo invoca a chamada de sistema inotify_init() e adiciona um monitor (inotify_add_watch()) no diretório onde os arquivos .journal residem (/var/log/journal/<machine-id>/). Ele escuta eventos do tipo IN_MODIFY e IN_CREATE.
  3. Espera Bloqueante (Poll/Epoll): O journalctl entra em um laço de espera não-ocupativa (epoll_wait()), consumindo 0% de CPU enquanto nenhum novo dado é gravado no disco pelo systemd-journald.
  4. Despertar e Rotação Dinâmica: Quando o systemd-journald executa a chamada write() ou mmap_write() adicionando uma nova entrada no arquivo ativo, o kernel dispara o evento IN_MODIFY. O journalctl acorda, lê o novo trecho utilizando a estrutura indexada do cursor atual, atualiza seu ponteiro interno e imprime a linha na tela. Se o journal sofrer rotação (o arquivo ativo é fechado como .journal~ e um novo .journal é criado), a API intercepta o evento IN_CREATE e altera silenciosamente os descritores de arquivo monitorados sem interromper o fluxo de saída no terminal do usuário.

5. Serialização de Saída e Formatos de Exportação (-o / --output)

O journalctl possui um compilador de formatação interna que lê as estruturas de dicionário da libsystemd e as serializa em variados formatos de apresentação via flag -o (ou --output=):

Formato Comportamento Arquitetural e Estrutural
short (Padrão) Formato Syslog clássico em linha única (Mon DD HH:MM:SS host service[PID]: mensagem).
short-precise Idêntico ao short, mas exibe o timestamp com precisão de microssegundos (essencial para debugging de concorrência).
json Serializa o dicionário completo de cada entrada em um objeto JSON válido por linha (formato JSON Lines / ndjson). Transforma todos os campos internos (_SYSTEMD_UNIT, _PID, etc.) em chaves de primeiro nível.
json-pretty Formatador de exibição humana do JSON, identado e espaçado. Ineficiente para pipelines de texto, mas ideal para inspeção de campos raros.
cat Limpa absolutamente todos os metadados, timestamps, nomes de host e PIDs, emitindo estritamente o texto bruto contido dentro do campo MESSAGE=.
export Formato binário/texto nativo da suíte systemd (Systemd Journal Export Format). Preserva a integridade dos tipos primitivos e blocos binários. É o formato utilizado pelo comando systemd-journal-remote para streaming de logs via rede HTTP/HTTPS.
verbose Exibe a estrutura chave-valor completa do registro no formato de bloco legível, exibindo hash de integridade, offsets de inode e flags do FSS.

Exemplo de saída utilizando o formato json:

{
  "__CURSOR": "s=3f1b2c...;i=2c4;b=8f5a...",
  "__REALTIME_TIMESTAMP": "1791888000000000",
  "__MONOTONIC_TIMESTAMP": "123456789",
  "_BOOT_ID": "8f5a4e3c2b1a0987654321fedcba0987",
  "_SYSTEMD_UNIT": "sshd.service",
  "_PID": "2045",
  "_UID": "0",
  "_COMM": "sshd",
  "MESSAGE": "Accepted publickey for root from 192.168.1.50 port 54321 ssh2",
  "PRIORITY": "6"
}


6. Análise de Desempenho e Custo Computacional das Consultas

Compreender o custo de execução das chamadas no journalctl é vital para a escrita de automações que não causem exaustão de I/O em servidores sob alta carga.

+-----------------------------------------------------------------------+
|                Estratégia de Busca e Custo de I/O                     |
+-----------------------------------------------------------------------+
|                                                                       |
|  1. Filtro por Campo Indexado (_SYSTEMD_UNIT=, _PID=, _UID=)           |
|     [Tabela Hash / Árvore B+] ---> Busca O(1) a O(log N)               |
|     (Desempenho Extremo - Acesso Direto aos Blocos Indexados)          |
|                                                                       |
|  2. Filtro Temporal (--since, --until, -b)                            |
|     [Busca Binária sobre Timestamps Monotônicos/Realtime]             |
|     (Desempenho Alto - Descarta Arquivos Inteiros Fora do Intervalo)   |
|                                                                       |
|  3. Filtro por Expressão Regular / Texto Bruto (-g / --grep)          |
|     [Varredura Sequencial + Descompactação de Mensagens]              |
|     (Custo Elevado - Requer Leitura Exaustiva O(N) do Subconjunto)    |
|                                                                       |
+-----------------------------------------------------------------------+

Regras de Otimização de Consultas:

  1. Sempre aplique restrições de campo antes de expressões regulares: Rodar journalctl -g "error" força o sistema a ler e descompactar a mensagem de todas as entradas gravadas no disco. Rodar journalctl -u app.service -g "error" reduz a busca por regex estritamente ao subconjunto de entradas previamente indexadas daquela unidade.
  2. Combine limites temporais com cursores em pipelines automatizados: Evite ler o arquivo do início continuamente. O utilitário que consome logs deve gravar o __CURSOR da última linha lida e passar --cursor="..." na invocação subsequente.
  3. Evite a conversão para texto se o destino for outro utilitário systemd: Ao transferir logs entre máquinas através da rede, utilize journalctl -o export em conjunto com o systemd-journal-remote. Isso evita a sobrecarga de serializar dados em texto no remetente para desparsear o texto no destino, mantendo a integridade binária dos metadados através do pipeline de transporte.