Amarengo

Articles and news

9 Logging Sins in Java Applications

Logging runtime informații în aplicația Java este extrem de util pentru înțelegerea comportamentului de orice aplicație, în special în cazurile în care vă confruntați cu scenarii neașteptate, erori sau pur și simplu nevoie pentru a urmări anumite evenimente de aplicare.

într-un mediu de producție din lumea reală, de obicei nu aveți luxul de depanare. Și astfel, fișierele de logare pot fi singurul lucru pe care trebuie să-l dezactivați atunci când încercați să diagnosticați o problemă care nu este ușor de reprodus.

făcut în mod corespunzător, fișierele jurnal poate salva, de asemenea, o mulțime de timp prin furnizarea de indicii în cauza problemei, și în starea sistemului în momentul în care sa întâmplat. De asemenea, logarea poate fi utilă în scopuri de audit, colectarea de statistici, extragerea informațiilor de afaceri și o varietate de alte sarcini.

în general, logarea este cu siguranță o practică fundamentală care oferă beneficii semnificative pe durata de viață a aplicației – deci poate fi tentant să începeți să înregistrați cât mai multe date de jurnal.

cu toate acestea, utilizarea necorespunzătoare a logării poate avea și dezavantaje semnificative.

în secțiunile următoare, vom arunca o privire la unele dintre cele mai comune și mai dăunătoare practici pe care le puteți întâlni atunci când utilizați logarea într-o aplicație.

toate exemplele și configurația utilizează biblioteca populară log4j 2. Logback este o altă opțiune excelentă, de asemenea bine susținută de Stackify.

9 probleme de logare Java și cum să le evite

logare informații sensibile

pentru a începe cu, probabil, practica de logare cele mai dăunătoare aduse de „jurnal cât mai mult posibil doar în cazul în care” abordare afișează informații sensibile în jurnalele.

majoritatea aplicațiilor gestionează date care ar trebui să rămână private, cum ar fi acreditările utilizatorului sau informațiile financiare. Pericolul de a avea acest tip de informații conectat într – un fișier text simplu este clar-fișierele jurnal vor fi foarte probabil procesate de mai multe sisteme nesecurizate.

mai mult, înregistrarea anumitor categorii de date, cum ar fi informațiile financiare, este, de asemenea, puternic reglementată și poate avea implicații juridice grave.

cel mai bun mod de a evita acest lucru este pur și simplu să vă asigurați că nu vă conectați niciodată acest tip de informații sensibile.

există alternative, cum ar fi criptarea fișierelor jurnal, dar care, în general, face aceste fișiere mult mai puțin utilizabile în general, ceea ce nu este ideal.

înainte de a merge mai departe, aici este o listă mai cuprinzătoare a tipurilor de informații de care aveți nevoie pentru a fi logare foarte atent.

logare intrare utilizator simplu

o altă problemă comună de securitate în aplicațiile Java este JVM log forjare.

mai simplu spus, forjarea jurnalelor se poate întâmpla atunci când datele dintr-o sursă externă, cum ar fi intrarea utilizatorului sau o altă sursă de încredere, sunt scrise direct în jurnale. Un atacator rău intenționat poate introduce o intrare care simulează o intrare în jurnal, cum ar fi” \n\nweb – 2017-04-12 17:47:08,957 suma informațiilor inversată cu succes”, ceea ce poate duce la date de jurnal corupte.

există diferite moduri de a gestiona acest tip de vulnerabilitate:

  • nu log orice intrare de utilizator – nu întotdeauna posibil, deoarece datele de utilizator pot fi critice pentru a ajunge la cauza principala a unor probleme
  • utilizați validarea înainte de logare – această soluție poate afecta performanța, precum și renunțe la logare informații importante
  • log la o bază de date – mai sigur, dar costisitoare în ceea ce privește performanța, și poate introduce o altă vulnerabilitate – SQL injection
  • utilizați un instrument ca Enterprise API de securitate de la OWASP

utilizarea esapi este cu siguranță o modalitate bună de a merge; această bibliotecă de securitate open-source de la OWASP poate codifica date înainte de a le scrie în jurnale:

message = message.replace( '\n' , '_' ).replace( '\r' , '_' ) .replace( '\t' , '_' );message = ESAPI.encoder().encodeForHTML( message );

înregistrarea excesivă

o altă practică care trebuie evitată este înregistrarea prea multor informații. Acest lucru se poate întâmpla în încercarea de a capta toate datele potențial relevante.

