لاگ‌ها

لاگ ساخت‌یافته: چرا لاگ JSON عیب‌یابی رو سریع‌تر می‌کنه.

نویسنده: تیم noc724۳ دقیقه مطالعهبه‌روزرسانی: ۲۶ مهر ۱۴۰۵

یه خط لاگ متنی ساده برای آدمی نوشته شده که هر بار یه خط می‌خونه. عیب‌یابی در محیط تولید به‌ندرت این‌جوریه: بین میلیون‌ها خط دنبال یه شناسه‌ی سفارش می‌گردید، خطاها رو به تفکیک endpoint می‌شمرید، یا یه درخواست رو بین پنج سرویس دنبال می‌کنید. لاگ ساخت‌یافته (معمولاً JSON) هر مقدار رو به یه فیلد تبدیل می‌کنه که ابزارها مستقیم می‌تونن روش جستجو کنن.

نکته‌های کلیدی

  • لاگ ساخت‌یافته رویدادها رو به‌جای متن آزاد، به‌شکل فیلدهای کلید-مقدار ثبت می‌کنه.
  • فیلدها فیلتر کردن، شمردن و ربط دادن رو سریع و مطمئن می‌کنن.
  • در هر رویداد زمان، سطح، سرویس، پیام و یه شناسه‌ی درخواست/trace بذارید.
  • اسم فیلدها رو بین سرویس‌ها یکسان نگه دارید.
  • هیچ‌وقت رمزها یا داده‌ی شخصی‌ای که لازم ندارید رو لاگ نکنید.
قطعی پیش میاد. زود باخبر شید!

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
leveldebug / 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"}})

Go (log/slog)

logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Error("payment failed", "order_id", 58114, "reason", "gateway_timeout", "duration_ms", 10002)

Node.js

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

تیم فنی مانیتورینگ آپتایم

ما noc724 رو می‌سازیم و اداره می‌کنیم؛ سرویس مانیتورینگ آپتایمی که سایت، سرور و API رو از چند شهر ایران چک می‌کنه. این راهنماها از مشکل‌هایی میان که خودمون و کاربرهامون موقع آنلاین نگه داشتن سرویس‌ها باهاشون روبه‌رو می‌شیم.

تماس با تیم

تخصص:لاگ‌ها

سؤالی دارید؟تماس با پشتیبانی
پیشنهادی دارید؟بفرستید

تازه‌ترین مقاله‌ها