排查 Flashduty monitor 监控告警 - 数据不符合预期的场景

巴辉特 2025-12-19 21:58:45

问题说明

用户收到了 Flashduty monitor 监控告警,但是认为数据不符合预期,想要排查具体原因。本文侧重讲解 Prometheus 类型的数据源。

原理说明

Flashduty monitor 会周期性查询时序库(比如 Prometheus)中的监控数据,调用的是 /api/v1/query 接口(Prometheus 原生告警引擎也是这个逻辑),如果使用 Grafana 查看折线图数据,可能会发现数据不符合预期,通常原因是时序库的 query lookback 参数导致的。

咱们也可以不关心具体原理,就直接模仿 Flashduty monitor 的查询方式,去查询告警的时候的数据,看看结果是否符合预期即可。

排查脚本

下面用 AI 生成了一个 Python 脚本,可以用来查询:

import requests
import argparse
import time
from datetime import datetime, timezone, timedelta

promql = """mem_available_percent"""

def cst_to_unix(cst_str):
    """将东八区时间字符串转换为 Unix 时间戳"""
    tz_cst = timezone(timedelta(hours=8))
    cst_str = cst_str.replace('T', ' ')
    dt = datetime.strptime(cst_str, '%Y-%m-%d %H:%M:%S')
    dt_cst = dt.replace(tzinfo=tz_cst)
    return int(dt_cst.timestamp())

def unix_to_cst_str(ts):
    """将 Unix 时间戳转换回人类易读的东八区时间字符串"""
    tz_cst = timezone(timedelta(hours=8))
    dt = datetime.fromtimestamp(ts, tz=tz_cst)
    return dt.strftime('%Y-%m-%d %H:%M:%S')

def main():
    parser = argparse.ArgumentParser(description="Prometheus Query Tool (SRE Debug Version)")
    parser.add_argument("--prometheus_url", required=True, help="Prometheus base URL")
    parser.add_argument("--start_time", required=True, help="Start time in CST (e.g., '2023-10-01 08:00:00')")
    parser.add_argument("--end_time", required=True, help="End time in CST (e.g., '2023-10-01 08:10:00')")
    # 第四个参数:步长
    parser.add_argument("--step", type=int, default=15, help="Step in seconds (default: 15)")
    
    args = parser.parse_args()

    try:
        start_ts = cst_to_unix(args.start_time)
        end_ts = cst_to_unix(args.end_time)
    except ValueError as e:
        print(f"Time format error: {e}. Please use 'YYYY-MM-DD HH:MM:SS'")
        return

    api_endpoint = f"{args.prometheus_url.rstrip('/')}/api/v1/query"

    current_ts = start_ts
    print(f"\nQuerying: {args.start_time} to {args.end_time} with step {args.step}s\n")
    
    while current_ts <= end_ts:
        # 获取人类易读的时间字符串
        readable_time = unix_to_cst_str(current_ts)
        
        params = {
            "query": promql,
            "time": current_ts
        }
        
        try:
            response = requests.get(api_endpoint, params=params, timeout=5)
            response.raise_for_status()
            data = response.text
            
            # 修改后的打印语句:同时包含时间戳和易读时间
            print(f"------------ {current_ts} | {readable_time} -----------")
            print(data + "\n")
        except Exception as e:
            print(f"------------ {current_ts} | {readable_time} -----------\n")
            print(f"Error: {str(e)}\n")
        
        # 使用传入的步长参数进行递增
        current_ts += args.step

    print(f"Done!")

if __name__ == "__main__":
    main()

最上面的 promql 变量可以修改成你想要查询的 PromQL 表达式。可以把脚本内容保存为 debug.py,然后用下面的命令运行:

python3 debug.py \
  --prometheus_url http://10.99.1.107:9090 \
  --start_time "2025-12-19 21:38:11" \
  --end_time "2025-12-19 21:39:11" \
  --step 15
  • prometheus_url:Prometheus 的访问地址
  • start_time:查询的开始时间,东八区时间
  • end_time:查询的结束时间,东八区时间
  • step:查询的时间步长,单位秒,默认是 15 秒,改成你的告警规则里的频率

比如 2025-12-19 21:39:10 告警了,规则里配置的是 15s 执行一次,连续 4 次告警,那么就可以把结束时间设置成 2025-12-19 21:39:11,开始时间设置成 2025-12-19 21:38:11,步长设置成 15 秒。然后查询测试,看看到底查到什么数据。

这里我故意把结束时间设置为告警时间往后一秒,是担心一些边界情况。具体测试时,你可以多尝试几次不同的时间戳,看看结果。

(py3venv) ulric@ulric-fcc01 misc % python3 debug.py \
  --prometheus_url http://10.99.1.107:9090 \
  --start_time "2025-12-19 21:38:11" \
  --end_time "2025-12-19 21:39:11" \
  --step 15

Querying: 2025-12-19 21:38:11 to 2025-12-19 21:39:11 with step 15s

------------ 1766151491 | 2025-12-19 21:38:11 -----------
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"mem_available_percent","ident":"cn-beijing.10.99.1.109"},"value":[1766151491,"21.608323685048916"]}]}}

------------ 1766151506 | 2025-12-19 21:38:26 -----------
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"mem_available_percent","ident":"cn-beijing.10.99.1.109"},"value":[1766151506,"22.473846026331397"]}]}}

------------ 1766151521 | 2025-12-19 21:38:41 -----------
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"mem_available_percent","ident":"cn-beijing.10.99.1.109"},"value":[1766151521,"21.02999645150345"]}]}}

------------ 1766151536 | 2025-12-19 21:38:56 -----------
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"mem_available_percent","ident":"cn-beijing.10.99.1.109"},"value":[1766151536,"21.231924036272368"]}]}}

------------ 1766151551 | 2025-12-19 21:39:11 -----------
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"mem_available_percent","ident":"cn-beijing.10.99.1.109"},"value":[1766151551,"22.203590456875407"]}]}}

Done!
快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云
OpenSource
开源版
Flashcat
Flashcat
Flashduty
Flashduty