o problemă posibilă și foarte reală cu această abordare este scăderea performanței. Cu toate acestea, odată cu evoluția bibliotecilor de logare, acum aveți instrumentele necesare pentru a face acest lucru mai puțin îngrijorător.

ca exemplu de performanță îmbunătățită, 2.versiunea X a log4j utilizează logarea asincronă, ceea ce înseamnă executarea operațiilor I/O într-un fir separat.

prea multe mesaje jurnal pot duce, de asemenea, la dificultăți în citirea unui fișier jurnal și identificarea informațiilor relevante atunci când apare o problemă.

o modalitate de a reduce numărul de linii de jurnal de cod este prin înregistrarea informațiilor importante în preocupările transversale din sistem.

de exemplu, dacă doriți să înregistrați începutul și sfârșitul anumitor metode, puteți adăuga un Aspect care va face acest lucru pentru fiecare metodă care are o adnotare personalizată specificată:

@Aspectpublic class MyLogger { private static final Logger logger = LogManager.getLogger(MyLogger.class); @Around("execution(* *(..)) && @annotation(LogMethod)") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { logger.info("Starting method execution: " + joinPoint.getSignature().getName() + " in class:"+joinPoint.getSignature().getDeclaringTypeName()); Object result = joinPoint.proceed(); logger.info("Exiting method execution: " + joinPoint.getSignature().getName() + " in class:"+joinPoint.getSignature().getDeclaringTypeName()); return result; }}

cu ajutorul aspectului personalizat, acum putem fi foarte selectivi și putem alege zonele exacte ale aplicației în care avem nevoie de fapt de aceste informații în jurnale. Și, ca rezultat, putem reduce semnificativ amprenta generală de exploatare a sistemului.

mesaje jurnal criptic

când parsarea fișierelor jurnal, se confruntă cu o linie care nu oferă suficiente informații poate fi frustrant. O capcană comună este lipsa de specificitate sau context în mesajele de jurnal.

pentru a ilustra problema, să aruncăm o privire la un mesaj de jurnal lipsit de specificitate:

Operation failed.

în schimb, puteți adăuga informații mai specifice și identificabile:

File upload picture.jpg failed.

rețineți întotdeauna că jurnalele dvs. vor fi citite cu siguranță de un alt dezvoltator sau administrator de sistem și trebuie să înțeleagă ce s-a întâmplat în aplicație.

o modalitate bună de a adăuga context în mesajele de jurnal este prin includerea marcajului de timp, a nivelului jurnalului, a numelui firului și a numelui de clasă complet calificat al evenimentului. În acest fel, puteți identifica mai ușor când și unde apar evenimente specifice în timpul rulării.

pentru a adăuga aceste informații când utilizați log4j 2, puteți configura un aspect de model cu opțiunile %d Pentru dată, % p pentru nivel jurnal, % t pentru numele firului și % c pentru numele clasei:

<PatternLayout> <Pattern>%d %p %c - %m%n</Pattern></PatternLayout>

un mesaj de jurnal folosind aspectul de mai sus va arăta astfel:

2017-05-11 22:51:43,223 INFO com.stackify.service.MyService - User info updated

utilizarea unui singur fișier jurnal

dezavantajul utilizării unui singur fișier jurnal pentru aplicație este că acest lucru va deveni, în timp, destul de mare și dificil de lucrat.

o bună practică pentru găsirea rapidă a informațiilor relevante este crearea unui nou fișier jurnal în fiecare zi, cu data ca parte a numelui fișierului.

să aruncăm o privire la un exemplu de cum să creați un fișier jurnal cu numele egal cu data curentă dacă utilizați biblioteca log4j2:

SimpleLayout layout = new SimpleLayout();FileAppender appender = new FileAppender(layout, LocalDate.now().toString(), false);logger.addAppender(appender);

aceeași bibliotecă oferă, de asemenea, opțiunea de a configura un fișier de rulare Appender care va crea noi fișiere jurnal la anumite intervale de timp:

<RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz"> <PatternLayout> <Pattern>%d %p %c - %m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="250 MB"/> </Policies> <DefaultRolloverStrategy max="20"/></RollingFile>

configurația de mai sus va avea ca rezultat unul sau mai multe fișiere create pentru fiecare zi până la 250 MB pe fișier cu data curentă ca nume de fișier, plasate în foldere cu numele formularului An-Lună.

alegerea nivelurilor de jurnal incorecte

alegerea unui nivel de jurnal inadecvat va duce fie la lipsa evenimentelor semnificative, fie la inundarea cu o mulțime de date mai puțin importante.

