أساسيات Spring Boot

التسجيل في Spring Boot

18 دقيقة الدرس 8 من 13

التسجيل في Spring Boot

كل تطبيق Spring Boot في مرحلة الإنتاج يُولّد مخرجات تسجيل. إتقان هذه المخرجات — منظّمة، بمستوى تفصيل مناسب، موجَّهة إلى الوجهة الصحيحة — هو ما يُفرّق بين تطبيق تستطيع تشغيله وتطبيق لا تفعل سوى التخمين حين تسوء الأمور. يتناول هذا الدرس مكدّس التسجيل الافتراضي الذي يمنحك إياه Spring Boot، وكيفية عمل مستويات التسجيل، وكيفية ضبط كل شيء عبر application.properties أو application.yml.

المكدّس الافتراضي: SLF4J + Logback

يستخدم Spring Boot SLF4J واجهةً للتسجيل (logging facade) وLogback التنفيذَ الفعلي خلفها. يصلان معًا إلى مسار الفئات تلقائيًا عند تضمين spring-boot-starter (الذي يُعدّ تبعيةً انتقاليةً لكل starter آخر). لا تحتاج إلى إضافة أي تبعية تسجيل يدويًا في معظم التطبيقات.

لماذا واجهة (facade)؟ يفصل SLF4J الواجهة البرمجية التي تكتب من خلالها (org.slf4j.Logger) عن وقت التشغيل الذي ينتج المخرجات الفعلية. يمكنك استبدال Logback بـ Log4j 2 أو java.util.logging لاحقًا دون لمس سطر واحد من كود تطبيقك. يستخدم Spring Boot هذه الواجهة نفسها داخليًا، لذا تتدفق جميع سجلات الإطار عبر نفس خط الأنابيب.

يأتي Spring Boot أيضًا مع ملفات JAR جسرية (jcl-over-slf4j وlog4j-to-slf4j وjul-to-slf4j) تُحوّل مسارات التسجيل القديمة إلى خط أنابيب SLF4J. هذا يعني أن المكتبات الخارجية التي تستخدم Commons Logging أو Log4j 1.x أو java.util.logging تنتهي جميعها في Logback تلقائيًا.

الحصول على Logger

