Loki + Grafana: logs centralizados na VPS

    Grafana Loki é o "Prometheus para logs" — armazena apenas os metadados (labels) dos logs com índices, mantendo o texto bruto comprimido em storage. É 10× mais econômico que o Elasticsearch para a maioria dos casos de uso. Integrado ao Grafana que você já tem, centraliza logs de todos os containers e serviços em um único painel.

    Instalar Loki com Docker Compose

    Stack completa com Loki, Promtail e Grafana:

    yaml
    # docker-compose.yml
    services:
      loki:
        image: grafana/loki:latest
        restart: always
        ports:
          - "127.0.0.1:3100:3100"
        command: -config.file=/etc/loki/local-config.yaml
        volumes:
          - loki_data:/loki
          - ./loki-config.yaml:/etc/loki/local-config.yaml
    
      promtail:
        image: grafana/promtail:latest
        restart: always
        volumes:
          - /var/log:/var/log:ro
          - /var/lib/docker/containers:/var/lib/docker/containers:ro
          - ./promtail-config.yaml:/etc/promtail/config.yaml
        command: -config.file=/etc/promtail/config.yaml
    
      grafana:
        image: grafana/grafana:latest
        restart: always
        ports:
          - "127.0.0.1:3000:3000"
        environment:
          GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
        volumes:
          - grafana_data:/var/lib/grafana
    
    volumes:
      loki_data:
      grafana_data:

    Configurar Promtail para coletar logs

    promtail-config.yaml para ler logs do Docker e do sistema:

    yaml
    # promtail-config.yaml
    server:
      http_listen_port: 9080
    
    positions:
      filename: /tmp/positions.yaml
    
    clients:
      - url: http://loki:3100/loki/api/v1/push
    
    scrape_configs:
      # Logs de containers Docker:
      - job_name: docker
        docker_sd_configs:
          - host: unix:///var/run/docker.sock
            refresh_interval: 5s
        relabel_configs:
          - source_labels: ['__meta_docker_container_name']
            target_label: container
          - source_labels: ['__meta_docker_container_log_stream']
            target_label: stream
          - source_labels: ['__meta_docker_compose_service']
            target_label: service
    
      # Logs do Nginx:
      - job_name: nginx
        static_configs:
          - targets: [localhost]
            labels:
              job: nginx
              __path__: /var/log/nginx/*.log
    
      # Logs do sistema (auth, syslog):
      - job_name: system
        static_configs:
          - targets: [localhost]
            labels:
              job: system
              __path__: /var/log/{auth,syslog}.log

    Queries LogQL no Grafana

    Pesquisar e filtrar logs com a linguagem LogQL:

    bash
    # LogQL — sintaxe similar ao PromQL
    
    # Todos os logs de um container:
    {container="minha-api-app-1"}
    
    # Filtrar por texto (grep):
    {container="minha-api-app-1"} |= "ERROR"
    
    # Excluir linha:
    {job="nginx"} != "health"
    
    # Parsear JSON estruturado e filtrar por campo:
    {container="minha-api"} | json | level="error"
    
    # Parsear log do Nginx (logfmt):
    {job="nginx"} | logfmt | status >= 500
    
    # Contar erros por minuto (métrica a partir de log):
    rate({container="minha-api"} |= "ERROR" [1m])
    
    # Top 10 IPs com mais erros 500:
    topk(10,
      sum by (remote_addr) (
        rate({job="nginx"} | logfmt | status=~"5.." [5m])
      )
    )
    
    # No Grafana — Explore → Loki → inserir query LogQL
    # Ou criar dashboard com painéis de log

    Configurar alertas baseados em logs

    Alertar quando padrão de erro aparece nos logs:

    yaml
    # No Grafana — Alerting → Alert Rules → New rule
    # Usar Loki como data source
    
    # Exemplo: alertar quando > 10 erros 500 em 5 min:
    # Query:
    sum(rate({job="nginx"} | logfmt | status=~"5.." [5m])) > 0.033
    
    # Ou via arquivo de regras do Loki (ruler):
    # loki-config.yaml — adicionar:
    ruler:
      storage:
        type: local
        local:
          directory: /loki/rules
      rule_path: /loki/rules
      alertmanager_url: http://alertmanager:9093
    
    # /loki/rules/default/rules.yaml:
    groups:
      - name: api-errors
        rules:
          - alert: HighErrorRate
            expr: |
              sum(rate({container="minha-api"} |= "ERROR" [5m])) > 1
            for: 2m
            labels:
              severity: warning
            annotations:
              summary: "Taxa de erros alta na API"
    Dica
    Loki precisa de acesso ao socket Docker (/var/run/docker.sock) no Promtail para descoberta automática de containers. Adicione o volume no compose do Promtail.

    Enviar logs da aplicação diretamente ao Loki

    Integrar Node.js com Loki via Pino ou Winston:

    typescript
    // npm install pino pino-loki
    
    import pino from 'pino'
    
    const logger = pino({
      transport: {
        targets: [
          // Console (desenvolvimento):
          { target: 'pino-pretty', level: 'debug', options: {} },
          // Loki (produção):
          {
            target: 'pino-loki',
            level: 'info',
            options: {
              host: 'http://localhost:3100',
              labels: {
                app: 'minha-api',
                env: process.env.NODE_ENV,
              },
              // Enriquecer com campos do log como labels:
              propsToLabels: ['level', 'service'],
              // Intervalo de envio em batch (ms):
              interval: 5,
            },
          },
        ],
      },
    })
    
    // Usar o logger na aplicação:
    logger.info({ userId: '123', route: '/api/pedidos' }, 'Pedido criado')
    logger.error({ err: error, userId: '123' }, 'Falha ao processar pedido')
    
    // Os logs aparecem automaticamente no Grafana Explore → Loki

    $ runstack deploy --plan starter

    Não quer configurar manualmente?

    Não quer configurar manualmente? Implante o VPS em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.

    Perguntas frequentes