CodeGym /Java Blogu /Rastgele /Günlüğe kaydetme: ne, nasıl, nerede ve ne ile?
John Squirrels
Seviye
San Francisco

Günlüğe kaydetme: ne, nasıl, nerede ve ne ile?

grupta yayınlandı
CodeGym topluluğundaki herkese merhaba! Günlüğe kaydetme: ne, nasıl, nerede ve ne ile?  - 1 Bugün günlük kaydı hakkında konuşalım:
  1. Nedir, neden var, ne zaman kullanmalısınız, ne zaman kaçınmalısınız?
  2. Java'da hangi günlük tutma uygulamaları mevcuttur ve tüm bu günlük tutma seçenekleriyle ne yapmanız gerekir.
  3. Ve günlük seviyeleri. Appender'ın ne olduğunu ve doğru şekilde nasıl yapılandırılacağını tartışacağız.
  4. Düğümlerin günlüğe kaydedilmesi ve her şeyin istediğimiz gibi çalışması için bunların nasıl doğru şekilde yapılandırılacağı.
Bu materyal geniş bir kitleye yöneliktir. Java'yı yeni tanıyan herkes için olduğu kadar halihazırda çalışmakta olan ancak yalnızca keşfetmiş kişiler için de anlaşılır olacaktır logger.info("log something"); .

Neden günlüğe kaydetmeye ihtiyacınız var?

Günlük tutmanın bir sorunu çözebileceği bazı gerçek durumlara bakalım. İşte çalışmalarımdan bir örnek. Bir uygulamanın diğer servislerle entegre olduğu noktalar vardır. Bir tür "mazeret" oluşturmak için bu noktalarda günlüğe kaydetmeyi kullanıyorum : entegrasyon çalışmıyorsa, o zaman sorunun hangi tarafta olduğunu anlamak kolaylaşır. Bir veritabanında saklanan önemli bilgilerin günlüğe kaydedilmesi de arzu edilir. Örneğin, bir yönetici kullanıcının oluşturulması. Bu tam olarak günlüğe kaydetmenin iyi olacağı türden bir şey.

Java'da oturum açmak için araçlar

Java'daki iyi bilinen günlük kaydı çözümleri arasında aşağıdakileri vurgulayabiliriz:
  • Log4j
  • TEMMUZ — java.util.logging
  • JCL - Jakarta Commons Günlüğü
  • Yeniden giriş yap
  • SLF4J — Java için Basit Günlüğe Kaydetme Cephesi
Her birine genel bir bakış sunacağız. Daha sonra pratik bir tartışmanın temeli olarak bir slf4j - log4j bağını ele alacağız . Bu şimdi garip gelebilir, ancak merak etmeyin: makalenin sonunda her şey netleşecek.

System.err.println

Başlangıçta, System.err.println (konsolda günlük girişlerini görüntüleyen) vardı. Bugün bile, bu teknik hata ayıklama sırasında hızlı bir şekilde günlük tutmak için kullanılmaktadır. Elbette burada tartışılacak bir ayar yok, bu yüzden bu yöntemi hatırlayın ve devam edelim.

Log4j

Bu, geliştiricilerin zorunluluktan yarattığı eksiksiz bir çözümdür. Sonuç, kullanabileceğiniz gerçekten ilginç bir araçtır. Çeşitli koşullar nedeniyle, bu çözüm tüm topluluğu büyük ölçüde üzen bir gerçek olan JDK'da sona ermedi. Log4j, pakette oturum açmayı etkinleştirmenize com.example.typeve alt pakette kapatmanıza izin veren yapılandırma seçeneklerine sahiptir com.example.type.generic. Bu, günlüğe kaydedilmesi gerekmeyen kodu hızlı bir şekilde hariç tutmayı mümkün kılar. Burada Log4j'nin iki versiyonu olduğunu belirtmek önemlidir : 1.2.x ve 2.xx ve birbirleriyle uyumsuzdurlar . Log4j, appender kavramlarını ekledi(günlük yazmak için kullanılan bir araç) ve düzen (günlük biçimlendirme). Bu, yalnızca ihtiyacınız olanı günlüğe kaydetmenizi ve tam da ihtiyacınız olan şekilde günlüğe kaydetmenizi sağlar. Biraz sonra appender hakkında daha fazla konuşacağız.

TEMMUZ — java.util.logging

