2016-06-01 41 views
8

Mój zespół pracuje nad wtyczką do NetBeans, która używa logowania do określonego pliku. System rejestrowania wykorzystuje SLF4J + Log4J2; tylko informacje o konfiguracji, że jestem świadomy jest plikiem log4j2.xml z właściwości rejestrowania dla wtyczki i dodaje:Jak prawidłowo zarządzać cyklem życia logów utworzonych za pomocą wtyczek za pomocą logowania Java z log4j2

LoggerContext loggerContext = (LoggerContext)LogManager.getContext(false); 
    loggerContext.reconfigure(); 

(Fakt, że używam slf4j i NetBeans naprawdę nie jest istotne tutaj).

Pytanie, które mam, to, jaki jest właściwy sposób rozpoczęcia rejestrowania po uruchomieniu wtyczki i zatrzymaniu rejestrowania po wyjściu wtyczki? (JVM utrzymuje się na zabawę z NetBeans więc pliki dziennika nie są automatycznie zamykane.)

Spojrzałam LoggerContext i widzę stop() i terminate() metod, ale nie mogę znaleźć żadnej dokumentacji, jak aplikacje mają używać LoggerContext , więc nie wiem, czy ten materiał jest wewnętrznym szczegółem, czy czymś, co powinna użyć aplikacja.


Niektóre bardziej specyficzne szczegóły:

