प्रोग्राम लॉग के लिए रूट लॉगिंग स्तर को प्रोग्रामेटिक रूप से कैसे बदलें


144

मेरे पास निम्नलिखित logback.xml फ़ाइल है:

<configuration debug="true"> 

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
<encoder>
  <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<root level="debug">
  <appender-ref ref="STDOUT" />
</root>
</configuration>

अब, किसी विशिष्ट घटना के होने पर, मैं डिबग से एरर में रूट लॉगर के स्तर को प्रोग्रामेटिक रूप से बदलना चाहता हूं । मैं चर प्रतिस्थापन का उपयोग नहीं कर सकता, यह अनिवार्य है कि मैं कोड के भीतर ऐसा करूं।

यह कैसे किया जा सकता है ? धन्यवाद।

जवाबों:


235

इसे इस्तेमाल करे:

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

Logger root = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
root.setLevel(Level.INFO);

ध्यान दें कि आप लॉगबैक को समय-समय पर अपनी कॉन्फ़िगरेशन फ़ाइल को इस तरह स्कैन करने के लिए भी कह सकते हैं:

<configuration scan="true" scanPeriod="30 seconds" > 
  ...
</configuration> 

64
यह ध्यान दिया जाना चाहिए कि slf4j का उद्देश्य लॉगिंग फ्रेमवर्क को दूर करना है, लेकिन यह पहला तरीका लॉगिंग फ्रेमवर्क को सीधे संदर्भित करके दूर करता है।
टिम गौटियर

3
यदि आप ऐसा करते हैं और एक ClassCastException प्राप्त करते हैं, तो यह क्लासपाथ पर कई SLF4J बाइंडिंग होने के कारण सबसे अधिक संभावना है। लॉग आउटपुट यह इंगित करेगा और कौन सा बाइंडिंग आपको यह निर्धारित करने के लिए मौजूद है कि आपको किसको बाहर करना है।
icfantv

4
Slf4j एक एपीआई प्रदान करता है जिससे कि पुस्तकालयों को एप्लिकेशन लॉग लॉग कर सकते हैं जो कि एप्लिकेशन डेवलपर जो भी लॉग फ्रेमवर्क चाहता है। मुद्दा यह है कि एप्लिकेशन डेवलपर को अभी भी एक लॉग फ्रेमवर्क चुनना होगा, उस पर निर्भर होना चाहिए, और इसे कॉन्फ़िगर करना होगा। लकड़हारे को कुत्ते के रूप में कॉन्फ़िगर करना इस सिद्धांत का उल्लंघन नहीं करता है।
मैक्स

4
@ जोहानिसमैन यदि आप चाहते हैं कि इसे कॉन्फ़िगर किया जाए, तो आपको इसे कहीं कॉन्फ़िगर करना होगा । जैसा कि slf4j इस संबंध में कुछ भी प्रदान नहीं करता है, हमेशा अंतर्निहित लकड़हारे पर निर्भर कुछ होगा। यह कोड या एक कॉन्फ़िगरेशन फ़ाइल का एक टुकड़ा हो। +++ यदि यह ओपी के अनुरोध के अनुसार प्रोग्रामेटिक रूप से किया जाना चाहिए, तो आपके पास कोई विकल्प नहीं है। फिर भी, लाभ बने हुए हैं: 1. कोड का केवल एक छोटा हिस्सा कंक्रीट लकड़हारा इंजन पर निर्भर करता है (और इसे लिखा जा सकता है ताकि यह अलग-अलग कार्यान्वयन को संभाल सके)। 2. आप अन्य लॉगर का उपयोग करके लिखी गई लाइब्रेरी को भी कॉन्फ़िगर कर सकते हैं।
माॅर्टिनस

4
लॉगिंग जैसी किसी चीज़ के लिए इसे इतना जटिल क्यों होना चाहिए, कोड में ही लॉगिंग स्तर को बदलने का एक सीधा तरीका नहीं होना चाहिए। किसी विशेष पुस्तकालय के सिद्धांत का पालन करने से उसकी सादगी पर पूर्वता कैसे होती है? एक पायथन दुनिया से आते हुए, मैं यह समझने में असफल रहा कि जावा / स्काला में लॉगिंग जितना सरल क्यों है।
अभिनंदन दुबे

