So ändern Sie die Root-Protokollierungsebene programmgesteuert für die Protokollierung

Lesezeit: 6 Minuten

Benutzer-Avatar
Kai Sternad

Ich habe die folgende logback.xml-Datei:

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

Jetzt möchte ich beim Auftreten eines bestimmten Ereignisses die Ebene des Root-Loggers programmgesteuert ändern debuggen zu Error. Ich kann keine Variablensubstitution verwenden, es ist zwingend erforderlich, dass ich dies innerhalb des Codes mache.

Wie kann es gemacht werden? Vielen Dank.

Benutzer-Avatar
Hundebann

Versuche dies:

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

Beachten Sie, dass Sie logback auch anweisen können, Ihre Konfigurationsdatei wie folgt regelmäßig zu scannen:

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

  • Es sollte beachtet werden, dass der Zweck von slf4j darin besteht, das Protokollierungs-Framework zu abstrahieren, aber diese erste Methode beseitigt dies, indem sie direkt auf das Protokollierungs-Framework verweist.

    – Tim Gautier

    11. April 2013 um 21:14 Uhr

  • Wenn Sie dies tun und eine ClassCastException erhalten, liegt dies höchstwahrscheinlich daran, dass mehrere SLF4J-Bindungen im Klassenpfad vorhanden sind. Die Protokollausgabe zeigt dies an und welche Bindungen vorhanden sind, damit Sie bestimmen können, welche Sie ausschließen müssen.

    – icfantv

    15. August 2013 um 17:54 Uhr

  • Slf4j stellt eine API bereit, damit Bibliotheken Anwendungsprotokolle mit einem beliebigen Protokoll-Framework protokollieren können, das der Anwendungsentwickler wünscht. Der Punkt ist, dass der Anwendungsentwickler immer noch ein Protokoll-Framework auswählen, sich darauf verlassen und es konfigurieren muss. Die Konfiguration des Loggers, wie es Dogbane getan hat, verstößt nicht gegen dieses Prinzip.

    – max

    6. Februar 2016 um 13:35 Uhr

  • @JohnWiseman Wenn Sie möchten, dass es konfiguriert wird, müssen Sie es konfigurieren irgendwo. Da slf4j in dieser Hinsicht nichts bietet, wird es immer etwas abhängig vom zugrunde liegenden Logger geben. Sei es ein Stück Code oder eine Konfigurationsdatei. +++ Wenn es wie vom OP angefordert programmgesteuert erfolgen soll, haben Sie keine Wahl. Dennoch bleiben Vorteile: 1. Nur ein winziger Teil des Codes hängt von der konkreten Logger-Engine ab (und er könnte so geschrieben werden, dass er mit verschiedenen Implementierungen umgehen kann). 2. Sie können auch Bibliotheken konfigurieren, die mit anderen Loggern geschrieben wurden.

    – maaartinus

    15. Mai 2016 um 15:34 Uhr

  • Warum muss es für so etwas wie Logging so kompliziert sein, sollte es nicht eine direkte Möglichkeit geben, das Logging-Level im Code selbst zu ändern? Inwiefern hat das Befolgen des Prinzips der bestimmten Bibliothek Vorrang vor seiner Einfachheit? Da ich aus einer Python-Welt komme, verstehe ich nicht, warum etwas so Einfaches wie Logging in Java/Scala so kompliziert ist.

    – Abhinandan Dubey

    15. Januar 2019 um 16:04 Uhr


Ich nehme an, Sie verwenden Logback (aus der Konfigurationsdatei).

Aus Logback-HandbuchAha

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

Vielleicht hilft dir das, den Wert zu ändern?

Benutzer-Avatar
Todor Kolev

Mit Logback 1.1.3 musste ich Folgendes tun (Scala-Code):

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

Benutzer-Avatar
Einfach-Lösung

Wie von anderen betont, erstellen Sie einfach mockAppender und erstellen Sie dann eine LoggingEvent Instanz, die im Wesentlichen auf das darin registrierte/geschiehte Protokollierungsereignis lauscht mockAppender.

So sieht es im Test aus:

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

Ich denke, Sie können MDC verwenden, um die Protokollierungsebene programmgesteuert zu ändern. Der folgende Code ist ein Beispiel zum Ändern der Protokollierungsebene im aktuellen Thread. Dieser Ansatz erzeugt keine Abhängigkeit von der Logback-Implementierung (SLF4J-API enthält 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");

Ich scheine dabei Erfolg zu haben

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

Um dann eine detaillierte Protokollierung von netty zu erhalten, wurde Folgendes getan

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

Benutzer-Avatar
alevilla86

Hier ist ein Controller

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

}

1344760cookie-checkSo ändern Sie die Root-Protokollierungsebene programmgesteuert für die Protokollierung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy