Extragerea de informații utile din fișierele de log este esențială pentru succesul aplicației dumneavoastră Java. Datele de jurnal vă vor oferi informații valoroase despre performanța, stabilitatea și capacitatea de utilizare a aplicației dumneavoastră.

Analiza datelor de jurnal poate părea plictisitoare, dar nu trebuie să fie. Există o varietate de instrumente pentru citirea, analizarea și consolidarea datelor de jurnal. Instrumentele de bază din linia de comandă, cum ar fi grep, uniq și sort, pot combina și extrage informații utile din fișierele jurnal. Analizatori de jurnale mai avansați, cum ar fi Logstash sau Fluentd, pot extrage date cheie din jurnalele dvs. în token-uri ușor de căutat. Serviciile de logare bazate pe cloud, cum ar fi SolarWinds® Loggly®, stochează pentru dumneavoastră datele de logare și oferă capabilități sofisticate de analiză, eliminând necesitatea de a întreține jurnalele dumneavoastră.

Această secțiune explorează câteva metode și instrumente de analiză a jurnalelor cu scopul de a vă îmbunătăți aplicațiile.

Descoperirea celor mai frecvente excepții

Descoperirea celor mai frecvente excepții vă poate ajuta să identificați zonele cu performanțe slabe din aplicația dumneavoastră Java. Majoritatea cadrelor de logare înregistrează tipul de excepție, mesajul de excepție și metoda în care a apărut excepția. Utilizând Log4j, un jurnal de excepții va arăta asemănător cu unul dintre următoarele.

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)

Dacă ieșirea dvs. include urme de stivă, consultați secțiunea Parsarea urmelor de stivă cu mai multe linii din acest ghid.

Să începem cu un exemplu simplu, utilizând popularul instrument GNU grep. Apoi, vom arăta cum un instrument de gestionare a jurnalelor poate face acest lucru și mai ușor.

Căutarea excepțiilor în funcție de tip folosind Grep

Cuprinsa comandă Unix următoare va găsi excepții, va extrage tipul de excepție și va număra numărul de apariții. grep este un instrument popular de linie de comandă care efectuează potrivirea tiparelor, în timp ce uniq și sort grupează și, respectiv, sortează rezultatele:

$ grep -o "\w*Exception" myLog.log | sort -r | uniq -c

În acest exemplu, expresia regulată \w*Exception se potrivește cu orice cuvânt care se termină cu „Exception”. Semnalizatorul -o îi spune lui grep să tipărească numai părțile din rezultat care se potrivesc cu șirul de căutare. sort -r sortează rezultatul în ordine inversă, în timp ce uniq -c grupează rezultatele și numără numărul de apariții. Ca rezultat, ajungem la o numărătoare a excepțiilor în funcție de tip.

2 FileNotFoundException1 ArithmeticException

De asemenea, putem folosi grep pentru a căuta în jurnal fiecare instanță specifică a acestor excepții.

$ grep ArithmeticException myLog.log09:54:44.565 ERROR Log4jTest.Log4jTest - java.lang.ArithmeticException: / by zero

Aceasta returnează fiecare linie care conține o instanță a șirului de căutare ArithmeticException, cu șirul de căutare însuși evidențiat în ieșire.

Căutarea excepțiilor în funcție de clasă folosind Grep

De asemenea, puteți căuta excepțiile în funcție de clasa în care au apărut. Pentru evenimentele de jurnal pe o singură linie, următoarea comandă grupează numărul de excepții în funcție de clasă și de tip. grep extrage numele clasei prin căutarea unui cuvânt urmat de un anumit caracter (în acest exemplu se folosește o cratimă, deși se poate folosi orice caracter atâta timp cât este unic pentru intrare). Deși acest caracter nu este esențial, el ne ajută să localizăm numele clasei în evenimentul din jurnal. Cu ajutorul operatorului OR (notat cu |), grep va extrage, de asemenea, numele excepției prin căutarea unui cuvânt care conține șirul „Exception.”

sed este un alt utilitar de linie de comandă care poate fi utilizat pentru a formata ieșirea din grep. În acest exemplu, sed elimină caracterul special din ieșirea noastră, precum și orice caracter de linie nouă. Ieșirea este apoi dirijată către comenzile uniq și sort pentru a grupa și, respectiv, sorta rezultatele.

