Slf4j'de çalışma zamanında ileti günlük düzeyini ayarlama


100

Log4j kullanılırken, bu Logger.log(Priority p, Object message)yöntem kullanılabilir ve çalışma zamanında belirlenen bir günlük seviyesinde bir mesajın günlüğe kaydedilmesi için kullanılabilir. Bu gerçeği ve bu ipucunu stderr'i belirli bir günlük düzeyindeki bir kaydediciye yönlendirmek için kullanıyoruz .

slf4j'nin bulabildiğim genel bir log()yöntemi yok . Bu, yukarıdakileri uygulamanın hiçbir yolu olmadığı anlamına mı geliyor?


4
Bunu geliştirici posta listesinde slf4j 2.0'a eklemekle ilgili bir tartışma var gibi görünüyor: qos.ch/pipermail/slf4j-dev/2010-March/002865.html
Edward Dale

1
Marker'a bir göz atın, bu günlük zincirine iletebileceğiniz özel verilerdir.
tuxSlayer

1
@tuxSlayer, bu durumda Marker'ı nasıl kullanacağınızı açıklar mısınız?
Miserable Variable

Muhtemelen "günlüğe kaydetme" için en iyi fikir değildir, ancak günlük girişi "önceliği" (yüksek | düşük | normal, bilgi | uyarı | ölümcül) için birkaç işaretçi kullanabilir ve işaretçileri ve günlük girişlerini tüketmek için geri oturum açmada veya özel ekleyicide filtrelemeyi kullanabilirsiniz ayrı kanallara (günlük bilgisi, önemli e-posta vb.). Bununla birlikte, daha düz yol, aşağıdaki cevaplarda işaret edildiği gibi bunun için bir cepheye sahip olmaktır.
tuxSlayer

2
Bu özelliğin bir parçası olması gerekiyor slf4j 2.0. jira.qos.ch/browse/SLF4J-124 Ayrıntılar ve olası bir slf4j 1.xgeçici çözüm için cevabıma bakın .
slartidan

Yanıtlar:


47

Bunu yapmanın bir yolu yok slf4j.

Bu işlevselliğin eksik olmasının nedeninin , cephenin arkasındaki tüm olası kayıt uygulamalarında kullanılan (veya eşdeğer) türle verimli bir şekilde eşleştirilebilecek bir Leveltip oluşturmanın neredeyse imkansız olması olduğunu hayal ediyorum . Alternatif olarak, tasarımcılar kullanım durumunuzun, onu desteklemenin genel giderlerini haklı çıkarmak için çok sıra dışı olduğuna karar verdiler .slf4jLevel

Dair @ ripper234 'ın kullanım senaryosunu (birim testi), ben pragmatik çözüm birim testleri çalıştırırken günlük sistemi ... slf4j cephe gerisinde ne olduğu sert telli bilgisine birim testi (ler) değiştirmek olduğunu düşünüyorum.


9
Gerçekten haritalamaya gerek yok. Yöntemler tarafından zaten örtülü olarak tanımlanmış beş seviye vardır org.slf4j.Logger: debug, error, info, trace, warn.
Edward Dale

1
Ve sorunlar Geçersiz olarak kapatıldı. Bunu anladığım kadarıyla bilinçli bir tasarım tercihi.
ripper234

9
@ ripper234 - Hatanızın scompt.com'un orijinal sorusuyla aynı sorunu ele aldığını sanmıyorum. SLF4J API aracılığıyla temeldeki günlük kaydı sisteminin düzeyini yapılandırmayı istediniz. Scompt.com'un peşinde olduğu şey, SLF4J API'sinde mesajın günlüğe kaydetme düzeyini parametre olarak alan genel bir 'günlük' yöntemiydi .
Richard Fearn

1
+1 @RichardFearn Ve 60 saniye sonra yorum olumlu oyu geri alınamaz, meh . Özellik isteği arada mevcut olduğu: bugzilla.slf4j.org/show_bug.cgi?id=133
Ocak

3
RFE bağlantıları artık çözülmüyor. İlgili bağlantılar şimdi: jira.qos.ch/browse/SLF4J-124 ve jira.qos.ch/browse/SLF4J-197 ... ve ikisi de kapatıldı. Gerekçe için yorumları okuyun.
Stephen C

27

Richard Fearn'ın doğru fikri var, bu yüzden sınıfın tamamını iskelet koduna göre yazdım. Umarım buraya gönderilecek kadar kısadır. Keyif için kopyalayıp yapıştırın. Muhtemelen sihirli bir büyü de eklemeliyim: "Bu kod kamu malı olarak yayınlandı"

import org.slf4j.Logger;

public class LogLevel {

    /**
     * Allowed levels, as an enum. Import using "import [package].LogLevel.Level"
     * Every logging implementation has something like this except SLF4J.
     */

    public static enum Level {
        TRACE, DEBUG, INFO, WARN, ERROR
    }

    /**
     * This class cannot be instantiated, why would you want to?
     */

    private LogLevel() {
        // Unreachable
    }

    /**
     * Log at the specified level. If the "logger" is null, nothing is logged.
     * If the "level" is null, nothing is logged. If the "txt" is null,
     * behaviour depends on the SLF4J implementation.
     */

    public static void log(Logger logger, Level level, String txt) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(txt);
                break;
            case DEBUG:
                logger.debug(txt);
                break;
            case INFO:
                logger.info(txt);
                break;
            case WARN:
                logger.warn(txt);
                break;
            case ERROR:
                logger.error(txt);
                break;
            }
        }
    }

    /**
     * Log at the specified level. If the "logger" is null, nothing is logged.
     * If the "level" is null, nothing is logged. If the "format" or the "argArray"
     * are null, behaviour depends on the SLF4J-backing implementation.
     */

    public static void log(Logger logger, Level level, String format, Object[] argArray) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(format, argArray);
                break;
            case DEBUG:
                logger.debug(format, argArray);
                break;
            case INFO:
                logger.info(format, argArray);
                break;
            case WARN:
                logger.warn(format, argArray);
                break;
            case ERROR:
                logger.error(format, argArray);
                break;
            }
        }
    }

    /**
     * Log at the specified level, with a Throwable on top. If the "logger" is null,
     * nothing is logged. If the "level" is null, nothing is logged. If the "format" or
     * the "argArray" or the "throwable" are null, behaviour depends on the SLF4J-backing
     * implementation.
     */

    public static void log(Logger logger, Level level, String txt, Throwable throwable) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(txt, throwable);
                break;
            case DEBUG:
                logger.debug(txt, throwable);
                break;
            case INFO:
                logger.info(txt, throwable);
                break;
            case WARN:
                logger.warn(txt, throwable);
                break;
            case ERROR:
                logger.error(txt, throwable);
                break;
            }
        }
    }

    /**
     * Check whether a SLF4J logger is enabled for a certain loglevel. 
     * If the "logger" or the "level" is null, false is returned.
     */

    public static boolean isEnabledFor(Logger logger, Level level) {
        boolean res = false;
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                res = logger.isTraceEnabled();
                break;
            case DEBUG:
                res = logger.isDebugEnabled();
                break;
            case INFO:
                res = logger.isInfoEnabled();
                break;
            case WARN:
                res = logger.isWarnEnabled();
                break;
            case ERROR:
                res = logger.isErrorEnabled();
                break;
            }
        }
        return res;
    }
}

Bunun bir variadic (Object ...) args parametresiyle kullanılması daha kolay olacaktır.
Anonymoose

"org.slf4j.Logger", yukarıdaki sınıfta ele alınmayan epeyce günlüğe kaydetme yöntemi imzasına sahiptir, bu nedenle bir uzantı muhtemelen garantilidir: slf4j.org/api/org/slf4j/Logger.html
David Tonhofer

1
Bu uygulamanın istenmeyen bir değişiklik katacağını düşünüyorum. Call logger.info (...) 'yu kullandığınızda, günlükçünün çağıran sınıfına ve yöntemine erişimi vardır ve günlük girişine otomatik olarak eklenebilir. Şimdi, bu uygulama ile, çağrı günlüğü (logger, level, txt) her zaman aynı arayana sahip olan bir günlük girişi üretecektir: Loglevel.log. Haklı mıyım
Domin

@Domin Merhaba, yani kaydedici mevcut çağrı yığınını inceleyebilir, ardından otomatik günlük kaydı için son girişi çıkarabilir, burada durum böyle değil mi? Prensip olarak evet, ama aslında, yığın bundan sonra bile asıl mesaj yazılıncaya kadar biraz daha fazla büyüyecektir (özellikle, bir noktada, daha sonra gerçek ekleyici olarak oturum açma çağrılmalıdır). Bence ilginç olmayan yığın satırlarını atmak ekleyicinin rolü olmalı, böylece onu bu Loglevel sınıfına yapılan çağrı da dahil olmak üzere her şeyi bir kenara atacak şekilde uyarlayabilirsiniz.
David TONHOFER

