Level.FINE günlük mesajları neden gösterilmiyor?


110

İçin JavaDocsjava.util.logging.Level devlet:


Azalan sıradaki seviyeler şunlardır:

  • SEVERE (en yüksek değer)
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST (en düşük değer)

Kaynak

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        logger.setLevel(Level.FINER);
        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

Çıktı

Logging level is: FINER
Jun 11, 2011 9:39:23 PM LoggingLevelsBlunder main
INFO: 0 0
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 1 1
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 2 4
Press any key to continue . . .

Sorun bildirimi

Benim örnek setleri Leveliçin FINERben her döngü için 2 iletileri görmek için bekliyordum bu yüzden. Bunun yerine her döngü için tek bir mesaj görüyorum ( Level.FINEmesajlar eksik).

Soru

FINE( FINERVeya FINEST) çıktısını görmek için neyin değişmesi gerekiyor ?

Güncelleme (çözüm)

Sayesinde Vineet Reynolds' cevabı , bu sürüm benim beklenti göre çalışır. 3 x INFOmesaj ve 3 x FINEmesaj görüntüler.

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        // LOG this level to the log
        logger.setLevel(Level.FINER);

        ConsoleHandler handler = new ConsoleHandler();
        // PUBLISH this level
        handler.setLevel(Level.FINER);
        logger.addHandler(handler);

        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

10
Bana, INFO ve üzeri için konsolda mesajların iki kez yazdırılacağını düşünüyorsunuz: önce anonim günlükçü tarafından, sonra da ana birimi, varsayılan olarak bir ConsoleHandler'ı da INFO'ya ayarlayan global günlükçü tarafından. Global logger'ı devre dışı bırakmak için şu kod satırını eklemeniz gerekir: logger.setUseParentHandlers (false);
dakika

Ben sadece çiftler hakkındaki mins yorumunu onaylamak istiyorum. .setUseParentHandlers (false) kullanmadığınız sürece iki çıktı alırsınız;
xpagesbeast

Yanıtlar:


124

Kaydediciler yalnızca mesajı günlüğe kaydeder, yani günlük kayıtlarını (veya günlük isteklerini) oluştururlar. İşleyiciler tarafından bakılan hedeflere mesajları yayınlamazlar. Bir kaydedicinin düzeyini ayarlamak, yalnızca bu düzey veya daha yüksek bir düzeyle eşleşen günlük kayıtları oluşturmasına neden olur .

Bir ConsoleHandler(çıktınızın System.err veya bir dosya nerede olduğunu anlayamadım, ancak bunun eski olduğunu varsayabilirim), varsayılan olarak seviyenin günlük kayıtlarını yayınlıyor olabilirsiniz Level.INFO. Level.FINERİstenen sonuç için seviye ve daha yüksek günlük kayıtlarını yayınlamak için bu işleyiciyi yapılandırmanız gerekecektir .

Temel tasarımı anlamak için Java Günlüğe Genel Bakış kılavuzunu okumanızı tavsiye ederim . Kılavuz, Kaydedici ve İşleyici kavramı arasındaki farkı kapsar.

İşleyici düzeyini düzenleme

1. Yapılandırma dosyasını kullanma

Java.util.logging özellikler dosyası (varsayılan olarak bu logging.propertiesdosyadır JRE_HOME/lib), ConsoleHandler'ın varsayılan düzeyini değiştirmek için değiştirilebilir:

java.util.logging.ConsoleHandler.level = FINER

2. Çalışma zamanında işleyiciler oluşturma

Bu, genel konfigürasyonun geçersiz kılınmasına neden olacağı için önerilmez. Bunu kod tabanınız boyunca kullanmak, muhtemelen yönetilemez bir günlükçü konfigürasyonu ile sonuçlanacaktır.

Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);

