Slf4j में रनटाइम पर संदेश का लॉग स्तर सेट करना


100

Logger.log(Priority p, Object message)लॉग 4 जे का उपयोग करते समय, विधि उपलब्ध है और रनटाइम पर निर्धारित लॉग स्तर पर एक संदेश को लॉग करने के लिए उपयोग किया जा सकता है। हम इस तथ्य और इस टिप का उपयोग किसी विशिष्ट लॉग स्तर पर एक लकड़हारे के लिए stderr को पुनर्निर्देशित करने के लिए कर रहे हैं ।

slf4j के पास एक सामान्य log()विधि नहीं है जिसे मैं पा सकता हूं। इसका मतलब यह है कि ऊपर लागू करने का कोई तरीका नहीं है?


4
ऐसा लगता है कि देव मेलिंग सूची में slf4j 2.0 में इसे जोड़ने की कुछ चर्चा है: qos.ch/pipermail/slf4j-dev/2010-arch/002865.html
एडवर्ड डेल

1
मार्कर पर एक नज़र डालें, यह कस्टम डेटा है जिसे आप लॉग चेन में पास कर सकते हैं।
tuxSlayer

1
@tuxSlayer क्या आप इस मामले में मार्कर का उपयोग करने के बारे में विस्तार से बता सकते हैं?
दुःखद परिवर्तनीय

संभवतः इसका "लॉगिंग" के लिए सबसे अच्छा विचार नहीं है, लेकिन आप लॉग एंट्री "प्राथमिकता" (उच्च - निम्न; सामान्य, जानकारी: चेतावनी | घातक) के लिए कई मार्करों का उपयोग कर सकते हैं और मार्कर या ड्राइव लॉग प्रविष्टियों का उपभोग करने के लिए लॉगबैक या कस्टम ऐपेंडर में फ़िल्टरिंग का उपयोग कर सकते हैं। अलग-अलग चैनलों (लॉग जानकारी, ईमेल घातक आदि) में। हालाँकि, इसका सीधा तरीका यह है कि इसके लिए एक पहलू होना चाहिए जैसा कि नीचे दिए गए उत्तरों में बताया गया है।
tuxSlayer

2
इस सुविधा का हिस्सा माना जाता है slf4j 2.0jira.qos.ch/browse/SLF4J-124 विवरण के लिए और संभावित- slf4j 1.xशोध के लिए मेरा उत्तर देखें ।
शाम

जवाबों:


47

ऐसा करने का कोई तरीका नहीं है slf4j

मुझे लगता है कि यह कार्यक्षमता गायब होने का कारण यह है कि यह एक Levelप्रकार का निर्माण करने के लिए असंभव के बगल में है , slf4jजिसे कुशलतापूर्वक Level(या समतुल्य) प्रकार से मैप किया जा सकता है , जो कि मुखौटे के पीछे सभी संभावित लॉगिंग कार्यान्वयन में उपयोग किया जाता है। वैकल्पिक रूप से, डिजाइनरों ने फैसला किया कि आपके उपयोग-मामले का समर्थन करने के ओवरहेड्स को सही ठहराने के लिए बहुत असामान्य है।

विषय @ ripper234 के यूज-केस (इकाई परीक्षण), मुझे लगता है कि व्यावहारिक समाधान क्या लॉगिंग सिस्टम slf4j मुखौटा के पीछे है ... जब इकाई परीक्षण चलाने की कड़ी मेहनत से तार ज्ञान के लिए इकाई परीक्षण (रों) संशोधित है।


9
वास्तव में कोई मैपिंग आवश्यक नहीं है। org.slf4j.Loggerडीबग, त्रुटि, जानकारी, ट्रेस, चेतावनी: पाँच स्तर पहले से ही स्पष्ट रूप से तरीकों से परिभाषित हैं ।
एडवर्ड डेल

1
और मुद्दे अमान्य के रूप में बंद हो गए। जहां तक ​​मैं इसे समझता हूं, यह एक जानबूझकर डिजाइन विकल्प है।
ripper234

