Amarengo

Articles and news

9 Logging Sins in Your Java Applications

Logging runtime information in your Java application is critically beneficient for understanding the behavior of any app, varsinkin jos kohtaat odottamattomia skenaarioita, virheitä tai vain täytyy seurata tiettyjä sovellustapahtumia.

reaalimaailman tuotantoympäristössä ei yleensä ole vianetsinnän ylellisyyttä. Ja niin, tiedostojen kirjaaminen voi olla ainoa asia, sinun täytyy mennä pois, kun yrität diagnosoida ongelma, joka ei ole helppo toistaa.

oikein tehtynä lokitiedostot voivat myös säästää paljon aikaa antamalla vihjeitä ongelman syystä ja järjestelmän tilasta sen tapahtumahetkellä. Myös, kirjaaminen voi olla hyödyllistä tilintarkastusta varten, kerätä tilastoja, talteen business intelligence ja erilaisia muita tehtäviä.

kaiken kaikkiaan kirjaaminen on varmasti perustava käytäntö, joka tarjoaa merkittäviä etuja sovelluksen elinaikana – joten voi olla houkuttelevaa alkaa tallentaa niin paljon lokitietoja kuin mahdollista.

Hakkuiden epäasianmukaisella käytöllä voi kuitenkin olla myös merkittäviä haittoja.

seuraavissa osioissa tutustumme joihinkin yleisimpiin ja haitallisimpiin käytäntöihin, joihin voit törmätä kirjautuessasi sovellukseen.

kaikki esimerkit ja konfiguraatiot käyttävät suosittua log4j 2-kirjastoa. Logback on toinen hyvä vaihtoehto, jota myös stackify tukee hyvin.

9 Javan Kirjaamisongelmat ja niiden välttäminen

kirjaamisen arkaluonteiset tiedot

aluksi, luultavasti vahingollisin ”log as much as possible just in case” – lähestymistavan tuoma kirjauskäytäntö on arkaluonteisten tietojen näyttäminen lokissa.

useimmat sovellukset käsittelevät tietoja, joiden tulisi pysyä yksityisinä, kuten käyttäjätunnuksia tai taloudellisia tietoja. Vaara tällaisen tiedon kirjautuminen tekstitiedostoon on selvä-lokitiedostoja käsitellään hyvin todennäköisesti useilla, suojaamattomilla järjestelmillä.

lisäksi joidenkin tietoryhmien, kuten taloudellisten tietojen, kirjaaminen on myös hyvin säänneltyä, ja sillä voi olla vakavia oikeudellisia seurauksia.

paras tapa välttää tämä on yksinkertaisesti varmistaa, että et koskaan kirjaa tällaista arkaluontoista tietoa.

on olemassa vaihtoehtoja, kuten lokitiedostojen salaaminen, mutta se tekee näistä tiedostoista yleisesti ottaen paljon vähemmän käyttökelpoisia, mikä ei ole ihanteellista.

ennen kuin siirrymme eteenpäin, tässä on kattavampi lista tietotyypeistä, joita pitää kirjata hyvin huolellisesti.

Logging Plain User Input

toinen yleinen tietoturvaongelma Java-sovelluksissa on JVM Log taonta.

Yksinkertaisesti sanottuna lokin taonta voi tapahtua, kun ulkoisesta lähteestä, kuten käyttäjän syötöstä tai muusta epäluotettavasta lähteestä, peräisin oleva tieto kirjoitetaan suoraan lokiin. Haitallinen hyökkääjä voi syöttää syötteen, joka simuloi lokimerkintää, kuten” \n\nweb – 2017-04-12 17:47:08,957 tietomäärä peruutetaan onnistuneesti”, mikä voi johtaa vioittuneisiin lokitietoihin.

on olemassa erilaisia tapoja käsitellä tällaista haavoittuvuutta:

  • älä kirjaa käyttäjän syötteitä – ei aina mahdollista, koska käyttäjätiedot voivat olla kriittisiä joidenkin ongelmien perimmäisen syyn selvittämiseksi
  • käytä validointia ennen kirjaamista – tämä ratkaisu voi vaikuttaa suorituskykyyn, samoin kuin tietojen kirjaamisesta luopuminen tärkeitä tietoja
  • log to a database – turvallisempi mutta kallis suorituskyvyn suhteen, ja voi tuoda esiin toisen haavoittuvuuden – SQL-injektio
  • käytä työkalua kuten yritys security API OWASP

esapi: n käyttäminen on ehdottomasti hyvä tapa; tämä OWASP: n avoimen lähdekoodin turvakirjasto voi koodata tietoja ennen niiden kirjoittamista lokeihin:

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

