Come modificare il livello di registrazione root a livello di codice per il logback


144

Ho il seguente file 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>

Ora, al verificarsi di un evento specifico, voglio modificare a livello di programmazione il livello del root logger da debug a errore . Non riesco a usare la sostituzione delle variabili, è obbligatorio farlo all'interno del codice.

Come si può fare? Grazie.

Risposte:


235

Prova questo:

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

Nota che puoi anche dire al logback di scansionare periodicamente il tuo file di configurazione in questo modo:

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

64
Va notato che lo scopo di slf4j è quello di sottrarre il framework di registrazione, ma quel primo metodo elimina ciò facendo riferimento direttamente al framework di registrazione.
Tim Gautier,

3
Se lo fai e ottieni una ClassCastException, molto probabilmente è dovuto al fatto che ci sono più associazioni SLF4J sul percorso di classe. L'output del registro indicherà questo e quali associazioni sono presenti per consentire di determinare quale (i) è necessario escludere.
Icfantv,

4
Slf4j fornisce un'API in modo che le librerie possano registrare i log delle applicazioni utilizzando qualsiasi framework di log lo sviluppatore dell'applicazione desideri. Il punto è che lo sviluppatore dell'applicazione deve ancora scegliere un framework di registro, dipendere da esso e configurarlo. La configurazione del logger come ha fatto dogbane non viola questo principio.
Max

4
@JohnWiseman Se vuoi che sia configurato, devi configurarlo da qualche parte . Poiché slf4j non offre nulla al riguardo, ci sarà sempre qualcosa che dipende dal logger sottostante. Sia esso un pezzo di codice o un file di configurazione. +++ Se dovrebbe essere fatto a livello di codice come richiesto dall'OP, allora non hai scelta. Tuttavia, i vantaggi rimangono: 1. Solo una piccola parte del codice dipende dal motore del logger concreto (e potrebbe essere scritto in modo da poter gestire diverse implementazioni). 2. È possibile configurare librerie scritte usando anche altri logger.
maaartinus,

4
Perché deve essere così complicato per qualcosa come Registrazione, non dovrebbe esserci un modo diretto per cambiare il livello di registrazione nel codice stesso. In che modo seguire il principio di una particolare biblioteca ha la precedenza sulla sua semplicità? Proveniente da un mondo Python, non riesco a capire perché qualcosa di così semplice come la registrazione sia così complicato in Java / Scala.
Abhinandan Dubey,

11

Presumo che tu stia utilizzando il logback (dal file di configurazione).

Dal manuale di logback , vedo

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

Forse questo può aiutarti a cambiare il valore?


10

usando il logback 1.1.3 ho dovuto fare quanto segue (codice Scala):

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

4

Penso che puoi utilizzare MDC per modificare il livello di registrazione a livello di codice. Il codice seguente è un esempio per modificare il livello di registrazione sul thread corrente. Questo approccio non crea dipendenza dall'implementazione del logback (l'API SLF4J contiene 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

Come sottolineato da altri, è sufficiente creare mockAppendere quindi creare LoggingEventun'istanza che essenzialmente ascolta l'evento di registrazione registrato / accade all'interno mockAppender.

Ecco come appare nel test:

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

Mi sembra di avere successo

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

Quindi per ottenere la registrazione dettagliata da netty, è stato eseguito quanto segue

org.slf4j.impl.SimpleLogger.setLevel(org.slf4j.impl.SimpleLogger.TRACE);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.