9
@ ripper234 - मुझे नहीं लगता कि आपके बग ने scompt.com के मूल प्रश्न के समान मुद्दे को संबोधित किया। आपने SLF4J API के माध्यम से अंतर्निहित लॉगिंग सिस्टम के स्तर को कॉन्फ़िगर करने के बारे में पूछा । SLF4J एपीआई में जेनेरिक 'लॉग' पद्धति के बाद scompt.com क्या था, जो संदेश के लॉगिंग स्तर को एक पैरामीटर के रूप में लेता है ।
रिचर्ड फर्न

1
+1 @RichardFearn और कोई भी 60 सेकंड के बाद टिप्पणी को पूर्ववत नहीं कर सकता, meh । फ़ीचर अनुरोध इस बीच मौजूद है: Bugzilla.slf4j.org/show_bug.cgi?id=133
jan

3
RFE लिंक किसी भी अधिक हल नहीं है। प्रासंगिक लिंक अब हैं: jira.qos.ch/browse/SLF4J-124 और jira.qos.ch/browse/SLF4J-197 ... और दोनों को बंद कर दिया गया है। औचित्य के लिए टिप्पणियाँ पढ़ें।
स्टीफन सी

27

रिचर्ड फर्न का सही विचार है, इसलिए मैंने उनके कंकाल कोड के आधार पर पूरी कक्षा लिखी। यहाँ पोस्ट करने के लिए यह काफी कम उम्मीद है। आनंद के लिए कॉपी और पेस्ट करें। मुझे शायद कुछ जादू संसेचन जोड़ना चाहिए: "यह कोड सार्वजनिक डोमेन पर जारी किया गया है"

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;
    }
}

यह एक वैरेडिक (ऑब्जेक्ट ...) आर्ग्स पैरामीटर के साथ उपयोग करना आसान होगा।
बेनामी

"org.slf4j.Logger" में कुछ लॉगिंग विधि के हस्ताक्षर हैं जो उपरोक्त वर्ग में संभाले नहीं हैं, इसलिए संभवतः एक एक्सटेंशन को वारंट किया गया
डेविड टोनहोफर

1
मुझे लगता है कि यह कार्यान्वयन एक गैर-वांछित बदलाव को जोड़ देगा। जब आप कॉल logger.info (...) का उपयोग करते हैं, तो लकड़हारे के पास कॉलर क्लास और विधि तक पहुंच होती है और इसे लॉग प्रविष्टि में स्वचालित रूप से जोड़ा जा सकता है। अब इस कार्यान्वयन के साथ, कॉल लॉग (लकड़हारा, स्तर, txt) एक लॉग प्रविष्टि का उत्पादन करेगा जिसमें हमेशा एक ही कॉलर होगा: Loglevel.log। क्या मैं सही हू?
डोमिनियन

@ डोमिन हाय, आपका मतलब है, लकड़हारा वर्तमान कॉल स्टैक की जांच कर सकता है, फिर स्वचालित लॉगिंग के लिए अंतिम प्रविष्टि निकाल सकता है, जो यहां नहीं है? सिद्धांत रूप में हां, लेकिन वास्तव में, इसके बाद भी स्टैक थोड़ा अधिक बढ़ेगा, जब तक कि वास्तविक संदेश नहीं लिखा जाता है (विशेष रूप से, कुछ बिंदु पर लॉगबैक को कॉल करना होगा, फिर एक वास्तविक ऐपेंडर)। मुझे लगता है कि गैर-दिलचस्प स्टैक लाइनों को फेंकने के लिए यह ऐपेंडर की भूमिका होनी चाहिए, इसलिए आप इसे इस लॉवेल क्लास को कॉल करने और शामिल करने के लिए सब कुछ दूर फेंकने के लिए अनुकूलित कर सकते हैं।
डेविड टोनहोफर