@David, Evet, haklısın :-). Bunun ekleyici için bir görev olduğundan emin değilim çünkü bu durumda ekleyen ve kaydedici arasında sıkı bir bağımlılık tanımlıyorsunuz ... ama ... bu bir çözüm. Thanks David
Domin

14

Logback'e geçmeyi deneyin ve şunu kullanın:

ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(Level.toLevel("info"));

Bunun Logback için tek çağrı olacağına ve kodunuzun geri kalanının değişmeyeceğine inanıyorum. Logback SLF4J kullanır ve geçiş ağrısız olur, sadece xml yapılandırma dosyalarının değiştirilmesi gerekir.

İşiniz bittiğinde günlük düzeyini geri ayarlamayı unutmayın.


Zaten Logback destekli slf4j kullanıyordum ve bu anında birim testlerimi temizlememe izin verdi. Teşekkürler!
Lambart

2
Bu benim ilk -1'imdi, teşekkürler. Sanırım yanılıyorsun Logback SLF4J kullanır, bu nedenle cevap önemlidir.
Αλέκος

3
@AlexandrosGelbessis Soruyu tekrar okumalısınız. Herhangi bir düzeyde programlı olarak bir günlük mesajı kaydedebilen bir yöntem istendi. Yalnızca bir mesaj için değil, tüm mesajlar için kök kaydedicinin düzeyini değiştiriyorsunuz.
ocak

12

Bunu Java 8 lambdas kullanarak uygulayabilirsiniz.

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;

public class LevelLogger {
    private static final Logger LOGGER = LoggerFactory.getLogger(LevelLogger.class);
    private static final Map<Level, LoggingFunction> map;

    static {
        map = new HashMap<>();
        map.put(Level.TRACE, (o) -> LOGGER.trace(o));
        map.put(Level.DEBUG, (o) -> LOGGER.debug(o));
        map.put(Level.INFO, (o) -> LOGGER.info(o));
        map.put(Level.WARN, (o) -> LOGGER.warn(o));
        map.put(Level.ERROR, (o) -> LOGGER.error(o));
    }

    public static void log(Level level, String s) {
        map.get(level).log(s);
    }

    @FunctionalInterface
    private interface LoggingFunction {
        public void log(String arg);
    }
}

Peki evet ... ama şimdi bu API'yi slf4j yerine veya bunun yerine kullanmak için kod tabanınızı değiştirmeniz gerekiyor. Bunu slf4j yerine kullanırsanız 1) muhtemelen daha zengin olması gerekir, 2) çok sayıda (en azından) ithalatın değiştirilmesi gerekir ve 3) slf4j önündeki bu yeni katman fazladan bir günlükleme ek yükü ekler.
Stephen C

4
Ayrıca, bu çözüme gittiğinizde, gerçek günlüğe kaydetmeyi yapan sınıfın günlüğe kaydedilmeyeceğini unutmayın (çünkü günlükçü ile başlatılır LevelLogger), bu iyi bir şey değildir çünkü bu genellikle çok yararlı bilgilerdir.
Dormouse

6

Bu, bir enumve yardımcı yöntemle yapılabilir:

enum LogLevel {
    TRACE,
    DEBUG,
    INFO,
    WARN,
    ERROR,
}

public static void log(Logger logger, LogLevel level, String format, Object[] argArray) {
    switch (level) {
        case TRACE:
            logger.trace(format, argArray);
            break;
        case DEBUG:
            logger.debug(format, argArray);
            break;
        case INFO:
            logger.info(format, argArray);
            break;
        case WARN:
            logger.warn(format, argArray);
            break;
        case ERROR:
            logger.error(format, argArray);
            break;
    }
}

// example usage:
private static final Logger logger = ...
final LogLevel level = ...
log(logger, level, "Something bad happened", ...);

logÖrneğin, SLF4J'nin 1-parametresi veya 2-parametre warn/ error/ vb. İçin jenerik eşdeğerlerini istiyorsanız, diğer değişkenleri ekleyebilirsiniz . yöntemler.


3
Doğru, ancak slf4j'nin amacı günlük sarmalayıcılar yazmak zorunda değil.
djjeck

5
SLF4J'nin amacı, farklı günlükleme çerçeveleri için bir soyutlama sağlamaktır. Bu soyutlama tam olarak ihtiyacınız olanı sağlamıyorsa, yardımcı bir yöntem yazmaktan başka seçeneğiniz yoktur. Diğer tek alternatif, SLF4J projesine cevabımdaki gibi bir yönteme katkıda bulunmaktır.
Richard Fearn

