Comment modifier le niveau de journalisation racine par programme pour la connexion

144

J'ai le fichier logback.xml suivant:

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

Maintenant, lors de l'occurrence d'un événement spécifique, je veux changer par programme le niveau de l'enregistreur racine du débogage à l' erreur . Je ne peux pas utiliser la substitution de variable, il est obligatoire que je le fasse dans le code.

Comment ceci peut être fait ? Merci.

Kai Sternad
la source

Réponses:

235

Essaye ça:

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

Notez que vous pouvez également demander à logback d'analyser périodiquement votre fichier de configuration comme ceci:

<configuration scan="true" scanPeriod="30 seconds" > 
  ...
</configuration> 
dogbane
la source
64
Il convient de noter que le but de slf4j est d'abstraire le cadre de journalisation, mais cette première méthode supprime cela en référençant directement le cadre de journalisation.
Tim Gautier
3
Si vous faites cela et obtenez une ClassCastException, cela est probablement dû à plusieurs liaisons SLF4J sur le chemin de classe. La sortie du journal indiquera cela et quelles liaisons sont présentes pour vous permettre de déterminer laquelle (s) vous devez exclure.
icfantv
4
Slf4j fournit une API afin que les bibliothèques puissent consigner les journaux d'application en utilisant le cadre de journalisation souhaité par le développeur de l'application. Le fait est que le développeur de l'application doit toujours choisir un cadre de journalisation, en dépendre et le configurer. Configurer l'enregistreur comme l'a fait dogbane ne viole pas ce principe.
Max
4
@JohnWiseman Si vous voulez qu'il soit configuré, vous devez le configurer quelque part . Comme slf4j n'offre rien à cet égard, il y aura toujours quelque chose qui dépendra de l'enregistreur sous-jacent. Que ce soit un morceau de code ou un fichier de configuration. +++ Si cela doit être fait par programme comme l'OP l'a demandé, vous n'avez pas le choix. Néanmoins, des avantages demeurent: 1. Seule une infime partie du code dépend du moteur de journalisation concret (et il pourrait être écrit de manière à pouvoir gérer différentes implémentations). 2. Vous pouvez également configurer des bibliothèques écrites à l'aide d'autres enregistreurs.
maaartinus
4
Pourquoi cela doit-il être si compliqué pour quelque chose comme la journalisation, ne devrait-il pas y avoir un moyen direct de modifier le niveau de journalisation dans le code lui-même. Comment le respect du principe d'une bibliothèque particulière a-t-il préséance sur sa simplicité? Venant d'un monde Python, je ne comprends pas pourquoi quelque chose d'aussi simple que la journalisation est si compliqué en Java / Scala.
Abhinandan Dubey
11

Je suppose que vous utilisez logback (à partir du fichier de configuration).

Depuis le manuel de connexion , je vois

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

Peut-être que cela peut vous aider à changer la valeur?

Raghuram
la source
10

en utilisant logback 1.1.3, j'ai dû faire ce qui suit (code Scala):

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

Je pense que vous pouvez utiliser MDC pour modifier le niveau de journalisation par programme. Le code ci-dessous est un exemple pour modifier le niveau de journalisation sur le thread actuel. Cette approche ne crée pas de dépendance à l'implémentation de la journalisation (l'API SLF4J contient 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");
SATO Yusuke
la source
3

Comme indiqué par d'autres, vous créez simplement mockAppender, puis créez une LoggingEventinstance qui écoute essentiellement l'événement de journalisation enregistré / qui se produit à l'intérieur mockAppender.

Voici à quoi cela ressemble en 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"));
}
}
Solution simple
la source
0

Je semble avoir du succès en faisant

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

Ensuite, pour obtenir une journalisation détaillée de netty, ce qui suit l'a fait

org.slf4j.impl.SimpleLogger.setLevel(org.slf4j.impl.SimpleLogger.TRACE);
user7610
la source