$ grep -o "w* -|\w*Exception" myLog.log | sed 'N; s/ -n/ /' | sort -r | uniq -c

Rezultatul ne aduce mai aproape de zonele cu probleme cheie:

2 Log4jTest FileNotFoundException1 MathClass ArithmeticException

Cu aceste rezultate, putem folosi grep pentru a găsi mai multe detalii despre problemele care apar în clase specifice. De exemplu, următoarea comandă regăsește excepțiile care au avut loc în clasa MathClass.

$ grep -e "MathClass.*Exception" myLog.log09:54:44.565 ERROR Log4jtest.MathClass - java.lang.ArithmeticException: / by zero

Utilizarea unei soluții de gestionare a jurnalelor

Majoritatea soluțiilor de gestionare a jurnalelor oferă modalități de grupare și căutare a intrărilor din jurnale pe baza tipului de jurnal, conținutului mesajului, clasei, metodei și firului. În cazul în care jurnalele dvs. sunt deja analizate și stocate, multe soluții pot reprezenta grafic și sorta excepțiile în funcție de numărul de apariții. Aceasta este o operațiune de tip „point and click” în Loggly, astfel încât nu trebuie să memorați comenzi grep complicate. Loggly indexează, de asemenea, înregistrările din jurnal, făcând căutările și numărătorile mult mai rapide decât grep. De exemplu, putem folosi exploratorul de câmpuri pentru a vedea o listă de excepții și frecvența acestora, apoi să facem clic pe o excepție pentru a vizualiza toate jurnalele relevante.

Utilizarea exploratorului de câmpuri Loggly pentru a găsi rapid jurnalele după tipul de excepție.

Loggly oferă, de asemenea, instrumente de vizualizare care pot fi mai informative decât ieșirea bazată pe text din grep. Graficele de acest tip vă pot ajuta să prioritizați resursele pentru sprinturile de dezvoltare sau pentru patch-uri în urma unei noi versiuni.

Cartografierea excepțiilor în funcție de frecvență în Loggly.

Depanarea problemelor de producție

Când vine vorba de probleme de producție, timpul este esențial. O eroare critică în aplicația dvs. nu doar că îi va lăsa nemulțumiți pe utilizatorii dvs.; de asemenea, va scădea vânzările și va reduce încrederea în aplicația sau serviciul dvs.

În cele mai multe cazuri, rezolvarea unei probleme poate fi împărțită în trei pași cheie:

  1. Colectați informații despre problemă
  2. Identificați cauza problemei
  3. Găsește o soluție și previne reapariția problemei

Colectați informații despre problemă

Primul pas este să colectați informații despre problemă. Adunați cât mai multe informații posibile – capturi de ecran, rapoarte de accident, jurnale, linkuri (pentru servicii web) etc. – pentru a ajuta la restrângerea cauzelor potențiale. Veți dori ca utilizatorul care a întâmpinat problema să furnizeze informații detaliate despre eveniment, inclusiv: când și unde în program a apărut problema, acțiunile sale care au condus la problemă, mediul de operare și orice comportament ciudat sau neobișnuit al programului înainte și după apariția problemei.

De aici, puteți începe să colectați informații din jurnal. Dacă aplicația dvs. este un serviciu găzduit, începeți să preluați jurnalele de la serverele web și de aplicație. Dacă aplicația dvs. este un pachet software distribuit, cereți utilizatorului să includă datele din jurnal în raportul său de eroare. Alternativ, dacă aplicația dvs. trimite evenimente de jurnal către un server de jurnal centralizat, atunci jurnalele dvs. vor fi disponibile imediat.

După ce aveți o cantitate rezonabilă de date referitoare la problemă, puteți începe să o urmăriți în cod.

Identificați cauza problemei

După ce ați colectat informații despre problemă, următorul pas este să identificați cauza acesteia. Reproducerea unei erori într-un mediu de dezvoltare este una dintre cele mai simple modalități de validare a existenței acesteia, dar poate consuma mult timp și este posibil să nu funcționeze în toate cazurile. Având un set complet de jurnale vă va duce direct la sursa problemei, economisind timp și frustrare.