Kabul ediyorum, ancak bu durumda, bunun için başka bir geçici çözüm uygulamadıkça, artık dosya ve satır numarası sağlayamayacağınız gibi uyarılar var. Bu durumda, çerçeve özelliği destekleyene kadar log4j ile takılıp kalırdım - ki bu, sonunda bir uzantı yoluyla gerçekleşti, Robert Elliot'ın daha yeni cevabına bakın.
djjeck


3

Sadece bunun gibi bir şeye ihtiyacım vardı ve şunu buldum:

@RequiredArgsConstructor //lombok annotation
public enum LogLevel{

    TRACE(l -> l::trace),
    INFO (l -> l::info),
    WARN (l -> l::warn),
    ERROR(l -> l::error);

    private final Function<Logger, Consumer<String>> function;

    public void log(Logger logger, String message) {
        function.apply(logger).accept(message);
    }
}

kullanım:

    LogLevel level = LogLevel.TRACE;
    level.log(logger, "message");

Çağrı sırasında kaydedici aktarılır, bu nedenle sınıf bilgisi iyi durumda olmalıdır ve @ Slf4j lombok ek açıklamasıyla iyi çalışır.


Bu harika yaklaşım için çok teşekkür ederim - fikrinize dayanarak benzer bir cevap gönderdim.
slartidan

DEBUGsabit olarak eksik.
slartidan

Bu çözüm her zaman LogLevelsınıf ve logyöntem olarak günlüğe kaydedilir, bu da günlükleri daha az anlamlı hale getirir.
slartidan

2

Öyle değil sjf4j bir günlük düzeyinin belirtmek mümkün 1.xkutudan. Ancak slf4j'nin sorunu çözmesi 2.0için umut var . 2.0'da şöyle görünebilir:

// POTENTIAL 2.0 SOLUTION
import org.slf4j.helpers.Util;
import static org.slf4j.spi.LocationAwareLogger.*;

// does not work with slf4j 1.x
Util.log(logger, DEBUG_INT, "hello world!");

Bu arada, slf4j 1.x için şu geçici çözümü kullanabilirsiniz:

Bu sınıfı sınıf yolunuza kopyalayın:

import org.slf4j.Logger;
import java.util.function.Function;

public enum LogLevel {

    TRACE(l -> l::trace, Logger::isTraceEnabled),
    DEBUG(l -> l::debug, Logger::isDebugEnabled),
    INFO(l -> l::info, Logger::isInfoEnabled),
    WARN(l -> l::warn, Logger::isWarnEnabled),
    ERROR(l -> l::error, Logger::isErrorEnabled);

    interface LogMethod {
        void log(String format, Object... arguments);
    }

    private final Function<Logger, LogMethod> logMethod;
    private final Function<Logger, Boolean> isEnabledMethod;

    LogLevel(Function<Logger, LogMethod> logMethod, Function<Logger, Boolean> isEnabledMethod) {
        this.logMethod = logMethod;
        this.isEnabledMethod = isEnabledMethod;
    }

    public LogMethod prepare(Logger logger) {
        return logMethod.apply(logger);
    }

    public boolean isEnabled(Logger logger) {
        return isEnabledMethod.apply(logger);
    }
}

O zaman bunu şu şekilde kullanabilirsiniz:

Logger logger = LoggerFactory.getLogger(Application.class);

LogLevel level = LogLevel.ERROR;
level.prepare(logger).log("It works!"); // just message, without parameter
level.prepare(logger).log("Hello {}!", "world"); // with slf4j's parameter replacing

try {
    throw new RuntimeException("Oops");
} catch (Throwable t) {
    level.prepare(logger).log("Exception", t);
}

if (level.isEnabled(logger)) {
    level.prepare(logger).log("logging is enabled");
}

Bu, şöyle bir günlük çıkaracaktır:

[main] ERROR Application - It works!
[main] ERROR Application - Hello world!
[main] ERROR Application - Exception
java.lang.RuntimeException: Oops
    at Application.main(Application.java:14)
[main] ERROR Application - logging is enabled

Buna değer mi?

  • ProBu tutar kaynak kod konumunu (sınıf isimleri, yöntem adları, satır numaraları işaret eder senin kod)
  • ProDeğişkenleri , parametreleri ve dönüş türlerini aşağıdaki gibi kolayca tanımlayabilirsiniz:LogLevel
  • Proİşletme kodunuz kısa kalır ve okunması kolaydır ve ek bağımlılık gerekmez.