@ डेविड, हां, आप सही हैं :-)। मुझे यकीन नहीं है कि यह परिशिष्ट के लिए एक कार्य है क्योंकि उस मामले पर आप परिशिष्ट और लकड़हारे के बीच एक कठिन निर्भरता को परिभाषित कर रहे हैं ... लेकिन ... यह एक समाधान है। धन्यवाद डेविड
डोमिनिकन

14

लॉगबैक पर स्विच करने का प्रयास करें और उपयोग करें

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"));

मेरा मानना ​​है कि यह लॉगबैक का एकमात्र कॉल होगा और आपके बाकी कोड अपरिवर्तित रहेंगे। लॉगबैक SLF4J का उपयोग करता है और माइग्रेशन दर्द रहित होगा, बस xml कॉन्फिग फाइलों को बदलना होगा।

काम पूरा करने के बाद लॉग स्तर वापस सेट करना याद रखें।


मैं पहले से ही लॉगबैक-समर्थित slf4j का उपयोग कर रहा था, और इसने तुरंत मुझे अपनी इकाई परीक्षणों को साफ करने की अनुमति दी। धन्यवाद!
लैम्बर्ट

2
यह मेरा पहला -1 था, धन्यवाद। मेरा मानना ​​है कि आप गलत हैं। लॉगबैक SLF4J का उपयोग करता है, इसलिए उत्तर प्रासंगिक है।
λ18ος

3
@AlexandrosGelbessis आपको प्रश्न को फिर से पढ़ना चाहिए। यह एक ऐसी विधि के लिए कहा गया था जो किसी भी स्तर पर प्रोग्रामेटिक रूप से एक लॉग संदेश लॉग कर सके। आप केवल एक के लिए ही नहीं, सभी संदेशों के लिए रूट लॉगर का स्तर बदल रहे हैं।
jan ’को

12

आप इसे जावा 8 लैम्ब्डा का उपयोग करके लागू कर सकते हैं।

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);
    }
}

ठीक है हाँ ... लेकिन अब आपको इस API का उपयोग करने के लिए या slf4j के बजाय अपने कोडबेस को संशोधित करने की आवश्यकता है। यदि आप इसे slf4j 1 के बजाय उपयोग करते हैं) तो इसे संभवतः अधिक अमीर होने की आवश्यकता है, 2) बहुत सारे (कम से कम) आयातों को बदलने की आवश्यकता है, और 3) slf4j के सामने यह नई परत एक अतिरिक्त लॉगिंग ओवरहेड जोड़ता है।
स्टीफन सी

4
यह भी जान लें कि जब आप इस समाधान के लिए जाते हैं, तो वास्तविक लॉगिंग करने वाले वर्ग को लॉग नहीं किया जाएगा (क्योंकि लकड़हारा प्रारंभिक है LevelLogger), जो अच्छी बात नहीं है क्योंकि यह आम तौर पर बहुत उपयोगी जानकारी है।
छात्रावास

6

यह एक enumऔर सहायक विधि के साथ किया जा सकता है :

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यदि आप SLF4J के 1-पैरामीटर या 2-पैरामीटर warn/ error/ आदि के सामान्य समकक्ष चाहते हैं, तो आप अन्य प्रकार जोड़ सकते हैं । तरीकों।


3
सच है, लेकिन slf4j उद्देश्य लॉग रैपर लिखना नहीं है।
djjeck

5
SLF4J का उद्देश्य विभिन्न लॉगिंग रूपरेखाओं के लिए एक अमूर्तता प्रदान करना है। यदि वह अमूर्तता आपको वही प्रदान नहीं करता है जिसकी आपको आवश्यकता है, तो आपके पास सहायक विधि लिखने के अलावा कोई विकल्प नहीं है। केवल अन्य विकल्प SLF4J परियोजना के लिए मेरे जवाब में एक की तरह एक विधि का योगदान है।
रिचर्ड फर्न