2
Teşekkürler. Bu hile yaptı. Başlangıçta neden bu kadar kafamın karışık olduğunu şimdi anlıyorum. Daha önce günlük seviyeleriyle çalışmıştım, ancak o zamanki uygulamam, her günlüğe kaydedilen iletiyi Handler.
Andrew Thompson

3
Rica ederim. Ve evet, dizeleri basitçe bir dosyaya, konsola vb.
Atan

7
Ve global JRE kitaplığındaki logging.properties'i değiştirmek yönetilebilir mi?
James Anderson

2
Kaydedicinin seviyesinin, işleyici seviyesinden daha az kısıtlayıcı olması gerektiğini lütfen unutmayın. Java günlüğe kaydetmeden önce, kaydedici ile işleyici arasındaki maksimum seviyeyi kontrol eder. Yani, yalnızca handler.setLevel (Level.FINER) ayarlarsanız; hiçbir şey görmeyeceksiniz çünkü varsayılan kaydedici seviyesi Level.INFO. HASSAS, HASSAS veya TÜMÜ olarak ayarlamalısınız. Logger.setLevel (Level.ALL) deyin;
Jeff_Alieffson

Sanırım bu, varsayılan bir ortamda anonim ve adlandırılmış kaydediciler kullandığınızda bile sorunu tek Logger.getGlobal().getParent().getHandlers()[0].setLevel(Level.FINER);
satırlık bir çözüm olarak çözecektir

27

Neden

java.util.logging, varsayılan değerine sahip bir kök günlük kaydediciye Level.INFOve buna bağlı bir ConsoleHandler'a sahiptir ve bu da varsayılan olarak Level.INFO. FINEdeğerinden daha düşüktür INFO, bu nedenle hassas mesajlar varsayılan olarak görüntülenmez.


1.Çözüm

Paket adınızdan veya kullanımınızdan tüm uygulamanız için bir kaydedici oluşturun Logger.getGlobal()ve kendi ConsoleLogger'ınızı ona bağlayın. Sonra ya kök kaydediciden kapanmasını isteyin (daha yüksek seviyeli mesajların yinelenen çıkışını önlemek için) ya da kaydedicinizden günlükleri köke iletmemesini isteyin .

public static final Logger applog = Logger.getGlobal();
...

// Create and set handler
Handler systemOut = new ConsoleHandler();
systemOut.setLevel( Level.ALL );
applog.addHandler( systemOut );
applog.setLevel( Level.ALL );

// Prevent logs from processed by default Console handler.
applog.setUseParentHandlers( false ); // Solution 1
Logger.getLogger("").setLevel( Level.OFF ); // Solution 2

2.Çözüm

Alternatif olarak, kök kaydedicinin çubuğunu düşürebilirsiniz.

Bunları koda göre ayarlayabilirsiniz:

Logger rootLog = Logger.getLogger("");
rootLog.setLevel( Level.FINE );
rootLog.getHandlers()[0].setLevel( Level.FINE ); // Default console handler

Ya yapılandırma dosyasını günlüğü, sen eğer bunu kullanarak :

.level = FINE
java.util.logging.ConsoleHandler.level = FINE

Global seviyeyi düşürerek, bazı Swing veya JavaFX bileşenleri gibi çekirdek kitaplıklardan mesajlar görmeye başlayabilirsiniz. Bu durumda , programınızdan olmayan mesajları filtrelemek için kök kaydedicide bir Filtre ayarlayabilirsiniz .


applog.setUseParentHandlers (false) bu kod bana yardımcı oluyor, çok teşekkürler.
aolphn

4

Java günlüğüm neden çalışmıyor

oturum açmanızın neden beklendiği gibi çalışmadığını anlamanıza yardımcı olacak bir jar dosyası sağlar. Hangi kaydedicilerin ve işleyicilerin kurulu olduğuna ve hangi düzeylerin ve günlük hiyerarşisinde hangi düzeyde ayarlandığına dair eksiksiz bir döküm sağlar.


Bu bir yorum, cevap değil.
hfontanez

