loki 日志监控
1、创建目录
#loki数据目录
sudo mkdir -p /data/promthues/loki/loki-data
#采集agent 目录
sudo mkdir -p /data/promthues/loki/promtail/data
#存放告警规则目录
sudo mkdir -p /data/promthues/loki/loki-data/rules/fake
#告警规则临时目录
sudo mkdir -p /data/promthues/loki/loki-data/rules-temp
2、创建compose.yml
cat docker-compose.yml
services:
loki:
image: grafana/loki:3.7.8
container_name: loki
ports:
- "3100:3100"
volumes:
- ./loki-config.yaml:/etc/loki/loki-config.yaml:ro
- ./loki-data:/loki
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command:
- -config.file=/etc/loki/loki-config.yaml
- -target=all
- -log.level=info
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
restart: unless-stopped
networks:
- loki-net
promtail:
image: grafana/promtail:latest
container_name: promtail
# ports:
# - "9080:9080"
volumes:
- ./promtail-config.yaml:/etc/promtail/promtail-config.yaml:ro
- /var/log:/var/log:ro
- ./promtail-data:/var/lib/promtail
- /var/run/docker.sock:/var/run/docker.sock
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command:
- -config.file=/etc/promtail/promtail-config.yaml
restart: unless-stopped
depends_on:
- loki
networks:
- loki-net
networks:
loki-net:
name: loki-net
driver: bridge
ipam:
config:
# ★ 如果不空闲,把下面两行换成验证通过的那个网段即可
- subnet: 10.99.0.0/24
gateway: 10.99.0.1
3、编辑 loki-config.yaml
cat loki-config.yaml
# ==========================================================================
# Loki 单机 all-in-one 配置 —— 优化版(日志保留 2 天)
#
# 相对原配置的关键改动:
# 1. 保留策略改用 compactor 的 retention 机制(TSDB 下唯一生效的方式),
# limits_config.retention_period: 48h → 日志只保留 2 天
# 2. 删除已废弃且对 TSDB 无效的 table_manager 段(原配置里它根本不起作用)
# 3. 路径统一为 /loki/...(容器挂载点),不再混用 ./loki 与 /loki
# 4. 增加写入/查询限制与 compactor 调优,控制内存与查询开销
# 5. 关闭匿名统计上报,适配内网离线环境
#
# 版本要求:Loki 2.9+ / 3.x(delete_request_store 字段在 2.9 引入)
# ==========================================================================
auth_enabled: false
target: all
server:
http_listen_port: 3100
grpc_listen_port: 9095
log_level: info
# 单机场景放大单条消息上限,避免大查询/大日志块被截断
grpc_server_max_recv_msg_size: 8388608 # 8MB
grpc_server_max_send_msg_size: 8388608 # 8MB
# 关闭匿名使用统计上报(内网离线环境建议关闭)
analytics:
reporting_enabled: false
common:
path_prefix: /loki
ring:
instance_addr: 0.0.0.0
kvstore:
store: inmemory
replication_factor: 1
schema_config:
configs:
- from: 2026-07-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
storage_config:
tsdb_shipper:
active_index_directory: /loki/tsdb-index
cache_location: /loki/tsdb-cache
filesystem:
directory: /loki/chunks
ingester:
wal:
enabled: true
dir: /loki/wal
# 单机可适当拉长 chunk 空闲时间,减少小 chunk 数量、降低对象存储压力
chunk_idle_period: 30m
chunk_block_size: 262144
chunk_encoding: snappy
lifecycler:
ring:
kvstore:
store: inmemory
replication_factor: 1
final_sleep: 0s
# ------------------------------------------------------------------
# 保留策略执行者:必须开启 retention_enabled,否则 48h 不会真正删除
# ------------------------------------------------------------------
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true # 关键开关
delete_request_store: filesystem # Loki 2.9+ 必填,否则启动报错
retention_delete_delay: 2h # 删除请求落盘后延迟 2h 再物理删除
retention_delete_worker_count: 150
limits_config:
# >>> 日志只保留 2 天 <<<
retention_period: 48h
# 查询回溯上限,避免扫描已过期数据、降低查询成本
max_query_lookback: 48h
# 拒绝写入过旧样本
reject_old_samples: true
reject_old_samples_max_age: 48h
# 写入限流(按实际日志量微调)
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
# 查询保护,防止大范围查询打爆单机内存
max_query_series: 5000
max_query_parallelism: 32
split_queries_by_interval: 1h
query_timeout: 5m
# 已废弃:TSDB + compactor 场景下 table_manager 对保留策略无效,故注释掉
# (原配置里的 retention_period: 48h 放在这里是不生效的)
# table_manager:
# retention_deletes_enabled: true
# retention_period: 48h
ruler:
storage:
type: local
local:
directory: /loki/rules
rule_path: /loki/rules-temp
alertmanager_url: http://10.10.0.28:9093
enable_api: true
enable_alertmanager_v2: true
# 单机本地运行,限制并发查询数避免资源争抢
querier:
max_concurrent: 4
4、创建采集promtail-config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0
log_level: info
positions:
filename: /var/lib/promtail/positions.yaml
sync_period: 10s
clients:
- url: http://10.10.0.28:3100/loki/api/v1/push
batchwait: 1s # 默认 1s;★ 无下划线
batchsize: 1048576 # 默认 1048576 (1MB);★ 无下划线
timeout: 10s
backoff_config:
min_period: 500ms
max_period: 5m
max_retries: 10
scrape_configs:
# ====================================================================== #
# 一、Ubuntu 系统日志(syslog 格式) #
# ====================================================================== #
- job_name: ubuntu_system_logs
static_configs:
- targets:
- localhost
labels:
job: auth_log
host: "10.10.0.28"
department: "总部"
log_type: auth
__path__: /var/log/auth.log
- targets:
- localhost
labels:
job: kernel_logs
host: "10.10.0.28"
department: "总部"
log_type: kernel
# O4:kern.log 是 syslog 格式且持续写入;若该主机只跑 journald 没有 kern.log,
# 请改回 /var/log/dmesg 或改用 journald 采集方式。
__path__: /var/log/kern.log
pipeline_stages:
# ① 解析 syslog 头部:时间 / 主机 / 程序 / PID / 消息(syslog 时间不含年份)
- regex:
expression: '^(?P<timestamp>\w{3}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})\s+(?P<hostname>\S+)\s+(?P<program>[\w\-\/]+)(?:\[(?P<pid>\d+)\])?:\s*(?P<message>.*)$'
# ② O7:用日志自身的时间替换采集时间。
# promtail 对不含年份的 layout 会自动补当前年,并正确处理跨年零点。
# action_on_failure=fudge:解析失败则沿用采集时间,不会丢日志。
- timestamp:
source: timestamp
format: "Jan _2 15:04:05"
location: Asia/Shanghai
action_on_failure: fudge
# ③ 按 log_type 分别提取 level
# ★ Bug 1 修复处:selector 必须与上面的标签值完全一致
- match:
selector: '{log_type="auth"}'
stages:
- regex:
expression: '(?i)\b(?P<level>failed|failure|invalid|error|warning|critical|accepted)\b'
- labels:
level:
- match:
selector: '{log_type="kernel"}'
stages:
- regex:
expression: '(?i)\b(?P<level>error|failed|failure|panic|critical|oom|segfault|call trace)\b'
- labels:
level:
# ====================================================================== #
# 二、Docker 容器日志 #
# ====================================================================== #
- job_name: docker_container_logs
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 30s
# O3:只采集运行中的容器,避免已停止容器的历史日志被反复扫到
filters:
- name: status
values: [running]
relabel_configs:
# 容器名称
- source_labels:
- __meta_docker_container_name
regex: '/(.*)'
target_label: container
# 镜像名称
- source_labels:
- __meta_docker_container_image
target_label: image
# 容器 ID
- source_labels:
- __meta_docker_container_id
target_label: container_id
# 可选:若 container_id 基数压力大,可只保留 12 位短 ID(与 docker ps 一致)。
# 注意:现有面板/LogQL 若按完整 64 位 ID 过滤会失效,改前先确认。
# - source_labels:
# - __meta_docker_container_id
# regex: '(.{12}).*'
# target_label: container_id
# stdout / stderr
- source_labels:
- __meta_docker_container_log_stream
target_label: stream
# O3:排除监控组件自身容器,防止日志自循环(按镜像匹配,比按名字可靠)
- source_labels:
- __meta_docker_container_image
regex: '.*(grafana/loki|grafana/promtail|grafana/grafana|grafana/alloy|prom/alertmanager|prom/node-exporter)(:.*)?'
action: drop
# 固定标签
- target_label: host
replacement: "10.10.0.28"
- target_label: department
replacement: "总部"
- target_label: log_type
replacement: docker
pipeline_stages:
# ① 拆 Docker json-file 外壳:{"log":"...","stream":"...","time":"..."}
- json:
expressions:
output: log
stream: stream
timestamp: time
# ② O6:非 JSON 文本日志的 level 兜底(先执行;若下面是合法 JSON,会被精确值覆盖)
- regex:
source: output
expression: '(?i)\b(?P<level>trace|debug|info|warn|warning|error|fatal|panic|critical)\b'
# ③ ★ Bug 2 修复处:source: output 才是「两阶段 JSON 解析」
# 容器内应用自己输出的 JSON 日志(如 {"level":"error","msg":"..."})在此解析。
# drop_malformed=false(默认):非 JSON 行不会被丢弃,安全。
- json:
source: output
expressions:
level: level
msg: msg
drop_malformed: false
# ④ ★ Bug 3 修复处:使用容器内真实时间,RFC3339Nano 即 Docker 的 time 字段格式
- timestamp:
source: timestamp
format: RFC3339Nano
action_on_failure: fudge
# ⑤ 只把 level 提升为标签;msg 不建标签(避免标签基数爆炸)
- labels:
level:
# ⑥ O5:落库内容替换为剥离外壳后的 output
- output:
source: output
5、编写告警规则
cat system.yaml
groups:
- name: ubuntu_system_logs_alerts
rules:
# 1. SSH登录失败告警(来自auth.log)
- alert: SSHFailedLogin
expr: |
count_over_time(
{job="auth_logs"}
|~ "(?i)Failed password|authentication failure"
[5m]
) > 10
for: 1m
labels:
severity: 警告
category: security
annotations:
summary: "SSH登录失败次数过多"
description: |
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
日志类型: {{ $labels.log_type }}
告警内容: 过去5分钟内SSH登录失败次数超过10次(当前: {{ $value }}次),可能存在暴力破解攻击,请及时检查。
# 3. 系统内核错误告警(来自kern.log)
- alert: KernelPanic
expr: |
count_over_time(
{job="kernel_logs"}
|~ "(?i)panic|Oops|BUG:"
[1m]
) > 0
for: 1m
labels:
severity: 严重告警
category: system
annotations:
summary: "内核发生严重错误"
description: |
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
日志类型: {{ $labels.log_type }}
告警内容: 检测到内核panic/Oops/BUG错误,系统可能面临崩溃风险,请立即介入处理。
# 4. 硬件错误告警(来自kern.log)
- alert: HardwareError
expr: |
count_over_time(
{job="kernel_logs"}
|~ "(?i)hardware error|PCIe.*error|EDAC|MCE"
[1h]
) > 10
for: 2m
labels:
severity: 严重告警
category: hardware
annotations:
summary: "检测到硬件错误"
description: |
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
日志类型: {{ $labels.log_type }}
告警内容: 检测到硬件相关错误(PCIe/EDAC/MCE等),请检查服务器硬件状态。
# 5. 系统关机/重启告警(来自kern.log)
- alert: SystemReboot
expr: |
count_over_time(
{job="kernel_logs"}
|~ "(?i)system reboot|Restarting system|shutdown"
[1m]
) > 0
for: 0m
labels:
severity: 警告
category: system
annotations:
summary: "系统发生重启或关机"
description: |
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
日志类型: {{ $labels.log_type }}
告警内容: 检测到系统重启/关机事件,请确认是否为计划内操作。
# 6. 内核OOM告警(来自kern.log)
- alert: OutOfMemory
expr: |
count_over_time(
{job="kernel_logs"}
|~ "(?i)Out of memory|Kill process|oom-killer"
[2m]
) > 0
for: 1m
labels:
severity: 严重告警
category: performance
annotations:
summary: "系统发生OOM(内存溢出)"
description: |
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
日志类型: {{ $labels.log_type }}
告警内容: 检测到OOM事件,系统内存不足导致进程被终止,请检查内存使用情况。
建议: |
1、查看系统日志: journalctl -k | grep -i 'oom\|killed process'
2、查看 OOM 日志及被杀进程: dmesg -T | grep -i 'Out of memory'
# 7. 综合ERROR级别日志告警(涵盖所有日志类型)
- alert: SystemErrorLog
expr: |
count_over_time(
{job=~".+"}
|~ "(?i)error|fail|fatal"
[5m]
) > 50
for: 3m
labels:
severity: 警告
category: general
annotations:
summary: "系统ERROR日志数量过多"
description: |
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
日志类型: {{ $labels.log_type }}
告警内容: 过去5分钟内ERROR/FATAL/FAIL日志超过10条(当前: {{ $value }}条),请检查系统运行状态。
6、容器日志告警规则
groups:
- name: docker_app_logs_sy7
rules:
- alert: AppErrorRate
expr: |
count_over_time(
{log_type="docker", container!="", container!="promtail", container!="loki", container!="kibana0", host!="10.10.0.153", host!="10.10.0.68", host!="10.10.0.69", host!="10.10.0.70"}
!= "查询老师失败"
!= "插入或更新课程章节信息异常"
!= "插入或更新课程信息异常"
!= "msgprocess no rs"
!= "'failed': 0"
!= "hits"
!= "WARN"
!= "Warn"
!= "warn"
!= "communication"
!= "data/media/"
!= "CTRL-CHAR"
|~ "(?i)(error|exception|fatal|failure|panic)"
!~ `(?i)"level": *"(info|warn|warning|debug|trace)"`
[5m]
) > 35
for: 2m
labels:
severity: 警告
category: application
annotations:
summary: "应用错误日志过多"
description: |
容器: {{ $labels.container }}
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
告警内容: 过去5分钟内错误日志超过35条(当前: {{ $value }}条)
建议: 请检查应用运行状态和业务日志
# 2. Docker容器频繁重启告警(新增)
- alert: ContainerRestart
expr: |
count_over_time(
{log_type="docker", container!="loki", host!="10.10.0.68", host!="10.10.0.69", host!="10.10.0.70"}
|~ "(?i)restart|reload|stop|start"
|~ "(?i)container"
[10m]
) > 2
for: 0m
labels:
severity: 警告
category: container
annotations:
summary: "容器频繁重启"
description: |
容器: {{ $labels.container }}
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
镜像: {{ $labels.image }}
告警内容: 过去10分钟内检测到容器重启/启停操作超过2次 restart|reload|stop|start
建议: 请检查容器健康检查和OOM情况
# 3. 数据库连接失败告警(应用级)
- alert: DBConnectionFailed
expr: |
count_over_time(
{log_type="docker", container!="loki", container!="promtail", host!="10.10.0.68", host!="10.10.0.69", host!="10.10.0.70"}
|~ "(?i)connection refused|connection timeout|SQLSTATE|database down|DB error"
!~ `(?i)"level": *"(info|warn|warning|debug|trace)"`
[3m]
) > 3
for: 1m
labels:
severity: 严重告警
category: dependency
annotations:
summary: "数据库连接异常"
description: |
容器: {{ $labels.container }}
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
镜像: {{ $labels.image }}
告警内容: 检测到数据库连接失败或超时错误 出现 'connection refused|connection timeout|SQLSTATE|database down|DB error'
建议: 请检查数据库服务是否正常运行
# 4. API响应错误告警(HTTP 5xx)
- alert: Http5xxErrors
expr: |
count_over_time(
{log_type="docker", container!="loki", host!="10.10.0.68", host!="10.10.0.69", host!="10.10.0.70"}
|~ "(?i)Internal Server Error|Bad Gateway|Gateway Timeout"
!~ `(?i)"level": *"(info|warn|warning|debug|trace)"`
[5m]
) > 5
for: 2m
labels:
severity: 严重告警
category: application
annotations:
summary: "API服务返回5xx错误"
description: |
容器: {{ $labels.container }}
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
镜像: {{ $labels.image }}
告警内容: 过去5分钟内HTTP 出现Internal Server Error、Bad Gateway、Gateway Timeout
建议: 请检查应用逻辑和上游服务状态
# 6. 特定业务错误码告警(示例)
- alert: BusinessErrorCode
expr: |
count_over_time(
{log_type="docker", container!="loki", host!="10.10.0.69", host!="10.10.0.68", host!="10.10.0.70"}
|~ "(?i)错误码|errorcode|业务异常|系统异常|BadSqlGrammarException|SQLSyntaxErrorException|NullPointerException|RuntimeException"
!~ `(?i)"level": *"(info|warn|warning|debug|trace)"`
[5m]
) > 5
for: 1m
labels:
severity: 警告
category: business
annotations:
summary: "业务错误码频繁出现"
description: |
容器: {{ $labels.container }}
服务器: {{ $labels.host }}
部门: {{ $labels.department }}
镜像: {{ $labels.image }}
告警内容: 过去5分钟内出现业务错误码 |errorcode|业务异常|系统异常|BadSqlGrammarException|SQLSyntaxErrorException|NullPointerException|RuntimeException
建议: 请结合业务日志分析根本原因

浙公网安备 33010602011771号