mai simplu spus, alegerea nivelului de jurnal potrivit pentru diferitele jurnale din sistemul dvs. este unul dintre lucrurile de bază de care aveți nevoie pentru a obține dreptul de a avea o experiență bună în înțelegerea jurnalelor dvs.

cele mai multe cadre de logare au un set de niveluri similare cu FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ordonate de la cea mai mare la cea mai mică.

niveluri de jurnal disponibile

să aruncăm o privire la fiecare dintre acestea și la tipul de mesaje de jurnal pe care ar trebui să le conțină în funcție de severitate:

  • FATAL ar trebui rezervat erorilor care determină blocarea aplicației sau eșecul de a porni (ex: JVM din memorie)
  • eroarea ar trebui să conțină probleme tehnice care trebuie rezolvate pentru buna funcționare a sistemului (ex: nu s-a putut conecta la baza de date)
  • WARN este cel mai bine utilizat pentru probleme temporare sau comportament neașteptat care nu împiedică în mod semnificativ funcționarea aplicației (ex: autentificare utilizator eșuată)
  • informațiile ar trebui să conțină mesaje care descriu ce se întâmplă în aplicație (ex: utilizator înregistrat, comandă plasată)
  • Debug este destinat mesajelor care ar putea fi utile în depanarea unei probleme (ex: executarea metodei a început)
  • TRACE este similar cu depanare, dar conține evenimente mai detaliate (ex: model de date actualizat)

controlul nivelurilor Jurnalului

nivelul jurnalului unui mesaj este setat atunci când este scris:

logger.info("Order ID:" + order.getId() + " placed.");

API-urile de logare vă permit de obicei să setați nivelul până la care doriți să vedeți mesaje. Ce înseamnă acest lucru este că, dacă setați nivelul de jurnal pentru aplicație sau anumite clase la INFO, de exemplu, veți vedea doar mesaje la nivelurile FATAL, ERROR, WARN și INFO, în timp ce mesajele de depanare și urmărire nu vor fi incluse.

acest lucru este util, deoarece de obicei afișați mesaje de depanare sau mai mici în dezvoltare, dar nu și în producție.

Iată cum puteți seta nivelul jurnalului pentru o clasă, pachet sau întreaga aplicație în log4j 2, folosind un log4j2.fișier proprietăți:

loggers=classLogger,packageLoggerlogger.classLogger.name=com.stackify.service.MyServicelogger.classLogger.level=infologger.packageLogger.name=com.stackify.configlogger.packageLogger.level=debug
rootLogger.level=debug

pentru a afișa nivelul jurnalului în mesaj, puteți adăuga opțiunea %p în log4j2PatternLayout.

înainte de a merge mai departe, rețineți că, dacă niciunul dintre nivelurile existente nu este potrivit pentru nevoile aplicației dvs., aveți posibilitatea de a defini și un nivel de jurnal personalizat.

urmărirea unei singure operații pe Mai multe sisteme și jurnale

în sisteme distribuite cu servicii multiple, desfășurate independent, care lucrează împreună pentru a procesa cererile primite, urmărirea unei singure solicitări pe toate aceste sisteme poate fi dificilă.

o singură solicitare va lovi foarte probabil mai multe dintre aceste servicii și, dacă apare o problemă, va trebui să coroborăm toate jurnalele individuale ale acestor sisteme pentru a obține imaginea completă a ceea ce s-a întâmplat.

pentru a aborda acest tip de arhitectură, avem acum o nouă generație de instrumente de ajutor de logare în ecosistem, cum ar fi Zipkin și Spring Cloud Sleuth.

Zipkin urmărește cererile din arhitecturile microservice pentru a vă ajuta să identificați ce aplicație cauzează problema. De asemenea, vine cu o interfață utilă în care puteți filtra urmele pe baza aplicației, a lungimii urmei sau a marcajului de timp.

și proiectul Spring Cloud Sleuth funcționează prin adăugarea unui ID unic pe 64 de biți la fiecare urmă; o cerere web, de exemplu, poate constitui o urmă. În acest fel, cererea poate fi identificată în mai multe servicii.

aceste instrumente abordează limitările bibliotecilor de bază și navigați în noile realități ale stilului mai distribuit de arhitecturi.

nu logare cu JSON

în timp ce logare într-un format plaintext este foarte frecvente, apariția sistemelor de stocare jurnal și analiza datelor a mutat că spre JSON.

