Loading... <div class="tip share">请注意,本文编写于 998 天前,最后修改于 996 天前,其中某些信息可能已经过时。</div> ##什么是Exporter? 理论上所有可以向Prometheus提供监控样本数据的程序都可以被称为一个Exporter。而Exporter的一个实例称为target,Prometheus通过轮询的方式定时从这些target中获取样本数据 ##Exporter规范 Exporter的Content-Type必须是text类型,如果当前行以`# HELP`开始,Promtheus将会对内容进行解析,得到当前的指标名称以及相应的说明信息,如果当前行以`# TYPE`开始,Prometheus会对内容进行解析,得到当前的指标名称以及指标类型,TYPE注释行必须出现在指标的第一个样本之前。如果没有明确的指标类型需要返回为untyped。 除了`# `开头的所有行都会被视为是监控样本数据。 ##工作流程  ##数据类型 Prometheus提供4种类型的Metrics:`Counter`, `Gauge`, `Summary`, `Histogram` Summary/Histogram概念比较复杂,一般场景不会使用到 > **Counter(计数器类型)** Counter类型的指标的工作方式和计数器一样,只增不减(除非系统重置),Counter一般用于累计值,例如记录请求次数、任务完成数、错误发生次数。 ```python # 将counter值加1 Inc() # 将指定值加到counter值上,如果指定值< 0会panic Add(float64) ``` ```python requests_total = Counter("requests_total", "总请求次数") @app.route("/metrics") def requests_count(): # 每请求一次将requests_total值加1 requests_total.inc() # 以字符串的形式返回 return Response(prometheus_client.generate_latest(requests_total), mimetype="text/plain") ``` 上面示例将会在web页面返回如下内容,并且请求次数会随着页面刷新递增 ``` # HELP requests_total 总请求次数 # TYPE requests_total counter requests_total 5.0 # HELP requests_created 总请求次数 # TYPE requests_created gauge requests_created 1.6002211412159185e+09 ``` > Counter类型数据可以让用户方便的了解事件产生的速率的变化,在PromQL内置的相关操作函数可以提供相应的分析,比如以HTTP应用请求量来进行说明 ```python # 通过rate()函数获取HTTP请求量的增长率 rate(http_requests_total[5m]) # 查询当前系统中,访问量前10的HTTP地址 topk(10, http_requests_total) ``` > **Gauge(仪表盘类型)** Gauge是可增可减的指标类,可以用于反应当前应用的状态。比如在监控服务器时,当前内存大小(node_memory_MemFree),可用内存大小(node_memory_MemAvailable)。或者容器当前的cpu使用率,内存使用率。 Gauge指标对象主要包含两个方法inc()以及dec(),用户添加或者减少计数。 对于Gauge类型的监控指标,通过PromQL内置函数delta()可以获取样本在一段时间内的变化情况,例如 ```python # 计算CPU温度在两小时内的差异 dalta(cpu_temp_celsius{host="zeus"}[2h]) # 预测系统磁盘空间在4小时之后的剩余情况 predict_linear(node_filesystem_free{job="node"}[1h], 4*3600) ``` ```python # 定义Gauge 类型 requests_total = Gauge("request_count", "测试Gauge类型") @app.route("/metrics") def requests_count(): # 此类型的值用set方法传参,没有默认值,必须要传值,否则报错 requests_total.set(5) return Response(prometheus_client.generate_latest(requests_total),mimetype="text/plain") ``` 以上示例访问Web将会返回如下内容,无论怎么刷新,值都会是5.0 ``` # HELP request_count 测试Gauge类型 # TYPE request_count gauge request_count 5.0 ``` > **Histogram(直方图类型)** Histogram 由 < basename>_bucket{le="< upper inclusive bound>"},< basename>_bucket{le="+Inf"}, < basename>_sum,_count 组成,主要用于表示一段时间范围内对数据进行采样(通常是请求持续时间或响应大小),并能够对其指定区间以及总数进行统计,通常它采集的数据展示为直方图。 ```python # 事件发生的总次数,basename_count。 # 当前一共发生了2次http请求 io_namespace_http_requests_latency_seconds_histogram_count{path="/",method="GET",code="200",} 2.0 ``` ```python # 所有事件产生值的大小的总和,basename_sum # 发生的2次http请求总的响应时间为13.107670803000001 秒 io_namespace_http_requests_latency_seconds_histogram_sum{path="/",method="GET",code="200",} 13.107670803000001 ``` > **Summary(摘要类型)** Summary类型和Histogram类型相似,由< basename>{quantile="< φ>"},< basename>_sum,< basename>_count组成,主要用于表示一段时间内数据采样结果(通常时请求持续时间或响应大小),它直接存储了quantile数据,而不是根据统计区间计算出来的。 Summary与Histogram相比区别如下 - 都包含 < basename>_sum和< basename>_count; - Histogram需要通过< basename>_bucket计算quantile,而Summary直接存储了quantile的值。 | 序号 | histogram | Summary | | ----------- | ---------------------------- | ---------------------- | | 配置 | 区间配置 | 分位数和滑动窗口 | | 客户端性能 | 只需增加counters代价小 | 需要流式计算代价高 | | 服务端性能 | 计算分位数消耗大,可能会耗时 | 无需计算,代价小 | | 时序数量 | sum、_count、bucket | _sum、_count、quantile | | 分位数误差 | bucket的大小有关 | φ的配置有关 | | φ和滑动窗口 | Prometheus 表达式设置 | 客户端设置 | | 聚合 | 根据表达式聚合 | 一般不可聚合 | ```python # 事件发生总的次数 # 当前http请求发生总次数为12次 io_namespace_http_requests_latency_seconds_summary_count{path="/",method="GET",code="200",} 12.0 ``` ```python # 事件产生的值的总和 # 这12次http请求的总响应时间为 51.029495508s io_namespace_http_requests_latency_seconds_summary_sum{path="/",method="GET",code="200",} 51.029495508 ``` ```python # 事件产生的值的分布情况 # 这12次http请求响应时间的中位数是3.052404983s io_namespace_http_requests_latency_seconds_summary{path="/",method="GET",code="200",quantile="0.5",} 3.052404983 # 这12次http请求响应时间的9分位数是8.003261666s io_namespace_http_requests_latency_seconds_summary{path="/",method="GET",code="200",quantile="0.9",} 8.003261666 ``` ##示例 使用labels,可以一次加多组值,同一组值labels不能完全一致 ```python app = Flask(__name__) # 在Gauge类型里定义两个labels,可以定义多个 port_up = Gauge("server_port", "monitor server port status.",["host","port"]) @app.route("/metrics") def metrics(): # 传入不同的 lables 即可一次获得多项 port_up.labels("192.168.1.1", "22").set(0) port_up.labels("192.168.1.2", "22").set(0) port_up.labels("192.168.1.3", "22").set(1) return Response(prometheus_client.generate_latest(port_up), mimetype="text/plain") ``` 上面的示例将会返回如下值 ``` # HELP server_port monitor server port status. # TYPE server_port gauge server_port{host="192.168.1.1",port="22"} 0.0 server_port{host="192.168.1.2",port="22"} 0.0 server_port{host="192.168.1.3",port="22"} 1.0 ``` 但是这样写,labels需要做一些操作才能一次请求获取到多项变量,正确的方法应该是使用CollectorRegistry,CollectorRegistry可以同时注册多个自定义指标并返回给prometheus ```python REGISTRY = CollectorRegistry(auto_describe=False) #自定义指标必须利用CollectorRegistry进行注册,注册后返回给prometheus #CollectorRegistry必须提供register,一个指标收集器可以注册多个collectoryregistry ``` ##完整示例 ```python import prometheus_client from prometheus_client import Gauge from prometheus_client.core import CollectorRegistry from flask import Response, Flask from nmap import nmap from flask_apscheduler import APScheduler from psutil import virtual_memory from psutil import cpu_times app = Flask(__name__) scan_data = [] def scan_port(): host_list = ['192.168.80.100', '192.168.80.101', '192.168.80.102', '192.168.80.103', '192.168.80.104', '192.168.10.11'] for i in host_list: nm = nmap.PortScanner() port = '22' nm.scan(i, port) name = nm[i]['tcp'][int(port)]['name'] port_state = nm[i]['tcp'][int(port)]['state'] version = nm[i]['tcp'][int(port)]['version'] scan_data.append({'host': i, 'port': port, 'port_state': port_state, 'name': name, 'version': version}) class SchedulerConfig(object): JOBS = [ { 'id': 'update_job', 'func': '__main__:update_job', 'args': None, 'trigger': 'interval', 'seconds': 10, } ] def update_job(): scan_port() print("数据更新完成") # 为实例化的flask引入定时任务配置 app.config.from_object(SchedulerConfig()) REGISTRY = CollectorRegistry(auto_describe=False) host_info = Gauge("host_info", "主机信息扫描", ["host", "port", "port_state", "name", "version"], registry=REGISTRY) mem_percent = Gauge("system_memory_percent", "内存使用率", registry=REGISTRY) cpu_percent = Gauge("system_cpu_percent", "CPU使用率", registry=REGISTRY) @app.route("/metrics") def metrics(): mem_percent.set(virtual_memory().percent) cpu_percent.set(cpu_times().system) for i in scan_data: host = i.get('host') port = i.get('port') port_state = i.get('port_state') name = i.get('name') version = i.get('version') host_info.labels(host, port, port_state, name, version) return Response(prometheus_client.generate_latest(REGISTRY), mimetype="text/plain") if __name__ == "__main__": # 实例化APScheduler scheduler = APScheduler() # 把任务列表载入实例flask scheduler.init_app(app) # 启动任务计划 scheduler.start() # 在debug模式下,Flask的重新加载器将加载两次,因此flask总共有两个进程,会导致定时任务重复执行,禁用重新加载器可解决此问题,或者debug设为false app.run(host="0.0.0.0", port=8000, debug=True, use_reloader=False) ``` ##返回值 ``` # HELP host_info 主机信息扫描 # TYPE host_info gauge host_info{host="192.168.80.100",name="ssh",port="22",port_state="open",version="7.6p1 Ubuntu 4ubuntu0.3"} 0.0 host_info{host="192.168.80.101",name="ssh",port="22",port_state="open",version="7.6p1 Ubuntu 4ubuntu0.3"} 0.0 host_info{host="192.168.80.102",name="ssh",port="22",port_state="open",version="7.4"} 0.0 host_info{host="192.168.80.103",name="ssh",port="22",port_state="open",version="7.4"} 0.0 host_info{host="192.168.80.104",name="ssh",port="22",port_state="open",version="7.4"} 0.0 host_info{host="192.168.10.11",name="ssh",port="22",port_state="closed",version=""} 0.0 # HELP system_memory_percent 内存使用率 # TYPE system_memory_percent gauge system_memory_percent 83.2 # HELP system_cpu_percent CPU使用率 # TYPE system_cpu_percent gauge system_cpu_percent 3456.140625 ``` 最后修改:2020 年 09 月 17 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏
5 条评论
谢谢分享,日常打卡~ 滴滴~(๑•̀ㅁ•́ฅ)
博主怎么两个主题换来换去的
zero这是又回归了