أعلن عن logger كحقل private static final في كل فئة. النمط المتعارف عليه مع SLF4J هو:

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @Service public class OrderService { private static final Logger log = LoggerFactory.getLogger(OrderService.class); public void placeOrder(Long orderId) { log.debug("Placing order id={}", orderId); // منطق العمل ... log.info("Order {} placed successfully", orderId); } }

محددات {} هي صيغة التسجيل المُعلمَّة في SLF4J. تحدث عملية دمج السلسلة النصية فقط إذا كان مستوى التسجيل مُفعَّلًا، لذا لا تكلفة أداء لاستدعاء log.debug(...) حين يكون تسجيل debug معطلًا.

استخدم @Slf4j من Lombok للتخلص من الكود الزائد. إضافة @Slf4j من org.projectlombok:lombok يُولّد حقل private static final Logger log = LoggerFactory.getLogger(...); وقت الترجمة، مما يُبقي فئتك نظيفة. الحقل المُولَّد مطابق تمامًا لما ستكتبه يدويًا.

مستويات التسجيل

يُعرّف SLF4J خمسة مستويات بترتيب تصاعدي للخطورة:

  • TRACE — أدق مستوى تفصيلي؛ يشمل عادةً استدعاءات الطرق المفردة أو تكرارات الحلقات أو إطارات البروتوكول منخفضة المستوى. غالبًا معطّل في الإنتاج.
  • DEBUG — معلومات تشخيصية مفيدة أثناء التطوير واستكشاف الأخطاء. عادةً معطّل في الإنتاج أو مُفعَّل لحزم محددة فقط.
  • INFO — أحداث التشغيل العادية: بدء التطبيق، استقبال طلب، تنفيذ طلب. المستوى الافتراضي لكودك.
  • WARN — حدث شيء غير متوقع لكن التطبيق تعافى: نجاح إعادة المحاولة، استدعاء واجهة برمجية مُهملة، تعيين قيمة إعداد افتراضية.
  • ERROR — فشل يستدعي الانتباه: استثناء غير معالج، فشل استدعاء خارجي، كشف تلف في البيانات.

حين تضبط logger على مستوى معين، يكون ذلك المستوى وكل المستويات الأعلى مُفعَّلة. ضبط حزمة على DEBUG يُفعّل DEBUG و INFO و WARN و ERROR لكل فئة في تلك الحزمة.

الإعدادات الافتراضية في Spring Boot

بشكل افتراضي، يُهيّئ Spring Boot:

  • المستوى الجذري: INFO — كود تطبيقك وجميع المكتبات الخارجية تُسجّل عند INFO وما فوق.
  • Spring الداخلية: INFO لحزم org.springframework.
  • Hibernate SQL: WARN — لا يُسجَّل SQL المُولَّد ما لم تُفعّله صراحةً.
  • مخرج وحدة التحكم: مخرج ملوّن بالطابع الزمني ومستوى التسجيل والخيط واسم الـ logger والرسالة.

تبدو صيغة وحدة التحكم الافتراضية هكذا:

2024-03-15T10:42:01.123+00:00 INFO 12345 --- [main] com.example.OrderService : Order 42 placed successfully

ضبط مستويات التسجيل في application.properties

الطريقة الأساسية لتغيير مستويات التسجيل هي عبر application.properties (أو application.yml) باستخدام البادئة logging.level. متبوعةً بالاسم المؤهل كليًا للحزمة أو الفئة:

# تعيين الـ logger الجذري على WARN (أهدأ في الإنتاج) logging.level.root=WARN # حزمة تطبيقك: إبقاؤها عند INFO logging.level.com.example=INFO # تفعيل DEBUG لفئة خدمة واحدة logging.level.com.example.OrderService=DEBUG # رؤية كل SQL المُولَّد بواسطة Hibernate (للتطوير فقط) logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.orm.jdbc.bind=TRACE # رؤية تفاصيل ربط الطلبات في Spring MVC logging.level.org.springframework.web=DEBUG
لا تترك org.hibernate.orm.jdbc.bind=TRACE مُفعَّلًا في الإنتاج أبدًا. يُسجّل هذا الإعداد كل قيمة معاملة مُرتبطة، مما يكشف عن كلمات مرور وبيانات شخصية ومعلومات حساسة في ملفات السجل. استخدمه فقط أثناء التطوير المحلي لتصحيح مشاكل الاستعلامات، ثم احذفه قبل commit.

ضبط ملف السجل

افتراضيًا، يُسجّل Spring Boot فقط في وحدة التحكم. للكتابة أيضًا في ملف، اضبط إحدى الخصائص التالية:

# الكتابة في مسار ملف ثابت logging.file.name=/var/log/myapp/app.log # الكتابة في ملف باسم spring.log داخل هذا المجلد logging.file.path=/var/log/myapp

يطبّق Spring Boot تلقائيًا سياسة التدوير (rolling policy) عند الكتابة في ملف: تُدوَّر ملفات السجل عند وصولها إلى 10 ميغابايت، وتُحتفظ بما يصل إلى 7 أيام من السجل افتراضيًا. يمكنك ضبط الاثنين:

logging.logback.rollingpolicy.max-file-size=50MB logging.logback.rollingpolicy.max-history=30 logging.logback.rollingpolicy.total-size-cap=1GB

تخصيص نمط المخرجات

نمطا وحدة التحكم والملف قابلان للتخصيص أيضًا دون الحاجة للمس أي ملف XML:

# صيغة مخرجات وحدة التحكم logging.pattern.console=%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n # صيغة مخرجات الملف (غالبًا أكثر تفصيلًا) logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{50} - %msg%n

التسجيل المُهيكَل (JSON) — Spring Boot 3.4 فأحدث

من Spring Boot 3.4، التسجيل المُهيكَل بصيغة JSON مدمج ويتطلب خاصية واحدة فقط:

logging.structured.format.console=ecs

يُنتج هذا مخرجات JSON وفق مخطط Elastic Common Schema (ECS) في وحدة التحكم — مثالي لمنصات تجميع السجلات مثل OpenSearch أو Elasticsearch أو Loki. الصيغ البديلة هي logstash وgelf. كل حدث تسجيل هو كائن JSON واحد، مما يجعله قابلًا للتحليل بسهولة من قِبَل أي مجمّع سجلات.

الملف logback-spring.xml الكامل — حين تحتاج تحكمًا أعمق

إذا لم تكفِ application.properties — مُخرجات مخصصة، ملفات متعددة، أنماط مختلفة لكل بيئة — أنشئ src/main/resources/logback-spring.xml. يكتشفه Spring Boot ويستخدمه تلقائيًا. اللاحقة -spring (مقابل logback.xml العادي) تتيح لـ Spring معالجة عناصر <springProfile>:

<configuration> <springProfile name="prod"> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>/var/log/myapp/app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>/var/log/myapp/app.%d{yyyy-MM-dd}.gz</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="WARN"> <appender-ref ref="FILE"/> </root> </springProfile> <springProfile name="dev"> <root level="DEBUG"> <appender-ref ref="CONSOLE"/> </root> </springProfile> </configuration>

مجموعات التسجيل (Log Groups)

يتيح لك Spring Boot تعريف مجموعات تسجيل — أسماء مستعارة لمجموعة من الحزم — ثم التحكم في المجموعة كلها بخاصية واحدة. مجموعتان مُعرَّفتان مسبقًا: web وsql.

# استخدام مجموعة "web" المدمجة لتصحيح جميع loggers طبقة الويب دفعة واحدة logging.level.web=DEBUG # استخدام مجموعة "sql" المدمجة لتفعيل جميع loggers المرتبطة بـ SQL logging.level.sql=DEBUG # تعريف مجموعة مخصصة logging.group.billing=com.example.billing,com.example.payment logging.level.billing=DEBUG

الخلاصة

يأتي Spring Boot مُجهَّزًا بـ SLF4J فوق Logback، مُهيَّئًا مسبقًا عند مستوى INFO مع مخرجات وحدة تحكم ملوّنة وتدوير تلقائي للملفات. تتحكم في كل شيء عبر خصائص logging.level.* وlogging.file.* وlogging.pattern.* — لا حاجة لـ XML في معظم التطبيقات. حين تحتاج مُخرجات خاصة بالبيئة أو توجيهًا دقيقًا، أنشئ ملف logback-spring.xml في src/main/resources. في الدرس القادم ستتعرف على كيفية تسريع دورة التطوير باستخدام Spring Boot DevTools مع إعادة التشغيل التلقائية والتحديث الفوري.