मैं सहमत हूं, लेकिन इस मामले में कैविएट हैं, जैसे कि आप अब तक फ़ाइल और लाइन नंबर प्रदान करने में सक्षम नहीं होंगे, जब तक कि आप उस के लिए एक और वर्कअराउंड लागू नहीं करते। इस मामले में मैं log4j के साथ फंस गया होगा, जब तक कि फ्रेमवर्क ने सुविधा का समर्थन नहीं किया - जो अंततः एक एक्सटेंशन के माध्यम से हुआ, रॉबर्ट इलियट का और हालिया उत्तर देखें।
djjeck


3

मुझे बस कुछ ऐसा चाहिए था और साथ आया:

@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);
    }
}

उपयोग:

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

लकड़हारा मंगलाचरण के दौरान पारित किया जाता है, इसलिए वर्ग की जानकारी ठीक होनी चाहिए, और यह @ Slf4j lombok घोषणा के साथ अच्छी तरह से काम करता है।


इस भयानक दृष्टिकोण के लिए बहुत बहुत धन्यवाद - मैंने आपके विचार के आधार पर एक समान उत्तर पोस्ट किया।
slartidan

DEBUGलगातार याद आ रही है।
slartidan

यह समाधान हमेशा LogLevelकक्षा और logविधि के रूप में लॉग करेगा , जिससे लॉग कम अर्थपूर्ण हो जाते हैं।
slartidan

2

यह है नहीं sjf4j में एक लॉग स्तर निर्दिष्ट करना संभव 1.xबॉक्स से बाहर। लेकिन इस मुद्दे2.0 को ठीक करने के लिए slf4j के लिए आशा है । 2.0 में ऐसा लग सकता है:

// 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!");

इस बीच, slf4j 1.x के लिए, आप इस समाधान का उपयोग कर सकते हैं:

इस वर्ग को अपने वर्गपथ में कॉपी करें:

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);
    }
}

तो आप इसे इस तरह से उपयोग कर सकते हैं:

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");
}

यह इस तरह एक लॉग आउटपुट करेगा:

[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

यह इसके लायक है?

  • Proयह स्रोत कोड स्थान रखता है (वर्ग नाम, विधि नाम, लाइन संख्या आपके कोड को इंगित करेगा )
  • Proआप आसानी से चर , मापदंडों और वापसी प्रकार को परिभाषित कर सकते हैंLogLevel
  • Proआपका व्यवसाय कोड पढ़ने में छोटा और आसान है, और इसके लिए कोई अतिरिक्त निर्भरता की आवश्यकता नहीं है।

कम से कम उदाहरण के रूप में स्रोत कोड GitHub पर होस्ट किया गया है


नोट: LogMethodइंटरफ़ेस को इसके पैकेज के बाहर की कक्षाओं के साथ काम करने के लिए सार्वजनिक होना चाहिए। इसके अलावा, यह इरादा के अनुसार काम करता है। धन्यवाद!
andrebrait

1

Slf4j एपीआई के साथ लॉग स्तर को गतिशील रूप से बदलना संभव नहीं है, लेकिन आप लॉगबैक (यदि आप इसका उपयोग करते हैं) को अपने स्वयं के द्वारा कॉन्फ़िगर कर सकते हैं। उस स्थिति में अपने लकड़हारे के लिए फ़ैक्टरी क्लास बनाएं और रूट लॉगर को कॉन्फ़िगरेशन के साथ लागू करें, जिसकी आपको ज़रूरत है।

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);

जब आप रूट लकड़हारा कॉन्फ़िगर करते हैं (केवल एक बार पर्याप्त होता है) तो आप नया लकड़हारा प्राप्त कर सकते हैं

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

उसी का उपयोग करना याद रखें loggerContext

लॉग लेवल को बदलना रूट लॉगर से दिया गया आसान है loggerContext

root.setLevel(Level.DEBUG);

1

उत्तर की पुष्टि 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);

आपको परिणाम मिलेगा:

2020-05-14 14: 01: 16,644 TRACE [] [oakcmMetrics] टेस्ट वर्कर ने मेट्रिक नाम से पंजीकृत मेट्रिक नाम दिया [नाम = बफरपुल-वेट-टाइम-टोटल, ग्रुप = प्रोड्यूसर-मेट्रिक्स, विवरण = स्पेस एलोकेशन के लिए अपेंडेंट वेटर्स का कुल समय ।, टैग = {क्लाइंट-आईडी = निर्माता -2}]