Bu çözümün en önemli faydalarından biri, JUL'un JDK'ya (Java Geliştirme Kiti) dahil edilmiş olmasıdır. Ne yazık ki, geliştirildiğinde, yaratıcıları onu popüler Log4j yardımcı programına değil, IBM'in bir çözümüne dayandırdı. Bu kararın sonuçları oldu. Gerçek şu ki, artık kimse JUL kullanmıyor. JUL'daki günlük seviyeleri, Logback, Log4j ve Slf4j'nin sahip olduklarından farklıdır. Bu da birbirlerini anlamalarını zorlaştırır. Bir kaydedici oluşturmak aşağı yukarı benzerdir. Bunu yapmak için bir içe aktarma yapmanız gerekir:

java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Sınıf adı iletildi, bu nedenle günlük kaydımızın nereden geleceğini biliyoruz. Java 8'den başlayarak Supplier<String>. Bu, daha önce olduğu gibi her seferinde değil, yalnızca gerçekten ihtiyacımız olduğunda bir satır okuyup oluşturmamıza yardımcı olur. Geliştiriciler ancak Java 8'in piyasaya sürülmesiyle nihayet önemli sorunları çözdüler ve JUL'u gerçekten kullanılabilir hale getirdiler. Supplier<String> msgSupplierYani, aşağıda gösterildiği gibi parametreli yöntemler :

public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL - Jakarta Commons Günlüğü

Uzun süredir günlük kaydıyla ilgili bir endüstri standardı olmadığından ve birçok kişi kendi özel kaydedicilerini yarattığından, diğerlerinin üzerinde kullanılabilecek genel bir paketleyici olan JCL'nin piyasaya sürülmesine karar verildi. Neden? Bazen projeye eklenen bağımlılıklar, projedekinden farklı bir günlükçü kullanırdı. Bu nedenle projeye geçişli bağımlılıklar olarak eklendiler ve bu, hepsini bir araya getirmeye çalışırken gerçek sorunlar yarattı. Ne yazık ki, ambalaj çok işlevsel değildi ve hiçbir şey eklemedi. Herkesin JCL kullanması muhtemelen uygun olacaktır. Ama olan bu değil, bu yüzden JCL'yi kullanmak şu anda en iyi fikir değil.

Yeniden giriş yap

Açık kaynak yolu çetrefilli... Log4j'yi yazan aynı geliştirici, Logback'i de ardıl bir günlük çerçevesi olarak yazdı. Log4j ile aynı fikre dayanıyordu. Logback'teki farklar şunlardır:
  • gelişmiş performans
  • Slf4j için yerel destek eklendi
  • genişletilmiş filtreleme seçenekleri
Varsayılan olarak, Logback herhangi bir konfigürasyon gerektirmez ve tüm olayları DEBUG seviyesinde ve daha yüksek seviyede kaydeder. Biraz özelleştirmeye ihtiyacınız varsa, bunu bir XML yapılandırmasıyla elde edebilirsiniz:

<configuration> 
    <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
        <file>app.log</file> 
        <encoder> 
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern> 
        </encoder> 
    </appender> 
    <logger name="org.hibernate.SQL" level="DEBUG" /> 
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" /> 
    <root level="info"> 
        <appender-ref ref="FILE" /> 
    </root> 
</configuration>

SLF4J — Java için Basit Günlüğe Kaydetme Cephesi

2006 yılında, Log4j'nin kurucu babalarından biri projeden ayrıldı ve Log4j, JUL, common-logging ve Logback için bir sarıcı olan Slf4j'yi (Java için Basit Günlük Kaydı Cephesi) yarattı. Gördüğünüz gibi bir wrapper üzerinden bir wrapper oluşturma noktasına geldik... Bu durumda iki kısma ayrılıyoruz: Uygulamada kullanılan bir API ve ayrı olarak eklenen bir implementasyon. her günlük kaydı türü için bağımlılıklar. Örneğin slf4j-log4j12.jarve slf4j-jdk14.jar. Doğru uygulamayı bağlamanız gerekiyor ve bu kadar: tüm projeniz onu kullanacak. Slf4j, günlüğe kaydetme için biçimlendirme dizeleri gibi en son özelliklerin tümünü destekler. Eskiden böyle bir sorun vardı. Diyelim ki şöyle bir günlük girişi oluşturduk:

