2013-07-01 11 views
11

Log4j2 również używa haków zamykających, aby zakończyć swoje usługi. Ale oczywiście chcę się zalogować przez cały cykl życia mojej aplikacji - włącznie z zamknięciem. W Log4j nie stanowiło to problemu. Teraz wydaje się to niemożliwe. Logowanie zostaje wyłączone, a moja aplikacja wciąż nad nim pracuje. Czy ktoś ma dla mnie jakąś nadzieję?Jak zalogować się w hakach wyłączania za pomocą Log4j2?

poważaniem Martin

+0

Rejestrowanie, lub w zależności od innych usług w hakach wyłączania, od samego początku było kiepską praktyką, a teraz nadrabia zaległości. –

+0

@MarkoTopolnik Jeśli uważasz, że jest to zła praktyka, co sugerujesz, czy wyjście wątku haka zamykającego wymaga nagrania/rejestracji? – vegemite4me

+0

Ponieważ w haku zamknięcia nie można liczyć na jakąkolwiek część stanu inicjalizowanego, aby nadal istnieć, jedyną rzeczą, którą widzę jako pół-niezawodną, ​​jest całkowicie samowystarczalny fragment kodu, który tworzy plik i zapisuje do niego. Podobnie do sposobu, w jaki tworzony jest zrzut rdzenia. –

Odpowiedz

19

Jako 2,0-beta9 to teraz konfigurowalny w xml

<configuration ... shutdownHook="disable"> 

Biorąc pod uwagę jej teraz wyłączone, myślę, trzeba ręcznie wyłączyć system rejestrowania na koniec mój hak zamykający. Jednak nie mogłem znaleźć sposób dokładny interfejs zewnętrzny, tylko w wewnętrznej api

import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.core.config.Configurator; 
import org.apache.logging.log4j.core.LoggerContext; 
... 

public static void main(String[] args) { 
    final AnnotationConfigApplicationContext springContext = new AnnotationConfigApplicationContext(AppConfig.class) 

    Runtime.getRuntime().addShutdownHook(new Thread() { 
     public void run() { 
      //shutdown application 
      LOG.info("Shutting down spring context"); 
      springContext.close(); 

      //shutdown log4j2 
      if(LogManager.getContext() instanceof LoggerContext) { 
       logger.info("Shutting down log4j2"); 
       Configurator.shutdown((LoggerContext)LogManager.getContext()); 
      } else 
       logger.warn("Unable to shutdown log4j2"); 
     } 
    }); 

    //more application initialization 
} 
+0

kiedykolwiek to rozgryzłeś? – user671731

+1

Problem polega na tym, że haki zamykające Java są uruchamiane równolegle. Aby naprawdę upewnić się, że możesz się logować wszędzie musisz unikać dodawania haków do podanego Runtime.getRuntime(). AddShutdownHook (Thread) -API, ale stwórz swój własny workflow, który ręcznie zatrzymuje log4j 2.0 po tym, jak wszystko jest w porządku. Ale główny problem został rozwiązany, gdy Log4j zaoferował shutdownHook-trigger. – Martin

+0

Zgadzam się, że musisz stworzyć swój własny workflow. Zwykle uruchamiam moją aplikację na Linuksie i wyłączam ją poprzez sygnał do JVM, więc hak do zamykania jest odpowiedni do tego celu (zaktualizowałem fragment kodu, aby pokazać ten kontekst).Nie mogłem znaleźć żadnych odwołańHookTrigger po krótkim Google, czy mógłbybyś połączyć? – Chomeh

7

I w zasadzie tylko odpowiedział na to samo pytanie i trudne będę dzielić moją odpowiedź tutaj. Zachęcam do przeczytania complete answer available here. Spróbuję tu przedstawić podsumowanie i dostosować moją odpowiedź do obecnego kontekstu.

W pierwszej wersji Log4j udostępnia interfejs API do ręcznego wywoływania procedury zamykania. Z przyczyn, o których nie wiemy, it was removed from the second version. Teraz właściwym sposobem (zgodnie z nieistniejącą dokumentacją) jest zapewnienie własnej implementacji interfejsu ShutdownCallbackRegistry, który jest odpowiedzialny za procedurę zamykania.

Proponowane rozwiązanie

Co zrobiłem, aby rozwiązać ten problem jest to, że realizowane własną wersję interfejsu ShutdownCallbackRegistry. Zwykle robi to samo, co robi domyślna implementacja, ale zamiast rejestrować się jako przechwyt awaryjny na maszynie JVM, czeka na jej ręczne wywołanie.

Kompletne rozwiązanie i instrukcje można znaleźć na stronie GitHub/DjDCH/Log4j-StaticShutdown i można z niego korzystać we własnych projektach. Zasadniczo, na koniec, trzeba tylko zrobić coś takiego w swojej aplikacji:

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      // Do your usual shutdown stuff here that need logging 
     } finally { 
      // Shutdown Log4j 2 manually 
      StaticShutdownCallbackRegistry.invoke(); 
     } 
    } 
})); 

Nie mogę powiedzieć bez żadnej wątpliwości, że jest to idealne rozwiązanie i że moje wykonanie jest doskonałe, ale starałem zrobić to we właściwy sposób. Chętnie wysłucham opinii użytkowników, jeśli uznasz to rozwiązanie za odpowiednie lub nie.