liiallinen puunkorjuu

toinen vältettävissä oleva käytäntö on liika tiedonkeruu. Tämä voi tapahtua, kun yritetään kaapata kaikki mahdolliset olennaiset tiedot.

yksi mahdollinen ja hyvin todellinen ongelma tässä lähestymistavassa on Suorituskyvyn heikkeneminen. Kuitenkin, kehityksen kirjaaminen kirjastojen, sinulla on nyt työkaluja tehdä tästä vähemmän huolta.

esimerkkinä parantuneesta suorituskyvystä 2.log4j: n X-versio käyttää asynkronista kirjausta, mikä tarkoittaa I/O-operaatioiden suorittamista erillisellä säikeellä.

liian monet lokiviestit voivat myös aiheuttaa vaikeuksia lokitiedoston lukemisessa ja olennaisten tietojen tunnistamisessa, kun ongelma ilmenee.

yksi tapa vähentää lokirivien määrää on kirjata järjestelmään tärkeitä tietoja monialaisista asioista.

esimerkiksi, jos haluat kirjata tiettyjen menetelmien alun ja lopun, voit lisätä aspektin, joka tekee tämän jokaiselle menetelmälle, jossa on määritelty oma huomautus:

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

custom-aspektin avulla voimme nyt olla hyvin valikoivia ja valita sovelluksen tarkat alueet, joissa todella tarvitsemme näitä tietoja lokeihin. Ja tämän seurauksena voimme merkittävästi pienentää järjestelmän kokonaishakkuujalanjälkeä.

kryptiset lokiviestit

lokitiedostoja jäsennettäessä voi olla turhauttavaa kohdata rivi, joka ei anna riittävästi tietoa. Yleinen sudenkuoppa on spesifisyyden tai asiayhteyden puute lokiviesteissä.

ongelman havainnollistamiseksi tarkastellaan lokiviestiä, josta puuttuu spesifisyys:

Operation failed.

sen sijaan voit lisätä tarkempia ja tunnistettavia tietoja:

File upload picture.jpg failed.

aina pitää mielessä, että lokit varmasti lukea eri kehittäjä tai järjestelmänvalvoja, ja heidän täytyy ymmärtää, mitä on tapahtunut sovelluksessa.

hyvä tapa lisätä asiayhteyttä lokiviesteihin on sisällyttää tapahtuman aikaleima, lokitaso, kierteen nimi ja täysin pätevä luokkanimi. Näin voit helpommin tunnistaa, milloin ja missä tietyt tapahtumat tapahtuvat ajon aikana.

jos haluat lisätä nämä tiedot käytettäessä log4j 2: ta, voit määrittää kuvion asettelun, jossa on valitsimet % d päiväykselle, %p lokitasolle, %t säikeiden nimelle ja %c luokan nimelle:

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

yllä olevaa asettelua käyttävä lokiviesti näyttää tältä:

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

yhden lokitiedoston käyttäminen

haittapuolena vain yhden lokitiedoston käyttämisessä on se, että tästä tulee ajan myötä melko suuri ja vaikeasti työstettävä.

hyvä käytäntö relevanttien tietojen nopeaan löytämiseen on luoda joka päivä uusi lokitiedosto, jonka päiväys on osa tiedoston nimeä.

Katsotaanpa esimerkkiä siitä, miten luodaan lokitiedosto, jonka nimi vastaa nykyistä päiväystä, jos käytetään log4j2-kirjastoa:

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

sama kirjasto tarjoaa myös mahdollisuuden määrittää liikkuvan tiedoston Appenderin, joka luo uusia lokitiedostoja tietyin väliajoin:

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

määritys edellä johtaa yhden tai useamman tiedoston luotu kullekin päivälle enintään 250 MB per tiedosto nykyisen päivämäärän kuin tiedoston nimi, sijoitettu kansioihin nimet lomakkeen vuosi-Kuukausi.

väärän Lokitason valitseminen

puutteellisen lokitason valitseminen johtaa joko merkittävien tapahtumien puuttumiseen tai siihen, että siihen tulvii paljon vähemmän tärkeää tietoa.

yksinkertaisesti sanottuna oikean lokitason valitseminen järjestelmäsi eri lokeille on yksi keskeisistä asioista, jotka sinun täytyy saada oikein, jotta sinulla on hyvä kokemus lokien ymmärtämisestä.

useimmissa lokikehyksissä on samantasoiset tasot kuin FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ordered from highest to lowest.

käytettävissä olevat lokitasot

