انتقل إلى المحتوى الرئيسي

الفصل 4: إعداد Logback

مقدمة​

Logback هو التنفيذ الافتراضي لتسجيل الدخول في Spring Boot. هذا الفصل يعلمك كيفية إعداده لبيئات مختلفة.


🎯 أهداف الفصل​

في نهاية هذا الفصل، ستتمكن من:

  1. ✅ إنشاء ملف logback-spring.xml
  2. ✅ إعداد الملاحق (Console، File، Rolling)
  3. ✅ تخصيص أنماط السجلات
  4. ✅ استخدام ملفات تعريف Spring
  5. ✅ إعداد سجلات JSON للإنتاج

1. الإعداد الأساسي​

ملف logback-spring.xml​

قم بإنشاء src/main/resources/logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<!-- استيراد قيم Spring Boot -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>

<!-- متغير لاسم التطبيق -->
<springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="myapp"/>

<!-- Console Appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<!-- الإعداد الافتراضي -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>

<!-- مستوى محدد لتطبيقك -->
<logger name="com.myapp" level="DEBUG"/>

</configuration>

2. أنماط السجلات​

صيغة الأنماط​

النمطالوصفالمثال
%d\{format\}التاريخ/الوقت2024-01-15 10:30:00
%threadاسم الخيطhttp-nio-8080-exec-1
%level / %-5levelالمستوى (مبطن)INFO
%logger\{n\}اسم المسجل (n حروف)c.m.s.UserService
%msgالرسالةUser logged in
%nسطر جديد
%X\{key\}قيمة MDCabc-123
%highlight()الألوان (للكونسول)

أمثلة على الأنماط​

<!-- بسيط -->
<pattern>%d{HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
<!-- Output: 10:30:00 INFO c.m.s.UserService - User logged in -->

<!-- مع MDC -->
<pattern>%d{HH:mm:ss} [%X{requestId}] [%X{userId}] %-5level %logger{36} - %msg%n</pattern>
<!-- Output: 10:30:00 [abc-123] [42] INFO c.m.s.UserService - User logged in -->

<!-- ملون للكونسول -->
<pattern>%d{HH:mm:ss} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>

<!-- مفصل للملف -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId:-N/A}] %-5level %logger{50} - %msg%n</pattern>

3. الملاحق​

Console Appender​

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>

File Appender (ملف بسيط)​

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logs/application.log</file>
<append>true</append>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>

Rolling File Appender (مع التدوير)​

<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>

<!-- سياسة التدوير -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- اسماء الملفات المؤرشفة -->
<fileNamePattern>logs/application.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<!-- الحجم الأقصى لكل ملف -->
<maxFileSize>10MB</maxFileSize>
<!-- عدد أيام الاحتفاظ -->
<maxHistory>30</maxHistory>
<!-- الحجم الكلي الأقصى -->
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>

<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>

4. ملفات تعريف Spring​

الإعداد حسب الملف التعريفي​

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<include resource="org/springframework/boot/logging/logback/defaults.xml"/>

<!-- Appender Console (دائمًا موجود) -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>

<!-- ===== الملف التعريفي DEV ===== -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
<logger name="com.myapp" level="DEBUG"/>
<logger name="org.hibernate.SQL" level="DEBUG"/>
</springProfile>

<!-- ===== الملف التعريفي PROD ===== -->
<springProfile name="prod">

<!-- ملف مع التدوير -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/myapp/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/myapp/application.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>

<root level="WARN">
<appender-ref ref="FILE"/>
</root>
<logger name="com.myapp" level="INFO"/>
</springProfile>

<!-- ===== الملف التعريفي TEST ===== -->
<springProfile name="test">
<root level="WARN">
<appender-ref ref="CONSOLE"/>
</root>
<logger name="com.myapp" level="INFO"/>
</springProfile>

</configuration>

5. سجلات JSON للإنتاج​

لماذا JSON؟​

سجلات نصية:
2024-01-15 10:30:00 INFO UserService - User 42 logged in

سجلات JSON (قابلة للتحليل بواسطة ELK، Datadog، إلخ.):
{"timestamp":"2024-01-15T10:30:00.000Z","level":"INFO","logger":"UserService","message":"User logged in","userId":42}

التبعية​

<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>

إعداد JSON​

