ELK Stack 重量级(Java + Elasticsearch 几个 GB 内存),
小规模团队用 Loki 更合适:
- Go 写的,单机版几百 MB 内存
- 不全文索引,只按 label 索引(像 Prometheus)
- 存储用对象存储(S3 / 本地磁盘)
- Grafana 一等公民支持,UI 体验和 Prometheus 一致
架构
节点 → promtail (agent) → Loki (中心) → Grafana
1. 装 Loki
sudo useradd -rs /bin/false loki
sudo mkdir -p /var/lib/loki /etc/loki
sudo chown -R loki:loki /var/lib/loki
curl -fsSL https://github.com/grafana/loki/releases/latest/download/loki-linux-amd64.zip \
-o /tmp/loki.zip
sudo unzip /tmp/loki.zip -d /usr/local/bin
sudo mv /usr/local/bin/loki-linux-amd64 /usr/local/bin/loki
sudo chmod +x /usr/local/bin/loki
最简单的"all-in-one"配置 /etc/loki/config.yml:
auth_enabled: false
server:
http_listen_port: 3100
common:
path_prefix: /var/lib/loki
storage:
filesystem:
chunks_directory: /var/lib/loki/chunks
rules_directory: /var/lib/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
reject_old_samples: true
reject_old_samples_max_age: 168h
systemd /etc/systemd/system/loki.service:
[Unit]
Description=Loki
After=network.target
[Service]
User=loki
ExecStart=/usr/local/bin/loki -config.file=/etc/loki/config.yml
Restart=on-failure
[Install]
WantedBy=multi-user.target
sudo systemctl enable --now loki
curl localhost:3100/ready
2. 装 promtail(每台被采集机器)
curl -fsSL https://github.com/grafana/loki/releases/latest/download/promtail-linux-amd64.zip \
-o /tmp/promtail.zip
sudo unzip /tmp/promtail.zip -d /usr/local/bin
sudo mv /usr/local/bin/promtail-linux-amd64 /usr/local/bin/promtail
sudo chmod +x /usr/local/bin/promtail
/etc/promtail/config.yml:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /var/lib/promtail/positions.yaml
clients:
- url: http://loki.example.com:3100/loki/api/v1/push
scrape_configs:
# systemd journal
- job_name: journal
journal:
max_age: 12h
labels:
job: systemd-journal
host: ${HOSTNAME}
relabel_configs:
- source_labels: ['__journal__systemd_unit']
target_label: unit
# nginx access log
- job_name: nginx
static_configs:
- targets: [localhost]
labels:
job: nginx
host: ${HOSTNAME}
__path__: /var/log/nginx/*.log
# 自定义应用日志
- job_name: myapp
static_configs:
- targets: [localhost]
labels:
job: myapp
host: ${HOSTNAME}
__path__: /var/log/myapp/*.log
systemd 类似,启动:
sudo systemctl enable --now promtail
journalctl -u promtail -n 20
3. Grafana 加数据源
Connections → Data sources → Loki
URL: http://loki.example.com:3100
4. LogQL 查询语法
# 看某 unit 的所有日志
{unit="nginx.service"}
# 多 label 过滤
{job="nginx", host="server1"} |= "500" # 含 "500"
# 排除
{job="nginx"} != "kube-probe"
# 正则匹配
{job="myapp"} |~ "ERROR|FATAL"
# JSON 日志解析后过滤
{job="myapp"} | json | level="error" | line_format "{{.timestamp}} {{.msg}}"
# 错误率 / 量
sum by (host) (rate({job="nginx"} |= "500" [5m]))
# Top N 出错的 unit
topk(5, sum by (unit) (count_over_time({job="systemd-journal"} |= "ERROR" [1h])))
|=、!=、|~、!~ 是按字符串 / 正则过滤;| json、| logfmt 是
解析。
5. 仪表盘
Grafana Explore 写 LogQL 查询;满意了用 "Add to dashboard" 保存。
社区仪表盘:搜 "Loki" 在 grafana.com/dashboards,有 nginx / docker /
k8s 现成版本。
6. 告警(log-based alerting)
rules/myapp.yml (Loki rule):
groups:
- name: myapp-alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate({job="myapp"} |~ "ERROR|FATAL" [5m])) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: 'myapp 错误率高'
Loki 内置 Ruler 跑这个规则,触发告警发给 Alertmanager(同 Prometheus 那套)。
7. retention / 存储
limits_config:
retention_period: 30d # 全局 30 天
per_stream_retention:
- selector: '{job="audit"}'
period: 1y # audit 日志保留 1 年
底层用 chunks(默认 filesystem)。生产建议 S3 / GCS:
common:
storage:
s3:
bucketnames: my-loki-logs
region: us-east-1
按需 prune 老 chunks 来控制成本。
8. JSON 结构化日志(推荐)
应用直接输出 JSON 日志:
import structlog
log = structlog.get_logger()
log.info('user signed up', user_id=42, plan='pro')
# {"event": "user signed up", "user_id": 42, "plan": "pro", "level": "info"}
Loki 里 {job="myapp"} | json | user_id="42" 直接过滤字段。
不要在 label 上加 user_id 这种高基数的 —— 用 query-time | json filter。
9. 资源占用
Loki + Promtail 在 4 core / 8GB 机器上能处理 100k logs/sec 或 5GB/day。
比 ES 节省 5-10x 资源。
10. 与 Prometheus 互补
Prometheus = 时序指标(数字)
Loki = 日志(文本)
同一仪表盘里:上面是请求数(Prom),下面是错误日志(Loki)。
按时间对齐看故障。
踩过的坑
- promtail 没权限读
/var/log/...:默认 root 才读;要么 user=root
跑 promtail,要么把日志 chmod。 - label cardinality:跟 Prometheus 一样,label 取 user_id 把 Loki 拖死。
日志的"高基数"信息应该在 line 里(用| json解析),不该在 label 上。 - 时区:Loki 内部 UTC;UI 按浏览器时区显示。日志原文里的时间戳格式不一
时需要pipeline_stages解析 timestamp。 - "all-in-one" 配置不适合多副本 / HA。生产规模上去后拆成 distributor /
ingester / querier 三类组件。
登录后参与评论。