Un aspect esențial în dezvoltarea software este înregistrarea precisă a evenimentelor. Având la dispoziție numeroase biblioteci Java pentru jurnalizare, alegerea uneia ușor de utilizat devine crucială. În același timp, framework-ul selectat trebuie să ofere performanțe ridicate, caracteristici extensibile și posibilitatea de personalizare. Log4j2 se evidențiază ca o bibliotecă gratuită de jurnalizare Java, care îndeplinește toate aceste cerințe.
Integrarea Log4j2 într-o aplicație deschide ușa către funcționalități avansate, cum ar fi filtrarea complexă, suportul pentru lambda Java 8, căutarea proprietăților și niveluri de jurnal personalizate. Vom explora modalitățile de a adăuga Log4j2 în proiectele dvs. și vom evidenția caracteristicile care vă pot oferi un avantaj competitiv.
Ce reprezintă Log4j2?
Jurnalizarea reprezintă procesul de colectare a informațiilor valoroase, cunoscute ca jurnale, care pot fi ulterior consultate și analizate. Aceste jurnale sunt instrumente esențiale pentru depanarea rapidă a codului unei aplicații. Ele facilitează înțelegerea fluxului de cod și soluționarea problemelor și erorilor din mediul de producție.
Dincolo de diagnosticare, jurnalele sunt folosite și în scopuri de audit, de exemplu, pentru a verifica dacă un mesaj de notificare a fost trimis cu succes utilizatorului.
Log4j2 se distinge ca una dintre cele mai populare biblioteci de jurnalizare Java. Reprezintă succesorul bibliotecii Log4j, care a avut un impact semnificativ. Dezvoltată de Apache Software Foundation și integrată în Apache Logging Services, Log4j2 este un software gratuit și open-source (FOSS), distribuit sub licența Apache, versiunea 2.0.
Log4j2 este construit pe fundamentele solide ale Log4j original. Utilizarea unui Logger, în comparație cu instrucțiunile simple de tipărire `System.out.println()`, aduce numeroase avantaje. Printre acestea se numără controlul asupra mesajelor afișate, eliminând afișarea altor mesaje de jurnal. Un sistem de jurnalizare adecvat este esențial în mediul de producție, unde instrumentele de depanare nu sunt disponibile.
Cum se integrează Log4j2 în proiectul dvs.?
Există mai multe metode pentru a include Log4j2 în proiectele Java. Este recomandat să folosiți Java 8 sau o versiune superioară pentru a beneficia de toate funcționalitățile Log4j2.
Vom discuta diversele abordări prin care puteți adăuga Log4j2, în funcție de cerințele specifice ale proiectului dvs.
Integrarea Log4j2 în proiecte folosind Apache Maven
Dacă proiectul dvs. utilizează Apache Maven ca sistem de build, dependențele Log4j2 trebuie adăugate în fișierul `pom.xml`.
<dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.20.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.20.0</version> </dependency> </dependencies>
Pentru a asigura o versiune uniformă în diverse artefacte, Log4j2 utilizează un fișier `pom.xml` Bill of Material (BOM). Adăugarea acestuia în secțiunea de gestionare a dependențelor elimină necesitatea specificării individuale a versiunilor.
<!-- Adăugarea BOM-ului în dependencyManagement --> <dependencyManagement> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-bom</artifactId> <version>2.20.0</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <!-- Odată adăugat BOM-ul, versiunile nu mai sunt necesare --> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> </dependency> </dependencies>
Integrarea Log4j2 în proiecte folosind Apache Gradle
În cazul în care folosiți Apache Gradle ca instrument de build, puteți include dependențele Log4j2 în fișierul `build.gradle`.
dependencies { implementation 'org.apache.logging.log4j:log4j-api:2.20.0' implementation 'org.apache.logging.log4j:log4j-core:2.20.0' }
Dacă utilizați Gradle versiunea 5.0 sau superioară, aveți posibilitatea de a importa lista de materiale (BOM) Log4j2 Maven pentru a menține versiuni consistente ale dependențelor. Acest lucru se realizează adăugând următoarele linii în fișierul `build.gradle`:
dependencies { implementation platform('org.apache.logging.log4j:log4j-bom:2.20.0') implementation 'org.apache.logging.log4j:log4j-api' runtimeOnly 'org.apache.logging.log4j:log4j-core' }
Pentru versiunile Gradle 2.8-4.10, nu există opțiunea de import direct a BOM-ului Maven. Este necesar să adăugați un plugin suplimentar pentru funcționalitatea de gestionare a dependențelor.
plugins { id 'io.spring.dependency-management' version '1.0.15.RELEASE' } dependencyManagement { imports { mavenBom 'org.apache.logging.log4j:log4j-bom:2.20.0' } } dependencies { implementation 'org.apache.logging.log4j:log4j-api' runtimeOnly 'org.apache.logging.log4j:log4j-core' }
Integrarea Log4j2 în aplicații independente fără instrument de build
Dacă proiectul dvs. nu utilizează un instrument de build, puteți descărca versiunile artefactelor Log4j2 necesare de pe pagina oficială de descărcare a Log4j2.
După descărcare, asigurați-vă că calea de clasă a aplicației dvs. include următoarele fișiere JAR:
- log4j-api-2.20.0.jar
- log4j-core-2.20.0.jar
Care sunt componentele Log4j2?
Pentru a înțelege caracteristicile Log4j2 și a utiliza la maximum capacitățile sale, este important să înțelegeți arhitectura sa. Mai multe componente alcătuiesc Log4j2, pe care le vom discuta în detaliu.
#1. LoggerContext
LoggerContext este elementul central al sistemului de jurnalizare. Acesta gestionează toate Logger-ele solicitate în cadrul aplicației și menține o referință către Configurație.
#2. Configurație
Configurația conține toate datele necesare pentru funcționarea sistemului de jurnalizare. Acestea includ Logger-ele, Appender-ele, Filtrele și alte elemente. În Log4j2, configurația poate fi definită prin diverse formate de fișiere, cum ar fi XML, JSON și YAML, precum și programatic, prin intermediul API-ului Log4j2.
Reîncărcarea automată a configurației are loc atunci când se modifică orice proprietate, eliminând necesitatea repornirii aplicației.
#3. Logger
Componenta principală a sistemului Log4j2 este Logger-ul. Logger-ele sunt obținute în codul aplicației prin instrucțiunea `LogManager.getLogger()` și sunt folosite pentru a genera jurnalele. Mesajele de jurnal pot fi generate la diferite niveluri de severitate, precum debug, info, warn, error și fatal.
#4. LoggerConfig
LoggerConfig este responsabil pentru comportamentul unui anumit Logger. El definește setările și modul de funcționare pentru înregistrarea evenimentelor generate de acel logger. Permite configurarea diferitelor niveluri de înregistrare, a anexelor și aplicarea filtrelor.
#5. Filtru
În Log4j2, evenimentele de jurnal pot fi procesate selectiv folosind Filtre. Acestea sunt aplicate pe baza unor criterii specifice și pot fi asociate cu logger-ele sau appender-ele. Filtrele controlează ce evenimente de jurnal sunt permise să treacă prin procesul de înregistrare pentru o procesare ulterioară. Ele permit ajustarea comportamentului de jurnalizare, asigurând că doar jurnalele relevante sunt procesate.
#6. Appender
Destinația oricărui mesaj de jurnal este determinată de Appender. Un singur Logger poate avea multiple Appender-e. Un eveniment de jurnal va fi trimis tuturor Appender-elor asociate cu Logger-ul respectiv. Log4j2 pune la dispoziție o varietate de appender-e preconfigurate. De exemplu, `ConsoleAppender` este folosit pentru a înregistra mesajele în consolă, iar `FileAppender` pentru a trimite mesajele într-un fișier. Fiecare Appender necesită un Layout care definește aspectul mesajului de jurnal final.
#7. Aspect (Layout)
În Log4j2, Layout-ul este utilizat pentru a defini aspectul mesajului de jurnal final. Un Layout este asociat unui Appender. În timp ce un Appender stabilește destinația ieșirii, Layout-ul descrie formatul mesajului care va fi transmis.
Top 5 caracteristici ale Log4j2
Log4j2 se remarcă prin bogăția sa funcțională, care îl diferențiază de alte biblioteci Java de jurnalizare. De la loggere asincrone la suportul pentru lambda Java 8, Log4j2 are un avantaj distinct. Să analizăm câteva dintre caracteristicile notabile ale acestui framework.
#1. Extinderea funcționalităților cu ajutorul plugin-urilor
În Log4j 1.x, crearea de extensii necesita modificări substanțiale de cod. Log4j2 rezolvă problema extensibilității prin introducerea sistemului de Plugin-uri.
Un plugin nou poate fi declarat folosind adnotarea `@Plugin` într-o clasă. Cu ajutorul plugin-urilor, se pot crea componente personalizate, cum ar fi filtre și appender-e. De asemenea, componente de la terți pot fi adăugate cu ușurință în bibliotecă.
#2. Suport pentru Java 8 Lambda
Odată cu lansarea Log4j2 versiunea 2.4, a fost introdus suportul pentru expresiile lambda Java 8. Cu aceste expresii, logica de jurnalizare poate fi definită în linie. Aceasta elimină necesitatea verificărilor pe mai multe linii sau a claselor interne anonime. Se asigură, de asemenea, că metodele costisitoare nu sunt executate inutil. Astfel, codul devine mai clar și mai ușor de citit, iar suprasolicitarea sistemului este redusă.
Să considerăm un exemplu în care se înregistrează rezultatul unei operații costisitoare, dar numai dacă nivelul de debug este activat. Înainte de suportul pentru lambda, acest lucru ar fi realizat cu următorul cod:
if (logger.isDebugEnabled()) { logger.debug("The output of the given operation is: {}", expensiveOperation()); }
Având mai multe astfel de cazuri, s-ar introduce inutil verificări condiționate. Cu toate acestea, cu Log4j2, aceeași acțiune poate fi efectuată după cum urmează:
logger.debug("The output of the given operation is: {}", () -> expensiveOperation()
Metoda `expensiveOperation()` este evaluată numai dacă nivelul de debug este activat. Nu este necesară nicio verificare explicită.
#3. Loggere Asincrone
Fiecare eveniment de jurnal este o operație I/O, care crește suprasolicitarea sistemului. Pentru a atenua acest lucru, Log4j2 introduce loggere asincrone, care rulează într-un fir separat de cel al aplicației. Când se utilizează loggere asincrone, firul apelant primește imediat controlul înapoi după invocarea metodei `logger.log()`.
Acest lucru îi permite să continue cu logica aplicației, fără a aștepta finalizarea evenimentului de înregistrare. Utilizarea acestui comportament asincron permite o capacitate de înregistrare mai mare. Se poate alege ca toate loggere-le să fie asincrone în mod implicit sau se poate combina un comportament sincron cu unul asincron.
#4. Înregistrare fără gunoi
În Java, colectarea gunoiului (garbage collection) este procesul prin care obiectele neutilizate din aplicație sunt eliminate automat. Deși nu trebuie să ne ocupăm manual de această operație, colectarea gunoiului vine cu propriile costuri de performanță.
Dacă o aplicație creează prea multe obiecte într-o perioadă scurtă de timp, procesul de colectare a gunoiului poate consuma mai multe resurse de sistem decât este necesar. Mai multe biblioteci de înregistrare, inclusiv versiunile anterioare ale Log4j, generează multe obiecte temporare în timpul procesului de jurnalizare. Acest lucru duce la o presiune crescută asupra colectorului de gunoi, afectând performanța sistemului.
Începând cu versiunea 2.6, Log4j2 funcționează în modul „fără gunoi”. Acesta este comportamentul implicit. Astfel, obiectele sunt reutilizate, iar crearea celor temporare este mult redusă.
Următoarele imagini ilustrează modul în care Log4j2 versiunea 2.6 atenuează problema obiectelor inutile, în comparație cu Log4j2 versiunea 2.5.
În Log4j2 versiunea 2.5, multe obiecte temporare sunt create în timpul procesului de jurnalizare; Sursa: apache.org
În Log4j2.6, nu există obiecte temporare create în timpul procesului de jurnalizare; Sursa: apache.org
#5. Căutări (Lookups)
În Log4j2, informații contextuale pot fi adăugate în jurnale folosind Căutări. Prin intermediul acestora, date din diverse surse, cum ar fi proprietățile sistemului, variabilele de mediu sau valori personalizate pot fi incluse. Astfel, informațiile relevante, obținute dinamic, sunt integrate în jurnale, sporind utilitatea acestora.
Să presupunem că doriți să înregistrați ID-ul sesiunii utilizatorului în toate înregistrările. Acest lucru ar permite căutarea tuturor jurnalele corespunzătoare unui ID de sesiune.
O modalitate simplă de a face acest lucru ar fi să adăugați explicit ID-ul sesiunii în fiecare înregistrare, ceea ce ar fi dificil de menținut. În curând, s-ar putea omite adăugarea acestui ID, pierzând astfel informații importante.
logger.info("The user data has been fetched for session id {}", sessionId); ... logger.info("The transaction has been processed for session id {}", sessionId); ... logger.info("Request has been successfully processed for session id {}", sessionId);
O abordare mai eficientă ar fi utilizarea Căutării hărții contextuale. ID-ul sesiunii poate fi adăugat la Contextul Thread-ului din codul aplicației. Această valoare poate fi apoi utilizată în configurația Log4j2, eliminând necesitatea menționării explicite a ID-ului în mesajele de jurnal.
ThreadContext.put("sessionId", sessionId);
Odată adăugată, valoarea poate fi utilizată în Căutare folosind cuvântul cheie `ctx`.
<File name="Application" fileName="application.log"> <PatternLayout> <pattern>%d %p %c{1.} [%t] $${ctx:sessionId} %m%n</pattern> </PatternLayout> </File>
Cum se creează niveluri de jurnal personalizate în Log4j2?
Nivelurile de jurnal din Log4j2 sunt folosite pentru a clasifica evenimentele de jurnal în funcție de importanța sau gravitatea lor. Nivelul de jurnal poate fi controlat atunci când se înregistrează un mesaj în codul aplicației.
De exemplu, `logger.debug()` adaugă nivelul DEBUG, iar `logger.error()` adaugă nivelul EROARE. Aceste nivele determină mesajele care vor fi afișate în final. Nivelul de jurnal poate fi configurat în fișierul de configurare.
Nivelurile de jurnal preconfigurate în Log4j2, împreună cu valorile lor corespunzătoare, sunt prezentate mai jos:
OFF0FATAL100ERROR200WARN300INFO400DEBUG500TRACE600ALLMAX VALUE
Dacă nivelul de jurnal este setat la o anumită valoare, atunci toate înregistrările cu acea valoare și cu valori inferioare (mai mici) vor fi afișate, în timp ce celelalte vor fi ignorate.
De exemplu, dacă nivelul de jurnal este setat la WARN, atunci mesajele WARN, ERROR și FATAL vor fi afișate, în timp ce mesajele de jurnal cu un nivel diferit vor fi ignorate. Acest lucru este util în special atunci când același cod este rulat în medii diferite.
Puteți seta nivelul jurnalului la INFO sau DEBUG când rulați codul în mediul de dezvoltare, ceea ce va afișa mai multe jurnale și va fi de ajutor în procesul de dezvoltare. În schimb, când rulați într-un mediu de producție, ați putea dori să setați nivelul la ERROR, pentru a vă concentra doar pe problemele care apar, evitând jurnalizarea inutilă.
În anumite cazuri, este posibil să doriți să adăugați propriul nivel de jurnal personalizat, pe lângă cele preconfigurate. Log4j2 vă permite să faceți acest lucru cu ușurință. Să vedem cum puteți adăuga propriile niveluri de jurnal și să le utilizați în aplicație.
#1. Adăugarea unui nivel de jurnal personalizat prin fișierul de configurare
Niveluri de jurnal personalizate pot fi adăugate prin declararea lor în fișierul de configurare.
În exemplul de mai jos, un nivel de jurnal personalizat numit NOTICE este definit cu valoarea 450, plasându-l între INFO (cu valoarea 400) și DEBUG (cu valoarea 500). Acest lucru înseamnă că, dacă nivelul este setat la NOTICE, mesajele INFO vor fi înregistrate, dar mesajele DEBUG vor fi omise.
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <CustomLevels> <CustomLevel name="NOTICE" intLevel="450" /> </CustomLevels> <Appenders> <File name="MyFile" fileName="logs/app.log"> <PatternLayout pattern="%d %-7level %logger{36} - %msg%n"/> </File> </Appenders> <Loggers> <Root level="trace"> <AppenderRef ref="MyFile" level="NOTICE" /> </Root> </Loggers> </Configuration>
#2. Adăugarea unui nivel de jurnal personalizat în cod
Pe lângă declararea în fișierul de configurare, nivelurile de jurnal personalizate pot fi definite și în cod.
final Level VERBOSE = Level.forName("VERBOSE", 550);
Acest cod creează un nou nivel de jurnal numit VERBOSE, care se află între DEBUG (cu valoarea 500) și TRACE (cu valoarea 600). Dacă logger-ul este setat la nivelul VERBOSE, atunci toate mesajele de jurnal VERBOSE și cu valori inferioare vor fi înregistrate, inclusiv DEBUG, în timp ce mesajele TRACE vor fi omise.
#3. Utilizarea nivelului de jurnal personalizat în cod
Nivelurile de jurnal personalizate trebuie declarate înainte de a fi utilizate. Ele pot fi declarate fie în fișierul de configurare, fie în cod. Odată declarate, ele pot fi folosite.
Acest exemplu de cod arată cum se declară un nivel personalizat numit NOTICE și cum se folosește.
final Level NOTICE = Level.forName("NOTICE", 550); final Logger logger = LogManager.getLogger(); logger.log(NOTICE, "a notice level message");
Deși acest cod va genera mesajul dorit cu noul nivel, poate deveni complicat să se specifice mereu nivelul în mod explicit. Din fericire, puteți genera cod sursă pentru a obține metode de ajutor pentru înregistrarea nivelurilor personalizate. Astfel, veți putea utiliza propria metodă `logger.notice()`, similar cu modul în care utilizați `logger.debug()` sau `logger.error()`.
Log4j2 oferă un utilitar pentru a crea înregistratoare extinse. Următoarea comandă creează un fișier Java numit `CustomLogger.java`, care conține metodele de jurnal existente, împreună cu metodele nou generate pentru nivelul NOTICE.
java -cp log4j-core-2.20.0.jar org.apache.logging.log4j.core.tools.ExtendedLoggerGenerator com.example.CustomLogger NOTICE=450 > com/example/CustomLogger.java
După generarea fișierului, clasa poate fi utilizată în cod pentru a crea noi loggere, care vor conține metode suplimentare pentru nivelul de jurnal personalizat. În acest fel, se extinde funcționalitatea logger-elor.
final Logger logger = CustomLogger.create(ValueFirstSmsSender.class); //această metodă nouă este similară cu utilizarea logger.debug() logger.notice("a notice level message");
Concluzie
Log4j2 este un framework de jurnalizare Java puternic, care oferă o gamă largă de funcționalități, configurații, îmbunătățiri de performanță și multe altele. Având în vedere că jurnalele sunt esențiale în dezvoltarea software, un framework robust precum Log4j2 îmbunătățește capacitățile aplicațiilor.
Flexibilitatea și extensibilitatea Log4j2 permit captarea eficientă a evenimentelor din cadrul unei aplicații. Aceasta transformă jurnalele într-un instrument puternic pentru depanare și auditare. Prin toate caracteristicile și îmbunătățirile sale, Log4j2 se remarcă și este alegerea preferată pentru o varietate de proiecte software.
S-ar putea să vă intereseze și aceste IDE-uri Java și compilatoare online.