11

मुझे लगता है कि आप लॉगबैक (कॉन्फ़िगरेशन फ़ाइल से) का उपयोग कर रहे हैं।

से logback मैनुअल , मैं देख रहा हूँ

Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

शायद इससे आपको मूल्य बदलने में मदद मिल सकती है?


10

1.1.3 का उपयोग करते हुए मुझे निम्नलिखित (स्काला कोड) करना था:

import ch.qos.logback.classic.Logger
import org.slf4j.LoggerFactory    
...
val root: Logger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME).asInstanceOf[Logger]

4

मुझे लगता है कि आप एमडीसी का उपयोग लॉगिंग स्तर को प्रोग्रामेटिक रूप से बदलने के लिए कर सकते हैं। नीचे दिया गया कोड वर्तमान थ्रेड पर लॉगिंग स्तर को बदलने के लिए एक उदाहरण है। यह दृष्टिकोण लॉगबैक कार्यान्वयन के लिए निर्भरता नहीं बनाता है (SLF4J API में MDC है)।

<configuration>
  <turboFilter class="ch.qos.logback.classic.turbo.DynamicThresholdFilter">
    <Key>LOG_LEVEL</Key>
    <DefaultThreshold>DEBUG</DefaultThreshold>
    <MDCValueLevelPair>
      <value>TRACE</value>
      <level>TRACE</level>
    </MDCValueLevelPair>
    <MDCValueLevelPair>
      <value>DEBUG</value>
      <level>DEBUG</level>
    </MDCValueLevelPair>
    <MDCValueLevelPair>
      <value>INFO</value>
      <level>INFO</level>
    </MDCValueLevelPair>
    <MDCValueLevelPair>
      <value>WARN</value>
      <level>WARN</level>
    </MDCValueLevelPair>
    <MDCValueLevelPair>
      <value>ERROR</value>
      <level>ERROR</level>
    </MDCValueLevelPair>
  </turboFilter>
  ......
</configuration>
MDC.put("LOG_LEVEL", "INFO");

3

जैसा कि दूसरों द्वारा बताया गया है, आप बस mockAppenderएक LoggingEventउदाहरण बनाते हैं और फिर एक उदाहरण बनाते हैं जो अनिवार्य रूप से लॉगिंग इवेंट में पंजीकृत / सुनता है mockAppender

यहाँ है कि यह परीक्षण में कैसा दिखता है:

import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;

@RunWith(MockitoJUnitRunner.class)
public class TestLogEvent {

// your Logger
private Logger log = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);

// here we mock the appender
@Mock
private Appender<ILoggingEvent> mockAppender;

// Captor is generic-ised with ch.qos.logback.classic.spi.LoggingEvent
@Captor
private ArgumentCaptor<LoggingEvent> captorLoggingEvent;

/**
 * set up the test, runs before each test
 */
@Before
public void setUp() {
    log.addAppender(mockAppender);
}

/**
 * Always have this teardown otherwise we can stuff up our expectations. 
 * Besides, it's good coding practise
 */
@After
public void teardown() {
    log.detachAppender(mockAppender);
}


// Assuming this is your method
public void yourMethod() {
    log.info("hello world");
}

@Test
public void testYourLoggingEvent() {

    //invoke your method
    yourMethod();

    // now verify our logging interaction
    // essentially appending the event to mockAppender
    verify(mockAppender, times(1)).doAppend(captorLoggingEvent.capture());

    // Having a generic captor means we don't need to cast
    final LoggingEvent loggingEvent = captorLoggingEvent.getValue();

    // verify that info log level is called
    assertThat(loggingEvent.getLevel(), is(Level.INFO));

    // Check the message being logged is correct
    assertThat(loggingEvent.getFormattedMessage(), containsString("hello world"));
}
}

0

मुझे लगता है कि वह सफलता हासिल कर रहा है

org.jboss.logmanager.Logger logger = org.jboss.logmanager.Logger.getLogger("");
logger.setLevel(java.util.logging.Level.ALL);

फिर नेटी से विस्तृत लॉगिंग प्राप्त करने के लिए, निम्नलिखित ने यह किया है

org.slf4j.impl.SimpleLogger.setLevel(org.slf4j.impl.SimpleLogger.TRACE);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.