server: http_listen_port: 9080 grpc_listen_port: 0 log_level: warn positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push batchwait: 1s batchsize: 1048576 timeout: 10s scrape_configs: # ─── Docker container log collection (Mac-compatible via Docker socket API) ─ - job_name: docker docker_sd_configs: - host: unix:///var/run/docker.sock refresh_interval: 5s filters: # Only collect containers with label: logging=promtail # Add this label to backend and frontend in docker-compose.dev.yml - name: label values: ['logging=promtail'] relabel_configs: # Use docker-compose service name as the "service" label - source_labels: ['__meta_docker_container_label_com_docker_compose_service'] target_label: service # Keep container name for context - source_labels: ['__meta_docker_container_name'] regex: '/?(.*)' replacement: '${1}' target_label: container # Log stream (stdout / stderr) - source_labels: ['__meta_docker_container_log_stream'] target_label: stream pipeline_stages: # Drop entries older than 15 min to avoid replaying full container log history - drop: older_than: 15m drop_counter_reason: entry_too_old # Drop noisy health-check / ping lines - drop: expression: 'GET /(health|metrics|minio/health)' # Try to parse JSON (NestJS/pino output) - json: expressions: level: level msg: msg context: context reqId: reqId # Promote parsed fields as Loki labels - labels: level: context: # Map pino numeric levels to strings - template: source: level template: >- {{ if eq .Value "10" }}trace{{ else if eq .Value "20" }}debug{{ else if eq .Value "30" }}info{{ else if eq .Value "40" }}warn{{ else if eq .Value "50" }}error{{ else if eq .Value "60" }}fatal{{ else }}{{ .Value }}{{ end }} - labels: level: