CodeGym /Kurslar /JAVA 25 SELF /Loqların formatlanması və səviyyələri: best practices

Loqların formatlanması və səviyyələri: best practices

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. Loq mesajının strukturu

Gəlin təsəvvür edək ki, loqlar — proqramınızın sadəcə «şüur axını» deyil, elə bir dəyərli jurnaldır ki, bir ay və ya bir il sonra siz və ya həmkarınız «Burada nə baş verib axı?» sualının cavabını tapa bilsin. Bunun mümkün olması üçün hər loq mesajı strukturlu olmalıdır. Adətən (və bu, kitabxınaların çoxunda standartdır) hər mesaj aşağıdakıları ehtiva edir:

  • Hadisənin vaxtı — nə vaxt baş verdiyi.
  • Səviyyə — bunun nə dərəcədə vacib olduğu (INFO, ERROR və s.).
  • Logger-in adı — adətən bu, sinifin və ya komponentin adıdır.
  • Mesaj mətni — dəqiq nə baş verdiyi.
  • Stack trace (səhv varsa) — harada və niyə baş verdiyini anlamaq üçün.

Log4j/SLF4J nümunəsində yaxşı formatlanmış loq sətiri:

2024-06-16 18:42:07,123 INFO  com.example.MainApp - İstifadəçi sistemə daxil oldu: username=vasya

Əgər səhv baş veribsə:

2024-06-16 18:42:10,456 ERROR com.example.LoginService - İstifadəçinin avtorizasiyasında səhv: vasya
java.lang.IllegalArgumentException: Yanlış şifrə
    at com.example.LoginService.checkPassword(LoginService.java:42)
    ...

Bu nə üçün vacibdir?
Tətbiq uzun müddət işləyəndə loqlar qiqabaytlarla yer tuta bilər. Mesajlar strukturlu deyilsə, problemi tapmaq «ventilyatorun səsindən melodiyanı tapmaq» səviyyəsində bir tapmacaya çevrilir.

2. Mesajların formatlanması

Niyə belə etmək olmaz:

logger.info("İstifadəçi " + username + " sistemə daxil oldu");

Hər şey sadə görünür, amma burada bir məqam var: loq səviyyəsi indi ERROR olsa belə, mötərizənin içindəki sətir yenə də yığılacaq (birləşdirmə işləyəcək), bu isə resursların artıq sərfidir. Saniyədə minlərlə sətirin loqlandığı böyük sistemlərdə bu, real gecikmələrə səbəb ola bilər.

Düzgün yanaşma: şablonlar və parametrlər

Müasir kitabxanalar (məsələn, SLF4J və Log4j 2) parametrli şablonları dəstəkləyir:

logger.info("İstifadəçi {} sistemə daxil oldu", username);

Burada sətir yalnız loq səviyyəsi bu mesajı çıxarmağa imkan verirsə formalaşdırılacaq. Məsələn, WARN qoyulubsa, sətir ümumiyyətlə hesablanmayacaq — resurs və əsəb qənaəti.

Bonus: bir neçə parametr ötürsəniz, onlar sırayla yerləşdiriləcək:

logger.info("İstifadəçi {} {} əməliyyatını {} obyektində icra etdi", username, action, objectId);

İstisnaların loqlaşdırılması (stack trace)

İstisnanı tutursunuzsa, stack trace-i əllə mesaja əlavə etməyin:

// ETMƏYİN:
logger.error("Xəta: " + ex.getMessage() + "\n" + Arrays.toString(ex.getStackTrace()));

Düzgün:

logger.error("Sorğunun emalı zamanı səhv", ex);

SLF4J və Log4j stack trace-i loqa özləri səliqəli şəkildə əlavə edəcək.

Nümunə: yanaşmaların müqayisəsi

// Pis (birləşdirmə həmişə icra olunur)
logger.debug("Obyekt: " + expensiveToString(obj));

// Yaxşı (tənbəl formalaşdırma)
logger.debug("Obyekt: {}", obj);

