پیامک، تلگرام یا بله؟ انتخاب کانال هشدار بدون خستگی از هشدار
کدوم هشدارهای قطعی با پیامک برن و کدوم با تلگرام یا بله، چطور بر اساس فوریت مسیریابی کنیم و چطور هشدارهای مهم زیر هشدارهای بیمورد گم نشن.
یه خط لاگ متنی ساده برای آدمی نوشته شده که هر بار یه خط میخونه. عیبیابی در محیط تولید بهندرت اینجوریه: بین میلیونها خط دنبال یه شناسهی سفارش میگردید، خطاها رو به تفکیک endpoint میشمرید، یا یه درخواست رو بین پنج سرویس دنبال میکنید. لاگ ساختیافته (معمولاً JSON) هر مقدار رو به یه فیلد تبدیل میکنه که ابزارها مستقیم میتونن روش جستجو کنن.
noc724 سایت، سرور و APIهای شما رو شبانهروز چک میکنه و همون لحظهای که چیزی خراب شد با پیامک، تلگرام یا بله خبرتون میکنه.
متن ساده:
2026-10-18 09:14:03 ERROR Payment failed for order 58114 after 10002ms (gateway timeout)ساختیافته:
{"ts":"2026-10-18T09:14:03.211Z","level":"error","service":"payments","msg":"payment failed","order_id":58114,"duration_ms":10002,"reason":"gateway_timeout","request_id":"7f3c2a"}با شکل دوم، «همهی پرداختهای ناموفق بالای ۵ ثانیه در یه ساعت گذشته، به تفکیک علت» یه کوئریه، نه یه regex که امیدوارید درست باشه.
| فیلد | کاربرد |
|---|---|
ts | زمان ISO 8601 به UTC |
level | debug / info / warn / error / fatal |
service | کدوم برنامه نوشته |
msg | یه پیام کوتاه و ثابت («payment failed»)، نه جملهای با مقدارها داخلش |
request_id / trace_id | همهی کارهای یه درخواست رو به هم وصل میکنه |
duration_ms | عملیات چقدر طول کشید |
| شناسههای دامنه | user_id، order_id؛ هر چی که باهاش جستجو میکنید |
error | نوع و پیام خطا؛ stack trace در فیلد جدا |
قانون کلیدی: پیام رو ثابت نگه دارید و متغیرها رو در فیلدها بذارید. «payment failed» با order_id: 58114 عالی گروهبندی میشه؛ «Payment failed for order 58114» برای هر سفارش یه پیام یکتا میسازه.
import logging, json, sys
class JsonFormatter(logging.Formatter):
def format(self, record):
event = {"ts": self.formatTime(record, "%Y-%m-%dT%H:%M:%S"), "level": record.levelname.lower(),
"service": "payments", "msg": record.getMessage()}
event.update(getattr(record, "fields", {}))
return json.dumps(event)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(JsonFormatter())
log = logging.getLogger("payments")
log.addHandler(handler)
log.setLevel(logging.INFO)
log.error("payment failed", extra={"fields": {"order_id": 58114, "reason": "gateway_timeout"}})logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Error("payment failed", "order_id", 58114, "reason", "gateway_timeout", "duration_ms", 10002)console.log(JSON.stringify({ ts: new Date().toISOString(), level: "error", msg: "payment failed", order_id: 58114 }));در پروژههای واقعی بهجای قالببندی دستی از یه کتابخانهی جاافتاده (structlog، pino، zap و مشابهها) استفاده کنید.
یه شناسهی درخواست در لبه (لودبالانسر یا اولین سرویس) بسازید، اون رو در یه هدر مثل X-Request-ID یا traceparent استاندارد W3C منتقل کنید و در هر رویداد لاگش کنید. اونوقت یه جستجو کل داستان یه درخواست ناموفق رو بین سرویسها نشون میده؛ پایهی مشاهدهپذیری.
{"user_58114": ...})؛ پلتفرمهای لاگ هر کلید رو ایندکس میکنن.userId، user_id و uid در سه سرویس جستجوی بینسرویسی رو عذاب میکنه. روی یه طرح کوتاه توافق کنید.کمی. ابزارهایی مثل jq یا یه نمایشگر لاگ قشنگ قالببندیشون میکنن و خیلی از کتابخانهها در توسعه خروجی خوانا و در تولید JSON چاپ میکنن.
نه. حتی با فایل روی یه سرور، jq لاگهای JSON رو خیلی مطمئنتر از grep فیلتر میکنه و میشمره. پلتفرم مرکزی جستجو بین سرورها و نگهداری بلندمدت رو اضافه میکنه.
مکمل همان. متریک ارزونه و برای هشدار و روند عالیه؛ لاگ رویدادهای تکی رو توضیح میده. با متریک بشمرید، با لاگ توضیح بدید.
نویسنده
تیم noc724
تیم فنی مانیتورینگ آپتایم
ما noc724 رو میسازیم و اداره میکنیم؛ سرویس مانیتورینگ آپتایمی که سایت، سرور و API رو از چند شهر ایران چک میکنه. این راهنماها از مشکلهایی میان که خودمون و کاربرهامون موقع آنلاین نگه داشتن سرویسها باهاشون روبهرو میشیم.
تماس با تیمتخصص:لاگها
کدوم هشدارهای قطعی با پیامک برن و کدوم با تلگرام یا بله، چطور بر اساس فوریت مسیریابی کنیم و چطور هشدارهای مهم زیر هشدارهای بیمورد گم نشن.
چرا مانیتورهای آپتایم هشدار اشتباه میدن (اختلال شبکه، timeout، محدودیت نرخ، تغییر محتوا) و تنظیماتی که اینها رو حذف میکنه و هشدار واقعی رو سریع نگه میداره.
چطور یه چرخهی آنکال ساده و سیاست ارجاع هشدار بچینیم که هر هشدار حیاتی جواب داده بشه، بدون اینکه یه تیم کوچیک فرسوده بشه.