Cómo cambiar el nivel de registro raíz mediante programación para el inicio de sesión

6 minutos de lectura

avatar de usuario
Kai Sternad

Tengo el siguiente archivo 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>

Ahora, ante la ocurrencia de un evento específico, quiero cambiar mediante programación el nivel del registrador raíz de depurar a error. No puedo usar la sustitución de variables, es obligatorio que haga esto dentro del código.

Cómo puede hacerse esto ? Gracias.

avatar de usuario
acónito

Prueba esto:

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

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

Tenga en cuenta que también puede indicarle a logback que escanee periódicamente su archivo de configuración de esta manera:

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

  • Cabe señalar que el propósito de slf4j es abstraer el marco de registro, pero ese primer método lo elimina al hacer referencia directamente al marco de registro.

    – Tim Gautier

    11/04/2013 a las 21:14

  • Si hace esto y obtiene una ClassCastException, lo más probable es que se deba a que tiene varios enlaces SLF4J en el classpath. La salida del registro indicará esto y qué enlaces están presentes para permitirle determinar cuáles necesita excluir.

    – icfantv

    15 de agosto de 2013 a las 17:54

  • Slf4j proporciona una API para que las bibliotecas puedan registrar registros de aplicaciones utilizando cualquier marco de registro que desee el desarrollador de la aplicación. El punto es que el desarrollador de la aplicación aún debe elegir un marco de registro, depender de él y configurarlo. Configurar el registrador como lo ha hecho dogbane no viola este principio.

    – Máx.

    06/02/2016 a las 13:35

  • @JohnWiseman Si desea configurarlo, debe configurarlo en algún lugar. Como slf4j no ofrece nada a este respecto, siempre habrá algo que dependa del registrador subyacente. Ya sea un fragmento de código o un archivo de configuración. +++ Si debe hacerse mediante programación como lo solicitó el OP, entonces no tiene otra opción. Aún así, quedan ventajas: 1. Solo una pequeña parte del código depende del motor de registro concreto (y podría escribirse para que pueda manejar diferentes implementaciones). 2. También puede configurar bibliotecas escritas con otros registradores.

    – maaartinus

    15 mayo 2016 a las 15:34

  • ¿Por qué tiene que ser tan complicado para algo como el registro? ¿No debería haber una forma directa de cambiar el nivel de registro en el código mismo? ¿Cómo tiene prioridad seguir el principio de una biblioteca particular sobre su simplicidad? Viniendo de un mundo de Python, no entiendo por qué algo tan simple como el registro es tan complicado en Java/Scala.

    – Abhinandan Dubey

    15 de enero de 2019 a las 16:04


Supongo que está utilizando el inicio de sesión (desde el archivo de configuración).

De manual de inicio de sesiónYa veo

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

¿Quizás esto pueda ayudarte a cambiar el valor?

avatar de usuario
Todor Kolev

usando logback 1.1.3 tuve que hacer lo siguiente (código Scala):

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

avatar de usuario
Solución simple

Como han señalado otros, simplemente creas mockAppender y luego crear un LoggingEvent instancia que esencialmente escucha el evento de registro registrado/sucede dentro mockAppender.

Así es como se ve en la prueba:

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

Creo que puede usar MDC para cambiar el nivel de registro mediante programación. El siguiente código es un ejemplo para cambiar el nivel de registro en el hilo actual. Este enfoque no crea dependencia para la implementación de inicio de sesión (la API de 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");

Parece que estoy teniendo éxito haciendo

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

Luego, para obtener un registro detallado de netty, lo siguiente lo ha hecho

org.slf4j.impl.SimpleLogger.setLevel(org.slf4j.impl.SimpleLogger.TRACE);

avatar de usuario
alevilla86

Aquí hay un controlador

@RestController
@RequestMapping("/loggers")
public class LoggerConfigController {

private final static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(PetController.class);

@GetMapping()
public List<LoggerDto> getAllLoggers() throws CoreException {
    
    LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    
    List<Logger> loggers = loggerContext.getLoggerList();
    
    List<LoggerDto> loggerDtos = new ArrayList<>();
    
    for (Logger logger : loggers) {
        
        if (Objects.isNull(logger.getLevel())) {
            continue;
        }
        
        LoggerDto dto = new LoggerDto(logger.getName(), logger.getLevel().levelStr);
        loggerDtos.add(dto);
    }
    
    if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("All loggers retrieved. Total of {} loggers found", loggerDtos.size());
    }
    
    return loggerDtos;
}

@PutMapping
public boolean updateLoggerLevel(
        @RequestParam String name, 
        @RequestParam String level
)throws CoreException {
    
    LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    
    Logger logger = loggerContext.getLogger(name);
    
    if (Objects.nonNull(logger) && StringUtils.isNotBlank(level)) {
        
        switch (level) {
            case "INFO":
                logger.setLevel(Level.INFO);
                LOGGER.info("Logger [{}] updated to [{}]", name, level);
                break;
                
            case "DEBUG":
                logger.setLevel(Level.DEBUG);
                LOGGER.info("Logger [{}] updated to [{}]", name, level);
                break;
                
            case "ALL":
                logger.setLevel(Level.ALL);
                LOGGER.info("Logger [{}] updated to [{}]", name, level);
                break;
                
            case "OFF":
            default: 
                logger.setLevel(Level.OFF);
                LOGGER.info("Logger [{}] updated to [{}]", name, level);
        }
    }
    
    return true;
}

}

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad