๋ช ์ค์ ์ฝ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ธก์ ํญ๋ชฉ์ ์์ฑํฉ๋๋ค. ์!
prometheus_์ ์๋ ๋ฐฉ์์ ์ดํดํ๋ ค๋ฉดํ๋ผ์คํฌ_์์ถ์ ์๋ ์ต์ํ์ ์๋ง์ผ๋ก ์ถฉ๋ถํฉ๋๋ค:
from flask import Flask
from prometheus_flask_exporter import PrometheusMetrics
app = Flask(__name__)
metrics = PrometheusMetrics(app)
@app.route('/')
def main():
return 'OK'
์์ํ๋ ๋ฐ ํ์ํ ์ ๋ถ์
๋๋ค! ์ด๊ธฐํ๋ฅผ ์ํ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ๋ผ์ธ ์ถ๊ฐ Prometheus๋ฉํธ๋ฆญ์ค, ์ธก์ ํญ๋ชฉ์ ์ป๊ฒ ๋ฉ๋๋ค. ์์ฒญ ๊ธฐ๊ฐ ะธ ์์ฒญ ์นด์ดํฐ, ์๋ํฌ์ธํธ์ ํ์๋จ /์ธก์ ํญ๋ชฉ ๋ฑ๋ก๋ Flask ์ ํ๋ฆฌ์ผ์ด์
๊ณผ ๊ธฐ๋ณธ์์ ์ป๋ ๋ชจ๋ ๊ธฐ๋ณธ ์ธก์ ํญ๋ชฉ
๋น์ ์ ์ฐพ์ ์ ์์ต๋๋ค
๋ํ ๋ค์์์ ์งํ ๋ชฉ๋ก์ ์ฐพ์ ์ ์์ต๋๋ค.
์กฐ์
๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ๋ง์ ๊ตฌ์ฑ ์ต์
์ด ์์ต๋๋ค.
๊ธฐ๋ณธ ๊ตฌ์ฑ์ ์์ ๋์ ์์ต๋๋ค. ๊ทธ๋ฅ ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ด ๋ณด์ธ์ Prometheus๋ฉํธ๋ฆญ์ค, ๋ถ๋ฌ๋ณด์ ํต๊ณ, ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ์ฌ์ฉํ์ฌ ํจ์๋ฅผ ์ฅ์ํ์ฌ ์์งํ๋ ค๋ ์ถ๊ฐ ์ธก์ ํญ๋ชฉ์ ์ ์ํฉ๋๋ค.
-
@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
์์ ์์์ ๋์ ์ ํด๋ฆญํ๋ฉด /์ปฌ๋ ์ /10002/ํญ๋ชฉ/76 ์๋ฅผ ๋ค์ด ์นด์ดํฐ๊ฐ ์ฆ๊ฐํ๊ฒ ๋ฉ๋๋ค. cnt_collection{collection = "10002", ์ํ = "200"}, ๋ํ ๊ธฐ๋ณธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๊ธฐ๋ณธ ์ธก์ ํญ๋ชฉ(์ด ์์์๋ ๊ฐ ์๋ํฌ์ธํธ์ ๋ํ)์ ๊ฐ์ ธ์ต๋๋ค.
-
flask_http_request_duration_seconds
โ ๋ฉ์๋, ๊ฒฝ๋ก ๋ฐ ์ํ๋ณ ๋ชจ๋ Flask ์์ฒญ์ ๋ํ 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๊ณผ ๊ฐ์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ๋ค์ค ์ฒ๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ํธ๋ฆฌํ ํ์ฅ ๊ธฐ๋ฅ์ด ์์ต๋๋ค. ๋ค์ค ์ฒ๋ฆฌ๋ฅผ ํฌํจํ์ฌ ๋์ ์ฌ์ฉ ์ฌ๋ก์ ์์ ์๋ ์ฐพ์ ์ ์์ต๋๋ค.
์ธก์ ํญ๋ชฉ ์์ง
์์์ ์ธ๊ธํ๋ฏ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ํฌ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. /์ธก์ ํญ๋ชฉ Flask ์ ํ๋ฆฌ์ผ์ด์
์์ ๋์์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
์์ ๋์๋ณด๋ ์์์๋ ๋ค์ ๊ตฌ์ฑ์ ์ฌ์ฉํ์ฌ ๊ธฐ๋ณธ ์ค์ ์ ์ฌ์ฉํ์ฌ Prometheus๋ฅผ Flask ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ํ๊ฒํ ํ ์ ์์ต๋๋ค.
scrape_configs:
- job_name: 'example'
dns_sd_configs:
- names: ['app']
port: 5000
type: A
refresh_interval: 5s
์ ์ฒด ์์๋ ๋ค์์์ ํ์ธํ์ธ์.
์ด๋ฌํ ๋ฐฉ์์ผ๋ก ์ธก์ ํญ๋ชฉ ๋์ ์ ๋ ธ์ถํ๋ ๊ฒ์ด ์ ํฉํ์ง ์์ ๊ฒฝ์ฐ(์๋ง๋ ์ธ๋ถ ์ก์ธ์ค๋ฅผ ํ์ฉํ๊ณ ์ถ์ง ์๊ธฐ ๋๋ฌธ์) ๋ค์์ ์ ๋ฌํ์ฌ ์ฝ๊ฒ ๋นํ์ฑํํ ์ ์์ต๋๋ค. ๊ฒฝ๋ก=์์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ๋ Prometheus๋ฉํธ๋ฆญ์ค.
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 ์์ ์์์. ๋๋ ๋์ผํ Flask ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ ์๋ํฌ์ธํธ์ ๋ง์กฑํ์ง๋ง ํด๋น ๊ฒฝ๋ก๋ฅผ ๋ค์์์ ๋ณ๊ฒฝํด์ผ ํ๋ ๊ฒฝ์ฐ /์ธก์ ํญ๋ชฉ, ๋ค๋ฅธ URI๋ฅผ ๊ฒฝ๋ก ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌํ๊ฑฐ๋ ๋ค์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ ์ง์คํฐ_์๋ํฌ์ธํธ(..)๋์ค์ ์ค์นํ๋ ค๋ฉด
์ฐธ์กฐ
-
rycus86/prometheus_flask_exporter โ ํ๋ก๋ฉํ ์ฐ์ค์ ๋ณ ์์ถ์ ์ -
ํ๋ก๋ฉํ ์ฐ์ค-ํ๋ผ์คํฌ-์์ถ๊ธฐ README โ ์ฌ์ฉ๋ฒ, ์์ ๋ฐ ๊ตฌ์ฑ ์ต์ -
prometheus-flask-exporter ์์ โ ๋ค์ํ ๋ฐฉ์์ผ๋ก Flask ์ ํ๋ฆฌ์ผ์ด์ ๋ชจ๋ํฐ๋ง์ ์ค์ ํ๋ ์ -
PyPI์ prometheus-flask-exporter โ ์ด ํ๋ก์ ํธ๋ PyPI์ ์์ต๋๋ค. -
ํ๋ก๋ฉํ ์ฐ์ค/client_python โ Python์ฉ ๊ณต์ Prometheus ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
ํ๋ฒ ์๋ํด ๋ณด์๊ธฐ๋ก ๊ฒฐ์ ํ์ จ๋ค๋ฉด GitHub์์ ๋ฌธ์ ๋ฅผ ๊ณต๊ฐํ์๊ฑฐ๋ ๋๊ธ, ํผ๋๋ฐฑ, ์ ์์ ๋จ๊ฒจ์ฃผ์ธ์!
๊ฐ์ฌํฉ๋๋ค!
์ถ์ฒ : habr.com