Un raport de eroare vă va oferi o idee generală despre ce este problema și unde a apărut. Folosind instrumentul de gestionare a jurnalelor ales, puteți restrânge căutarea la o gamă mai mică de intrări de jurnal prin căutarea unui simbol de date unic, cum ar fi un nume de utilizator, ID-ul sesiunii sau textul mesajului.

Să parcurgem un scenariu de exemplu pentru a demonstra cum să depanăm un sistem. Imaginați-vă că avem o interfață bazată pe web pentru conectarea de la distanță la un site web. Pagina web are un ecran de conectare care realizează autentificarea de bază folosind un nume de utilizator și o parolă. Utilizatorii au raportat că nu se pot conecta la site-ul web. Pagina web acceptă datele de intrare ale acestora, dar apoi eșuează cu o eroare generică.

Un exemplu de site web care raportează o eroare după o încercare de autentificare.

Acest mesaj nu ne oferă prea multe informații în afară de o indicație generică a severității jurnalului. Căutarea într-un manager de jurnale a intrărilor cu „Severe” în nivel sau mesaj ar putea avea ca rezultat sute de rezultate, fără nicio garanție că vreuna dintre ele are legătură cu problema în cauză. Din fericire, Logger nostru a înregistrat, de asemenea, numele de utilizator al utilizatorului care a experimentat eroarea, astfel încât putem filtra pe numele de utilizator „admin”.

Vizualizarea unei excepții Java în Loggly.

Dacă facem drill down, vedem că cauza erorii este un tabel lipsă sau invalid. Aceasta este o problemă serioasă, deoarece ar putea indica o ștergere accidentală sau o corupție a bazei de date.

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...

Urmărind prin urmărirea stivei, vedem că serviciul a eșuat la linia 33 din Test.java. Această linie constă într-o instrucțiune SQL care extrage date despre un utilizator din tabelul test_schema.users.

rs = stmt.executeQuery("SELECT * FROM test_schema.users WHERE username = " + username + " AND Password = " + password);

Când încercăm să executăm această interogare într-un front-end SQL, constatăm că tabelul „test_schema.users” nu există. Cu toate acestea, baza de date are o tabelă „test_schema.user”. La un moment dat, este posibil ca un dezvoltator să fi tastat din greșeală un nume de tabel greșit și să fi introdus formularul revizuit în producție. Acum știm care este problema și unde apare în codul nostru.

Utilizând SolarWinds Loggly, puteți depana și găsi cauza principală a problemelor prin urmărirea erorilor prin stiva de aplicații, prin mai multe evenimente de jurnal și chiar prin identificarea liniei de cod relevante în GitHub.

Rezolvați problema și împiedicați-o să se repete

Acum că am identificat problema și cauza ei, ultimul pas este să o rezolvăm. Exemplul nostru de conectare a fost un caz exagerat cu o soluție relativ ușoară, dar este posibil să întâlniți erori mai complicate care își au rădăcinile în diferite zone ale aplicației dumneavoastră. Înainte de a sări la o rezolvare rapidă și murdară, analizați cu atenție modul în care modificarea dvs. va avea impact asupra aplicației. Este aceasta cu adevărat cea mai bună soluție pentru această problemă? Este posibil ca modificarea dumneavoastră să interfereze cu o altă componentă? Această remediere va îngreuna introducerea de noi remedieri sau caracteristici în viitor? De asemenea, această remediere va împiedica apariția unor probleme similare mai târziu?

De exemplu, ce se întâmplă dacă doi utilizatori diferiți au reușit să creeze două conturi separate cu același nume de utilizator și aceeași parolă? Ați putea impune un nume de utilizator unic pentru toți utilizatorii, dar cum ar afecta asta structura bazei dvs. de date, codul de autentificare și baza dvs. de utilizatori existentă? Ați putea adăuga un nou câmp unic, cum ar fi o adresă de e-mail, și l-ați putea face obligatoriu, dar ce se întâmplă dacă unii dintre utilizatorii actuali nu au furnizat adrese de e-mail? Ce se întâmplă dacă unele adrese de e-mail sunt partajate pe mai multe conturi? Cum vor afecta aceste noi reguli paginile dvs. de înregistrare, de căutare și de administrare?

Voi dori, de asemenea, să luați în considerare intervalul de timp dintre crearea unei soluții și implementarea acesteia. Într-un mediu de întreprindere, codul dvs. va trebui să fie revizuit de alți dezvoltatori, integrat în baza de cod, construit, testat de QA, etapizat și poate trece prin mai multe etape înainte de a ajunge în producție. Este posibil ca întreprinderea dvs. să aibă protocoale specifice pentru bug-uri critice sau sensibile la timp pe care trebuie să le urmați. Odată ce ați găsit o soluție, includeți rezoluția în documentația dvs., precum și orice soluție rezonabilă pentru rezolvarea problemei. În acest fel, clienții dvs. pot utiliza în continuare produsul dvs., iar echipa dvs. de asistență poate reduce numărul de rapoarte de erori duplicate în timp ce soluția își croiește drum spre producție.

După implementarea soluției, continuați să monitorizați aplicația de producție pentru a verifica dacă problema a fost rezolvată. De exemplu, după implementarea remedierii pentru problema bazei de date din exemplul de mai sus, nu ar trebui să mai vedem evenimente cu „Tabelul ‘test_schema.users’ nu există”. Dacă erorile continuă sau dacă începem să vedem erori noi, știm că remedierea nu a funcționat. În mod ideal, vom vedea un tipar precum cel prezentat în următoarea captură de ecran, în care numărul de erori scade la zero imediat după ce am implementat patch-ul.

Charta numărului de jurnale care conțin o eroare în Loggly.

Mai multe instrumente de depanare a producției

În timp ce logarea este metoda încercată și adevărată de depanare și depanare a aplicațiilor, aceste instrumente vă pot ajuta să obțineți mai multe informații despre modul în care funcționează aplicația dumneavoastră.

jdb

jdb, Java Debugger, este un utilitar de linie de comandă pentru depanarea claselor Java. jdb este ușor de utilizat și este livrat împreună cu kitul de dezvoltare Java. Utilizarea jdb creează o nouă mașină virtuală Java (JVM), permițându-vă să depanați o clasă fără a afecta niciun program în curs de execuție. De asemenea, puteți utiliza jdb pentru depanarea aplicațiilor în curs de execuție adăugând următorii parametri la comanda java:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n

Când JVM-ul pornește, acesta atribuie un număr de port pentru conexiunile jdb primite. Puteți apoi să vă conectați la instanța JVM în curs de execuție folosind jdb -attach:

$ jdb -attach

Puteți folosi acest lucru, de exemplu, pentru a vă conecta depanatorul la o instanță de producție în curs de execuție. Aveți grijă la utilizarea punctelor de întrerupere în acest scenariu, deoarece ar putea întrerupe un fir activ. Acest lucru poate avea consecințe dacă, de exemplu, un client utilizează aplicația în timp ce o depanați. Pentru mai multe informații, consultați documentația Java despre jdb.

OverOps

OverOps este o suită de instrumente pentru monitorizarea aplicațiilor, analiza codului și detectarea problemelor. Spre deosebire de software-ul de logare, care se bazează pe ieșirea generată de o aplicație în execuție, OverOps se conectează direct la mașina virtuală Java pentru a cartografia baza de cod a aplicației, a citi variabilele și a înregistra erorile. Acest lucru îi permite să detecteze mai multe erori și să înregistreze mai multe date decât chiar și cadrul de logare al aplicației. OverOps utilizează un model de software ca serviciu (SaaS), în care metricile sunt colectate și stocate pe serverele cloud ale OverOps. Cu toate acestea, îl puteți implementa, de asemenea, la sediu. În ambele cazuri, puteți vizualiza datele utilizând o interfață bazată pe web.

BTrace

BTrace este un instrument de urmărire care vă permite să monitorizați toate aspectele aplicației dumneavoastră, de la numele claselor la erori. BTrace utilizează o abordare de programare orientată pe aspecte care implică utilizarea adnotărilor, care specifică unde și cum BTrace monitorizează aplicația dumneavoastră. De exemplu, următorul script BTrace monitorizează și înregistrează fiecare apel la pachetul javax.swing.

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)); }}

Pentru mai multe informații despre BTrace, consultați depozitul BTrace GitHub și Wiki.

Chronon

Chronon vă permite să derulați înapoi și să redați întregul flux de execuție al unei aplicații. Înregistrează fiecare modificare individuală efectuată pe durata de viață a unei aplicații, permițându-vă să reproduceți starea aplicației la un moment dat. Înregistrările sunt salvate în fișiere, ceea ce facilitează transferul istoricului execuției de pe o mașină de producție pe o mașină de dezvoltare pentru testare.

Chrononon este format din Chronon Recording Server, care vă permite să înregistrați aplicații Java de la distanță; Embedded Chronon, care încorporează înregistratorul în interiorul unei aplicații; și Time Travelling Debugger, care vă permite să redați înregistrările.

jhsdb

jhsdb (Java HotSpot Debugger) este o suită de instrumente pentru depanarea, analiza și profilarea JVM-ului implicit furnizat atât cu OpenJDK, cât și cu Oracle JDK. jhsdb vă permite să vă atașați la procesele Java în curs de execuție, să realizați instantanee ale urmelor de stivă și chiar să analizați JVM-urile care s-au prăbușit. Îl puteți utiliza pentru a accesa heap, memoria cache de cod, statisticile de colectare a gunoiului și multe altele. Pentru a afla mai multe, consultați pagina de documentație jhsdb.

Tractarea tranzacțiilor

Când apare o problemă, este important să știți de unde a pornit problema și cum a afectat restul aplicației dumneavoastră. Acest lucru este destul de dificil într-o aplicație monolitică, dar devine și mai dificil într-o arhitectură orientată pe servicii distribuite, unde o singură cerere poate afecta zeci de servicii. Nu este întotdeauna evident care serviciu conține cauza principală a erorii sau cum a afectat alte servicii. Urmărirea oferă datele necesare pentru a urmări calea de execuție a aplicației dvs. și pentru a detalia cauza exactă a unei probleme.

În secțiunea Depanarea problemelor de producție a ghidului, am parcurs un exemplu în care un utilizator întâmpina dificultăți la logarea într-o aplicație web din cauza unui tabel de bază de date invalid. În această secțiune, vom arăta modul în care urmărirea tranzacțiilor a jucat un rol central în rezolvarea problemei.

Tractarea ID-urilor unice

Pentru a urmări o secvență de evenimente de jurnal, aveți nevoie de o modalitate de a identifica în mod unic jurnalele aferente. Un mediu cu mai mulți utilizatori ar putea genera sute de jurnale identice, ceea ce îngreunează căutarea pe baza mărcii temporale sau Logger. O soluție mai ușoară este de a include un identificator unic cu intrările de jurnal aferente. Acest identificator ar putea fi un nume de utilizator, un ID de sesiune, o cheie API sau un identificator unic universal (UUID). Din fericire, ThreadContext se potrivește perfect pentru această sarcină.

În exemplul Debugging Production Problems, aveam o interfață utilizator bazată pe web care era găzduită într-un servlet Tomcat, care se conecta la o bază de date MySQL. Utilizatorii își introduceau acreditările pe pagina web, iar după ce apăsau butonul de trimitere, servlet-ul rula o interogare care compara acreditările lor cu cele stocate în baza de date. În cazul în care utilizatorul era autentificat cu succes, era redirecționat către pagina principală. Dacă apărea o eroare, erau înregistrate detalii despre eroare, iar utilizatorilor li se prezenta un mesaj generic.

Am reușit să depanăm această problemă prin includerea numelor de utilizator ale utilizatorilor în mesajul de jurnal. Acest lucru ne-a permis să căutăm rapid evenimentele din jurnal legate de utilizatorul administrator. Pornind de la același exemplu, putem folosi ThreadContext.put() pentru a mapa un nume de utilizator la un Logger. Atunci când utilizatorii își trimit acreditările, servlet-ul intră în metoda doPost(), care adaugă numele de utilizator al utilizatorilor la ThreadContext:

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {ThreadContext.put("username", request.getParameter("username"));logger.info("Entering doPost().");...}

Utilizarea Log4j cu modelul %p : %m%n are ca rezultat următoarea intrare:

