1. 程式人生 > 其它 >Prometheus 基於Python Django實現Prometheus Exporter

Prometheus 基於Python Django實現Prometheus Exporter

基於Python Django實現Prometheus Exporter

需求描述

執行監控需求,需要採集Nginx 每個URL請求的相關資訊,涉及兩個指標:一分鐘內平均響應時間,呼叫次數,並且為每個指標提供3個標籤:請求方法,請求狀態,請求URL,並向普羅米修斯暴露這些指標相關資料

實踐環境

Python 3.6.5

Django 3.0.6

prometheus-client 0.11.0

程式碼設計與實現

說明:為了更好的表達主題,程式碼中資料採集部分暫且採用data變數替代。

基於官方SDK

Gauge Metric為例

view檢視實現

CustomExporters.url_exporter_views.UrlExporterView

#!/usr/bin/env python
# -*- coding:utf-8 -*-

# Create your views here.
from django.http import HttpResponse
from django.views.generic import View
from prometheus_client import CollectorRegistry, Gauge, generate_latest

import logging
import traceback
logger = logging.getLogger('mylogger')

REGISTRY = CollectorRegistry()
LABELS = ['req_status', 'req_method', 'req_url'] # 標籤定義

# 指標定義
g_requests_total = Gauge('requests_total', 'url request num each minute', LABELS, registry=REGISTRY)
g_avg_response_time_seconds = Gauge('avg_response_time_seconds', 'url avg response time of one minute', LABELS, registry=REGISTRY)


class UrlExporterView(View):
    def get(self, request, *args, **kwargs):
        try:
            data = {
                'count': 34,
                'method': 'get',
                'status': 200,
                'url': 'url',
                'avg_rt':50
            }
            g_requests_total.labels(data.get('status'),data.get('method'),data.get('url')).set(data.get('count')) #set設定值
            g_avg_response_time_seconds.labels(data.get('status'),data.get('method'),data.get('url')).set(data.get('avg_rt'))

            return HttpResponse(generate_latest(REGISTRY),status=200, content_type="text/plain")
        except Exception:
            error_msg = '%s' % traceback.format_exc()
            logger.error(error_msg)
            return HttpResponse('# HELP Error occured', status=500, content_type="text/plain")

注意:通過官方SDK無法向普羅米修斯暴露資料生成時間(非採集時間),以上實現方式無法滿足這種需求

專案URL路由配置

CustomPrometheusExporters.CustomPrometheusExporters.urls.py

from django.contrib import admin
from django.urls import path, re_path, include

urlpatterns = [
    re_path(r'^exporters/',  include('CustomExporters.urls')),
    path('admin/', admin.site.urls),
]

應用urls.py url路由配置

CustomExporters.urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from django.urls import path,re_path

from CustomExporters.url_exporter_views import UrlExporterView


urlpatterns = [
    re_path(r'url-exporter/metrics$', UrlExporterView.as_view(), name='url-exporter')
]

檢視執行結果

瀏覽器中訪問 http://127.0.0.1:8000/exporters/url-exporter/metrics,輸出如下:

# HELP requests_total url request num each minute
# TYPE requests_total gauge
requests_total{req_method="get",req_status="200",req_url="url"} 34.0
# HELP avg_response_time_seconds url avg response time of one minute
# TYPE avg_response_time_seconds gauge
avg_response_time_seconds{req_method="get",req_status="200",req_url="url"} 50.0

不基於官方SDK

view檢視實現

CustomExporters.url_exporter_views.UrlExporterView

#!/usr/bin/env python
# -*- coding:utf-8 -*-

# Create your views here.
from django.http import HttpResponse
from django.views.generic import View
from prometheus_client.utils import floatToGoString

import logging
import traceback
logger = logging.getLogger('mylogger')