4

NEDEN

@Sheepy tarafından belirtildiği gibi, çalışmamasının nedeni java.util.logging.Logger, varsayılan olarak ayarlanmış bir kök kaydediciye sahip olmasıdır Level.INFOve ConsoleHandlerbu kök günlükçüye ekli de varsayılan olarak Level.INFO. Bu nedenle, görmek için FINE( FINERveya FINEST) çıkışı, kök kaydedicisi varsayılan değeri ayarlamak gerekir ve onun ConsoleHandleriçin Level.FINEaşağıdaki gibi:

Logger.getLogger("").setLevel(Level.FINE);
Logger.getLogger("").getHandlers()[0].setLevel(Level.FINE);


Güncellemenizin sorunu (çözüm)

@Mins tarafından belirtildiği gibi, sizin için konsolda iki kez basılmış iletileri olur INFOve üstü: İlk anonim günlüğü tarafından, daha sonra, ailesindeki de vardır kök kaydedici tarafindan ConsoleHandleriçin set INFOvarsayılan olarak. Kök kaydediciyi devre dışı bırakmak için şu kod satırını eklemeniz gerekir:logger.setUseParentHandlers(false);

Günlüklerin @Sheepy tarafından belirtilen kök kaydedicinin varsayılan Konsol işleyicisi tarafından işlenmesini önlemenin başka yolları da vardır, örneğin:

Logger.getLogger("").getHandlers()[0].setLevel( Level.OFF );

Ancak Logger.getLogger("").setLevel( Level.OFF );işe yaramaz çünkü yalnızca doğrudan kök kaydediciye iletilen iletiyi engeller, ileti çocuk kaydediciden gelmez. Nasıl Logger Hierarchyçalıştığını göstermek için aşağıdaki diyagramı çiziyorum:

görüntü açıklamasını buraya girin

public void setLevel(Level newLevel)bu günlükçü tarafından hangi ileti düzeylerinin günlüğe kaydedileceğini belirleyen günlük düzeyini ayarlayın. Bu değerin altındaki mesaj seviyeleri atılacaktır. Level.OFF seviye değeri, günlük kaydını kapatmak için kullanılabilir. Yeni düzey boş ise, bu düğümün düzeyini belirli (boş olmayan) bir düzey değeriyle en yakın atasından miras alması gerektiği anlamına gelir.


0

Asıl sorunumu buldum ve herhangi bir yanıtta bahsedilmedi: birim testlerimden bazıları, günlük başlatma kodunun aynı test paketi içinde birden çok kez çalıştırılmasına neden oluyor ve sonraki testlerdeki günlük kaydını bozuyordu.


0

Diğer varyantları denedim, bu uygun olabilir

    Logger logger = Logger.getLogger(MyClass.class.getName());        
    Level level = Level.ALL;
    for(Handler h : java.util.logging.Logger.getLogger("").getHandlers())    
        h.setLevel(level);
    logger.setLevel(level);
// this must be shown
    logger.fine("fine");
    logger.info("info");

0

Bu çözüm, sürdürülebilirlik ve değişim için tasarım açısından bana daha iyi görünüyor:

  1. Jar dosyasına dahil edilecek, kaynak proje klasörüne gömerek günlük kaydı özelliği dosyasını oluşturun:

    # Logging
    handlers = java.util.logging.ConsoleHandler
    .level = ALL
    
    # Console Logging
    java.util.logging.ConsoleHandler.level = ALL
  2. Özellik dosyasını koddan yükleyin:

    public static java.net.URL retrieveURLOfJarResource(String resourceName) {
       return Thread.currentThread().getContextClassLoader().getResource(resourceName);
    }
    
    public synchronized void initializeLogger() {
       try (InputStream is = retrieveURLOfJarResource("logging.properties").openStream()) {
          LogManager.getLogManager().readConfiguration(is);
       } catch (IOException e) {
          // ...
       }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.