السجلات وCloudWatch لـ Lambda
مقدمة
السجلات ضرورية لفهم سلوك وظائف Lambda الخاصة بك وتشخيص المشاكل. Amazon CloudWatch Logs هو الخدمة الأصلية لجمع وتخزين وتحليل هذه السجلات.
بنية سجلات Lambda
┌─────────────────────────────────────────────────────────────────┐
│ تدفق سجلات LAMBDA │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Lambda │────►│ CloudWatch │────►│ تحليل │ │
│ │ Function │ │ Logs │ │ / تنبيهات │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ كل استدعاء يولد : │
│ • START RequestId │
│ • سجلاتك (print, console.log) │
│ • END RequestId │
│ • REPORT (المدة، الذاكرة، الفوترة) │
│ │
└─────────────────────────────────────────────────────────────────┘
هيكل مجموعات السجلات
CloudWatch Logs
│
├── /aws/lambda/ma-fonction-1
│ ├── Log Stream 2024/01/15/[$LATEST]abc123
│ ├── Log Stream 2024/01/15/[$LATEST]def456
│ └── Log Stream 2024/01/16/[$LATEST]ghi789
│
├── /aws/lambda/ma-fonction-2
│ └── ...
│
└── /aws/lambda/ma-fonction-3
└── ...
المفاهيم الأساسية:
- Log Group : مجموعة لكل وظيفة Lambda (
/aws/lambda/nom-fonction) - Log Stream : تدفق لكل مثيل من حاوية Lambda
- Log Event : كل سطر سجل فردي
تنسيق سجلات Lambda
رسالة START
START RequestId: 12345-abcde-67890 Version: $LATEST
رسائل مخصصة (الكود الخاص بك)
# Python
print("معالجة المستخدم:", user_id)
logger.info("الاتصال بقاعدة البيانات")
logger.error("خطأ: الملف غير موجود")
// Node.js
console.log("معالجة المستخدم:", userId);
console.info("الاتصال بقاعدة البيانات");
console.error("خطأ: الملف غير موجود");
رسالة END
END RequestId: 12345-abcde-67890
رسالة REPORT (مهم جداً!)
REPORT RequestId: 12345-abcde-67890
Duration: 234.56 ms
Billed Duration: 235 ms
Memory Size: 128 MB
Max Memory Used: 67 MB
Init Duration: 145.23 ms
تحليل REPORT
┌─────────────────────────────────────────────────────────────────┐
│ تحليل REPORT │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Duration: 234.56 ms │
│ └── وقت التنفيذ الفعلي للكود الخاص بك │
│ │
│ Billed Duration: 235 ms │
│ └── الوقت المفوتر (مقرب لأعلى مللي ثانية) │
│ │
│ Memory Size: 128 MB │
│ └── الذاكرة المخصصة (المكونة) │
│ │
│ Max Memory Used: 67 MB │
│ └── الذاكرة المستخدمة فعلياً │
│ إذا كانت قريبة من Memory Size = خطر OOM! │
│ │
│ Init Duration: 145.23 ms (Cold Start فقط) │
│ └── وقت تهيئة الحاوية │
│ │
└─────────────────────────────────────────────────────────────────┘
أفضل ممارسات التسجيل
1. بنية التسجيل (JSON)
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
# بنية السجل لتسهيل التحليل
log_entry = {
"level": "INFO",
"request_id": context.aws_request_id,
"action": "process_order",
"order_id": event.get("order_id"),
"user_id": event.get("user_id")
}
logger.info(json.dumps(log_entry))
2. مستويات السجل
┌─────────────────────────────────────────────────────────────────┐
│ مستويات السجل │
├─────────────────────────────────────────────────────────────────┤
│ │
│ DEBUG → تفاصيل تقنية (للمطورين فقط) │
│ INFO → عمليات عادية │
│ WARNING → حالات غير طبيعية ولكنها معالجة │
│ ERROR → أخطاء تحتاج إلى اهتمام │
│ CRITICAL → أخطاء خطيرة، الوظيفة معرضة للخطر │
│ │
│ الإنتاج : INFO وما فوق │
│ التطوير : DEBUG وما فوق │
│ │
└─────────────────────────────────────────────────────────────────┘
3. المعلومات الأساسية للتسجيل
def lambda_handler(event, context):
# دائماً سجل في البداية
logger.info(f"START - RequestId: {context.aws_request_id}")
logger.info(f"Event: {json.dumps(event)}")
try:
# منطقك
result = process_data(event)
# سجل النجاح
logger.info(f"SUCCESS - Result: {result}")
return result
except Exception as e:
# سجل الخطأ مع التفاصيل
logger.error(f"ERROR - Type: {type(e).__name__}")
logger.error(f"ERROR - Message: {str(e)}")
logger.error(f"ERROR - Event: {json.dumps(event)}")
raise
البحث في السجلات
CloudWatch Logs Insights
-- العثور على جميع الأخطاء
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 100
-- تحليل أوقات التنفيذ
fields @timestamp, @duration
| filter @type = "REPORT"
| stats avg(@duration), max(@duration), min(@duration)
-- العثور على Cold Starts
fields @timestamp, @message
| filter @message like /Init Duration/
| sort @timestamp desc
-- الذاكرة القريبة من الحد
fields @timestamp, @maxMemoryUsed, @memorySize
| filter @type = "REPORT"
| filter @maxMemoryUsed / @memorySize > 0.8
فلاتر الأنماط
# العثور على الأخطاء
?ERROR ?Error ?error
# العثور على RequestId محدد
"12345-abcde-67890"
# العثور على timeouts
"Task timed out"
# العثور على OOM (Out of Memory)
"Runtime exited" "memory"
احتفاظ السجلات
┌─────────────────────────────────────────────────────────────────┐
│ احتفاظ السجلات │
├─────────────────────────────────────────────────────────────────┤
│ │
│ بشكل افتراضي : يتم الاحتفاظ بالسجلات إلى أجل غير مسمى │
│ └── انتبه لتكاليف التخزين! │
│ │
│ خيارات الاحتفاظ : │
│ • 1 يوم، 3 أيام، 5 أيام، 1 أسبوع │
│ • 2 أسبوع، 1 شهر، 2 شهر، 3 شهر │
│ • 6 شهر، 1 سنة، 13 شهر، 18 شهر │
│ • 2 سنة، 3 سنوات، 5 سنوات، 10 سنوات │
│ • لا تنتهي أبداً │
│ │
│ التوصية : │
│ • Dev/Test : 1-7 أيام │
│ • الإنتاج : 30-90 يوم │
│ • الامتثال : حسب اللوائح │
│ │
└─────────────────────────────────────────────────────────────────┘
المقاييس الهامة
| المقياس | الوصف | العتبة النموذجية للتنبيه |
|---|---|---|
| Invocations | عدد الاستدعاءات | حسب الخط الأساسي |
| Duration | وقت التنفيذ | > 80% من المهلة |
| Errors | عدد الأخطاء | > 1% من الاستدعاءات |
| Throttles | الاستدعاءات المحدودة | > 0 |
| ConcurrentExecutions | التنفيذ المتوازي | > 80% من الحد |
تمرين عملي
السيناريو : تحليل سجلات وظيفة بها مشكلة
السجلات الملاحظة :
────────────────────────────────────────────────────────
START RequestId: abc-123
Connecting to database...
REPORT Duration: 29543.21 ms Billed: 29544 ms
Memory: 128 MB Max Used: 125 MB
START RequestId: def-456
Connecting to database...
Task timed out after 30.00 seconds
START RequestId: ghi-789
Runtime exited with error: signal: killed
────────────────────────────────────────────────────────
الأسئلة :
1. ما هي المشكلة الرئيسية؟
2. ما هي المقاييس غير الطبيعية؟
3. ما هي الحلول التي تقترحها؟
عرض التحليل
المشاكل المحددة :
- Timeout : الوظيفة تستغرق تقريباً 30 ثانية (الحد)
- الذاكرة : 125/128 MB مستخدمة (97% - حرج!)
- OOM : "Runtime exited... signal: killed" = Out of Memory
الحلول :
- زيادة الذاكرة (256 MB أو أكثر)
- تحسين كود الاتصال بقاعدة البيانات (connection pooling)
- زيادة المهلة إذا لزم الأمر
- إضافة سجلات لتحديد عنق الزجاجة
الملخص
- CloudWatch Logs تلتقط تلقائياً جميع سجلات Lambda
- رسالة REPORT تحتوي على مقاييس الأداء
- استخدم التسجيل الهيكلي (JSON) لتسهيل التحليل
- قم بتكوين الاحتفاظ للتحكم في التكاليف
- CloudWatch Logs Insights يسمح باستعلامات SQL على السجلات
القسم التالي : اختبار التحقق