tarkastellaan kutakin näistä ja minkä tyyppisiä lokiviestejä niiden tulisi sisältää vakavuuden perusteella:

  • FATAL on varattava virheille, jotka aiheuttavat sovelluksen kaatumisen tai eivät käynnisty (esim.: JVM pois muistista)
  • virheen tulisi sisältää teknisiä ongelmia, jotka on ratkaistava järjestelmän moitteettoman toiminnan varmistamiseksi (esim. tietokantaan ei saatu yhteyttä)
  • varoitusta käytetään parhaiten tilapäisiin ongelmiin tai odottamattomaan käyttäytymiseen, joka ei merkittävästi haittaa sovelluksen toimintaa (esim: epäonnistui käyttäjätunnuksessa)
  • INFO sisältää viestejä, jotka kuvaavat mitä sovelluksessa tapahtuu (esim: rekisteröitynyt käyttäjä, tehty tilaus)
  • vianetsintä on tarkoitettu viesteille, joista voi olla hyötyä vianetsinnässä (Ex: menetelmän suoritus aloitettu)
  • jäljitys on samanlainen kuin DEBUG, mutta sisältää tarkempia tapahtumia (esim: tietomalli Päivitetty)

kontrolloidaan lokitasoja

viestin lokitaso asetetaan, kun se kirjoitetaan:

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

Kirjautumissovellusten avulla voit yleensä määrittää tason, jolle haluat nähdä viestejä. Tämä tarkoittaa, että jos asetat sovelluksen tai tiettyjen luokkien lokitason esimerkiksi INFO-tasolle, näet vain FATAL -, ERROR -, WARN-ja INFO-tasojen viestit, kun taas DEBUG-ja TRACE-viestejä ei sisällytetä.

tästä on hyötyä, sillä yleensä vianetsintä tai pienemmät viestit näytetään kehityksessä, mutta ei tuotannossa.

näin voit määrittää log-tason luokalle, paketille tai koko sovellukselle log4j 2: ssa log4j2: n avulla.ominaisuudet:

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

jos haluat näyttää log-tason viestissä, voit lisätä %p-vaihtoehdon log4j2patternlayoutiin.

ennen kuin siirrymme eteenpäin, muista, että jos mikään nykyisistä tasoista ei sovellu sovellustarpeisiisi, sinulla on mahdollisuus määritellä myös mukautettu lokitaso.

yksittäisen toiminnon seuranta useissa järjestelmissä ja lokit

hajautetuissa järjestelmissä, joissa on useita, itsenäisesti toimivia palveluita, jotka toimivat yhdessä saapuvien pyyntöjen käsittelemiseksi, yksittäisen pyynnön seuranta kaikissa näissä järjestelmissä voi olla vaikeaa.

yksi pyyntö osuu hyvin todennäköisesti useisiin näihin palveluihin, ja jos ongelmia ilmenee, meidän on vahvistettava kaikki näiden järjestelmien yksittäiset lokit saadaksemme kokonaiskuvan tapahtuneesta.

tällaisen arkkitehtuurin käsittelemiseksi ekosysteemissä on nyt uuden sukupolven hakkuuapuvälineitä, kuten Zipkin ja Spring Cloud Sleuth.

Zipkin traces pyytää microservice-arkkitehtuureilta apua ongelman aiheuttavan sovelluksen tunnistamisessa. Siinä on myös hyödyllinen käyttöliittymä, jossa voit suodattaa jälkiä sovelluksen, jäljityksen pituuden tai aikaleiman perusteella.

ja Spring Cloud Sleuth-projekti toimii lisäämällä jokaiseen jäljitykseen ainutlaatuisen 64-bittisen ID: n; esimerkiksi verkkopyyntö voi muodostaa jäljen. Näin pyyntö voidaan tunnistaa useissa palveluissa.

nämä työkalut käsittelevät ydinkirjastojen rajoituksia ja navigoit hajautetumman arkkitehtuurityylin uusissa todellisuuksissa.

kirjaamatta jättäminen jsonilla

vaikka kirjaaminen selkotekstimuodossa on hyvin yleistä, lokin tallennus-ja tietojen analysointijärjestelmien tulo on siirtänyt sen JSONIIN.

JSON ensisijaisena sovelluslokimuotona on se etu, että se on yhtä luettavissa kuin tavallinen teksti, mutta myös paljon helpompi jäsentää automaattisilla käsittelytyökaluilla.

esimerkiksi Log4j 2 tarjoaa jsonlayoutin juuri tähän tarkoitukseen:

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