class UrlExporterView(View):

    def get(self, request, *args, **kwargs):
        try:
            data = {
                'count': 34,
                'method': 'get',
                'status': 200,
                'url': 'url',
                'avg_rt':50,
                'timestamp': 1634099490000
            }
            requests_total_line_list = ['# HELP requests_total The total requests number of url to req_service, req_method, status \n'] # 存放 requests_total指標輸出
            avg_response_time_line_list = ['# HELP avg_response_time_milseconds average request response time for url correspond to req_service, req_method, status\n'] # 存放 avg_response_time_seconds指標輸出
            line_template = '%(metric_name)s{req_method="%(req_method)s",req_status="%(req_status)s",req_url="%(req_url)s"} %(label_value)s %(timestamp)s\n'

            requests_total_line_list.append(line_template % {
                'metric_name':'requests_total',
                'req_method':data.get('method'),
                'req_status':data.get('status'),
                'req_url':data.get('url'),
                'label_value':floatToGoString(data.get('count')),
                'timestamp':data.get('timestamp')
            })

            avg_response_time_line_list.append(line_template % {
                'metric_name':'avg_response_time_milseconds',
                'req_method':data.get('method'),
                'req_status':data.get('status'),
                'req_url':data.get('url'),
                'label_value':floatToGoString(data.get('avg_rt')),
                'timestamp':data.get('timestamp')
            })

            output_list = []
            output_list.extend(requests_total_line_list)
            output_list.append('\n')
            output_list.extend(avg_response_time_line_list)

            return HttpResponse(''.join(output_list).encode('utf-8'), status=200, content_type="text/plain")
        except Exception:
            error_msg = '%s' % traceback.format_exc()
            logger.error(error_msg)
            return HttpResponse('# HELP Error occured', status=500, content_type="text/plain")

檢視執行結果

瀏覽器中訪問 http://127.0.0.1:8000/exporters/url-exporter/metrics,輸出如下:

# HELP requests_total The total requests number of url to req_service, req_method, status 
requests_total{req_method="get",req_status="200",req_url="url"} 34.0 1634099490000

# HELP avg_response_time_milseconds average request response time for url correspond to req_service, req_method, status
avg_response_time_milseconds{req_method="get",req_status="200",req_url="url"} 50.0 1634099490000

樣本資料格式說明

普羅米修斯基於文字的(text-based)格式是面向行的。行由換行符(\n)分隔。最後一行必須以換行字元結尾。空行將被忽略

在一行中,tokens可以由任意數量的空格和/或製表符分隔(如果它們與前一個令牌合併,則必須至少由一個空格分隔)。忽略行收尾隨空格。

# 作為首個非空白字元的行,被當作註釋,且除非#後面第一個token為HELPTYPE,形如 # HELP# TYPE,否則羅米修斯會自動忽略該行。

如果token為HELP,則至少需要1個token,該token為Metric名稱,剩餘所有token為該屬性的文件字串說明(dockstring)。HELP行可以是任意UTF-8序列字元,如果包含反斜槓 \、 換行符\n字元,需要進行顯示轉義,形如 \\, \n

如果token為TYPE,則至少需要2個token,第一個token為Metric名稱,第二個為counter,gauge, histogram, summary, 或者 untyped,定義名稱指定的Metric的型別。針對同一個給定的Metric名稱,只能存在一種TypeTYPE行必須位於該Metric的第一行資料樣本行之前。如果該Metric沒有定義對應的TYPE行,則預設TYPEuntyped

剩餘的行描述樣本(每行對應一個數據樣本)使用以下格式

metric_name[{label_name1="label_value",label_name2="label_value",..,label_nameN="label_valueN"}] value [timestamp]
  • metric_namelabel_name遵守普羅米修斯慣用的語言表示式限制
  • label_value 可以是任意UTF-8序列字元,如果包含反斜槓 \、雙引號"、 換行符\n字元,需要進行顯示轉義,形如 \\, \", \n
  • value 代表浮點數,正如Go ParseFloat()所需引數。此外,除標準數值外,NaN+Inf-Inf分別表示非數字、正無窮大和負無窮大的有效值
  • timestamp 資料自身生成時間,為64整數(1970-01-01 00:00:00 UTC到現在的毫秒數) ,正如Go ParseInt()所需引數

作者:授客
QQ:1033553122
全國軟體測試QQ交流群:7156436

Git地址:https://gitee.com/ishouke
友情提示:限於時間倉促,文中可能存在錯誤,歡迎指正、評論!
作者五行缺錢,如果覺得文章對您有幫助,請掃描下邊的二維碼打賞作者,金額隨意,您的支援將是我繼續創作的源動力,打賞後如有任何疑問,請聯絡我!!!
微信打賞 支付寶打賞全國軟體測試交流QQ群