INFO : Entering doPost().

Potem adăuga evenimente similare pentru accesarea bazei de date MySQL, părăsirea metodei doPost și efectuarea altor acțiuni. În acest fel, dacă utilizatorul declanșează o excepție, știm exact ce făcea utilizatorul în momentul în care s-a produs excepția.

Cercetarea apelurilor de metode

Multe cadre de logare oferă metode native pentru a urmări calea de execuție a unei aplicații. Aceste metode variază ușor între cadre, dar urmează același format general.

  • traceEntry() marchează începutul unei metode.
  • traceExit() marchează sfârșitul unei metode. Pentru metodele care returnează un obiect, puteți returna simultan obiectul și consemna evenimentul cu return logger.exit(object).
  • throwing() marchează o excepție care este puțin probabil să fie tratată, cum ar fi o RuntimeException.
  • catching() marchează o excepție care nu va fi respinsă.

Puteți găsi informații specifice cadrului de lucru cu privire la aceste metode în documentația Logger pentru Log4j, Logback și java.util.logging.

Metode de urmărire în Log4j

Ca un exemplu de utilizare a Log4j, vom înlocui metodele Logger.info() din servlet-ul nostru cu metode de urmărire.

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { logger.entry(); ... logger.exit();}

De asemenea, vom schimba Appender's PatternLayout pentru a afișa numele clasei, metoda și numărul de linie (modelele de conversie %class, %M și %line).

<PatternLayout pattern="%p %class %M %line: %m%n" />

Metodele de urmărire înregistrează evenimentele la nivelul TRACE, ceea ce înseamnă că va trebui să schimbăm nivelul Logger's de la DEBUG la TRACE. În caz contrar, mesajele de jurnal vor fi suprimate.

<Loggers> <Root level="trace"> <AppenderRef ref="Console"/> </Root></Loggers> TRACE DatabaseApplication.Login doPost 26: entry...TRACE DatabaseApplication.Login doPost 59: exit

Metodele de urmărire oferă, de asemenea, propriile Markers. De exemplu, metodele Logger.entry() și Logger.exit() afișează ENTER și, respectiv, EXIT.

ENTER 14:47:41.074 TRACE DatabaseApplication.Login - EnterEXIT 14:47:41.251 TRACE DatabaseApplication.Login - Exit

Metode de urmărire în SLF4J

Utilizatorii SLF4J pot profita de MDC pentru a urmări evenimentele din jurnal. Similar cu Log4j, valorile MDC pot fi utilizate cu un Appender folosind modelul de conversie %X.

SLF4J oferă, de asemenea, metodele entry(), exit(), throwing() și catching() prin intermediul clasei XLogger (Extended Logger). Puteți crea o instanță XLogger folosind XLoggerFactory.getXLogger().

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(); }}

Adaugați modelele de conversie %class și %line la logback.xml.

<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>

Înregistrările de jurnal rezultate sunt identice cu cele create de Log4j.

Managementul utilizării memoriei

Managementul memoriei este adesea trecut cu vederea în limbajele de nivel superior, cum ar fi Java. În timp ce cantitatea medie de memorie din dispozitivele moderne este în creștere, o utilizare ridicată a memoriei poate avea un impact mare asupra stabilității și performanței aplicației dumneavoastră. Odată ce mașina virtuală Java nu mai poate aloca memorie de la sistemul de operare, programul dvs. ar putea să se termine și să se blocheze. Cunoașterea modului de gestionare a memoriei va preveni problemele pe măsură ce aplicația dvs. crește în dimensiune.

De exemplu, imaginați-vă că dorim să stocăm un set de numere începând de la unu. Un utilizator furnizează o limită superioară, iar programul stochează fiecare număr întreg de la „1” până la acea limită. Vom folosi o buclă while cu un contor pentru a adăuga fiecare număr la un tablou.

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);}

Ați putut observa că count nu se incrementează în buclă. Aceasta este o mare problemă; dacă utilizatorul introduce orice număr mai mare decât zero, matricea va continua să crească până când JVM utilizează toată memoria disponibilă și programul se blochează.

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)

Garbage Collection