log.debug("User " + user + " connected from " + request.getRemoteAddr());
Birleştirme işleci nedeniyle, usernesne sayesinde sessizce bir dize haline gelir user.toString(). Bu zaman alır ve sistemi yavaşlatır. Ve eğer uygulamada hata ayıklıyorsak bu sorun olmayabilir. Bu sınıf için log seviyesi INFO veya daha yüksek ise problemlerle karşılaşmaya başlıyoruz. Başka bir deyişle, bu günlük girişini (INFO veya üstü için) yazmamalı ve dizi birleştirme kullanmamalıyız. Teorik olarak, kayıt kitaplığının kendisi bunu ele almalıdır. Tesadüf eseri bu, Log4j'nin ilk sürümündeki en büyük sorun olarak ortaya çıktı. İyi bir çözüm sunmadı, bunun yerine şöyle bir şey yapmayı önerdi:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Yani, günlük kaydı için bir satır kod yerine 3 yazmayı önerdiler! Günlüğe kaydetme, kod değişikliklerini en aza indirmelidir ve üç satır, bu genel yaklaşımı açıkça ihlal etmektedir. Slf4j'nin JDK ve API ile uyumluluk sorunu yoktu, bu nedenle hemen güzel bir çözüm ortaya çıktı:

log.debug("User {} connected from {}", user, request.getRemoteAddr());
nerede, {}yönteme iletilen bağımsız değişkenler için yer tutucuları belirtir. Yani, ilk {}karşılık gelir userve ikincisi {}karşılık gelir request.getRemoteAddr(). Bu şekilde yaparak, yalnızca günlük seviyesi günlük girdisini yazmamızı gerektiriyorsa dize birleştirme gerçekleştireceğiz. Bundan sonra, Sjf4j'nin popülaritesi hızla artmaya başladı. Şu anda, en iyi çözüm. Buna göre, bir bağlama kullanarak günlüğe kaydetmeye bir göz atalım slf4j-log4j12.

Günlüğe kaydedilmesi gerekenler

Tabii ki, her şeyi kaydetmemelisiniz. Bu genellikle gerekli değildir ve hatta bazen tehlikelidir. Örneğin, birinin kişisel verilerini kaydederseniz ve bir şekilde sızdırılırsa, özellikle Batı pazarlarına odaklanan projelerde gerçek sorunlar olacaktır. Ancak kesinlikle kaydetmeniz gereken şeyler de var :
  1. Uygulamanın başlangıcı/bitişi. Uygulamanın gerçekten beklendiği gibi başlayıp bitmediğini bilmemiz gerekiyor.
  2. Güvenlik sorunları. Burada birinin parolasını tahmin etme girişimlerini, yöneticilerin oturum açtığı durumları vb. günlüğe kaydetmek iyi olur.
  3. Belirli uygulama durumları . Örneğin, bir iş sürecinde bir durumdan diğerine geçiş.
  4. Karşılık gelen günlük düzeyiyle birlikte belirli hata ayıklama bilgileri .
  5. Bazı SQL betikleri. Bunun gerekli olduğu gerçek dünya vakaları vardır. Ancak yine de, günlük seviyelerini ustaca ayarlayarak mükemmel sonuçlar elde edebilirsiniz.
  6. İşlerin düzgün çalıştığı doğrulanırken çalışan iş parçacıkları günlüğe kaydedilebilir.

Günlük kaydındaki popüler hatalar

Burada pek çok nüans var, ancak birkaç yaygın hatadan özel olarak bahsedeceğiz:
  1. Aşırı günlük kaydı. Teorik olarak önemli olabilecek her adımı günlüğe kaydetmemelisiniz. İşte iyi bir kural: Günlükler, yükün %10'unu geçmemelidir. Aksi halde performans sorunları olacaktır.
  2. Tüm verileri tek bir dosyaya kaydetme. Bir noktada bu, günlüğün okunmasını/yazılmasını çok zorlaştıracak, belirli sistemlerin dosya boyutunda sınırlamaları olduğu gerçeğinden bahsetmiyorum bile.
  3. Hatalı günlük seviyeleri kullanılıyor. Her günlük seviyesinin net sınırları vardır ve bunlara saygı gösterilmelidir. Bir sınır net değilse, hangi seviyenin kullanılacağı konusunda bir anlaşmaya varabilirsiniz.

Günlük seviyeleri