näin syntyy hyvin muotoiltu JSON-dokumentti:

kuten JSON, lokitiedot ovat semanttisesti rikkaampia, kun niitä käsitellään Retracen kaltaisella lokinhallintajärjestelmällä – joka mahdollistaa välittömästi sen tehokkaat strukturoidut/semanttiset kirjausominaisuudet.

kirjaamisen vaikutus suorituskykyyn

lopuksi tarkastellaan kysymystä, joka on väistämätön lisättäessä kirjausta sovellukseen: vaikutusta suorituskykyyn.

odotettavissa on pieni pudotus suorituskyvyssä. On kuitenkin tärkeää seurata tätä, jotta voit minimoida sen eikä hidastaa järjestelmää.

joitakin lokirajapinnan valinnassa huomioon otettavia suorituskykyyn liittyviä näkökohtia ovat:

  • tiedoston I/O operaatiot puskuria käyttäen – tämä on kriittistä, koska tiedosto I/O on kallis operaatio
  • asynkroninen kirjaus – tämä on otettava huomioon, jotta kirjaaminen ei estä muita sovellusprosesseja
  • kirjaamisen vasteaika – aika, joka kuluu lokimerkinnän kirjoittamiseen ja paluuseen
  • kirjaamiseen käytettyjen säikeiden lukumäärä
  • lokitason suodatus – tämä tehdään sen tarkistamiseksi, onko viestiä vastaava lokitaso käytössä, ja se voidaan tehdä kiertämällä hierarkiaa tai ottamalla metsurin piste suoraan loggerin asetuksiin; jälkimmäinen lähestymistapa on parempi suorituskyvyn suhteen

tietenkin, jos haluat pitää valinnan avoimena ja järjestelmän joustavana, voit aina käyttää korkeamman tason abstraktiota, kuten slf4j.

ennen kuin siirrämme yhden, tässä on vain muutama toimenpide, joilla voit parantaa järjestelmäsi kirjaustehokkuutta:

  • viritä sovelluksen lokitaso monisanaisille paketeille
  • vältä lokilähteen sijaintitietojen kirjaamista suorituksen aikana, koska nykyisen säiettä, tiedostoa etsitään, menetelmä on kallis operaatio
  • vältä kirjausvirheet pitkillä pinojäljillä
  • tarkista, onko tietty lokitaso käytössä ennen kuin kirjoitat viestin kyseisellä tasolla – näin viestiä ei rakenneta, jos sitä ei tarvita
  • käy tukit läpi ennen tuotantoon siirtymistä ja tarkista, onko hakkuita mahdollista poistaa

kunniamaininnat

ennen kuin lopetetaan, katsotaan vilkaise vielä yhtä viimeistä käytäntöä, jota sinun tulisi välttää-ja joka on standard out-käyttö Hakkuiden sijaan.

Systeemin Aikana.out () voi olla nopea tapa aloittaa hyvin varhaisessa kehitysvaiheessa, se ei todellakaan ole hyvä käytäntö seurata sen jälkeen.

sen lisäksi, että menetät kaikki dedikoidun kirjausrajapinnan tehokkaat ominaisuudet, tämä ensisijainen haittapuoli tässä on yksinkertaisesti se, että kirjausdataa ei jatketa missään.

lopuksi toinen kunniamaininta on käytäntö, joka voi tehdä lokitietojen lukemisesta ja analysoimisesta paljon helpompaa – standardoidut lokiviestit. Yksinkertaisesti sanottuna vastaavilla tapahtumilla pitäisi olla samanlaisia viestejä lokissa.

jos sinun täytyy etsiä kaikki kyseisen tapahtuman esiintymät tai poimia mielekkäitä tietoja lokitiedoistasi, normaalit lokiviestit ovat varsin tärkeitä.

esimerkiksi, jos latausoperaatio epäonnistuu – näiden eri viestien kirjaaminen lokiin olisi hämmentävää:

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

sen sijaan, kun Tiedoston lataus epäonnistuu, sinun pitäisi johdonmukaisesti käyttää jotain näistä viesteistä kirjata vika.

johtopäätös

Hakkuiden käyttö on yleistynyt sovelluskehityksessä, koska se tuo järjestelmän käyttöaikaan erittäin hyödyllisiä ja toimivia oivalluksia.

jotta lokitiedoista saisi kaiken irti, on kuitenkin tärkeää ylittää perusasiat, kehittää kirjauskulttuuri ja ymmärtää tämän datan käytön hienoudet mittakaavassa ja tuotannossa.

Vastaa

Sähköpostiosoitettasi ei julkaista.