3. Loq səviyyələrinin seçimi

Əgər loqlarda hər şey ERROR səviyyəsindədirsə, bu artıq loq deyil, «qırmızı xəbərdarlıq lampasıdır». Hər şey DEBUG-dirsə, detallarda boğulacaqsınız. Gəlin hansı səviyyəni nə vaxt istifadə etməyi aydınlaşdıraq.

Səviyyə Nə üçün istifadə olunur Mesaj nümunəsi
ERROR
Sistemin səhv işləməsinə və ya ümumiyyətlə işləməməsinə səbəb olan kritik nasazlıqlar «Məlumat bazasına qoşulma xətası»
WARN
Vacib xəbərdarlıqlar, kritik deyil, amma diqqət tələb edir «İstifadəçini tapmaq mümkün olmadı, guest istifadə olunur»
INFO
Tətbiqin normal işini əks etdirən adi hadisələr «İstifadəçi qeydiyyatdan keçdi: vasya»
DEBUG
Sazlama üçün ətraflı məlumat, production-da lazım deyil «checkPassword metodu parametrlərlə çağrıldı ...»
TRACE
Ən detallı məlumat, adətən dərin diaqnostika üçün «Emal dövrünün başlanğıcı: i=0»

Tipik mesaj nümunələri

  • ERROR — fayl yazıla bilmədi, emal olunmamış istisna tutuldu, servis əlçatan deyil.
  • WARN — köhnəlmiş (deprecated) API, şübhəli istifadəçi davranışı, cəhd limiti aşılıb.
  • INFO — istifadəçi daxil oldu/çıxdı, sifarişin emalı başa çatdı, tətbiqin startı.
  • DEBUG — sorğu parametrləri, dəyişənlərin dəyərləri, hesablamaların aralıq nəticələri.
  • TRACE — metodlara giriş/çıxış, daxili döngələr, alqoritmlərin işinin təfərrüatları.

Məsləhət:
Production mühitində adətən yalnız INFO və yuxarı səviyyələr açıq olur, bəzən WARNERROR. DEBUGTRACE — yalnız mürəkkəb bug-ların axtarışı zamanı.

4. Best practices (loqlaşdırma üçün ən yaxşı təcrübələr)

Həssas məlumatları loqa yazmayın

Parollar, tokenlər, kredit kartı nömrələri — bunların heç birinin loqlarda yeri yoxdur. «Loq faylı — yalnız mənim üçündür» kimi görünsə belə, GDPR-ı və loqu təsadüfən ümumi çata göndərən həmkarınızı xatırlayın.

// Pis:
logger.info("İstifadəçi {} parol {} ilə daxil oldu", username, password);

// Yaxşı:
logger.info("İstifadəçi {} sistemə daxil oldu", username);

ERROR səviyyəsini sui-istifadə etməyin

Hər şeyi logger.error ilə yazırsınızsa, həqiqətən fəlakət olanda bunu heç kim görməyəcək — hamı «qırmızı lampalara» öyrəşəcək. ERROR səviyyəsini yalnız tətbiq həqiqətən işi davam etdirə bilməyəndə və ya biznes məntiqi pozulanda istifadə edin.

İstisnaları tam stack ilə loqlaşdırın

Təkcə ex.getMessage() yazmayın, yoxsa səhvin dəqiq harada baş verdiyini heç vaxt bilməyəcəksiniz. İstisnanı logger-ə ikinci parametr kimi ötürün.

logger.error("Sorğunun emalı zamanı səhv", ex);

Unikal identifikatorlardan istifadə edin (hadisələrin korrelyasiyası)

Böyük sistemlərdə hər bir sorğuya, istifadəçiyə və ya əməliyyata unikal identifikator vermək faydalıdır. Bu, sistemin müxtəlif hissələrindən gələn hadisələri «birləşdirməyə» kömək edəcək.

