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
        建议: 请结合业务日志分析根本原因

 

posted @ 2026-07-24 16:07  追梦$少年  阅读(23)  评论(0)    收藏  举报