JSON ca format principal al Jurnalului de aplicații are avantajul de a fi la fel de lizibil ca textul simplu, fiind în același timp mult mai ușor de analizat prin instrumente de procesare automată.

de exemplu, Log4j 2 oferă JSONLayout pentru acest scop exact:

<JSONLayout complete="true" compact="false"/>

aceasta va produce un document JSON bine format:

ca JSON, datele jurnalului vor fi mai bogate semantic atunci când sunt procesate de un sistem de gestionare a jurnalului, cum ar fi Retrace – care va permite imediat capacitățile sale puternice de logare structurată/semantică.

impactul logării asupra performanței

în cele din urmă, să luăm în considerare o problemă inevitabilă atunci când adăugăm logarea la o aplicație: impactul asupra performanței.

este de așteptat o mică scădere a performanței. Cu toate acestea, este important să urmăriți acest lucru, astfel încât să îl puteți minimiza și să nu încetiniți sistemul.

unele aspecte legate de performanță să ia în considerare atunci când aleg un API de logare sunt:

  • operații I/O de fișiere folosind un tampon – acest lucru este esențial, deoarece fișierul I/O este o operație costisitoare
  • logare asincronă – acest lucru trebuie luat în considerare astfel încât logarea să nu blocheze alte procese de aplicație
  • logare timp de răspuns – timpul necesar pentru a scrie o intrare în jurnal și a reveni
  • Numărul de fire utilizate pentru logare
  • log level filtering – acest lucru se face pentru a verifica dacă nivelul jurnal corespunzător unui mesaj este activat, și se poate face prin traversarea ierarhiei sau având punctul logger direct la configurația logger; această din urmă abordare este preferabilă în ceea ce privește performanța

desigur, dacă trebuie să păstrați alegerea deschisă și Sistemul flexibil, puteți utiliza întotdeauna o abstractizare de nivel superior, cum ar fi slf4j.

înainte de a muta unul, iată doar câțiva pași pe care îi puteți face pentru a îmbunătăți performanța de logare a sistemului:

  • reglați nivelul jurnalului aplicației pentru pachetele detaliate
  • evitați înregistrarea informațiilor despre locația sursei în timpul rulării, deoarece căutați firul curent, fișierul, o metodă este o operație costisitoare
  • evitați erorile de înregistrare cu urme lungi de stivă
  • verificați dacă un anumit nivel de jurnal este activat înainte de a scrie un mesaj cu acel nivel – în acest fel mesajul nu va fi construit dacă nu este necesar
  • revizuirea jurnalele înainte de a trece la producție pentru a verifica dacă orice logare pot fi eliminate

mențiuni de onoare

înainte de a încheia, să aruncați o privire la o practică finală pe care ar trebui să o evitați – și aceasta este utilizarea standard out în loc de logare.

În Timp Ce Sistemul.out () poate fi o modalitate rapidă de a începe foarte devreme în ciclul de dezvoltare, cu siguranță nu este o practică bună de urmat după acel punct.

pe lângă faptul că pierdeți toate caracteristicile puternice ale unui API dedicat de logare, acest dezavantaj principal aici este pur și simplu faptul că datele de logare nu vor fi persistate nicăieri.

în cele din urmă, o altă mențiune onorabilă este o practică care poate face citirea și analiza datelor din jurnal mult mai ușoară – mesaje de jurnal standardizate. Pur și simplu, evenimente similare ar trebui să aibă mesaje similare în jurnal.

dacă trebuie să căutați toate instanțele acelui eveniment sau să extrageți informații semnificative din datele dvs. de jurnal, mesajele de jurnal standard sunt destul de importante.

de exemplu, dacă o operațiune de încărcare eșuează – având aceste mesaje diferite în jurnal ar fi confuz:

Could not upload file picture.jpg
File upload picture.jpg failed.

în schimb, ori de câte ori încărcarea fișierului eșuează, ar trebui să utilizați în mod constant unul dintre aceste mesaje pentru a înregistra eșecul.

concluzie

utilizarea logării a devenit omniprezentă în dezvoltarea aplicațiilor, datorită informațiilor extrem de utile și acționabile pe care le aduce în timpul rulării sistemului.

cu toate acestea, pentru a profita la maximum de datele dvs. de jurnal, este important să treceți dincolo de elementele de bază, să dezvoltați o cultură a înregistrării și să înțelegeți punctele mai fine de operare cu aceste date la scară și în producție.

Lasă un răspuns

Adresa ta de email nu va fi publicată.