x: Görünür
ÖLÜMCÜL HATA UYARMAK BİLGİ HATA AYIKLAMA İZ TÜM
KAPALI
ÖLÜMCÜL X
HATA X X
UYARMAK X X X
BİLGİ X X X X
HATA AYIKLAMA X X X X X
İZ X X X X X X
TÜM X X X X X X X
Günlük seviyeleri nelerdir? Bir şekilde bir günlük girişleri hiyerarşisi oluşturmak için belirli kurallar ve sınırlamalar gereklidir. Bu nedenle günlük seviyeleri tanıtıldı. Seviye uygulamada ayarlanır. Bir giriş belirli bir düzeyin altındaysa günlüğe kaydedilmez. Örneğin, uygulamada hata ayıklarken kullandığımız günlüklerimiz var. Normal çalışma sırasında (uygulama amaçlanan amacı için kullanıldığında), bu tür günlüklere gerek yoktur. Bu nedenle, günlük düzeyi hata ayıklamadan daha yüksektir. Log4j kullanarak günlük seviyelerine bakalım. JUL dışında, diğer çözümler aynı günlük seviyelerini kullanır. İşte azalan sırada:
  • KAPALI: Hiçbir günlük girişi kaydedilmez; her şey göz ardı edilir.
  • ÖLÜMCÜL: Uygulamanın çalışmaya devam etmesini engelleyen bir hata. Örneğin, "JVM yetersiz bellek hatası".
  • HATA: Bu seviyedeki hatalar, çözülmesi gereken sorunları gösterir. Hata, uygulamayı bir bütün olarak durdurmaz. Diğer istekler düzgün çalışabilir.
  • UYAR: Bir uyarıyı temsil eden günlük girişleri. Beklenmedik bir şey oldu, ancak sistem bununla başa çıkmayı başardı ve isteği yerine getirdi
  • BİLGİ: Uygulamadaki önemli eylemleri gösteren günlük girişleri. Bunlar hata veya uyarı değildir. Beklenen sistem olaylarıdır.
  • DEBUG: Günlük girişlerinin uygulamada hata ayıklaması gerekir. Uygulamanın tam olarak bekleneni yapmasını sağlamak veya uygulama tarafından gerçekleştirilen eylemleri açıklamak için, yani "Girilen yöntem1".
  • TRACE: Hata ayıklama için düşük öncelikli günlük girişleri. En düşük günlük düzeyi.
  • ALL: Uygulamanın tüm günlük girişlerini yazmak için bir günlük düzeyi.
Uygulamada bir yerde INFO günlük düzeyi etkinleştirilirse, INFO'dan FATAL'a kadar her düzey için girişler günlüğe kaydedilir. FATAL log seviyesi ayarlanmışsa, sadece bu seviyedeki log girişleri yazılacaktır.

Günlükleri kaydetme ve gönderme: Appender

Günlük yazmak/göndermek için geniş fırsatlar sunan Log4j'yi kullandığımızda tüm bunların nasıl çalıştığını düşünelim:
  • bir dosyaya yazmak için —DailyRollingFileAppender
  • konsola bilgi yazmak için —ConsoleAppender
  • günlükleri bir veritabanına yazmak için —JDBCAppender
  • TCP/IP üzerinden günlük göndermeyi yönetmek için —TelnetAppender
  • günlük tutmanın performansı olumsuz etkilememesini sağlamak için —AsyncAppender
Birkaç uygulama daha var: tam bir liste burada mevcuttur . Bu arada, ihtiyacınız olan apender yoksa sorun değil. Log4j'nin desteklediği Appender arabirimini uygulayarak kendi ekleyicinizi yazabilirsiniz .

Günlük düğümleri

Gösterim amacıyla, Log4j'den bir uygulama ile bir Slf4j arabirimi kullanacağız. Bir kaydedici oluşturmak çok basittir: biraz günlük kaydı yapacak olan adlı bir sınıfta MainDemoaşağıdakileri eklememiz gerekir:

org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Bu bizim için bir kaydedici oluşturacaktır. Bir günlük girişi yapmak için, adları hangi günlük seviyesinin kullanılacağını yansıtan birkaç kullanılabilir yöntem vardır. Örneğin:

logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find the log4j.properties file. Please fix this.");
logger.error("Connection refused to host = {}", host);
Sınıfı geçmemize rağmen son isim sınıfın paketler dahil tam ismidir. Bu, daha sonra günlüğü düğümlere bölebilmeniz ve her düğüm için günlük düzeyini ve ekleyiciyi yapılandırabilmeniz için yapılır. Örneğin, kaydedici sınıfta oluşturuldu com.github.romankh3.logginglecture.MainDemo. Ad, günlük düğümleri hiyerarşisi oluşturmak için temel sağlar. Ana düğüm, üst düzey RootLogger'dır . Bu, uygulamanın tamamı için tüm günlük girişlerini alan düğümdür. Kalan düğümler aşağıda gösterildiği gibi gösterilebilir: Günlüğe kaydetme: ne, nasıl, nerede ve ne ile?  - 3Ekler, belirli günlük düğümleri için yapılandırılır. Şimdi bunların nasıl yapılandırılacağına dair bir örnek görmek için log4j.properties dosyasına bakacağız .

