A Java-alkalmazás sikeréhez elengedhetetlen a hasznos információk kinyerése a naplófájlokból. A naplóadatok értékes betekintést nyújtanak az alkalmazás teljesítményébe, stabilitásába és használhatóságába.
A naplóadatok elemzése fárasztónak tűnhet, de nem kell annak lennie. Számos eszköz áll rendelkezésre a naplóadatok olvasására, elemzésére és konszolidálására. Az olyan alapvető parancssori eszközök, mint a grep, az uniq és a sort kombinálhatják és kivonhatják a hasznos információkat a naplófájlokból. A fejlettebb naplóelemzők, mint például a Logstash vagy a Fluentd, könnyen kereshető tokenekké alakíthatják a naplófájlok kulcsfontosságú adatait. A felhőalapú naplózási szolgáltatások, mint például a SolarWinds® Loggly®, tárolják az Ön számára a naplóadatokat, és kifinomult elemzési lehetőségeket kínálnak, így nem kell saját maga karbantartania a naplókat.
Ez a szakasz néhány módszert és eszközt vizsgál meg a naplók elemzéséhez az alkalmazások javítása céljából.
- A leggyakoribb kivételek megtalálása
- A kivételek típus szerinti keresése a grep használatával
- A kivételek keresése osztályok szerint a grep segítségével
- Naplókezelő megoldás használata
- Termelési problémák hibakeresése
- Információk gyűjtése a problémáról
- A probléma okának azonosítása
- A probléma megoldása és az ismétlődés megakadályozása
- Még több termelési hibakeresési eszköz
- jdb
- OverOps
- BTrace
- Chronon
- jhsdb
- Tranzakciók nyomon követése
- Egyedi azonosítók nyomon követése
- Módszerhívások nyomon követése
- Tracing metódusok a Log4j-ben
- Követési módszerek az SLF4J-ben
- Memóriahasználat kezelése
- Szemétgyűjtés
- Memóriaszivárgás
- Kiegészítő források
- See it. Analyze it. Vizsgáld meg. Oldd meg
A leggyakoribb kivételek megtalálása
A leggyakoribb kivételek megtalálása segíthet a gyenge teljesítményű területek meghatározásában a Java-alkalmazásban. A legtöbb naplózási keretrendszer rögzíti a kivétel típusát, a kivétel üzenetét és azt a metódust, amelyben a kivétel előfordult. A Log4j használatával a kivételek naplója az alábbiak egyikéhez hasonlóan fog kinézni.
09:54:44.565 ERROR Log4jTest.MathClass - java.lang.ArithmeticException: / by zero10:00:10.157 ERROR Log4jTest.Log4jTest - java.io.FileNotFoundException: myFile (No such file or directory)10:00:10.157 ERROR Log4jTest.Log4jTest - java.io.FileNotFoundException: newFile (No such file or directory)
Ha a kimenete stack traces-t is tartalmaz, olvassa el az útmutató Többsoros stack traces elemzése című részét.
Kezdjük egy egyszerű példával a népszerű GNU grep eszközzel. Ezután megmutatjuk, hogy egy naplókezelő eszközzel hogyan lehet ezt még egyszerűbbé tenni.
A kivételek típus szerinti keresése a grep használatával
A következő Unix-parancs megkeresi a kivételeket, kivonja a kivétel típusát, és megszámolja az előfordulások számát. grep egy népszerű parancssori eszköz, amely mintaillesztést végez, míg az uniq és a sort az eredményeket csoportosítja, illetve rendezi:
$ grep -o "\w*Exception" myLog.log | sort -r | uniq -c
Ebben a példában a \w*Exception
szabályos kifejezés minden olyan szóra illik, amely “Exception” végű. A -o
jelző arra utasítja a grep-et, hogy a kimenetnek csak azokat a részeit írja ki, amelyek megfelelnek a keresési karakterláncnak. A sort -r
fordított sorrendbe rendezi az eredményt, míg a uniq -c
csoportosítja az eredményeket és számolja az előfordulások számát. Ennek eredményeként a végén a kivételek típusonkénti megszámlálását kapjuk.
2 FileNotFoundException1 ArithmeticException
A grep segítségével a naplóban is kereshetünk a kivételek minden egyes konkrét példányára.
$ grep ArithmeticException myLog.log09:54:44.565 ERROR Log4jTest.Log4jTest - java.lang.ArithmeticException: / by zero
Ez minden olyan sort visszaad, amely a keresett ArithmeticException
karakterlánc egy példányát tartalmazza, magát a keresett karakterláncot kiemelve a kimeneten.
A kivételek keresése osztályok szerint a grep segítségével
A kivételeket az osztály alapján is kereshetjük, amelyben előfordultak. Egysoros naplóesemények esetén a következő parancs osztály és típus szerint csoportosítja a kivételek számát. grep az osztály nevét úgy nyeri ki, hogy egy szót keres, amelyet egy adott karakter követ (ez a példa kötőjelet használ, bár bármilyen karakter használható, amíg az egyedi a bejegyzéshez). Bár ez a karakter nem lényeges, segít megtalálni az osztály nevét a napló eseményében. A grep a VAGY operátorral (jelölve |) a kivétel nevét is kinyerheti a “Kivétel” karakterláncot tartalmazó szó keresésével.”
sed egy másik parancssori segédprogram, amely a grep kimenetének formázására használható. Ebben a példában a sed eltávolítja a speciális karaktert a kimenetünkből, valamint az új sor karaktereket. A kimenetet ezután átvezetjük az uniq és a sort parancsokhoz az eredmények csoportosításához, illetve rendezéséhez.
$ grep -o "w* -|\w*Exception" myLog.log | sed 'N; s/ -n/ /' | sort -r | uniq -c
Az eredmény közelebb visz minket a legfontosabb problémás területekhez:
2 Log4jTest FileNotFoundException1 MathClass ArithmeticException
Az eredmények segítségével a grep segítségével további részleteket találhatunk az egyes osztályokban előforduló problémákról. A következő parancs például a MathClass
osztályban előforduló kivételeket keresi meg.
$ grep -e "MathClass.*Exception" myLog.log09:54:44.565 ERROR Log4jtest.MathClass - java.lang.ArithmeticException: / by zero
Naplókezelő megoldás használata
A legtöbb naplókezelő megoldás lehetőséget kínál a naplóbejegyzések csoportosítására és keresésére naplótípus, üzenettartalom, osztály, módszer és szál alapján. Ha a naplókat már elemzi és tárolja, sok megoldás képes a kivételek grafikus ábrázolására és rendezésére az előfordulások száma alapján. A Logglyban ez egy pont és kattintás művelet, így nem kell bonyolult grep-parancsokat memorizálnia. A Loggly a naplóbejegyzéseket is indexeli, így a keresés és a számolás sokkal gyorsabb, mint a grep. A mező-kutató segítségével például megtekinthetjük a kivételek listáját és azok gyakoriságát, majd egy kivételre kattintva megtekinthetjük az összes vonatkozó naplójegyzetet.
A Loggly mező-kutatójának használata a naplójegyzetek gyors kereséséhez kivétel típusa szerint.
A Loggly olyan vizualizációs eszközöket is kínál, amelyek informatívabbak lehetnek, mint a grep szövegalapú kimenete. Az ilyen grafikonok segíthetnek a fejlesztési sprintek vagy egy új kiadást követő javítások erőforrásainak rangsorolásában.
A kivételek gyakoriság szerinti ábrázolása a Logglyban.
Termelési problémák hibakeresése
Ha termelési problémákról van szó, az idő a legfontosabb. Egy kritikus hiba az alkalmazásában nem csak a felhasználókat teszi elégedetlenné, hanem csökkenti az eladásokat és az alkalmazásába vagy szolgáltatásába vetett bizalmat is.
A legtöbb esetben a probléma megoldása három kulcsfontosságú lépésre bontható:
- Információk gyűjtése a problémáról
- A probléma okának azonosítása
- Megoldás keresése és a probléma ismétlődésének megakadályozása
Információk gyűjtése a problémáról
Az első lépés a problémával kapcsolatos információk gyűjtése. Gyűjtsön össze minél több információt – képernyőképeket, összeomlási jelentéseket, naplókat, hivatkozásokat (webes szolgáltatások esetén) stb. -, hogy segítsen leszűkíteni a lehetséges okokat. Azt szeretné, ha a problémát tapasztalt felhasználó részletes információkat adna az eseményről, többek között a következőket: mikor és hol történt a probléma a programban, a problémát előidéző műveletei, a működési környezet, valamint a program bármilyen furcsa vagy szokatlan viselkedése a probléma megjelenése előtt és után.
Ezek után elkezdheti a naplóadatok összegyűjtését. Ha az alkalmazás egy hosztolt szolgáltatás, kezdje el a naplók lekérdezését a web- és alkalmazáskiszolgálókról. Ha az alkalmazás egy elosztott szoftvercsomag, kérje meg a felhasználót, hogy csatolja a naplóadatokat a hibajelentéséhez. Alternatív megoldásként, ha az alkalmazása naplóeseményeket küld egy központi naplószerverre, akkor a naplófájlok azonnal rendelkezésre állnak.
Mihelyt ésszerű mennyiségű adattal rendelkezik a problémával kapcsolatban, megkezdheti a probléma kódban történő felkutatását.
A probléma okának azonosítása
A problémával kapcsolatos információk összegyűjtése után a következő lépés a probléma okának azonosítása. A hiba reprodukálása a fejlesztői környezetben az egyik legegyszerűbb módja a hiba létezésének igazolásának, de időigényes lehet, és nem minden esetben működik. Az alapos naplófájlok birtokában egyenesen a probléma forrásához juthat el, időt és frusztrációt spórolva meg.
A hibajelentés általános képet ad arról, hogy mi a probléma és hol lépett fel. A választott naplókezelő eszköz segítségével a keresést a naplóbejegyzések egy kisebb körére szűkítheti egy egyedi adatjegy, például felhasználónév, munkamenetazonosító vagy üzenetszöveg keresésével.
Fussunk végig egy példaforgatókönyvön, hogy bemutassuk, hogyan kell hibakeresést végezni egy rendszerben. Képzeljük el, hogy van egy webes felületünk egy weboldalra való távoli bejelentkezésre. A weboldalon van egy bejelentkezési képernyő, amely egy felhasználónév és jelszó segítségével elvégzi az alapvető hitelesítést. A felhasználók jelezték, hogy nem tudnak bejelentkezni a weboldalra. A weboldal elfogadja a bevitelüket, de aztán egy általános hibaüzenettel meghiúsul.
Egy minta weboldal, amely hibát jelent a bejelentkezési kísérlet után.
Ez az üzenet nem sok információt ad a napló súlyosságának általános jelzésén kívül. Ha a naplókezelőben olyan bejegyzéseket keresünk, amelyeknek a szintje vagy üzenete “Súlyos”, több száz találatot kaphatunk, és nem garantálhatjuk, hogy ezek közül bármelyik is kapcsolódik a szóban forgó problémához. Szerencsére a mi Logger
ünk a hibát észlelő felhasználó felhasználónevét is rögzítette, így az “admin” felhasználónévre szűrhetünk.
A Java kivétel megtekintése a Logglyban.
Ha tovább fúrunk, láthatjuk, hogy a hiba oka egy hiányzó vagy érvénytelen táblázat. Ez komoly probléma, mivel véletlen törlésre vagy adatbázis sérülésre utalhat.
ERROR: Exception for user admincom.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test_schema.users' doesn't exist...com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1651) at TestApplication.Test.doPost(Test.java:33) at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at...
A stack trace-t átnézve látjuk, hogy a szolgáltatás a Test.java 33. sorában sikertelen volt. Ez a sor egy SQL utasításból áll, amely a test_schema.users táblából hívja le egy felhasználó adatait.
rs = stmt.executeQuery("SELECT * FROM test_schema.users WHERE username = " + username + " AND Password = " + password);
Amikor megpróbáljuk futtatni ezt a lekérdezést egy SQL frontendben, azt találjuk, hogy a “test_schema.users” tábla nem létezik. Az adatbázisban azonban van egy “test_schema.user” tábla. Valamikor egy fejlesztő tévedésből rosszul írhatta be a tábla nevét, és a javított űrlapot tolta be a termelésbe. Most már tudjuk, hogy mi a probléma, és hol jelenik meg a kódunkban.
A SolarWinds Loggly használatával hibakeresést végezhet és megtalálhatja a problémák kiváltó okát azáltal, hogy nyomon követi a hibákat az alkalmazás stackjén keresztül, több naplóeseményen keresztül, és még a GitHubban is pontosan meghatározhatja a megfelelő kódsort.
A probléma megoldása és az ismétlődés megakadályozása
Most, hogy azonosítottuk a problémát és annak okát, az utolsó lépés a probléma javítása. A bejelentkezési példánk egy eltúlzott eset volt, viszonylag egyszerű megoldással, de előfordulhat, hogy bonyolultabb, az alkalmazás különböző területein gyökerező hibákkal találkozik. Mielőtt a gyors és piszkos javításra ugranál, gondosan fontold meg, hogy a változtatásod milyen hatással lesz az alkalmazásra. Valóban ez a legjobb megoldás a problémára? Lehetséges, hogy a változtatásod zavarni fog egy másik komponenst? Ez a javítás megnehezíti az új javítások vagy funkciók bevezetését a későbbiekben? Megakadályozza-e ez a javítás azt is, hogy később hasonló problémák merüljenek fel?
Mi van például, ha két különböző felhasználónak sikerült két külön fiókot létrehoznia ugyanazzal a felhasználónévvel és jelszóval? Kényszeríthetne egy egyedi felhasználónevet minden felhasználó számára, de ez hogyan hatna az adatbázis szerkezetére, a hitelesítési kódra és a meglévő felhasználói bázisra? Hozzáadhatna egy új, egyedi mezőt, például egy e-mail címet, és kötelezővé tehetné, de mi van akkor, ha a jelenlegi felhasználók egy része nem adta meg az e-mail címét? Mi van, ha néhány e-mail cím több fiókban is megoszlik? Hogyan hatnak majd ezek az új szabályok a regisztrációs, keresési és adminisztrációs oldalakra?
A javítás létrehozása és telepítése közötti késedelmet is figyelembe kell vennie. Egy vállalati környezetben a kódját más fejlesztőknek is át kell nézniük, be kell építeni a kódbázisba, meg kell építeni, a minőségbiztosításnak tesztelnie kell, be kell állítani, és talán még több lépésen is át kell esnie, mielőtt a gyártásba kerül. Előfordulhat, hogy a vállalatnak speciális protokolljai vannak a kritikus vagy időérzékeny hibákra, amelyeket be kell tartania. Ha megtaláltad a megoldást, vedd fel a dokumentációba a megoldásodat, valamint a probléma ésszerű kerülőútjait. Így ügyfelei továbbra is használhatják a terméket, a támogatási csapat pedig csökkentheti a duplikált hibajelentések számát, amíg a javítás eljut a gyártásig.
A javítás telepítése után folytassa a gyártott alkalmazás felügyeletét, hogy ellenőrizze a probléma megoldását. Például a fenti példában szereplő adatbázis-probléma javításának telepítése után nem szabad többé “A ‘test_schema.users’ tábla nem létezik” típusú eseményeket látni. Ha a hibák továbbra is fennállnak, vagy ha új hibákat kezdünk látni, akkor tudjuk, hogy a javítás nem működött. Ideális esetben a következő képernyőképen látható mintát látjuk, ahol a hibák száma a javítás telepítése után azonnal nullára csökken.
A hibát tartalmazó naplók számának grafikonja a Logglyban.
Még több termelési hibakeresési eszköz
Míg a naplózás az alkalmazások hibaelhárításának és hibakeresésének bevált módszere, ezek az eszközök segíthetnek nagyobb betekintést nyerni az alkalmazás működésébe.
jdb
A jdb, a Java Debugger egy parancssori segédprogram a Java osztályok hibakereséséhez. jdb könnyen használható, és a Java Development Kithez mellékelve van. A jdb használata új Java virtuális gépet (JVM) hoz létre, amely lehetővé teszi egy osztály hibakeresését anélkül, hogy befolyásolná a futó programokat. A jdb-t a futó alkalmazások hibakeresésére is használhatja, ha a következő paramétereket adja hozzá a java parancshoz:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n
A JVM indításakor hozzárendel egy portszámot a bejövő jdb-kapcsolatokhoz. Ezután a jdb -attach:
$ jdb -attach
segítségével csatlakozhat a futó JVM-példányhoz. Ezt használhatja például arra, hogy a hibakeresőjét egy futó termelési példányhoz csatlakoztassa. Legyen óvatos a töréspontok használatával ebben a forgatókönyvben, mivel ez megállíthat egy aktív szálat. Ennek következményei lehetnek, ha például egy ügyfél használja az alkalmazást, miközben Ön hibakeresést végez. További információkat a Java dokumentációban talál a jdb-ről.
OverOps
AzOverOps egy eszközkészlet az alkalmazások felügyeletére, a kód elemzésére és a problémák felderítésére. A naplózó szoftverekkel ellentétben, amelyek a futó alkalmazás által generált kimenetekre támaszkodnak, az OverOps közvetlenül a Java Virtual Machine-hez csatlakozik, hogy feltérképezze az alkalmazás kódbázisát, kiolvassa a változókat és rögzítse a hibákat. Ez lehetővé teszi, hogy több hibát észleljen és több adatot rögzítsen, mint akár az alkalmazás naplózási keretrendszere. Az OverOps egy SaaS (Software as a Service) modellt használ, ahol a metrikákat az OverOps felhőszervereken gyűjtik és tárolják. Azonban helyben is telepíthető. Az adatokat mindkét esetben egy webes felület segítségével tekintheti meg.
BTrace
A BTrace egy olyan nyomkövető eszköz, amellyel az alkalmazás minden aspektusát nyomon követheti, az osztálynevektől a hibákig. A BTrace aspektusorientált programozási megközelítést használ, amely magában foglalja a megjegyzések használatát, amelyek meghatározzák, hogy a BTrace hol és hogyan figyeli az alkalmazást. A következő BTrace szkript például a javax.swing
csomag minden egyes hívását figyeli és naplózza.
import com.sun.btrace.annotations.*;import static com.sun.btrace.BTraceUtils.*; @BTrace public class AllMethods { @OnMethod( clazz="/javax\.swing\..*/", method="/.*/" ) public static void m(@ProbeClassName String probeClass, @ProbeMethodName String probeMethod) { print(Strings.strcat("entered ", probeClass)); println(Strings.strcat(".", probeMethod)); }}
A BTrace-ről további információkat a BTrace GitHub tárolóban és a Wikiben talál.
Chronon
A kronon lehetővé teszi az alkalmazás teljes végrehajtási folyamatának visszatekerését és lejátszását. Az alkalmazás élettartama alatt végrehajtott minden egyes módosítást rögzít, így bármikor reprodukálhatja az alkalmazás adott időpontban fennálló állapotát. A felvételek fájlba menthetők, így a végrehajtás előzményei könnyen átvihetők egy termelő gépről egy fejlesztő gépre tesztelés céljából.
A Chrononon a következőkből áll: a Chronon Recording Server, amellyel távolról rögzíthet Java-alkalmazásokat; a Embedded Chronon, amely beágyazza a felvevőt egy alkalmazásba; és az Time Travelling Debugger, amellyel a felvételek visszajátszhatók.
jhsdb
jhsdb (Java HotSpot Debugger) egy eszközkészlet az OpenJDK és az Oracle JDK által biztosított alapértelmezett JVM hibakeresésére, elemzésére és profilozására. A jhsdb segítségével csatlakozhat a futó Java-folyamatokhoz, pillanatképeket készíthet a stack tracesről, és még a lezuhant JVM-eket is elemezheti. Segítségével hozzáférhet a halomhoz, a kódcache-hez, a szemétgyűjtési statisztikákhoz és még sok máshoz. Ha többet szeretne megtudni, tekintse meg a jhsdb dokumentációs oldalát.
Tranzakciók nyomon követése
Ha probléma merül fel, fontos tudni, honnan indult a probléma, és hogyan hatott az alkalmazás többi részére. Ez elég nehéz egy monolitikus alkalmazásban, de még nehezebbé válik egy elosztott szolgáltatásorientált architektúrában, ahol egyetlen kérés több tucatnyi szolgáltatást érinthet. Nem mindig nyilvánvaló, hogy melyik szolgáltatás tartalmazza a hiba kiváltó okát, vagy hogy az hogyan hatott a többi szolgáltatásra. A nyomon követés biztosítja a szükséges adatokat ahhoz, hogy követni lehessen az alkalmazás végrehajtási útvonalát, és le lehessen fúrni a probléma pontos okát.
Az útmutató Gyártási problémák hibakeresése című fejezetben végigvettünk egy példát, ahol egy felhasználónak nehézségei voltak egy webes alkalmazásba való bejelentkezéssel egy érvénytelen adatbázis-tábla miatt. Ebben a szakaszban bemutatjuk, hogy a tranzakciók nyomon követése hogyan játszott központi szerepet a probléma megoldásában.
Egyedi azonosítók nyomon követése
A naplóesemények sorozatának nyomon követéséhez valamilyen módon egyedileg azonosítani kell a kapcsolódó naplókat. Egy többfelhasználós környezet több száz azonos naplót generálhat, ami megnehezíti az időbélyeg vagy Logger
időbélyeg alapján történő keresést. Egyszerűbb megoldás, ha a kapcsolódó naplóbejegyzésekhez egyedi azonosítót csatolunk. Ez az azonosító lehet egy felhasználónév, egy munkamenet-azonosító, egy API-kulcs vagy egy univerzálisan egyedi azonosító (UUID). Szerencsére a ThreadContext tökéletesen alkalmas erre a feladatra.
A Gyártási problémák hibakeresése példában volt egy webalapú felhasználói felületünk, amelyet egy Tomcat szervletben tároltunk, és amely egy MySQL-adatbázishoz csatlakozott. A felhasználók megadták hitelesítő adataikat a weboldalon, majd a submit gomb megnyomása után a szervlet lefuttatott egy lekérdezést, amely összehasonlította a hitelesítő adataikat az adatbázisban tárolt adatokkal. Ha a felhasználó sikeresen hitelesített, akkor a főoldalra lett átirányítva. Ha hiba lépett fel, a hiba részletei naplózásra kerültek, és a felhasználók egy általános üzenetet kaptak.
Ezt a problémát úgy tudtuk elhárítani, hogy a naplóüzenetben szerepeltettük a felhasználók felhasználónevét. Ez lehetővé tette számunkra az admin felhasználóhoz kapcsolódó naplóesemények gyors keresését. Ugyanebből a példából kiindulva használhatjuk a ThreadContext.put()
-t egy felhasználónév Logger
-hez való hozzárendelésére. Amikor a felhasználók elküldik a hitelesítő adatokat, a szervlet belép a doPost()
metódusba, amely hozzáadja a felhasználók felhasználónevét a ThreadContexthez:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {ThreadContext.put("username", request.getParameter("username"));logger.info("Entering doPost().");...}
A Log4j %p : %m%n
mintával történő használata a következő bejegyzést eredményezi:
INFO : Entering doPost().
A MySQL adatbázis eléréséhez, a doPost metódus elhagyásához és más műveletek végrehajtásához hasonló eseményeket adhatunk hozzá. Így, ha a felhasználó kivételt vált ki, pontosan tudjuk, hogy mit csinált a felhasználó, amikor a kivétel bekövetkezett.
Módszerhívások nyomon követése
Sok naplózási keretrendszer kínál natív módszereket az alkalmazás végrehajtási útvonalának nyomon követésére. Ezek a módszerek keretrendszerenként kissé eltérnek, de ugyanazt az általános formátumot követik.
-
traceEntry()
egy metódus kezdetét jelöli. -
traceExit()
egy metódus végét jelöli. Az objektumot visszaadó metódusok esetében azreturn logger.exit(object)
segítségével egyszerre adhatja vissza az objektumot és naplózhatja az eseményt. -
throwing()
olyan kivételt jelöl, amelyet nem valószínű, hogy kezelni fognak, példáulRuntimeException
. -
catching()
olyan kivételt jelöl, amelyet nem fognak újra eldobni.
Ezekkel a metódusokkal kapcsolatos keretrendszer-specifikus információkat a Log4j, Logback és java.util.logging
Logger dokumentációjában talál.
Tracing metódusok a Log4j-ben
A Log4j használatának példájaként a szervletünkben lévő Logger.info() metódusokat tracing metódusokkal helyettesítjük.
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { logger.entry(); ... logger.exit();}
Az Appender's PatternLayout
-t is megváltoztatjuk, hogy megjelenjen az osztály neve, a metódus és a sorszám (a %class
, %M
és %line
konverziós minták).
<PatternLayout pattern="%p %class %M %line: %m%n" />
A nyomkövetési metódusok az TRACE
szinten naplózzák az eseményeket, ami azt jelenti, hogy a Logger's
szintet DEBUG
-ről TRACE
-re kell változtatnunk. Ellenkező esetben a naplóüzenetek el lesznek nyomva.
<Loggers> <Root level="trace"> <AppenderRef ref="Console"/> </Root></Loggers> TRACE DatabaseApplication.Login doPost 26: entry...TRACE DatabaseApplication.Login doPost 59: exit
A nyomkövetési módszerek saját Markers
-t is biztosítanak. Például a Logger.entry()
és a Logger.exit()
módszerek ENTER
, illetve EXIT
értékeket jelenítenek meg.
ENTER 14:47:41.074 TRACE DatabaseApplication.Login - EnterEXIT 14:47:41.251 TRACE DatabaseApplication.Login - Exit
Követési módszerek az SLF4J-ben
Az SLF4J felhasználók kihasználhatják az MDC előnyeit a naplóesemények követésére. A Log4j-hez hasonlóan az MDC-értékek a %X konverziós minta használatával használhatók egy Appenderrel.
Az SLF4J a XLogger
(Extended Logger) osztályon keresztül entry()
, exit()
, throwing()
és catching()
módszereket is biztosít. Egy XLogger
példányt a XLoggerFactory.getXLogger()
segítségével hozhatunk létre.
package DatabaseApplication;import org.slf4j.Logger;import org.slf4j.LoggerFactory; import org.slf4j.ext.XLogger;import org.slf4j.ext.XLoggerFactory; public class Login extends HTTPServlet { final static XLogger xlogger = XLoggerFactory.getXLogger(Login.class.getName()); final static Logger logger = LoggerFactory.getLogger(Login.class.getName()); @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { xlogger.entry(); .. xlogger.exit(); }}
Adjuk hozzá a %class és %line konverziós mintákat a logback.xml fájlhoz.
<configuration> <appender name="Console" class="ch.qos.Logback.core.ConsoleAppender"> <encoder> <pattern>%-5level %class{36} %M %L: %msg%xEx%n</pattern> </encoder> </appender> <root level="trace"> ... </root></configuration>
A kapott naplóbejegyzések megegyeznek a Log4j által létrehozottakkal.
Memóriahasználat kezelése
A memóriakezelést gyakran figyelmen kívül hagyják az olyan magasabb szintű nyelvekben, mint a Java. Bár a modern eszközök átlagos memóriamennyisége növekszik, a magas memóriahasználat nagy hatással lehet az alkalmazás stabilitására és teljesítményére. Amint a Java virtuális gép nem tud többé memóriát allokálni az operációs rendszerből, a programja leállhat és összeomolhat. Ha tudjuk, hogyan kezeljük a memóriát, megelőzhetjük a problémákat, amikor az alkalmazásunk mérete növekszik.
Képzeljük el például, hogy egytől kezdődően egy számhalmazt szeretnénk tárolni. A felhasználó megad egy felső határt, és a program minden egyes egész számot “1”-től a határig tárol. Egy számlálóval ellátott while ciklus segítségével minden egyes számot egy tömbhöz adunk hozzá.
import java.util.Scanner;...System.out.print("Please enter the maximum size of the array: ");Scanner scanner = new Scanner(System.in);int limit = scanner.nextInt(); ArrayList intArray = new ArrayList(); int count = 1;while (count <= limit) { intArray.add(count);}
Észrevehetted, hogy a count
nem növekszik a ciklusban. Ez nagy probléma; ha a felhasználó nullánál nagyobb számot ad meg, a tömb addig fog nőni, amíg a JVM el nem használja az összes rendelkezésre álló memóriát, és a program összeomlik.
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:2245)at java.util.Arrays.copyOf(Arrays.java:2219)at java.util.ArrayList.grow(ArrayList.java:242)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)at java.util.ArrayList.add(ArrayList.java:440)at MemoryTest.main(MemoryTest.java:10)
Szemétgyűjtés
A memóriahasználat csökkentése érdekében a Java Virtual Machine egy periodikus tisztítási folyamatot hajt végre, amelyet szemétgyűjtésnek nevezünk. A szemétgyűjtés megkeresi a már nem használt memóriablokkokat, és újrafelhasználhatóvá teszi őket. A következő források részletesebben ismertetik a Java szemétgyűjtési folyamatát.
- Java Garbage Collection Basics (Oracle)
- HotSpot Virtual Machine Garbage Collection Tuning Guide (Oracle)
- Understanding G1 GC Logs (Poonam Bajaj)
- Garbage Collection Tuning Guide (Atlassian)
A szemétgyűjtő diagnosztikai információkat generál, amelyek hasznosak lehetnek az alkalmazások teljesítményprofilozásához. Ezeket az információkat az alkalmazás indításakor a -Xlog:gc átadásával naplózhatja a JVM-nek. A szemétgyűjtő minden futtatás után az Unified JVM Logging formátumban statisztikákat nyomtat ki a szemétgyűjtési folyamatról. Íme egy példa:
Using G1 Periodic GC disabled GC(0) Pause Young (Normal) (G1 Evacuation Pause) 7M->1M(64M) 8.450ms
Using G1
megadja, hogy melyik szemétgyűjtési módszer van használatban. A Garbage-First (G1) gyűjtő gyakran alapértelmezés szerint engedélyezett a nagy mennyiségű RAM-mal rendelkező többprocesszoros számítógépeken. Periodic GC disabled
azt jelzi, hogy a szemétgyűjtési folyamat nem ismétlődik. A harmadik sor arról árulkodik, hogy ez egy evakuálási szünet, amikor az objektumok a memóriarégiók között aszerint másolódnak, hogy használatban vannak-e még. Pause Young
azt mondja nekünk, hogy a folyamat megtisztította a fiatal generációt, ahol az új objektumok kiosztásra kerülnek. Ennek eredményeképpen a fiatal generációban lévő objektumok teljes memóriahasználata 7M-ről 1M-re csökkent a kiosztott 64M-ból, és a folyamat 8.450ms
.
Mivel a szemétgyűjtő diagnosztikai információkat nyomtat a konzolra, láthatjuk, hogy a kiosztott memória mennyisége (a heap mérete) idővel tovább nő. Az egyszerűség kedvéért eltávolítjuk a CPU-időket.
$ java -Xlog:gc MemoryLeakDemo Using G1 Periodic GC disabled GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation) 25M->23M(64M) 4.372ms GC(1) Concurrent Cycle GC(1) Pause Remark 50M->34M(64M) 0.250ms GC(1) Pause Cleanup 94M->94M(124M) 0.057ms GC(1) Concurrent Cycle 169.695ms GC(2) Pause Young (Concurrent Start) (G1 Humongous Allocation) 94M->94M(124M) 3.738ms GC(3) Concurrent Cycle...
A JVM halomhasználatának fokozatos növekedését bemutató grafikon az idő múlásával.
Az egyes bejegyzésekhez -XX:+PrintGCDateStamps
és -XX:+PrintGCTimeStamps
időbélyegzőket adhatunk. A szemétgyűjtő kimenetét egy fájlba is naplózhatja, ha az alkalmazás indításakor átadja a JVM-nek az-Xlog:gc:file
: -t.
Ha a naplófájljait az rsyslog segítségével figyeli, akkor a naplókat továbbíthatja egy központi naplózási rendszerbe, ahol azok elemezve, közel valós idejű elemzésre készen állnak. Így néz ki egy idővonal grafikon a Logglyban. A teljes halomméretet, valamint a halomméretet mutatja a szemétgyűjtő futtatása előtt és után.
Memóriaszivárgás
A memóriaszivárgás olyan helyzet, amikor egy program gyorsabban rendel ki memóriát, mint ahogyan azt fel tudja szabadítani. A memóriaszivárgás legkönnyebben akkor észlelhető, ha a program nem reagál, instabillá válik, vagy OutOfMemoryErrors
okoz. A Java-ban a memóriahasználat növekedésével egyre több Full GC
gyűjtőpéldányt találunk.
A szemétgyűjtő kimenetéről és a memóriaszivárgások behatárolásáról többet megtudhat a Java dokumentáció Hibaelhárítás memóriaszivárgás fejezetében.
Kiegészítő források
Cut Debugging Time Without Writing a Single Line of Code (Loggly)-Guide to using Takipi
The Ultimate Guide: 5 Methods for Debugging Production Servers at Scale (High Scalability)-eszközök és technikák a termelési problémák hibakereséséhez
Memóriakezelés
Garbage Collection Tuning Guide (Oracle)-Útmutató a Java szemétgyűjtésének megértéséhez és finomhangolásához
Understanding Java Garbage Collection (CUBRID Blog)-Útmutató a garb
See it. Analyze it. Vizsgáld meg. Oldd meg
Lásd meg, ami számít.
START FREE TRIAL