Embedded Jetty v Mavene je skvelý príklad mäteže logov. Ako presvedčiť server, aby logoval rovnakým spôsobom ako vaša aplikácia, ak používate Spring? Toto je pokračovanie článku SLF4j a Spring MVC a Jetty a Maven.
Aktualizácia 6. 7. 2014: Postup funguje len v Mavene 3.0.x. Novšie verzie Mavenu využívajú na interné logovanie slf4j
, čo situáciu komplikuje a tento postup nefunguje. V takom prípade využije conf\logging\simplelogger.properties
v inštalačnom adresári Mavenu na doladenie konfigurácie. Vysvetlenie sa nachádza v dokumentácii k Mavenu.
Najprv ukážka z konzoly:
2013-08-07 17:40:18.047:INFO:oejs.ServerConnector:main: Started ServerConnector@a5c7c18{HTTP/1.1}{0.0.0.0:8080}
[INFO] Started Jetty Server
[INFO] Console reloading is ENABLED. Hit ENTER on the console to restart the context.
17:40:45.414 [qtp1433716617-27] DEBUG s.u.i.n.mjss.LoggingController - Accessing onLog()
Tieto štyri riadky zo života ukazujú tri (!) výstupy z rozličných systémov:
- prvý je logovaný samotným Jetty
- dvojica ukazuje log z Mavenu
- a posledný riadok vznikol prúdením Spring -> commons-logging -> SLF4J -> logback
Jetty môžeme veľmi jednoducho prehodiť na používanie SLF4J: pretože už od dávna (minimálne od verzie 8) môže interne logovať cez túto knižnicu. Možnosť výberu je pomerne zložitá, ale nám stačí vedieť, že ak sa v CLASSPATH
servera objaví SLF4J, Jetty ju použije.
Budeme potrebovať:
- zaviesť závislosti do
pom.xml
- nastaviť cestu ku konfiguračnému súboru
logback.xml
POM.XML
V Mavene to vyriešime dodaním závislostí pre plug-in Maven Jetty.
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.0.4.v20130625</version>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
</dependencies>
</plugin>
Pre plug-in (pozor, nie pre projekt!) sme dodali požadovaný SLF4J a rovno aj logback.
Cesta k logback.xml
Ak by sme logovali v normálnej webovej aplikácii, Logback konfigurujeme cez logback.xml
, ktorý sa má ocitnúť v CLASSPATH
. Tradične to znamená, že ho hodíme do koreňového balíčka, čo v zmysle mavenovských konvencií do src/main/resources/logback.xml
. Vo výslednej webovej aplikácii sa tento súbor ocitne zrejme vo WEB-INF/classes
.
Jetty, čo je embeddnutá v Mavene, však tieto finty nemôže použiť (a nefungujú ani bežné postupy pre samostatne bežiacu Jetty mimo Mavenu). Prakticky existujú dva spôsoby, ako uviesť cestu k logback.xml
:
- nastavením system property z príkazového riadku,
- uvedením do
pom.xml
.
Ukážeme si spôsob, kde v projekte aj Jetty, aj naša aplikácia bude používať rovnaký súbor logback.xml
. Konfigurácia logovania sa teda scentralizuje na jednom mieste.
Nastavenie systémového parametra
Ak nastavíme systémový parameter (system property) logback.configurationFile
, Jetty ho použije na nájdenie súboru. Hodnota musí obsahovať absolútnu cestu k súboru, napr. takto:
mvn -Dlogback.configurationFile=C:\Projects\maven-jetty-spring-slf4j-demo\src\main\resources\logback.xml jetty:run
Nechcel by som to písať z príkazového riadku…
Uvedenie do pom.xml
Druhou možnosťou je zavedenie systémového parametra priamo do pom.xml
. Plug-in pre Jetty síce podporuje v konfigurácii parameter systemProperties
, ale v tejto situácii to nefunguje:
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<systemProperties>
<systemProperty>
<name>fooprop</name>
<value>222</value>
</systemProperty>
</systemProperties>
Dokumentácia Jetty sa snaží hmlisto a nie celkom úspešne vysvetliť, že prečo to tak je, ale aspoň ponúka riešenie: cez ďalší plugin org.codehaus.mojo:properties-maven-plugin
:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>set-system-properties</goal>
</goals>
<configuration>
<properties>
<property>
<name>logback.configurationFile</name>
<value>${basedir}/src/main/resources/logback.xml</value>
</property>
</properties>
</configuration>
</execution>
</executions>
</plugin>
Z plug-inu využijeme goal set-system-properties
, ktorý naviažeme na fázu validate
: je to jedna z úvodných fáz životného cyklu mavenovského zostavovania projektu a teda sa vykoná skôr než spustenie Jetty.
Príslušný parameter musíme uviesť s celou cestou: ale v Mavene máme zabudovanú premennú basedir
, ktorá jednak ušetrí písanie a jednak je robustná krížom cez rozličné adresárové štruktúry.
Nastavenie logback.xml
Zmienený logback.xml
je potom jednoduchý:
<configuration>
<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="INFO">
<appender-ref ref="STDOUT" />
</root>
<logger name="org.springframework" level="DEBUG" />
<logger name="org.eclipse.jetty.plus.webapp.PlusConfiguration" level="WARN" />
<logger name="sk.upjs.ics.novotnyr.mjss" level="DEBUG" />
</configuration>
Implicitná úroveň logovania je na úrovni INFO, triedy zo Springu sme nastavili na DEBUG, špecifickú triedu z Jetty na úroveň WARN
a triedy z nášho projektu budú opäť DEBUG.
Ukážkový log potom vyzerá nasledovne:
11:34:02.721 [main] INFO org.eclipse.jetty.server.Server - jetty-9.0.4.v20130625
11:34:04.304 [main] INFO / - Spring WebApplicationInitializers detected on classpath: [sk.upjs.ics.novotnyr.mjss.WebInitializer@10a488e4]
11:34:04.307 [main] DEBUG s.u.ics.novotnyr.mjss.WebInitializer - No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context
Prvá hláška patrí Jetty, druhá Springu a tretia je z útrob nášho projektu.
Odkazy
- Demo kód na GitHub.com