Minimum örnek olarak kaynak kodu GitHub'da barındırılmaktadır .


Not: LogMethodArayüzün, paketi dışındaki sınıflarla çalışması için herkese açık olması gerekir. Bunun dışında amaçlandığı gibi çalışıyor. Teşekkürler!
andrebrait

1

Slf4j API ile günlük seviyesini dinamik olarak değiştirmek mümkün değildir, ancak günlük kaydını (eğer bunu kullanırsanız) kendi başınıza yapılandırabilirsiniz. Bu durumda, kaydediciniz için fabrika sınıfı oluşturun ve ihtiyacınız olan yapılandırmayla kök kaydediciyi uygulayın.

LoggerContext loggerContext = new LoggerContext();
ch.qos.logback.classic.Logger root = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

// Configure appender
final TTLLLayout layout = new TTLLLayout();
layout.start(); // default layout of logging messages (the form that message displays 
// e.g. 10:26:49.113 [main] INFO com.yourpackage.YourClazz - log message

final LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder<>();
encoder.setCharset(StandardCharsets.UTF_8);
encoder.setLayout(layout);

final ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
appender.setContext(loggerContext);
appender.setEncoder(encoder);
appender.setName("console");
appender.start();

root.addAppender(appender);

Kök kaydediciyi yapılandırdıktan sonra (yalnızca bir kez yeterlidir),

final ch.qos.logback.classic.Logger logger = loggerContext.getLogger(clazz);

Aynısını kullanmayı unutma loggerContext.

Verilen root logger ile günlük seviyesini değiştirmek kolaydır loggerContext.

root.setLevel(Level.DEBUG);

1

Cevabı onayla Ondrej Skopek

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;

var rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(Level.TRACE);

Sonuç alacaksınız:

2020-05-14 14: 01: 16.644 TRACE [] [oakcmMetrics] Test çalışanı MetricName adlı kayıtlı metrik [ad = bufferpool-bekleme-süresi-toplam, grup = üretici-metrics, açıklama = Bir ekleyicinin alan tahsisi için beklediği toplam süre ., etiketler = {müşteri-kimliği = üretici-2}]


0

Az önce benzer bir ihtiyaçla karşılaştım. Benim durumumda slf4j, java günlük bağdaştırıcısı (jdk14 olanı) ile yapılandırıldı. Aşağıdaki kod parçacığını kullanarak çalışma zamanında hata ayıklama düzeyini değiştirmeyi başardım:

Logger logger = LoggerFactory.getLogger("testing");
java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger("testing");
julLogger.setLevel(java.util.logging.Level.FINE);
logger.debug("hello world");

1
Diğer cevaplar gibi, bu da asıl soruyu ele almaz, farklı bir sorundur.
E-Riz

0

Massimo virgilio'nun cevabına göre ben de bunu slf4j-log4j ile iç gözlem kullanarak yapmayı başardım. HTH.

Logger LOG = LoggerFactory.getLogger(MyOwnClass.class);

org.apache.logging.slf4j.Log4jLogger LOGGER = (org.apache.logging.slf4j.Log4jLogger) LOG;

try {
    Class loggerIntrospected = LOGGER.getClass();
    Field fields[] = loggerIntrospected.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        String fieldName = fields[i].getName();
        if (fieldName.equals("logger")) {
            fields[i].setAccessible(true);
            org.apache.logging.log4j.core.Logger loggerImpl = (org.apache.logging.log4j.core.Logger) fields[i].get(LOGGER);
            loggerImpl.setLevel(Level.DEBUG);
        }
    }
} catch (Exception e) {
    System.out.println("ERROR :" + e.getMessage());
}

0

İşte tek yönden @Paul Croarkin'inki kadar kullanıcı dostu olmayan bir lambda çözümü (seviye etkili bir şekilde iki kez geçilir). Ancak (a) kullanıcının Logger'ı geçmesi gerektiğini düşünüyorum; ve (b) AFAIU'nun asıl sorusu, uygulamanın her yeri için uygun bir yol istemiyordu, sadece bir kütüphane içinde birkaç kullanımın olduğu bir durumdu.

package test.lambda;
import java.util.function.*;
import org.slf4j.*;

public class LoggerLambda {
    private static final Logger LOG = LoggerFactory.getLogger(LoggerLambda.class);