Nasz plugin cyklu wyglądał na poniższym wykresie (tylko jedna instancja jest dopuszczalne, aby uruchomić na raz). "A" i "B" odnoszą się do konfiguracji logów, które chcielibyśmy zastosować.

 [Something starts within the JVM to load log4j classes first. 
     It might be our plugin, it might be something else. 
A  log4j's default mechanism kicks in to create log configuration A] 
| 
| [time passes] 
| 
| [our plugin starts] 
A [log4j classes first loaded, 
| default mechanism kicks in to create log configuration A] 
A setup log configuration B 
A B log event 1 
A B log event 2 
A B log event 3 
A shutdown log configuration B 
| [our plugin exits] 
| 
| [time passes] 
| 
| [our plugin starts] 
A setup log configuration B 
A B log event 1 
A B log event 2 
A B log event 3 
A shutdown log configuration B 
| [our plugin exits] 
| 
| [time passes] 
| 
    [JVM exits] 

Konfiguracja A jest skojarzona z JVM i jest domyślną konfiguracją utworzoną przez log4j przy pierwszym ładowaniu przez maszynę JVM.

Konfiguracja B jest zarządzana programowo przez wtyczkę i powinna mieć jawne uruchomienie/wyłączenie niezależnie od konfiguracji A (i nie powinno to wpłynąć na konfigurację A).

Czy jest jakiś sposób osiągnięcia tego z log4j 2.0?

+1

Czy chcesz, aby dwie konfiguracje dzienników były aktywne jednocześnie? Tak właśnie wygląda diagram z aktywnymi A i B podczas zdarzeń dziennika 1, 2 i 3 ... –

+0

Tak. Nie chcemy, aby wtyczka zakłócała ​​globalną konfigurację rejestrowania (np. "Loguj wszystkie zdarzenia ERROR do dziennika globalnego"), ale wtyczka musi skonfigurować własny kontekst zdarzeń wtyczek. –

Odpowiedz

2

W Log4j 2.5 można wywołać Configurator.shutdown(). Za pomocą Log4j 2.6 możesz wywołać LogManager.shutdown().

+0

Ale w jaki sposób mogę się upewnić, że wyłączam tylko zasoby rejestrowania używane w mojej wtyczce? Jeśli NetBeans ma logowanie i/lub inną wtyczkę używa log4j, nie chcę wyłączać wszystkich działań logowania, tylko tych, które ustawiłem dla mojej wtyczki. –

+1

Szukam jakiejś dokumentacji "dużego obrazu", która mówi, jak używać log4j w maszynie JVM zawierającej wiele współpracujących aplikacji, takich jak wtyczki/serwlety/itp. –

2

Można bezpiecznie używać oddzielnych LoggerContext s dla różnych składników aplikacji.

terminate() i stop() są całkowicie identyczne. W rzeczywistości ten pierwszy po prostu nazywa to drugie i nic więcej nie robi. terminate() jest częścią własnego api LoggerContext, a stop() jest częścią szerszego interfejsu LifeCycle.

Jeśli chcesz odpowiednio rozdzielić konteksty rejestrowania, użyj mechanizmu selektorów kontekstowych. Lo4j2 udostępnia interfejs ContextSelector dla klas odpowiedzialnych za wybór kontekstu, który zostanie zwrócony przez LogManager.getContext(). Istnieje kilka implementacji po wyjęciu z pudełka:

  • BasicContextSelector wybiera kontekst na podstawie bieżącego wątku.
  • BundleContextSelector do używania w środowisku OSGI.
  • JndiContextSelector dla wielu aplikacji internetowych w jednym kontenerze serwletów.
  • ClassLoaderContextSelector wybiera kontekst na podstawie programu ładującego klasy dzwoniącego.

Aby określić, którego selektora chcesz użyć, ustaw opcję Java Log4jContextSelector.

Na przykład, jeśli wtyczki uruchamiane w osobnych wątkach, można wybrał BasicContextSelector:

-DLog4jContextSelector=org.apache.logging.log4j.core.selector.BasicContextSelector 

i używać oddzielnych LoggerContext s dla ciebie plugins ten sposób (kod ten musi być prowadzony w wątku Wtyczka jest):

// Create a separate context for the plugin 
LoggerContext pluginContext = new LoggerContext("PluginContext"); 

// Setup pluginContext... 

// BasicContextSelector uses ContextAnchor.THREAD_CONTEXT 
// to bind contexts to threads: 
ContextAnchor.THREAD_CONTEXT.set(pluginContext); 

// Your plugin works and has access to your logging context 
LogManager.getContext(false); // Returns pluginContext 

// Stop and remove the plugin's logging context 
pluginContext.stop(); 
ContextAnchor.THREAD_CONTEXT.set(null); 

zależności od architektury swoich wtyczek, można użyć jednego z tych implementacji lub dostarczyć własne, jest to dość proste, to po prostu trzeba wdrożyć następujące metody:

  • getContext() do tworzenia nowych kontekstów (lub zwracania istniejących) w oparciu o parametry dostarczone do LogManager.getContext(...).
  • getLoggerContexts(), aby zwrócić kolekcję dostępnych kontekstów (te, które zostały wcześniej utworzone).
  • removeContext() do usuwania kontekstów z pamięci, gdy są zatrzymane (zakończone).
+0

oznacza to, że rejestrowanie zdarzeń zostanie przeniesione do tego nowego niestandardowego kontekstu, ale nie będzie dłużej przejdź do domyślnego kontekstu? Czy jest jakiś sposób, żeby ich obu udało? –

+0

Zdarzenia zostaną przeniesione do kontekstu używanego do uzyskania programu rejestrującego, do którego wysyłane są te zdarzenia. Ponieważ każdy program rejestrujący jest własnością określonego kontekstu (zobacz architekturę tutaj: http://logging.apache.org/log4j/2.x/manual/architecture.html), wydarzenie zostanie przeniesione tylko do jednego z kontekstów. Jeśli jest to konieczne, aby wysłać zdarzenia do dwóch kontekstów, utworzyłbym swój własny Logger, który otoczyłby dwa rejestratory: jeden uzyskany przez 'getContext (true)' i jeden uzyskany przez 'getContext (false)'. Wszystkie operacje rejestrowania, które delegowałbym do tych dwóch rejestratorów. –

+1

Bardziej skomplikowanym, ale nieco bardziej idiomatycznym rozwiązaniem byłoby zaimplementowanie własnego 'LoggerContext', który obejmowałby dwa standardowe konteksty (wtyczki i główne) i zwrócenie opisanego powyżej opakowania wokół dwóch' Logger'ów z 'getLogger () '. Następnie możesz zwrócić ten niestandardowy kontekst z niestandardowego selektora kontekstu. W rezultacie kod klienta nie będzie wiedział o wszystkich tych opakowaniach i zwyczajnie użyje rejestratorów, ale wszystkie zdarzenia ostatecznie przejdą zarówno do wtyczki, jak i głównych rejestratorów. –