O logging centralizado torna-se essencial no momento em que você gerencia mais de um punhado de servidores, contêineres ou microsserviços. Sem ele, depurar um incidente em produção significa conectar-se via SSH a máquinas individuais e procurar em arquivos de log dispersos. A agregação de logs com Loki, Promtail e Grafana — o stack PLG — resolve isso enviando todos os seus logs para um armazenamento único e consultável, mantendo os custos de recursos dramaticamente menores do que soluções tradicionais como o Elasticsearch.
Pré-requisitos
- Um servidor Linux (Ubuntu 22.04 ou Debian 12 recomendado) com pelo menos 2 GB de RAM
- Docker 24+ e Docker Compose v2 instalados
- Familiaridade básica com os dashboards do Grafana (ver Grafana Dashboards para Monitoramento de Infraestrutura)
- Portas 3000 (Grafana), 3100 (Loki) e 9080 (Promtail) disponíveis
- Acesso sudo na máquina host
Entendendo o Stack PLG
O stack PLG consiste em três componentes que trabalham juntos como um pipeline de observabilidade leve:
Promtail é o agente de coleta de logs. Ele é executado junto às suas aplicações, acompanha arquivos de log ou lê do journal do systemd, anexa etiquetas (metadados chave-valor) e envia streams de log ao Loki via HTTP.
Loki é o backend de agregação de logs. Ao contrário do Elasticsearch, o Loki não indexa o conteúdo do log — ele indexa apenas as etiquetas anexadas pelo Promtail. As linhas de log brutas são comprimidas e armazenadas como chunks. Essa arquitetura torna o Loki dramaticamente mais barato de executar: um cluster lidando com gigabytes de logs por dia pode funcionar com algumas centenas de megabytes de RAM.
Grafana fornece a camada de consulta e visualização. Ele se conecta ao Loki como fonte de dados e permite escrever consultas LogQL, construir dashboards e configurar alertas — tudo na mesma interface que você usa para as métricas do Prometheus (ver Configuração de Prometheus e Grafana para Monitoramento de Servidores).
O fluxo de dados é: Aplicação → arquivo de log/journal → Promtail → Loki → Grafana.
Instalando o Loki com Docker Compose
Crie um diretório de trabalho e o seguinte docker-compose.yml:
version: "3.8"
networks:
logging:
driver: bridge
volumes:
loki_data:
grafana_data:
services:
loki:
image: grafana/loki:3.0.0
container_name: loki
ports:
- "3100:3100"
volumes:
- ./loki-config.yaml:/etc/loki/loki-config.yaml
- loki_data:/loki
command: -config.file=/etc/loki/loki-config.yaml
networks:
- logging
promtail:
image: grafana/promtail:3.0.0
container_name: promtail
volumes:
- ./promtail-config.yaml:/etc/promtail/promtail-config.yaml
- /var/log:/var/log:ro
- /run/log/journal:/run/log/journal:ro
- /etc/machine-id:/etc/machine-id:ro
command: -config.file=/etc/promtail/promtail-config.yaml
networks:
- logging
depends_on:
- loki
grafana:
image: grafana/grafana:11.0.0
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=changeme
volumes:
- grafana_data:/var/lib/grafana
networks:
- logging
depends_on:
- loki
Crie loki-config.yaml no mesmo diretório:
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
limits_config:
retention_period: 30d
compactor:
working_directory: /loki/compactor
retention_enabled: true
delete_request_store: filesystem
Inicie o stack:
docker compose up -d
docker compose ps
Os três serviços devem mostrar status healthy ou running em menos de 30 segundos.
Configurando o Promtail
Crie promtail-config.yaml:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: journal
journal:
max_age: 12h
labels:
job: systemd-journal
host: ${HOSTNAME}
relabel_configs:
- source_labels: [__journal__systemd_unit]
target_label: unit
- job_name: varlogs
static_configs:
- targets:
- localhost
labels:
job: varlogs
host: ${HOSTNAME}
__path__: /var/log/*.log
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
- source_labels: [__meta_docker_container_name]
regex: "/(.*)"
target_label: container
- source_labels: [__meta_docker_container_label_com_docker_compose_service]
target_label: service
O arquivo positions rastreia até onde o Promtail leu em cada arquivo de log, evitando ingestão duplicada após reinicializações.
Reinicie o Promtail para aplicar a configuração:
docker compose restart promtail
docker compose logs promtail --tail=20
Consultando Logs com LogQL
LogQL é a linguagem de consultas do Loki, inspirada no PromQL. As consultas têm duas partes: um seletor de stream entre chaves e estágios opcionais de pipeline.
Seletor de stream básico — obter todos os logs do job varlogs:
{job="varlogs"}
Filtro de linha — encontrar linhas contendo “error”:
{job="varlogs"} |= "error"
Filtro regex — encontrar linhas que correspondam a um padrão:
{job="systemd-journal"} |~ "fail(ed)?"
Filtro de etiqueta após parsing — parsear logs JSON e filtrar por nível:
{job="varlogs"} | json | level="error"
Consulta métrica — taxa de erros ao longo do tempo:
rate({job="varlogs"} |= "error" [5m])
Contar erros por host:
sum by (host) (count_over_time({job="varlogs"} |= "error" [1h]))
Para padrões mais complexos de parsing de logs, compare com a abordagem do Journalctl para Consultar e Analisar Logs do Sistema Linux para cenários apenas locais.
Configurando Dashboards no Grafana
Abra o Grafana em http://seu-servidor:3000 e faça login com admin / changeme.
Adicionar Loki como fonte de dados:
- Vá em Conexões > Fontes de dados > Adicionar fonte de dados
- Selecione Loki
- Defina a URL como
http://loki:3100 - Clique em Salvar e testar — você deve ver “Fonte de dados conectada e etiquetas encontradas”
Criar um painel de exploração de logs:
- Crie um novo dashboard e adicione um painel
- Selecione Loki como fonte de dados
- Mude a visualização para Logs
- Insira uma consulta LogQL:
{job="varlogs"} |= "error" - Ative Deduplicação e Quebra de linha nas opções do painel
Construir um dashboard de taxa:
Adicione um painel de Séries temporais com a consulta:
sum by (host) (rate({job="varlogs"} |= "error" [5m]))
Isso fornece um gráfico de taxa de erros em tempo real dividido por servidor.
Alertas sobre Padrões de Logs
O Loki inclui um componente ruler que avalia consultas métricas LogQL em um agendamento e dispara alertas para o Alertmanager.
Adicione a configuração do ruler ao loki-config.yaml:
ruler:
storage:
type: local
local:
directory: /loki/rules
rule_path: /loki/rules-temp
alertmanager_url: http://alertmanager:9093
enable_api: true
Crie /loki/rules/fake/rules.yaml:
groups:
- name: log-alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate({job="varlogs"} |= "error" [5m])) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "Alta taxa de erros detectada nos logs do sistema"
description: "A taxa de logs de erro excedeu 0.1 linhas/seg por 5 minutos."
- alert: SSHAuthFailures
expr: |
sum(count_over_time({unit="sshd.service"} |= "Failed password" [10m])) > 10
for: 2m
labels:
severity: critical
annotations:
summary: "Múltiplas falhas de autenticação SSH"
description: "Mais de 10 falhas de auth SSH em 10 minutos — possível força bruta."
Loki vs ELK vs Graylog — Comparação
| Característica | Loki | ELK Stack | Graylog |
|---|---|---|---|
| Estratégia de indexação | Apenas etiquetas | Índice de texto completo | Índice de texto completo |
| Uso de RAM (10 GB/dia) | ~512 MB | 8–16 GB | 4–8 GB |
| Linguagem de consultas | LogQL | KQL / Lucene | GELF / Elasticsearch |
| Integração com Grafana | Nativa | Plugin necessário | Plugin necessário |
| Complexidade de configuração | Baixa | Alta | Média |
| Escalabilidade horizontal | Boa (modo microsserviços) | Excelente | Boa |
| Custo em escala | Muito baixo | Alto | Médio |
| Melhor para | Logs de Kubernetes / contêineres | Pesquisa de texto em logs | Conformidade, SIEM |
O Loki vence em custo e simplicidade quando sua principal necessidade é agregação e correlação de logs com métricas. Para uma comparação com a configuração do Elasticsearch, ver Configuração do Elasticsearch para Análise de Logs.
Cenário Real
Você gerencia 15 servidores de produção executando uma combinação de Nginx, PostgreSQL e APIs Python personalizadas. Os incidentes acontecem mas a análise de causa raiz leva horas porque os logs estão espalhados por 15 máquinas. Veja como o PLG resolve isso:
- Implante o Promtail em cada servidor usando uma ferramenta de gerenciamento de configuração (Ansible/Puppet), apontando todas as instâncias para um único endpoint do Loki.
- Adicione etiquetas
hosteenvpara que cada stream de log seja marcado com o servidor de origem e o ambiente (produção/staging). - No Grafana, crie um dashboard com uma variável
$hostvinculada aos valores da etiquetahost. Agora um único dashboard mostra logs de todos os 15 servidores, com um menu suspenso para filtrar por host. - Adicione uma regra de alerta que dispare quando qualquer host produza mais de 50 linhas de erro por minuto — você recebe notificação no Slack antes que os usuários relatem o problema.
- Durante incidentes, use a visão Explore para correlacionar logs e métricas do Prometheus lado a lado: pico de erros nos logs às 14:32 → pico de CPU no mesmo host às 14:31.
Esse fluxo de trabalho substitui uma investigação SSH manual de 45 minutos por um drill-down no Grafana de 3 minutos.
Armadilhas e Casos Especiais
Explosão de cardinalidade de etiquetas. Cada combinação única de etiquetas cria um stream de log separado. Nunca use valores de alta cardinalidade (IDs de usuário, UUIDs, IDs de requisição) como etiquetas. Mantenha as etiquetas em valores estáveis e de baixa contagem: host, job, env, service.
Configuração de retenção. O retention_period em limits_config exige que o compactor esteja habilitado com retention_enabled: true. Sem isso, o Loki armazena logs indefinidamente até que o disco seja preenchido.
Cache de chunks e memória. O Loki armazena em cache chunks não comprimidos na memória durante a ingestão. Em servidores com menos de 2 GB de RAM, defina chunk_target_size: 1048576 e max_chunk_age: 1h para limitar a pressão de memória.
Perda do arquivo de posições do Promtail. Se o contêiner do Promtail for recriado sem um volume persistente para /tmp/positions.yaml, ele relê todos os arquivos de log desde o início e ingere duplicatas. Sempre monte o arquivo de posições em um volume persistente.
Ordenação de logs. O Loki exige que as linhas de log dentro de um único stream sejam ingeridas em ordem de timestamp. Se sua aplicação escreve logs com timestamps fora de ordem, habilite unordered_writes: true na configuração do ingester do Loki.
Acesso ao socket do Docker. A configuração de Docker SD no Promtail requer acesso ao socket do Docker. O contêiner do Promtail deve ser executado como root ou adicionado ao grupo docker.
Resumo
- O stack PLG (Promtail + Loki + Grafana) fornece agregação centralizada de logs a uma fração do custo do ELK
- O Loki indexa apenas etiquetas, não o conteúdo do log — mantendo o uso de armazenamento e RAM mínimo
- Os seletores de stream LogQL (
{job="varlogs"}) mais estágios de pipeline (|= "error",| json) permitem filtragem poderosa de logs - O Promtail realiza scraping do journal do systemd, arquivos e logs de contêineres Docker com anexação automática de etiquetas
- A fonte de dados Loki do Grafana permite dashboards unificados combinando logs (Loki) e métricas (Prometheus)
- Etiquetas de alta cardinalidade são o erro de desempenho mais comum no Loki — mantenha os valores das etiquetas estáveis e de baixa contagem
- As regras de alertas do Loki usam consultas métricas LogQL avaliadas pelo componente ruler