Pentru a reduce utilizarea memoriei, mașina virtuală Java efectuează un proces periodic de curățare cunoscut sub numele de garbage collection. Colectarea gunoiului caută blocurile de memorie care nu mai sunt utilizate și le face disponibile pentru reutilizare. Următoarele resurse explică mai în detaliu procesul de colectare a gunoiului din Java.

  • Java Garbage Collection Basics (Oracle)
  • HotSpot Virtual Machine Garbage Collection Tuning Guide (Oracle)
  • Understanding G1 GC Logs (Poonam Bajaj)
  • Garbage Collection Tuning Guide (Atlassian)

Garbage collector generează informații de diagnosticare care pot fi utile pentru profilarea performanței aplicațiilor. Puteți înregistra aceste informații trecând -Xlog:gc către JVM la pornirea aplicației dumneavoastră. După fiecare execuție, garbage collector tipărește statistici despre procesul de colectare a gunoiului în formatul Unified JVM Logging. Iată un exemplu.

 Using G1 Periodic GC disabled GC(0) Pause Young (Normal) (G1 Evacuation Pause) 7M->1M(64M) 8.450ms

Using G1 spune ce metodă de colectare a gunoiului este utilizată. Colectorul Garbage-First (G1) este adesea activat în mod implicit pe computerele multiprocesor cu cantități mari de memorie RAM. Periodic GC disabled Periodic GC disabled indică faptul că procesul de colectare a gunoiului nu se va repeta. A treia linie ne spune că aceasta este o pauză de evacuare, în care obiectele sunt copiate între regiunile de memorie în funcție de faptul dacă mai sunt sau nu utilizate. Pause Young ne spune că procesul a curățat generația tânără, care este locul unde sunt alocate obiecte noi. Ca urmare, utilizarea totală a memoriei de către obiectele din generația tânără a scăzut de la 7M la 1M din cei 64M alocați, iar procesul a avut nevoie de 8.450ms.

Cu ajutorul garbage collector-ului care imprimă informații de diagnosticare în consolă, putem vedea cum cantitatea de memorie alocată (dimensiunea heap-ului) continuă să crească în timp. Vom elimina timpii CPU pentru simplitate.

$ 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...

Graficul care arată o creștere treptată a utilizării heap-ului JVM în timp.

Puteți adăuga timbre de timp la fiecare intrare cu -XX:+PrintGCDateStamps și -XX:+PrintGCTimeStamps. De asemenea, puteți înregistra ieșirea colectorului de gunoi într-un fișier trecând-Xlog:gc:file: către JVM la pornirea aplicației.

Dacă monitorizați fișierele de jurnal cu rsyslog, puteți transmite jurnalele către un sistem de jurnal centralizat unde vor fi analizate și pregătite pentru o analiză aproape în timp real. Iată cum arată un grafic cronologic în Loggly. Acesta arată dimensiunea totală a heap-ului, precum și dimensiunea heap-ului înainte și după rularea colectorului de gunoi.

Fugile de memorie

O scurgere de memorie este o situație în care un program alocă memorie mai repede decât o poate elibera. Cel mai simplu mod de a detecta o scurgere de memorie este atunci când programul dumneavoastră nu mai răspunde, devine instabil sau provoacă OutOfMemoryErrors. În Java, veți găsi mai multe cazuri de colecții Full GC pe măsură ce crește utilizarea memoriei.

Puteți afla mai multe despre ieșirea colectorului de gunoi și despre identificarea scurgerilor de memorie în capitolul Troubleshoot Memory Leaks (Depanarea scurgerilor de memorie) din documentația Java.

Resurse suplimentare

Reduceți timpul de depanare fără să scrieți o singură linie de cod (Loggly) – Ghid de utilizare a Takipi

Ghidul suprem: 5 Methods for Debugging Production Servers at Scale (High Scalability)-Instrumente și tehnici pentru depanarea problemelor de producție

Memory Management

Garbage Collection Tuning Guide (Oracle)-Ghid pentru înțelegerea și reglarea fină a colectării gunoiului din Java

Understanding Java Garbage Collection (CUBRID Blog)-Ghid pentru garb

Vezi. Analizați-l. Inspectați-l. Rezolvați-o

Vezi ce contează.

START FREE TRIAL

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.