    private LoggerLambda() {}

    public static void log(BiConsumer<? super String, ? super Object[]> logFunc, Supplier<Boolean> logEnabledPredicate, 
            String format, Object... args) {
        if (logEnabledPredicate.get()) {
            logFunc.accept(format, args);
        }
    }

    public static void main(String[] args) {
        int a = 1, b = 2, c = 3;
        Throwable e = new Exception("something went wrong", new IllegalArgumentException());
        log(LOG::info, LOG::isInfoEnabled, "a = {}, b = {}, c = {}", a, b, c);

        // warn(String, Object...) instead of warn(String, Throwable), but prints stacktrace nevertheless
        log(LOG::warn, LOG::isWarnEnabled, "error doing something: {}", e, e);
    }
}

Slf4j , varargs parametresi içinde Throwable'a (yığın izlemesi günlüğe kaydedilmelidir) izin verdiğinden , logdiğer tüketiciler için helper yöntemini aşırı yüklemeye gerek olmadığını düşünüyorum (String, Object[]).


0

Bunu JDK14 bağlaması için önce SLF4J Logger örneğini talep ederek ve ardından bağlama düzeyini ayarlayarak yapabildim - bunu Log4J bağlaması için deneyebilirsiniz.

private void setLevel(Class loggerClass, java.util.logging.Level level) {
  org.slf4j.LoggerFactory.getLogger(loggerClass);
  java.util.logging.Logger.getLogger(loggerClass.getName()).setLevel(level);
}

0

Kullandığım yöntem ch.qos.logback modüllerini içe aktarmak ve ardından slf4j Logger örneğini bir ch.qos.logback.classic.Logger'a yazmaktır. Bu örnek bir setLevel () yöntemini içerir.

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;

Logger levelSet = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);

// Now you can set the desired logging-level
levelSet.setLevel( Level.OFF );

Olası Günlük düzeylerini bulmak için, Düzey için olası tüm değerleri görmek üzere ch.qos.logback sınıfını patlatabilirsiniz :

prompt$ javap -cp logback-classic-1.2.3.jar ch.qos.logback.classic.Level

Sonuçlar aşağıdaki gibidir:

{
   // ...skipping
   public static final ch.qos.logback.classic.Level OFF;
   public static final ch.qos.logback.classic.Level ERROR;
   public static final ch.qos.logback.classic.Level WARN;
   public static final ch.qos.logback.classic.Level INFO;
   public static final ch.qos.logback.classic.Level DEBUG;
   public static final ch.qos.logback.classic.Level TRACE;
   public static final ch.qos.logback.classic.Level ALL;
}

-2

java introspection kullanarak bunu yapabilirsiniz, örneğin:

private void changeRootLoggerLevel(int level) {

    if (logger instanceof org.slf4j.impl.Log4jLoggerAdapter) {
        try {
            Class loggerIntrospected = logger.getClass();
            Field fields[] = loggerIntrospected.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                String fieldName = fields[i].getName();
                if (fieldName.equals("logger")) {
                    fields[i].setAccessible(true);
                    org.apache.log4j.Logger loggerImpl = (org.apache.log4j.Logger) fields[i]
                            .get(logger);

                    if (level == DIAGNOSTIC_LEVEL) {
                        loggerImpl.setLevel(Level.DEBUG);
                    } else {
                        loggerImpl.setLevel(org.apache.log4j.Logger.getRootLogger().getLevel());
                    }

                    // fields[i].setAccessible(false);
                }
            }
        } catch (Exception e) {
            org.apache.log4j.Logger.getLogger(LoggerSLF4JImpl.class).error("An error was thrown while changing the Logger level", e);
        }
    }

}

5
Bu açıkça slf4j jenerik log4j atıfta değil
Thorbjorn Ravn Andersen

-6

hayır, bir dizi yöntemi vardır, info (), debug (), warn (), vb. (bu öncelik alanının yerini alır)

bir göz http://www.slf4j.org/api/org/slf4j/Logger.html tam Kaydedici API için.


üzgünüm, şimdi ne istediğini anladım. hayır, çalışma zamanında günlük düzeyini değiştirmenin genel bir yolu yoktur, ancak bir anahtar ifadesiyle kolayca yardımcı bir yöntem uygulayabilirsiniz.
chris

Evet, ancak o zaman "günlük" yönteminin her aşırı yüklenmiş sürümü için bunu bir kez yapmanız gerekir.
Andrew Swan
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.