`Written in: 2021-04-03`
چرا و چگونه برای نرمافزاری که مینویسیم، صادرکننده متریک پرومتئوس بسازیم. 
### پیشزمینه
**پرومته** یا **پرومتئوس** در [اسطورههای یونانی](https://fa.wikipedia.org/wiki/%D8%A7%D8%B3%D8%B7%D9%88%D8%B1%D9%87%E2%80%8C%D9%87%D8%A7%DB%8C_%DB%8C%D9%88%D9%86%D8%A7%D9%86%DB%8C)، یکی از [تیتانها](https://fa.wikipedia.org/wiki/%D8%AA%DB%8C%D8%AA%D8%A7%D9%86_%28%D8%A7%D8%B3%D8%A7%D8%B7%DB%8C%D8%B1_%DB%8C%D9%88%D9%86%D8%A7%D9%86%29) و پسر [یاپتوس](https://fa.wikipedia.org/wiki/%DB%8C%D8%A7%D9%BE%D8%AA%D9%88%D8%B3_%28%D8%A7%D8%B3%D8%B7%D9%88%D8%B1%D9%87%29) و [کلیمنه](https://fa.wikipedia.org/wiki/%DA%A9%D9%84%DB%8C%D9%85%D9%86%D9%87) و خدای [آتش](https://fa.wikipedia.org/wiki/%D8%A2%D8%AA%D8%B4) است. او عاشق [آتنا](https://fa.wikipedia.org/wiki/%D8%A2%D8%AA%D9%86%D8%A7) دختر [زئوس](https://fa.wikipedia.org/wiki/%D8%B2%D8%A6%D9%88%D8%B3) شد و تنها کسی بود که آتنا را بوسید. آنها بسیار همدیگر را دوست میداشتند و آتنا به او کمک کرد تا آتش را بدزدد. پس از زنجیر شدن پرومته آتنا هر هفته به دیدن او میرفت. (ویکیپدیا)
در حقیقت، پرومتئوس (Prometheus) یک ابزار برای مانیتور و دیدهبانیکردن نرمافزارهاست که ابتدا برای ساندکلاد ساخته شد. به زبان سادهتر، یک پایگاهدادهست که یکسری داده رو به صورت سریزمانی میگیره و میتونه از اون با زبان PromQL خروجی بگیره.
گرافانا (Grafana) هم یک ابزار نمایش دادههای مختلف روی جدولهای تعاملی هست و خیلی بیشتر.
### متریک چیه؟
معمولا اولینکاری که بعد از print زدن جاهای مختلف یک نرمافزار میکنیم، نوشتن یک سیستم loggingـه. این کار باعث میشه با فهمیدن خطاهای مختلف **اطلاعات بیشتری از کارکرد نرمافزار**مون بگیریم. نوشتن یک صادرکننده (exporter) متریکهای پرومتئوس هم دقیقا میتونه اطلاعات بیشتری از کارکرد نرمافزارمون بهمون بده.
در تئوری، میشه از لاگ، متریک استخراج کرد و برعکس. اما، این دو کاملا برای هدفهای متفاوتی ساخته میشن. درحالی که لاگ انجام یک اتفاق خاص رو نشون میده، متریک سنجه (معمولا تعداد) اتفاقات مختلف رو نشون میده. مقالههای بسیار زیاد و خوبی درباره تفاوت لاگ و متریک (Logs vs Metrics) وجود داره که میتونید بخونید.
برای مثال، فرض کنید که یک نرمافزار دارید که داره درخواستهای HTTP میگیره. لاگ از این بخش میتونه اینجوری باشه که برای هر درخواست خطی در یک فایل اضافه کنه یا توی stdout نمایش بده. اما متریک اینجوریه که فقط یک عدد شامل تعداد درخواستها نمایش بده که هر بار یدونه بهش اضافه میشه.
### خب بعدش
توی پرومتئوس، بعد از این که صادرکننده متریک نرمافزار روی یک پورت HTTP اطلاعات مربوطه رو نشون میده، خود پرومتئوس اونهارو به صورت سری زمانی میگیره و ذخیره میکنه. عموما این دادهها بعدا میتونه توسط گرافانا دیده بشه و روی جدولهای مختلف نشون داده بشه. البته با خود هم پرومتئوس میشه این روی این دادهها کوئری گرفت و در جدول نشون داد.

### حالا چهکار کنم؟
برای نرمافزارهات صادرکننده متریک بنویس! در خیلی از زبانها کتابخانه و [کارخواه](https://prometheus.io/docs/instrumenting/clientlibs/) برای صادرکننده پرومتئوس وجود داره اما نوشتنش برای زبانهایی که وجود ندارند هم خیلی سخت نیست. در ادامه من درباره کتابخانهاش در پایتون میگم.
```python
from prometheus_client import Gauge
g = Gauge('my_inprogress_requests', 'Description of gauge')
g.inc() # Increment by 1
g.dec(10) # Decrement by given value
g.set(4.2) # Set to a given value
```
نوشتن یک متریک از نوع Gauge در پایتون به همین راحتیه. برای دیدن انواع متریکهای پرومتئوس [اینجا](https://prometheus.io/docs/concepts/metric_types/) رو بخونید اما در اکثر مواقع کارتون با متریکهای Counter و Gauge راه میوفته. متریک Counter فقط یک عدد هست که میتونه فقط زیاد بشه ولی Gauge میتونه هم زیاد بشه هم کم. در ادامه همون مثال، میتونید Counter رو تعداد درخواستها بگیرید (از اونجایی که تعداد درخواستها هیچوقت کم نمیشه) و Gauge رو زمانی که صرف شده تا به درخواست پاسخ داده بشه.
هر متریک، جدا از مقدارشون، میتونن یک برچسب key-value به اسم label هم داشته باشند.
```python
from prometheus_client import Counter
c = Counter('my_requests_total', 'HTTP Failures', ['method', 'endpoint'])
c.labels(method='get', endpoint='/').inc()
c.labels(method='post', endpoint='/submit').inc()
```
در مثال بالا متریک my_requests_total دوتا برچسب داره که میتونن مقادیر مختلفی داشته باشن و توی هر تغییر کاملا از همدیگه عمل کنند. یعنی در نهایت، چیزی که پرومتئوس در هر درخواست از صادرکننده میگیره یک متریک x با برچسب char=a هست و یک char=b.
استفاده از برچسبها قدرت اصلی صادرکننده هستن ولی استفاده نادرست ازشون به راحتی میتونه تمام اون قدرت رو بگیره. **میدونیم هر حالت برچسب، یک صورت جدید از متریک درست میکنه**. پس اگر یک متریک دارای ۳ تا برچسب باشه که هر کدومشون میتونن ۵ حالت مختلف داشته باشن، ۵×۵×۵=۱۲۵ صورت جدید از متریک درست میشه. چیزی که مشکلساز میشه این هست که پرومتئوس در هر n ثانیه به جای ۱ متریک، باید ۱۲۵ متریک دریافت، پردازش و ذخیره کنه. در اینجا گفته میشه که صادر کننده cardinality بالایی داره و باید [کاهش](http://prometheus.io/docs/practices/instrumentation/#use-labels) پیدا کنه.
### دیگه چی؟
از صادرکنندههای معروف پرومتئوس node_exporter هست که اطلاعات مربوط به یک سیستم رو از کرنل لینوکس میگیره و به پرومتئوس میده. cadvisor هم یکی دیگه از صادرکنندههاست که اطلاعات مربوط به کانتینرهای داکر رو برای پرومتئوس صادر میکنه. شما هم میتونید برای درک بهتر از نرمافزار و سیستمی که روش نرمافزارتون درحال اجراست، از node_exporter و cadvisor در کنار صادرکننده نرمافزار خودتون استفاده کنید. برای وصل کردن همه اینها به هم با داکر و استفاده بهتر از صادرکنندهها من [اینجا](https://github.com/DearRude/prom-grafana) یک سری اسکریپت نوشتم و توی [این ویدئو](https://www.youtube.com/watch?v=3HkHhlWsKqg) هم راجع بهش بیشتر صحبت شده.