log4j.properties dosyası için adım adım kılavuz

Her şeyi adım adım ayarlayacağız ve nelerin mümkün olduğunu göreceğiz:

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Bu satır, org.apache.log4j.ConsoleAppender uygulamasını kullanan CONSOLE eklentisini kaydettiğimizi söylüyor. Bu ek, bilgileri konsola yazar. Sonra, başka bir eki kaydederiz. Bu bir dosyaya yazacak:

log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Eklerin kendilerinin hala yapılandırılması gerektiğine dikkat etmek önemlidir. Ekleyicilerimizi kaydettikten sonra düğümlerde hangi log seviyelerinin ve hangi eklerin kullanılacağını belirleyebiliriz.

log4j.rootLogger=HATA AYIKLAMA, KONSOL, DOSYA

  • log4j.rootLogger, tüm günlük girişlerini içeren kök düğümü yapılandırdığımız anlamına gelir
  • Eşittir işaretinden sonraki ilk kelime, yazılacak minimum günlük seviyesini gösterir (bizim durumumuzda bu, DEBUG'dur)
  • Virgülden sonra kullanılacak tüm ekleri belirtiyoruz.
Daha spesifik bir kayıt düğümü yapılandırmak için şuna benzer bir giriş kullanırsınız:

log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
belirli bir düğüme başvurmak için nerede log4j.logger.kullanılır. Bizim durumumuzda, com.github.romankh3.logginglecture. Şimdi CONSOLE eklentisini yapılandırma hakkında konuşalım:

# CONSOLE appender customization
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Burada, ekleyicinin çalışmaya başlayacağı belirli seviyeyi ayarlamanın mümkün olduğunu görüyoruz. İşte gerçekte ne olduğuna dair bir örnek: BİLGİ düzeyine sahip bir iletinin günlük düğümü tarafından alındığını ve kendisine atanan ekleyiciye iletildiğini varsayalım. Ekleyicinin eşiği WARN olarak ayarlanmışsa, günlük girişini alır ancak onunla hiçbir şey yapmaz. Ardından, mesajın hangi düzeni kullanacağına karar vermemiz gerekiyor. Örnekte PatternLayout kullanıyorum, ancak başka birçok seçenek var. Bu yazıda onlara değinmeyeceğiz. DOSYA ekleyiciyi yapılandırma örneği:

# File appender customization
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Bu satırdan görülebileceği gibi, günlük girişlerinin yazılacağı belirli dosyayı yapılandırabilirsiniz:

log4j.appender.FILE.File=./target/logging/logging.log
Giriş dosyaya yazılır logging.log. Dosya boyutuyla ilgili sorunlardan kaçınmak için, bu durumda 1 MB olan maksimum değeri yapılandırabilirsiniz. MaxBackupIndexkaç tane bu tür günlük dosyası olacağını gösterir. Bundan daha fazla dosya oluşturmamız gerekirse, ilk dosya silinecektir. Günlük kaydının yapılandırıldığı gerçek bir örneğe bakmak için GitHub'daki genel depoya gidebilirsiniz .

Tartıştığımız şeyi pekiştirin

Açıkladığımız her şeyi kendi başınıza yapmaya çalışın:
  • Yukarıdaki örneğimize benzer şekilde kendi projenizi oluşturun.
  • Maven'in nasıl kullanılacağını biliyorsanız, onu kullanın. Değilse, kitaplığın nasıl bağlanacağını açıklayan bu öğreticiyi okuyun.

Özetle

  1. Java'da bulunan günlük kaydı çözümlerinden bahsettik.
  2. Tanınmış günlük kitaplıklarının neredeyse tamamı bir kişi tarafından yazılmıştır :D
  3. Nelerin kaydedilip nelerin kaydedilmemesi gerektiğini öğrendik.
  4. Günlük seviyelerini bulduk.
  5. Günlük düğümleriyle tanıştırıldık.
  6. Apenderin ne olduğuna ve ne için olduğuna baktık.
  7. Adım adım bir log4j.proterties dosyası oluşturduk.

Ek materyaller

  1. CodeGym: Logger dersi
  2. Haftalık Geekly: Java günlüğü. Selam Dünya
  3. Kodlama Korkusu: Günlüğe Kaydetme Sorunu
  4. YouTube: Java Günlüğü Cehennemini Anlamak - Temel Bilgiler. Java Günlüğü Cehennemi ve Nasıl Bunun Dışında Kalınır?
  5. Log4j: Ekleyen
  6. Log4j: Düzen
Ayrıca diğer makaleme de bakın:
Yorumlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION