Dynamiczna zmiana poziomu dziennika log4j

127

Jakie są różne podejścia do dynamicznej zmiany poziomu dziennika log4j, aby nie musieć ponownie wdrażać aplikacji. Czy w tych przypadkach zmiany będą trwałe?

Ravi
źródło
Bardzo podobny do stackoverflow.com/questions/2115900/…
vsingh
3
Zaktualizowano pytanie do log4j2: stackoverflow.com/questions/23434252/ ...
slaadvak
1
Zauważ, że (prawie) wszystko na tej stronie dotyczy log4j, a nie log4j2. Cała ta strona jest tak pełna zamieszania i błędnych wskazówek, że jest BEZ UŻYCIA. Idź do stackoverflow.com/questions/23434252/ ... zgodnie z zaleceniami @slaadvak.
Lambart

Odpowiedzi:

86

Zmiana poziomu dziennika jest prosta; modyfikowanie innych części konfiguracji będzie stanowić bardziej szczegółowe podejście.

LogManager.getRootLogger().setLevel(Level.DEBUG);

Zmiany są trwałe w całym cyklu życia Logger . Podczas ponownej inicjalizacji konfiguracja zostanie odczytana i wykorzystana, ponieważ ustawienie poziomu w czasie wykonywania nie utrwala zmiany poziomu.

AKTUALIZACJA: Jeśli używasz Log4j 2, powinieneś usunąć wywołania setLevelzgodnie z dokumentacją, ponieważ można to osiągnąć za pomocą klas implementacji.

Wywołania logger.setLevel () lub podobne metody nie są obsługiwane w interfejsie API. Aplikacje powinny je usunąć. Równoważne funkcje są dostępne w klasach implementacji Log4j 2, ale mogą pozostawić aplikację podatną na zmiany w wewnętrznych elementach Log4j 2.

Aaron McIver
źródło
5
Tylko dla zależności wykonawczychLogManager.getLogger(Class.forName("org.hibernate.util.JDBCExceptionReporter")).setLevel(Level.FATAL);
CelinHC,
8
Należy zauważyć, że interfejs API log4j 2 nie udostępnia metody „setLevel”.
ChrisCantrell
5
Ale to tylko ustawia root logger, prawda? Jeśli indywidualne poziomy są ustawione dla loggerów jako root, ustawienie głównego loggera nie będzie miało wpływu na te LOGGER. Czy nie musielibyśmy zrobić czegoś takiego jak root.getLoggerRepository (). GetCurrentCategories (), iterować po każdej instancji programu rejestrującego i ustawić POZIOMY dla każdego rejestratora? @AaronMcIver
TheMonkWhoSoldHisCode
8
@ChrisCantrell Log4j 2 zapewnia sposób na zrobienie tego , chociaż nie jest to takie proste.
CorayThan
2
Log4j2 można skonfigurować tak, aby odświeżał swoją konfigurację, skanując plik log4j2.xml (lub odpowiednik) w określonych odstępach czasu. Np. <Configuration status = "warn" monitorInterval = "5" name = "tryItApp" packages = "">
Kimball Robinson
89

File Watchdog

Log4j jest w stanie obserwować log4j.xmlplik pod kątem zmian konfiguracji. Jeśli zmienisz plik log4j, log4j automatycznie odświeży poziomy dziennika zgodnie ze zmianami. Zobacz dokumentację org.apache.log4j.xml.DOMConfigurator.configureAndWatch(String,long), aby uzyskać szczegółowe informacje. Domyślny czas oczekiwania między sprawdzeniami to 60 sekund. Te zmiany byłyby trwałe, ponieważ bezpośrednio zmieniasz plik konfiguracyjny w systemie plików. Wystarczy raz wywołać DOMConfigurator.configureAndWatch ().

Uwaga: metoda configureAndWatch nie jest bezpieczna w środowiskach J2EE ze względu na wyciek wątku

JMX

Innym sposobem ustawienia poziomu dziennika (lub ogólnie rekonfiguracji) log4j jest użycie JMX. Log4j rejestruje swoje loggery jako JMX MBean. Korzystając z konsol MBeanServer serwerów aplikacji (lub jconsole.exe JDK) można rekonfigurować poszczególne rejestratory. Te zmiany nie są trwałe i zostaną zresetowane do konfiguracji określonej w pliku konfiguracyjnym po ponownym uruchomieniu aplikacji (serwera).

Wykonane samodzielnie

Zgodnie z opisem Aarona, poziom dziennika można ustawić programowo. Możesz zaimplementować to w swojej aplikacji tak, jak byś chciał. Na przykład możesz mieć GUI, w którym użytkownik lub administrator zmienia poziom dziennika, a następnie wywołuje setLevel()metody w programie rejestrującym. To, czy utrzymasz ustawienia gdzieś, czy nie, zależy od Ciebie.

mhaller
źródło
8
Uwaga dotycząca podejścia watchdog log4j: „Ponieważ configureAndWatch uruchamia oddzielny wątek watchdog i nie ma sposobu na zatrzymanie tego wątku w log4j 1.2, metoda configureAndWatch jest niebezpieczna w użyciu w środowiskach J2EE, w których aplikacje są odzyskiwane”. Źródła
Somu
Gdybym miał użyć funkcji configureAndWatch w Log4j, mógłbym zatrzymać ten wątek nadzorujący w metodzie @PostDestroy EJB (to wystarczająco dobry wskaźnik zamykania kontenera) To wszystko? A może jest coś więcej, czego mi brakuje…!
robin bajaj
przepraszam, miałem na myśli metodę @PreDestroy
robin bajaj
Log4j rejestruje swoje loggery jako JMX MBean ”. Mój serwlet używa log4j 1.2. Nie widzę żadnych MBean log4j.
Abdull
Wystarczy raz wywołać DOMConfigurator.configureAndWatch (). Jak mogę to osiągnąć?
gstackoverflow,
5

Log4j2 można skonfigurować tak, aby odświeżał swoją konfigurację, skanując plik log4j 2 .xml (lub odpowiednik) w określonych odstępach czasu. Po prostu dodaj parametr „ monitorInterval ” do tagu konfiguracyjnego. Zobacz wiersz 2 przykładowego pliku log4j 2 .xml, w którym program log4j ma przeskanować swoją konfigurację, jeśli minęło więcej niż 5 sekund od ostatniego zdarzenia w dzienniku.

<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="warn" monitorInterval="5" name="tryItApp" packages="">

    <Appenders>
        <RollingFile name="MY_TRY_IT"
                     fileName="/var/log/tryIt.log"
                     filePattern="/var/log/tryIt-%i.log.gz">
            <Policies>
                <SizeBasedTriggeringPolicy size="25 MB"/>
            </Policies>
            ...
        </RollingFile>
    </Appenders>


    <Loggers>
        <Root level="error">
            <AppenderRef ref="MY_TRY_IT"/>
        </Root>
    </Loggers>

</Configuration>

Istnieją dodatkowe kroki, aby to zadziałało, jeśli wdrażasz w instancji tomcat, wewnątrz IDE lub podczas korzystania z rozruchu sprężynowego. Wydaje się to nieco poza zakresem i prawdopodobnie zasługuje na osobne pytanie.

Kimball Robinson
źródło
@vsingh, czy wdrażasz wewnątrz buta sprężynowego, tomcat, kontener lub za pomocą IDE? Czasami w takich przypadkach mogą wystąpić dodatkowe kroki (nie jest to wina log4j2) - w zasadzie aplikacja nie widzi zmiany pliku, ponieważ został skopiowany do innej lokalizacji przez framework lub narzędzie.
Kimball Robinson
Cześć, przetestowałem to na Jboss6.4 i zaktualizowałem plik konfiguracyjny log4j2 w lokalizacji (wewnątrz pliku .war), gdzie aplikacja może zobaczyć plik. Jednak nadal nie działało. Jakieś sugestie?
MidTierDeveloper
3

Ta odpowiedź nie pomoże Ci dynamicznie zmienić poziomu logowania, musisz zrestartować usługę, jeśli możesz ponownie uruchomić usługę, skorzystaj z poniższego rozwiązania

Zrobiłem to, aby zmienić poziom dziennika log4j i zadziałało, nie poleciłem żadnego dokumentu. Użyłem tej wartości właściwości systemowej, aby ustawić nazwę mojego pliku dziennika. Użyłem tej samej techniki do ustawienia poziomu rejestrowania i zadziałało

przekazałem to jako parametr JVM (używam Java 1.7)

Przepraszamy, to nie zmieni dynamicznie poziomu logowania, wymaga ponownego uruchomienia usługi

java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java

w pliku log4j.properties dodałem ten wpis

log4j.rootLogger=${logging.level},file,stdout

próbowałem

 java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=INFO-cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=OFF -cp xxxxxx.jar  xxxxx.java

Wszystko działało. mam nadzieję że to pomoże!

Mam następujące zależności w moim pom.xml

<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>apache-log4j-extras</artifactId>
    <version>1.2.17</version>
</dependency>
Anandkumar
źródło
2
Cokolwiek wspomniałeś, wydaje się być w porządku, ale pytanie dotyczy dynamicznej zmiany poziomu logowania.
Azim,
Aby to zrobić, musisz ponownie uruchomić usługę. Nie zmienia to dynamicznie poziomów rejestrowania.
kk.
2

Z log4j 1.x uważam, że najlepszym sposobem jest użycie DOMConfigurator do przesłania jednej z predefiniowanych konfiguracji dziennika XML (powiedzmy, jednej do normalnego użytku, a drugiej do debugowania).

Skorzystanie z tych można zrobić za pomocą czegoś takiego:

  public static void reconfigurePredefined(String newLoggerConfigName) {
    String name = newLoggerConfigName.toLowerCase();
    if ("default".equals(name)) {
      name = "log4j.xml";
    } else {
      name = "log4j-" + name + ".xml";
    }

    if (Log4jReconfigurator.class.getResource("/" + name) != null) {
      String logConfigPath = Log4jReconfigurator.class.getResource("/" + name).getPath();
      logger.warn("Using log4j configuration: " + logConfigPath);
      try (InputStream defaultIs = Log4jReconfigurator.class.getResourceAsStream("/" + name)) {
        new DOMConfigurator().doConfigure(defaultIs, LogManager.getLoggerRepository());
      } catch (IOException e) {
        logger.error("Failed to reconfigure log4j configuration, could not find file " + logConfigPath + " on the classpath", e);
      } catch (FactoryConfigurationError e) {
        logger.error("Failed to reconfigure log4j configuration, could not load file " + logConfigPath, e);
      }
    } else {
      logger.error("Could not find log4j configuration file " + name + ".xml on classpath");
    }
  }

Po prostu wywołaj to z odpowiednią nazwą konfiguracji i upewnij się, że umieściłeś szablony w ścieżce klas.

ISparkes
źródło
jaki jest punkt wyzwalania tej metody? skąd wie, że ta metoda musi być wywoływana za każdym razem, gdy nastąpi zmiana w konfiguracji log4j?
asgs
Nadal nie rozumiem, co masz na myśli „na żądanie”. Czy możesz pokazać fragment, w którym podłączasz tę metodę?
asgs
2
Proszę bardzo: to jest fragment z kontrolera, w którym go używamy. Mamy stronę administratora z kilkoma linkami do dynamicznej rekonfiguracji logowania, która następnie wykonuje GET do linku / admin / setLogLevel? Level = Error, a następnie przechwytujemy to w kontrolerze, takim jak ten @RequestMapping (value = "setLogLevel", method = RequestMethod.GET) public ModelAndView setLogLevel (@RequestParam (value = "level", required = true) String level) {Log4jReconfigurator.reconfigureExisting (level);
ISparkes
Tak więc „na żądanie” oznacza „kiedy użytkownik kliknie przycisk” w moim przypadku
ISparkes,
Ach, rozumiem. Dlatego Twoja konsola administracyjna musi wysłać żądanie wywołania tej metody.
asgs
0

Z powodzeniem korzystałem z tej metody w celu zmniejszenia szczegółowości dzienników „org.apache.http”:

ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.apache.http");
logger.setLevel(Level.TRACE);
logger.setAdditive(false);
Thomas Bernardin
źródło
0

W przypadku interfejsu API log4j 2 możesz użyć

Logger logger = LogManager.getRootLogger();
Configurator.setAllLevels(logger.getName(), Level.getLevel(level));
mohamed stitane
źródło
-1

Jeśli chcesz zmienić poziom rejestrowania wszystkich rejestratorów, użyj poniższej metody. Spowoduje to wyliczenie wszystkich rejestratorów i zmianę poziomu rejestrowania na dany poziom. Upewnij się, że NIE masz log4j.appender.loggerName.Threshold=DEBUGustawionej właściwości w swoim log4j.propertiespliku.

public static void changeLogLevel(Level level) {
    Enumeration<?> loggers = LogManager.getCurrentLoggers();
    while(loggers.hasMoreElements()) {
        Logger logger = (Logger) loggers.nextElement();
        logger.setLevel(level);
    }
}
kk.
źródło
-3

Możesz użyć następującego fragmentu kodu

((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName)).setLevel(ch.qos.logback.classic.Level.toLevel(logLevel));
user2606570
źródło
Muszę tego spróbować.
user2045474