0

मुझे अभी इसी तरह की जरूरत का सामना करना पड़ा है। मेरे मामले में, slf4j को जावा लॉगिंग एडाप्टर (jdk14 एक) के साथ कॉन्फ़िगर किया गया है। निम्नलिखित कोड स्निपेट का उपयोग करके मैं रनटाइम पर डिबग स्तर को बदलने में कामयाब रहा:

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
अन्य उत्तरों की तरह, यह मूल प्रश्न को संबोधित नहीं करता है, यह एक अलग समस्या है।
ई-रिज़

0

मास्सिमो विर्गिलियो के उत्तर के आधार पर, मैं आत्मनिरीक्षण का उपयोग करके slf4j-log4j के साथ भी करने में कामयाब रहा। 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

यहाँ @Paul Croarkin के रूप में उपयोगकर्ता के अनुकूल नहीं एक लंबोतरा समाधान एक तरह से है (स्तर प्रभावी रूप से दो बार पारित किया गया है)। लेकिन मुझे लगता है कि (ए) उपयोगकर्ता को लकड़हारा पारित करना चाहिए; और (बी) AFAIU मूल प्रश्न आवेदन में हर जगह के लिए एक सुविधाजनक तरीका नहीं पूछ रहा था, केवल एक पुस्तकालय के अंदर कुछ उपयोगों के साथ एक स्थिति।

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 वेरिएग्स परम के अंदर एक थ्रॉलेबल (जिसका स्टैक ट्रेस लॉग होना चाहिए) की अनुमति देता है , मुझे लगता है कि logअन्य उपभोक्ताओं के लिए हेल्पर विधि को ओवरलोड करने की कोई आवश्यकता नहीं है (String, Object[])


0

मैं JDK14 बाइंडिंग के लिए पहले SLF4J लकड़हारा उदाहरण का अनुरोध करके और फिर बाध्यकारी पर स्तर सेट करके ऐसा करने में सक्षम था - आप इसे Log4J बाइंडिंग के लिए आज़मा सकते हैं।

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

मेरे द्वारा उपयोग की जाने वाली विधि ch.qos.logback मॉड्यूल को आयात करना है और फिर slf4j लकड़हारा उदाहरण को ch.qos.logback.classic.Logger में टाइप करें। इस उदाहरण में setLevel () विधि शामिल है।

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 );

संभव लॉगिंग स्तर जानने के लिए, आप के लिए सभी संभव मूल्यों को देखने के लिए ch.qos.logback वर्ग में विस्फोट कर सकते हैं स्तर :

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

परिणाम निम्नलिखित हैं:

{
   // ...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

जावा आत्मनिरीक्षण का उपयोग करके आप इसे कर सकते हैं, उदाहरण के लिए:

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
यह स्पष्ट रूप से log4j को संदर्भित करता है और सामान्य रूप से slf4j को नहीं
Andersen

-6

नहीं, इसकी कई विधियाँ हैं, जानकारी (), डिबग (), चेतावनी (), आदि (यह प्राथमिकता फ़ील्ड को प्रतिस्थापित करता है)

पूर्ण लकड़हारा एपीआई के लिए http://www.slf4j.org/api/org/slf4j/Logger.html पर एक नज़र डालें ।


क्षमा करें, मैं देख रहा हूं कि आप अब क्या पूछ रहे हैं। नहीं, रनटाइम पर लॉग स्तर को बदलने का कोई सामान्य तरीका नहीं है, लेकिन आप स्विच पद्धति के साथ एक सहायक विधि को आसानी से लागू कर सकते हैं।
क्रिस

हां, लेकिन फिर आपको "लॉग" विधि के प्रत्येक अतिभारित संस्करण के लिए एक बार करना होगा।
एंड्रयू स्वान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.