<!-- Appender JSON -->
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/myapp/application.json</file>

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/myapp/application.%d{yyyy-MM-dd}.%i.json.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
</rollingPolicy>

<!-- Encoder JSON -->
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdcKeyName>requestId</includeMdcKeyName>
<includeMdcKeyName>userId</includeMdcKeyName>
<customFields>{"app":"myapp","env":"prod"}</customFields>
</encoder>
</appender>

<springProfile name="prod">
<root level="INFO">
<appender-ref ref="JSON_FILE"/>
</root>
</springProfile>

مخرجات JSON​

{
"@timestamp": "2024-01-15T10:30:00.000Z",
"@version": "1",
"message": "User logged in",
"logger_name": "com.myapp.service.UserService",
"thread_name": "http-nio-8080-exec-1",
"level": "INFO",
"requestId": "abc-123",
"userId": "42",
"app": "myapp",
"env": "prod"
}

6. إعداد كامل احترافي​

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">

<include resource="org/springframework/boot/logging/logback/defaults.xml"/>

<springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="myapp"/>
<property name="LOG_PATH" value="${LOG_PATH:-logs}"/>

<!-- ===== CONSOLE APPENDER ===== -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%X{requestId:-}] %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>

<!-- ===== FILE APPENDER (نص) ===== -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APP_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/archived/${APP_NAME}.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId:-N/A}] [%X{userId:-anonymous}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>

<!-- ===== ERROR FILE APPENDER ===== -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APP_NAME}-error.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/archived/${APP_NAME}-error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{50} - %msg%n%ex</pattern>
</encoder>
</appender>

<!-- ===== ASYNC APPENDER (الأداء) ===== -->
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>512</queueSize>
<discardingThreshold>0</discardingThreshold>
<includeCallerData>false</includeCallerData>
<appender-ref ref="FILE"/>
</appender>

<!-- ===== الملف التعريفي DEV ===== -->
<springProfile name="dev,local">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
<logger name="com.myapp" level="DEBUG"/>
<logger name="org.hibernate.SQL" level="DEBUG"/>
<logger name="org.springframework.web" level="DEBUG"/>
</springProfile>

<!-- ===== الملف التعريفي PROD ===== -->
<springProfile name="prod">
<root level="WARN">
<appender-ref ref="ASYNC_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<logger name="com.myapp" level="INFO"/>
</springProfile>

<!-- ===== الملف التعريفي TEST ===== -->
<springProfile name="test">
<root level="WARN">
<appender-ref ref="CONSOLE"/>
</root>
<logger name="com.myapp" level="INFO"/>
</springProfile>

<!-- ===== الافتراضي (بدون ملف تعريفي) ===== -->
<springProfile name="default">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
<logger name="com.myapp" level="DEBUG"/>
</springProfile>

</configuration>

7. مسجلات محددة مفيدة​

<!-- استعلامات SQL Hibernate -->
<logger name="org.hibernate.SQL" level="DEBUG"/>
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>

<!-- Spring Security -->
<logger name="org.springframework.security" level="DEBUG"/>

<!-- استعلامات HTTP الواردة -->
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="DEBUG"/>

<!-- Connection Pool -->
<logger name="com.zaxxer.hikari" level="DEBUG"/>

<!-- المعاملات -->
<logger name="org.springframework.transaction" level="DEBUG"/>

<!-- تعطيل السجلات المزعجة -->
<logger name="org.apache.catalina" level="WARN"/>
<logger name="org.apache.tomcat" level="WARN"/>

8. ملخص​

ملفات الإعداد​

الملفالاستخدام
application.propertiesإعداد بسيط
logback-spring.xmlإعداد متقدم
logback.xmlإعداد بدون Spring

الملاحق الشائعة​

الملحقالاستخدام
ConsoleAppenderالكونسول (للتطوير)
FileAppenderملف بسيط
RollingFileAppenderملف مع التدوير
AsyncAppenderالأداء (للإنتاج)

النمط الموصى به​

%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] %-5level %logger{50} - %msg%n

🎯 الخطوة التالية​

حان وقت التطبيق العملي! لنقم بتنفيذ نظام كامل لإدارة الأخطاء وتسجيل الدخول.

➡️ TP10.1: إدارة الأخطاء المركزية


⬅️ العودة إلى الوحدة 10