рдХреЛрдбрдЪреНрдпрд╛ рджреЛрди рдУрд│реА рдЖрдгрд┐ рддреБрдордЪрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рд╡реНрдпреБрддреНрдкрдиреНрди рдХрд░рддреЛ, рд╡реНрд╡рд╛!
prometheus_ рдХрд╕реЗ рдХрд╛рд░реНрдп рдХрд░рддреЗ рд╣реЗ рд╕рдордЬреВрди рдШреЗрдгреНрдпрд╛рд╕рд╛рдареАрдлреНрд▓рд╛рд╕реНрдХ_рдирд┐рд░реНрдпрд╛рддрджрд╛рд░ рдПрдХ рдХрд┐рдорд╛рди рдЙрджрд╛рд╣рд░рдг рдкреБрд░реЗрд╕реЗ рдЖрд╣реЗ:
from flask import Flask
from prometheus_flask_exporter import PrometheusMetrics
app = Flask(__name__)
metrics = PrometheusMetrics(app)
@app.route('/')
def main():
return 'OK'
рдЖрдкрд▓реНрдпрд╛рд▓рд╛ рдкреНрд░рд╛рд░рдВрдн рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЗрддрдХреЗрдЪ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ! рдкреНрд░рд╛рд░рдВрдн рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЖрдпрд╛рдд рдЖрдгрд┐ рдПрдХ рдУрд│ рдЬреЛрдбреВрди PrometheusMetrics, рддреБрдореНрд╣рд╛рд▓рд╛ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдорд┐рд│рддреАрд▓ рд╡рд┐рдирдВрддреА рдХрд╛рд▓рд╛рд╡рдзреА ╨╕ рд╡рд┐рдирдВрддреА рдХрд╛рдЙрдВрдЯрд░, рдПрдВрдбрдкреЙрдЗрдВрдЯрд╡рд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХреЗрд▓реЗ рдЬрд╛рддреЗ /рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдлреНрд▓рд╛рд╕реНрдХ рдНрдкреНрд▓рд┐рдХреЗрд╢рди рдЬреНрдпрд╛рд╡рд░ рддреЗ рдиреЛрдВрджрдгреАрдХреГрдд рдЖрд╣реЗ, рддрд╕реЗрдЪ рддреБрдореНрд╣рд╛рд▓рд╛ рдмреЗрд╕рдордзреВрди рдорд┐рд│рдгрд╛рд░реЗ рд╕рд░реНрд╡ рдбреАрдлреЙрд▓реНрдЯ рдореЗрдЯреНрд░рд┐рдХреНрд╕
рдЖрдкрдг рд╢реЛрдзреВ рд╢рдХрддрд╛
рдордзреНрдпреЗ рдЖрдкрд▓реНрдпрд╛рд▓рд╛ рдирд┐рд░реНрджреЗрд╢рдХрд╛рдВрдЪреА рд╕реВрдЪреА рджреЗрдЦреАрд▓ рдорд┐рд│реЗрд▓
рд╕рдорд╛рдпреЛрдЬрди
рд▓рд╛рдпрдмреНрд░рд░реАрдордзреНрдпреЗ рдЕрдиреЗрдХ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рдкрд░реНрдпрд╛рдп рдЖрд╣реЗрдд, рдкрд╣рд╛
рдореВрд▓рднреВрдд рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рд╡рд░ рджрд░реНрд╢рд╡рд┐рд▓реЗ рдЖрд╣реЗ. рдлрдХреНрдд рдПрдХ рдЙрджрд╛рд╣рд░рдг рддрдпрд╛рд░ рдХрд░рд╛ PrometheusMetrics, рдЪрд▓рд╛ рдХреЙрд▓ рдХрд░реВрдпрд╛ рдореЗрдЯреНрд░рд┐рдХреНрд╕, рдЖрдгрд┐ рдирдВрддрд░ рдлрдВрдХреНрд╢рдиреНрд╕ рд╕рдЬрд╡реВрди рддреБрдореНрд╣реА рдЧреЛрд│рд╛ рдХрд░реВ рдЗрдЪреНрдЫрд┐рдд рдЕрддрд┐рд░рд┐рдХреНрдд рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рддреНрдпрд╛рдЪрд╛ рд╡рд╛рдкрд░ рдХрд░рд╛:
-
@metrics.counter(..)
-
@metrics.gauge(..)
-
@metrics.summary(..)
-
@metrics.histogram(..)
рдХрд╛рдЙрдВрдЯрд░ рдХреЙрд▓ рдореЛрдЬрддрд╛рдд рдЖрдгрд┐ рдЗрддрд░ рддреНрдпрд╛ рдХреЙрд▓рдЪреНрдпрд╛ рдХрд╛рд▓рд╛рд╡рдзреАрд╡рд░ рдЖрдзрд╛рд░рд┐рдд рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдЧреЛрд│рд╛ рдХрд░рддрд╛рдд. рд╡рд┐рдирдВрддреА рдХрд┐рдВрд╡рд╛ рдкреНрд░рддрд┐рд╕рд╛рдж рдЧреБрдгрдзрд░реНрдо рд╡рд╛рдкрд░реВрди рддреБрдореНрд╣реА рдпрд╛ рдкреНрд░рддреНрдпреЗрдХрд╛рд╕рд╛рдареА рд▓реЗрдмрд▓реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реВ рд╢рдХрддрд╛. рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде:
from flask import Flask, request
from prometheus_flask_exporter import PrometheusMetrics
app = Flask(__name__)
# group by endpoint rather than path
metrics = PrometheusMetrics(app, group_by='endpoint')
@app.route('/collection/:collection_id/item/:item_id')
@metrics.counter(
'cnt_collection', 'Number of invocations per collection', labels={
'collection': lambda: request.view_args['collection_id'],
'status': lambda resp: resp.status_code
})
def get_item_from_collection(collection_id, item_id):
pass
рд╡рд░реАрд▓ рдЙрджрд╛рд╣рд░рдгрд╛рдд, рдПрдВрдбрдкреЙрдЗрдВрдЯрд╡рд░ рдХреНрд▓рд┐рдХ рдХрд░рдгреЗ /collection/10002/item/76 рдХрд╛рдЙрдВрдЯрд░ рд╡рд╛рдврдгреНрдпрд╛рд╕ рдХрд╛рд░рдгреАрднреВрдд рдард░реЗрд▓, рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде cnt_collection{рд╕рдВрдХрд▓рди = "10002", рд╕реНрдерд┐рддреА = "200"}, рддрд╕реЗрдЪ рддреБрдореНрд╣рд╛рд▓рд╛ рдбреАрдлреЙрд▓реНрдЯ рд▓рд╛рдпрдмреНрд░рд░реАрдордзреВрди рдбреАрдлреЙрд▓реНрдЯ рдореЗрдЯреНрд░рд┐рдХреНрд╕ (рдпрд╛ рдЙрджрд╛рд╣рд░рдгрд╛рддреАрд▓ рдкреНрд░рддреНрдпреЗрдХ рдПрдВрдбрдкреЙрдЗрдВрдЯрд╕рд╛рдареА) рдорд┐рд│рддреАрд▓:
-
flask_http_request_duration_seconds
тАФ рдкрджреНрдзрдд, рдорд╛рд░реНрдЧ рдЖрдгрд┐ рд╕реНрдерд┐рддреАрдиреБрд╕рд╛рд░ рд╕рд░реНрд╡ рдлреНрд▓рд╛рд╕реНрдХ рд╡рд┐рдирдВрддреНрдпрд╛рдВрд╕рд╛рдареА HTTP рд╡рд┐рдирдВрддреА рдХрд╛рд▓рд╛рд╡рдзреА рд╕реЗрдХрдВрджрд╛рдд -
flask_http_request_total
тАФ рдкрджреНрдзрддреА рдЖрдгрд┐ рд╕реНрдерд┐рддреАрдВрдиреБрд╕рд╛рд░ HTTP рд╡рд┐рдирдВрддреНрдпрд╛рдВрдЪреА рдПрдХреВрдг рд╕рдВрдЦреНрдпрд╛
рд╡рд┐рд╢рд┐рд╖реНрдЯ рдПрдВрдбрдкреЙрдЗрдВрдЯреНрд╕рдЪрд╛ рдорд╛рдЧреЛрд╡рд╛ рдШреЗрдгреЗ рд╡рдЧрд│рдгреЗ, рдЕрддрд┐рд░рд┐рдХреНрдд рдбреАрдлреЙрд▓реНрдЯ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рд▓реЙрдЧ рдХрд░рдгреЗ рдХрд┐рдВрд╡рд╛ рд╡рд░ рд╕реВрдЪреАрдмрджреНрдз рдХреЗрд▓реЗрд▓реЗ рддреЗ рд╡рдЧрд│рдгреЗ рдХрд┐рдВрд╡рд╛ рдПрдХрд╛рдзрд┐рдХ рдПрдВрдбрдкреЙрдЗрдВрдЯреНрд╕рд╡рд░ рд╕рдорд╛рди рдХрд╕реНрдЯрдо рдореЗрдЯреНрд░рд┐рдХ рд▓рд╛рдЧреВ рдХрд░рдгреНрдпрд╛рдЪреЗ рдкрд░реНрдпрд╛рдп рдЖрд╣реЗрдд. рддрдкрд╛рд╕рд╛
app = Flask(__name__)
metrics = PrometheusMetrics(app)
@app.route('/')
def main():
pass # requests tracked by default
@app.route('/skip')
@metrics.do_not_track()
def skip():
pass # default metrics are not collected
# custom metric to be applied to multiple endpoints
common_counter = metrics.counter(
'by_endpoint_counter', 'Request count by endpoints',
labels={'endpoint': lambda: request.endpoint}
)
@app.route('/common/one')
@common_counter
def endpoint_one():
pass # tracked by the custom and the default metrics
@app.route('/common/two')
@common_counter
def endpoint_two():
pass # also tracked by the custom and the default metrics
# register additional default metrics
metrics.register_default(
metrics.counter(
'by_path_counter', 'Request count by request paths',
labels={'path': lambda: request.path}
)
)
рд▓рд╛рдпрдмреНрд░рд░реАрдордзреНрдпреЗ рд▓реЛрдХрдкреНрд░рд┐рдп рдорд▓реНрдЯреАрдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рд▓рд╛рдпрдмреНрд░рд░реА рдЬрд╕реЗ рдХреА uWSGI рдЖрдгрд┐ Gunicorn рд╕рд╛рдареА рд╕реЛрдпреАрд╕реНрдХрд░ рд╡рд┐рд╕реНрддрд╛рд░ рдЖрд╣реЗрдд. рдЖрдкрдг рдорд▓реНрдЯреАрдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧрд╕рд╣ рд▓рдХреНрд╖реНрдпрд┐рдд рд╡рд╛рдкрд░ рдкреНрд░рдХрд░рдгрд╛рдВрдЪреА рдЫреЛрдЯреА рдЙрджрд╛рд╣рд░рдгреЗ рджреЗрдЦреАрд▓ рд╢реЛрдзреВ рд╢рдХрддрд╛.
рдореЗрдЯреНрд░рд┐рдХреНрд╕ рд╕рдВрдЧреНрд░рд╣
рд╡рд░ рдирдореВрдж рдХреЗрд▓реНрдпрд╛рдкреНрд░рдорд╛рдгреЗ, рд▓рд╛рдпрдмреНрд░рд░реА рдбреАрдлреЙрд▓реНрдЯрдиреБрд╕рд╛рд░ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдкреНрд░рджрд╛рди рдХрд░рддреЗ /рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдлреНрд▓рд╛рд╕реНрдХ рдНрдкреНрд▓рд┐рдХреЗрд╢рдирдордзреНрдпреЗ, рдЬреЗ рд▓рдХреНрд╖реНрдп рдореНрд╣рдгреВрди рдХрд╛рдо рдХрд░реВ рд╢рдХрддреЗ
рд╡рд░реАрд▓ рдбреЕрд╢рдмреЛрд░реНрдб рдЙрджрд╛рд╣рд░рдгрд╛рдордзреНрдпреЗ, рддреБрдореНрд╣реА рддреБрдордЪреНрдпрд╛ рдкреНрд░реЛрдорд┐рдерд┐рдпрд╕рд▓рд╛ рдпрд╛ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рдирд╕рд╣ рдбреАрдлреЙрд▓реНрдЯ рд╕реЗрдЯрд┐рдВрдЧреНрдЬрд╕рд╣ рдлреНрд▓рд╛рд╕реНрдХ рдНрдкреНрд▓рд┐рдХреЗрд╢рдирд╡рд░ рд▓рдХреНрд╖реНрдп рдХрд░реВ рд╢рдХрддрд╛:
scrape_configs:
- job_name: 'example'
dns_sd_configs:
- names: ['app']
port: 5000
type: A
refresh_interval: 5s
рдпреЗрдереЗ рд╕рдВрдкреВрд░реНрдг рдЙрджрд╛рд╣рд░рдг рдкрд╣рд╛
рдЕрд╢рд╛ рдкреНрд░рдХрд╛рд░реЗ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдЙрдШрдб рдХрд░рдгреЗ рдЖрдкрд▓реНрдпрд╛рд╕ рдЕрдиреБрдХреВрд▓ рдирд╕рд▓реНрдпрд╛рд╕, рдХрджрд╛рдЪрд┐рдд рдЖрдкрдг рддреНрдпрд╛рд╕ рдмрд╛рд╣реНрдп рдкреНрд░рд╡реЗрд╢рд╛рд╕ рдЕрдиреБрдорддреА рджреЗрдК рдЗрдЪреНрдЫрд┐рдд рдирд╕рд▓реНрдпрд╛рдореБрд│реЗ, рдЖрдкрдг рдкрд╛рд╕ рдХрд░реВрди рддреЛ рд╕рд╣рдЬрдкрдгреЗ рдЕрдХреНрд╖рдо рдХрд░реВ рд╢рдХрддрд╛ рдорд╛рд░реНрдЧ = рдХрд╛рд╣реАрд╣реА рдирд╛рд╣реА рдПрдХ рдЙрджрд╛рд╣рд░рдг рддрдпрд╛рд░ рдХрд░рддрд╛рдирд╛ PrometheusMetrics.
from flask import Flask, request
from prometheus_flask_exporter import PrometheusMetrics
app = Flask(__name__)
metrics = PrometheusMetrics(app, path=None)
...
metrics.start_http_server(5099)
рдордЧ рдЖрдкрдг рд╡рд╛рдкрд░реВ рд╢рдХрддрд╛ start_http_server(рдкреЛрд░реНрдЯ)рд╣рд╛ рдПрдВрдбрдкреЙрдЗрдВрдЯ рд╡реЗрдЧрд│реНрдпрд╛ HTTP рдкреЛрд░реНрдЯрд╡рд░ рдЙрдШрдбрдгреНрдпрд╛рд╕рд╛рдареА, 5099 рд╡рд░реАрд▓ рдЙрджрд╛рд╣рд░рдгрд╛рдд. рд╡реИрдХрд▓реНрдкрд┐рдХрд░рд┐рддреНрдпрд╛, рд╕рдорд╛рди рдлреНрд▓рд╛рд╕реНрдХ рдНрдкреНрд▓рд┐рдХреЗрд╢рдирдордзреНрдпреЗ рдПрдВрдбрдкреЙрдИрдВрдЯ рдЕрд╕рд▓реНрдпрд╛рдмрджреНрджрд▓ рддреБрдореНрд╣реА рдЖрдирдВрджреА рдЕрд╕рд▓реНрдпрд╛рд╕, рдкрд░рдВрддреБ рддреБрдореНрд╣рд╛рд▓рд╛ рддреНрдпрд╛рдЪрд╛ рдорд╛рд░реНрдЧ рдмрджрд▓рдгреНрдпрд╛рдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЖрд╣реЗ /рдореЗрдЯреНрд░рд┐рдХреНрд╕, рддреБрдореНрд╣реА рдПрдХрддрд░ рджреБрд╕рд░рд╛ URI рдкрд╛рде рдкреЕрд░рд╛рдореАрдЯрд░ рдореНрд╣рдгреВрди рдкрд╛рд╕ рдХрд░реВ рд╢рдХрддрд╛ рдХрд┐рдВрд╡рд╛ рд╡рд╛рдкрд░реВ рд╢рдХрддрд╛ register_endpoint(..)рдирдВрддрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА.
рд╕рдВрджрд░реНрдн
-
rycus86/prometheus_flask_exporter - рдкреНрд░реЛрдорд┐рдерд┐рдпрд╕рд╕рд╛рдареА рд╣реА рдмрд╛рдЯрд▓реА рдирд┐рд░реНрдпрд╛рддрдХ -
prometheus-flask-рдирд┐рд░реНрдпрд╛рддрдХрд░реНрддрд╛ README тАФ рд╡рд╛рдкрд░, рдЙрджрд╛рд╣рд░рдгреЗ рдЖрдгрд┐ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рдкрд░реНрдпрд╛рдп -
prometheus-flask-exporter рдЙрджрд╛рд╣рд░рдгреЗ тАФ рдлреНрд▓рд╛рд╕реНрдХ рдНрдкреНрд▓рд┐рдХреЗрд╢рди рдореЙрдирд┐рдЯрд░рд┐рдВрдЧ рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ рдкреНрд░рдХрд╛рд░реЗ рд╕реЗрдЯ рдХрд░рдгреНрдпрд╛рдЪреА рдЙрджрд╛рд╣рд░рдгреЗ -
PyPI рд╡рд░ prometheus-flask-exporter тАФ рд╣рд╛ рдкреНрд░рдХрд▓реНрдк PyPI рд╡рд░ рдЖрд╣реЗ -
prometheus/client_python - рдкрд╛рдпрдердирд╕рд╛рдареА рдЕрдзрд┐рдХреГрдд рдкреНрд░реЛрдорд┐рдерд┐рдпрд╕ рдХреНрд▓рд╛рдпрдВрдЯ рд▓рд╛рдпрдмреНрд░рд░реА
рддреБрдореНрд╣реА рдПрдХрджрд╛ рдкреНрд░рдпрддреНрди рдХрд░рдгреНрдпрд╛рдЪреЗ рдард░рд╡рд┐рд▓реНрдпрд╛рд╕, GitHub рд╡рд░ рд╕рдорд╕реНрдпрд╛ рдЙрдШрдбрдгреНрдпрд╛рд╕ рдореЛрдХрд│реНрдпрд╛ рдордирд╛рдиреЗ рдХрд┐рдВрд╡рд╛ рддреБрдордЪреНрдпрд╛ рдЯрд┐рдкреНрдкрдгреНрдпрд╛, рдЕрднрд┐рдкреНрд░рд╛рдп рдЖрдгрд┐ рд╕реВрдЪрдирд╛ рджреНрдпрд╛!
рдзрдиреНрдпрд╡рд╛рдж!
рд╕реНрддреНрд░реЛрдд: www.habr.com