logger.info("Sifarişin emalına başlanıldı: orderId={}", orderId);
logger.info("Sifariş uğurla emal olundu: orderId={}", orderId);

Hər şeyi loqa yazmayın

Loqlar həddindən artıq çoxdursa — onlar faydasız olur. Hər sətiri loqlaşdırmayın, əks halda lazım olan məlumatı tapmaq mümkünsüzləşəcək.

Mesajları aydın formatlayın

Mesajları elə yazın ki, onu təkcə kodun müəllifi deyil, loqları altı aydan sonra oxuyacaq şəxs də başa düşsün. Abreviaturalardan, qeyri-aşkar qısaltmalardan və «öz aramızda zarafatlardan» qaçın.

5. Təcrübə: loqun formatını və səviyyələri qurmaq

Log4j2-də formatın nümunə konfiqurasiyası (log4j2.xml)

<Configuration>
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="info">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

Bu nə deməkdir?

  • %d{...} — hadisənin vaxtı.
  • %-5level — səviyyə (ERROR, INFO və s.).
  • %logger{36} — logger-in adı (adətən sinif).
  • %msg — mesajın özü.

Müxtəlif loq səviyyələri ilə kod nümunəsi (SLF4J)

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogDemo {
    private static final Logger logger = LoggerFactory.getLogger(LogDemo.class);

    public static void main(String[] args) {
        logger.info("Tətbiq işə salındı");
        logger.debug("x dəyişəninin dəyəri: {}", 42);

        try {
            throw new IllegalArgumentException("Ay-ay-ay!");
            // ...
        } catch (Exception ex) {
            logger.error("İşə salınma zamanı xəta baş verdi", ex);
        }
    }
}

Səviyyələr arasındakı fərqin nümayişi

Əgər logger konfiqurasiyasında INFO səviyyəsi qoyulubsa, DEBUG və daha aşağı səviyyəli mesajlar çıxarılmayacaq. Konfiqdə səviyyəni debug olaraq dəyişməyə çalışın — detalları görəcəksiniz.

6. Tipik səhvlər

Səhv №1: Loqlarda sətirlərin birləşdirilməsi. Tez-tez yeni başlayanlar belə yazır:

logger.debug("İstifadəçi: " + user.getName() + ", rol: " + user.getRole());

Nəticədə DEBUG səviyyəsi söndürülü olsa belə bu sətirlər yığılacaq və əlavə yüklənməyə səbəb olacaq. Parametrlərdən istifadə edin!

Səhv №2: İstisnanın stack olmadan loqlaşdırılması. Yalnız mesaj yazılır:

logger.error("Xəta: " + ex.getMessage());

Nəticədə loqlarda səhvin dəqiq harada baş verdiyi barədə məlumat olmur. Exception-u ikinci parametr kimi ötürün!

Səhv №3: Hər şeyi ERROR səviyyəsində loqlaşdırmaq. Hamısı qırmızıdırsa — heç nə qırmızı deyil. Səviyyələri təyinatı üzrə istifadə edin, əks halda vacib xətalar «xırdalıqlar» arasında itəcək.

Səhv №4: Həssas məlumatların loqlaşdırılması. Heç vaxt loqlara parolları, tokenləri, kart nömrələrini yazmayın. Heç kim görməyəcək kimi görünsə də, həyat sürprizləri sevir.

Səhv №5: Anlaşılmaz mesajlar. Əgər loqdakı mesaj «ERR42: fail» kimidirsə, bir aydan sonra özünüz də bunun nə demək olduğunu xatırlamayacaqsınız. Aydın və ətraflı yazın.

Səhv №6: Unikal identifikatorların olmaması. Mürəkkəb sistemlərdə orderId, userId və digər identifikatorlar olmadan hadisələri «birləşdirə» və konkret istifadəçi və ya sifarişlə nə baş verdiyini anlaya bilməyəcəksiniz.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Memar
Memar
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Sosial şəbəkə
Sosial şəbəkə
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION