JavaRush /Java Blog /Random-TL /Pag-log in sa Java: ano, paano, saan at ano?

Pag-log in sa Java: ano, paano, saan at ano?

Nai-publish sa grupo
Kumusta sa lahat, komunidad ng JavaRush! Ngayon ay pag-uusapan natin ang tungkol sa pag-log ng Java:
  1. Ano ba yan, bakit ganun. Sa anong mga kaso ito ay mas mahusay na gamitin, sa anong mga kaso ito ay hindi?
  2. Ano ang iba't ibang pagpapatupad ng pag-log sa Java at ano ang dapat nating gawin sa pagkakaiba-iba na ito?
  3. Mga antas ng pag-log. Talakayin natin kung ano ang appender at kung paano ito i-configure nang tama.
  4. Pag-log node at kung paano i-configure ang mga ito nang tama upang ang lahat ay gumana sa paraang gusto namin.
Ang materyal na ito ay inilaan para sa isang malawak na madla. Magiging malinaw ito kapwa sa mga kakakilala pa lang sa Java, at sa mga nagtatrabaho na, ngunit naisip lamang ito sa logger.info(“log something”); Let's Go!

Bakit kailangan ang pag-log?

Tingnan natin ang mga totoong kaso kung saan malulutas ng pag-log ang problema. Narito ang isang halimbawa mula sa aking trabaho. May mga application point na sumasama sa iba pang mga serbisyo. Gumagamit ako ng pag-log ng mga puntong ito bilang isang "alibi" : kung hindi gagana ang pagsasama, magiging madaling malaman kung saang panig nagmula ang problema. Maipapayo rin na mag-log ng mahalagang impormasyon na naka-save sa database. Halimbawa, ang paggawa ng administrator user. Ito ay eksakto kung ano ang magandang i-log.

Mga Tool sa Pag-log ng Java

Pag-log: ano, paano, saan at ano?  - 2Ang mga kilalang solusyon para sa pag-log in sa Java ay kinabibilangan ng:
  • log4j
  • JUL - java.util.logging
  • JCL - jakarta commons logging
  • Logback
  • SLF4J - simpleng pag-log facade para sa java
Tingnan natin ang bawat isa sa kanila, at sa praktikal na bahagi ng materyal ay gagawin natin ang koneksyon na Slf4j - log4j bilang batayan . Ito ay maaaring mukhang kakaiba ngayon, ngunit huwag mag-alala: sa pagtatapos ng artikulo ang lahat ay magiging malinaw.

System.err.println

Sa una, siyempre, mayroong System.err.println (record output sa console). Ginagamit pa rin ito para mabilis na makakuha ng log habang nagde-debug. Siyempre, hindi na kailangang pag-usapan ang anumang mga setting dito, kaya tandaan na lang natin ito at magpatuloy.

Log4j

Ito ay isa nang ganap na solusyon, na nilikha mula sa mga pangangailangan ng mga developer. Ito ay naging isang talagang kawili-wiling tool upang gamitin. Dahil sa iba't ibang pagkakataon, hindi nakapasok ang solusyong ito sa JDK, na labis na ikinagagalit ng buong komunidad. Ang log4j ay may mga opsyon sa pagsasaayos upang ang pag-log ay mai-on sa isang pakete com.example.typeat i-off sa isang subpackage com.example.type.generic. Ginawa nitong posible na mabilis na paghiwalayin ang kailangang i-log mula sa hindi kailangan. Mahalagang tandaan dito na mayroong dalawang bersyon ng log4j: 1.2.x at 2.x.x, na hindi tugma sa isa't isa . Nagdagdag si log4j ng ganitong konsepto bilang appender , iyon ay, isang tool kung saan naitala ang mga log at layout - pag-format ng log. Nagbibigay-daan ito sa iyo na i-record lamang ang kailangan mo at kung paano mo ito kailangan. Pag-uusapan natin ang higit pa tungkol sa appender mamaya.

JUL - java.util.logging

Isa sa mga pangunahing bentahe ay ang solusyon - ang JUL ay kasama sa JDK (Java development kit). Sa kasamaang palad, sa panahon ng pagbuo nito, hindi ang sikat na log4j ang kinuha bilang batayan, ngunit isang solusyon mula sa IBM, na nakaimpluwensya sa pag-unlad nito. Sa katunayan, sa sandaling ito ay may JUL, ngunit walang gumagamit nito. Mula sa "so-so": sa JUL ang mga antas ng pag-log ay iba sa kung ano ang nasa Logback, Log4j, Slf4j, at pinalala nito ang pagkakaunawaan sa pagitan nila. Ang paggawa ng isang logger ay halos magkapareho. Upang gawin ito kailangan mong mag-import:
java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Ang pangalan ng klase ay partikular na ipinasa upang malaman kung saan nanggagaling ang pag-log. Dahil ang Java 8, posibleng ipasa ang Supplier<String>. Nakakatulong ito upang mabilang at lumikha ng isang string lamang sa sandaling ito ay talagang kailangan, at hindi sa lahat ng oras, tulad ng dati. Sa paglabas lamang ng Java 8 nalutas ng mga developer ang mahahalagang problema, pagkatapos ay tunay na nagagamit ang JUL. Ibig sabihin, ang mga pamamaraan na may argumento Supplier<String> msgSuppliertulad ng ipinapakita sa ibaba:
public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL - jakarta commons logging

Dahil sa katotohanan na sa mahabang panahon ay walang pamantayan sa industriya sa pag-log at nagkaroon ng panahon na maraming tao ang lumikha ng kanilang sariling custom na logger, nagpasya silang ilabas ang JCL - isang karaniwang wrapper na gagamitin sa iba. Bakit? Kapag naidagdag ang ilang dependency sa proyekto, maaari silang gumamit ng ibang logger kaysa sa logger sa proyekto. Dahil dito, idinagdag sila nang palipat-lipat sa proyekto, na lumikha ng mga tunay na problema kapag sinusubukang pagsamahin ang lahat. Sa kasamaang palad, ang wrapper ay napakahina sa pag-andar at hindi nagpakilala ng anumang mga karagdagan. Malamang na magiging maginhawa kung ang lahat ay gumamit ng JCL upang gawin ang kanilang trabaho. Ngunit sa katotohanan ay hindi ito gumana sa ganoong paraan, kaya ang paggamit ng JCL ay hindi magandang ideya sa ngayon.

Logback

Gaano kahirap ang landas ng open-source... Ang Logback ay isinulat ng parehong developer bilang log4j upang lumikha ng kahalili dito. Ang ideya ay pareho sa log4j. Ang mga pagkakaiba ay sa pag-logback:
  • pinahusay na pagganap;
  • nagdagdag ng katutubong suporta para sa slf4j;
  • Ang opsyon sa pag-filter ay pinalawak.
Bilang default, ang pag-logback ay hindi nangangailangan ng anumang mga setting at itinatala ang lahat ng mga log mula sa antas ng DEBUG at mas mataas. Kung kailangan ang configuration, maaari itong gawin sa pamamagitan ng xml configuration:
<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>app.log</file>
        <encoder>
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" />
    <root level="info">
        <appender-ref ref="FILE" />
    </root>
</configuration>

SLF4J - simpleng pag-log facade para sa java

Noong 2006, isa sa mga founding father ng log4j ang umalis sa proyekto at lumikha ng slf4j - Simple Logging Facade para sa Java - isang wrapper sa paligid ng log4j, JUL, common-loggins at logback. Tulad ng nakikita mo, ang pag-unlad ay umabot sa punto na gumawa sila ng isang wrapper sa ibabaw ng wrapper... Bukod dito, nahahati ito sa dalawang bahagi: ang API, na ginagamit sa application, at ang pagpapatupad, na idinagdag bilang hiwalay na mga dependency para sa bawat uri ng pag-log. Halimbawa, slf4j-log4j12.jar, slf4j-jdk14.jar. Ito ay sapat na upang ikonekta ang tamang pagpapatupad at iyon lang: ang buong proyekto ay gagana dito. Sinusuportahan ng Slf4j ang lahat ng mga bagong tampok tulad ng pag-format ng string para sa pag-log. May ganyang problema noon. Sabihin nating mayroong isang log entry:
log.debug("User " + user + " connected from " + request.getRemoteAddr());
userMayroong implicit na conversion sa object user.toString()dahil sa string concatenation, at nangangailangan ito ng oras, na nagpapabagal sa system. At lahat ay ok kung i-debug natin ang application. Magsisimula ang mga problema kung ang antas ng pag-log para sa klase na ito ay INFO at mas mataas. Ibig sabihin, hindi dapat isulat ang log na ito, at hindi rin dapat isagawa ang string concatenation. Sa teorya, ito ay dapat na napagpasyahan ng logging library mismo. Bukod dito, ito ang naging pinakamalaking problema ng unang bersyon ng log4j. Hindi sila naghatid ng isang normal na solusyon, ngunit iminungkahi na gawin ito tulad nito:
if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Iyon ay, sa halip na isang linya ng pag-log, iminungkahi nila ang pagsulat ng 3(!). Ang pag-log ay dapat mabawasan ang mga pagbabago sa code, at ang tatlong linya ay malinaw na sumasalungat sa pangkalahatang diskarte. Ang slf4j ay walang mga problema sa compatibility sa JDK at API, kaya isang magandang solusyon ang agad na lumitaw:
log.debug("User {} connected from {}", user, request.getRemoteAddr());
kung saan {}nagsasaad ng mga pagpapasok ng mga argumento na ipinasa sa pamamaraan. Iyon ay, ang una {}ay tumutugma sa user, ang pangalawa {}- request.getRemoteAddr(). Dahil dito, kung pinapayagan lamang ng antas ng pag-log ang pag-log, ang mensaheng ito ay maaaring pagsamahin sa iisang isa. Pagkatapos nito, mabilis na sumikat ang SJF4J at kasalukuyang ang pinakamahusay na solusyon. Samakatuwid, isasaalang-alang namin ang pag-log gamit ang halimbawa ng isang bundle slf4j-log4j12.

Ano ang kailangang i-log

Siyempre, hindi mo dapat i-log ang lahat. Minsan ito ay hindi kailangan at mapanganib pa nga. Halimbawa, kung ipinangako mo ang personal na data ng isang tao at sa paanuman ay nalaman, magkakaroon ng mga tunay na problema, lalo na sa mga proyektong nakatuon sa Kanluran. Ngunit mayroon ding isang bagay na ipinag-uutos na mag-log :
  1. Pagsisimula/pagtatapos ng aplikasyon. Kailangan nating malaman na ang application ay aktwal na inilunsad tulad ng inaasahan namin at natapos tulad ng inaasahan.
  2. Mga tanong sa seguridad. Dito, mainam na mag-log ng mga pagtatangka sa paghula ng password, pag-log in ng mga mahahalagang user, atbp.
  3. Ang ilang mga estado ng aplikasyon . Halimbawa, ang paglipat mula sa isang estado patungo sa isa pa sa isang proseso ng negosyo.
  4. Ilang impormasyon para sa pag-debug , na may naaangkop na antas ng pag-log.
  5. Ilang SQL script. May mga totoong kaso kung kailan ito kinakailangan. Muli, sa pamamagitan ng mahusay na pagsasaayos ng mga antas, mahusay na mga resulta ay maaaring makamit.
  6. Maaaring mai-log ang mga naisagawang thread (Thread) sa mga kaso kung saan nasuri ang tamang operasyon.

Mga sikat na pagkakamali sa pag-log

Mayroong maraming mga nuances, ngunit narito ang ilang mga karaniwang pagkakamali:
  1. Labis na pag-log. Hindi mo dapat i-log ang bawat hakbang na maaaring maging mahalaga sa teorya. Mayroong isang panuntunan: ang mga log ay maaaring mag-load ng pagganap ng hindi hihigit sa 10%. Kung hindi, magkakaroon ng mga problema sa pagganap.
  2. Pag-log sa lahat ng data sa isang file. Ito ay magpapahirap sa pagbabasa/pagsusulat dito sa isang tiyak na punto, hindi sa banggitin na may mga limitasyon sa laki ng file sa ilang mga system.
  3. Paggamit ng mga maling antas ng pag-log. Ang bawat antas ng pag-log ay may malinaw na mga hangganan at dapat igalang. Kung malabo ang hangganan, maaari kang sumang-ayon sa kung aling antas ang gagamitin.

Mga antas ng pag-log

x: Nakikita
FATAL ERROR BALAAN IMPORMASYON DEBUG TRACE LAHAT
NAKA-OFF
FATAL x
ERROR x x
BALAAN x x x
IMPORMASYON x x x x
DEBUG x x x x x
TRACE x x x x x x
LAHAT x x x x x x x
Ano ang mga antas ng pag-log? Upang kahit papaano ay mai-rank ang mga log, kinakailangan na magbigay ng ilang mga pagtatalaga at pagkakaiba. Para sa layuning ito, ipinakilala ang mga antas ng pag-log. Ang antas ay nakatakda sa application. Kung ang isang entry ay kabilang sa isang antas sa ibaba ng itinalaga, hindi ito ipinasok sa log. Halimbawa, mayroon kaming mga log na ginagamit upang i-debug ang application. Sa normal na gawain sa produksyon (kapag ginamit ang aplikasyon para sa nilalayon nitong layunin), hindi kailangan ang mga naturang log. Samakatuwid, ang antas ng pag-log ay magiging mas mataas kaysa sa pag-debug. Tingnan natin ang mga antas gamit ang log4j bilang isang halimbawa. Ang ibang mga solusyon, maliban sa JUL, ay gumagamit ng parehong mga antas. Narito ang mga ito sa pababang pagkakasunud-sunod:
  • OFF: walang mga log na nakasulat, lahat ay hindi papansinin;
  • FATAL: isang error pagkatapos kung saan ang application ay hindi na gagana at ititigil, halimbawa, JVM out of memory error;
  • ERROR: Ang rate ng error kapag may mga problemang kailangang lutasin. Ang error ay hindi huminto sa application sa kabuuan. Maaaring gumana nang tama ang iba pang mga query;
  • WARN: Isinasaad ang mga log na naglalaman ng babala. Isang hindi inaasahang aksyon ang naganap, sa kabila nito ay nilabanan ng system at nakumpleto ang kahilingan;
  • INFO: isang log na nagtatala ng mahahalagang aksyon sa application. Ang mga ito ay hindi mga pagkakamali, ang mga ito ay hindi mga babala, ito ay mga inaasahang aksyon ng system;
  • DEBUG: kailangan ng mga log para i-debug ang application. Upang matiyak na ginagawa ng system ang eksaktong inaasahan dito, o upang ilarawan ang pagkilos ng system: "nagsimulang gumana ang pamamaraan1";
  • TRACE: mas mababang priyoridad na mga log para sa pag-debug, na may pinakamababang antas ng pag-log;
  • LAHAT: antas kung saan ire-record ang lahat ng log mula sa system.
Ito ay lumalabas na kung ang INFO logging level ay pinagana sa ilang lugar sa application, lahat ng antas ay mai-log, simula sa INFO at hanggang sa FATAL. Kung ang antas ng pag-log ay FATAL, ang mga log lamang na may ganitong antas ang itatala.

Pagre-record at pagpapadala ng mga log: Appender

Isasaalang-alang namin ang prosesong ito gamit ang log4j bilang isang halimbawa: nagbibigay ito ng maraming pagkakataon para sa pag-record/pagpapadala ng mga log:
  • para sa pagsulat sa isang file - solusyon DailyRollingFileAppender ;
  • upang makatanggap ng data sa application console - ConsoleAppender ;
  • upang magsulat ng mga log sa database - JDBCAppender ;
  • upang kontrolin ang paghahatid sa pamamagitan ng TCP/IP - TelnetAppender ;
  • upang matiyak na ang pag-log ay hindi makakaapekto sa pagganap - AsyncAppender .
Mayroong ilang iba pang mga pagpapatupad: ang buong listahan ay matatagpuan dito . Sa pamamagitan ng paraan, kung ang kinakailangang appender ay hindi magagamit, ito ay hindi isang problema. Maaari mong isulat ang iyong sariling appender sa pamamagitan ng pagpapatupad ng Appender interface , na tumatanggap lang ng log4j.

Pag-log node

Para sa pagpapakita ay gagamitin namin ang slf4j interface, at ang pagpapatupad mula sa log4j. Ang paglikha ng isang logger ay napaka-simple: kailangan mong isulat ang sumusunod sa isang klase na pinangalanang MainDemo, kung saan gagawin ang pag-log:
org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Ito ay lilikha ng isang logger para sa amin. Upang gumawa ng isang log entry, maaari kang gumamit ng maraming mga pamamaraan na nagpapahiwatig kung anong antas ang gagawin ng mga entry. Halimbawa:
logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find log4j.properties. Please, provide them");
logger.error("Connection refused to host = {}", host);
Kahit na pumasa kami sa klase, sa huli ito ang buong pangalan ng klase na may mga pakete na nakasulat. Ginagawa ito upang maaari mong hatiin ang pag-log sa mga node, at i-configure ang isang antas ng pag-log at isang appender para sa bawat node. Halimbawa, ang pangalan ng klase: com.github.romankh3.logginglecture.MainDemo- isang logger ang nilikha sa loob nito. At ito ay kung paano ito mahahati sa mga logging node. Ang pangunahing node ay ang null RootLogger . Ito ang node na tumatanggap ng lahat ng mga log ng buong application. Ang natitira ay maaaring ilarawan tulad ng ipinapakita sa ibaba: Pag-log: ano, paano, saan at ano?  - 4Kino-configure ng mga appenders ang kanilang trabaho partikular sa mga logging node. Ngayon, gamit ang log4j.properties bilang isang halimbawa , titingnan natin kung paano i-configure ang mga ito.

Hakbang-hakbang na pagsasaayos ng Log4j.properties

Ngayon ay ise-set up namin ang lahat ng hakbang-hakbang at tingnan kung ano ang maaaring gawin:
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Sinasabi ng linyang ito na nagrerehistro kami ng CONSOLE appender na gumagamit ng org.apache.log4j.ConsoleAppender na pagpapatupad. Ang appender na ito ay nagsusulat ng data sa console. Susunod, magrehistro tayo ng isa pang appender na magsusulat sa isang file:
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Mahalagang tandaan na ang mga appenders ay kailangan pa ring i-configure. Kapag mayroon na kaming mga nakarehistrong appenders, matutukoy namin kung anong antas ng pag-log ang magiging sa mga node at kung aling mga appender ang gagamitin.

log4j.rootLogger=DEBUG, CONSOLE, FILE

  • Ang ibig sabihin ng log4j.rootLogger ay iko-configure namin ang pangunahing node, na naglalaman ng lahat ng mga log;
  • pagkatapos ng pantay na tanda, ang unang salita ay nagpapahiwatig sa kung anong antas at mas mataas ang mga log ay itatala (sa aming kaso, ito ay DEBUG);
  • pagkatapos ay pagkatapos ng kuwit ang lahat ng mga appenders na gagamitin ay ipinahiwatig.
Upang i-configure ang isang partikular na logging node, kailangan mong gamitin ang sumusunod na entry:
log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
kung saan log4j.logger.ito ay ginagamit upang i-configure ang isang tiyak na node, sa aming kaso ito ay com.github.romankh3.logginglecture. At ngayon pag-usapan natin ang tungkol sa pag-set up ng CONSOLE appender:
# CONSOLE appender customisation
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Dito makikita natin na maaari nating itakda ang antas kung saan magpoproseso ang appender. Tunay na sitwasyon: ang isang mensahe na may antas ng impormasyon ay natanggap ng logging node at ipinasa sa appender na nakatalaga dito, ngunit ang appender, na may antas ng babala at mas mataas, ay tinanggap ang log na ito, ngunit walang ginawa dito. Susunod, kailangan mong magpasya kung anong template ang nasa mensahe. Gumagamit ako ng PatternLayout sa halimbawa, ngunit mayroong maraming mga solusyon doon. Hindi sila ibubunyag sa artikulong ito. Isang halimbawa ng pag-set up ng FILE appender:
# File appender customisation
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Dito maaari mong i-configure kung saang file isusulat ang mga log, gaya ng makikita mula sa
log4j.appender.FILE.File=./target/logging/logging.log
Ang pag-record ay napupunta sa file logging.log. Upang maiwasan ang mga problema sa laki ng file, maaari mong itakda ang maximum: sa kasong ito, 1MB. MaxBackupIndex - nagsasabi kung gaano karaming mga file ang magkakaroon. Kung higit pa sa numerong ito ang nagawa, ang unang file ay tatanggalin. Upang tingnan ang isang tunay na halimbawa kung saan naka-configure ang pag-log, maaari kang pumunta sa bukas na imbakan sa GitHub.

Pagsamahin natin ang resulta

Subukang gawin ang lahat ng inilarawan sa iyong sarili:
  • Lumikha ng iyong sariling proyekto katulad ng isa sa halimbawa sa itaas.
  • Kung mayroon kang kaalaman sa paggamit ng Maven, gagamitin namin ito; kung hindi, narito ang isang link sa isang artikulo na naglalarawan kung paano ikonekta ang library.

Isa-isahin natin

  1. Napag-usapan namin kung anong mga solusyon ang mayroon sa Java.
  2. Halos lahat ng kilalang logging library ay isinulat sa ilalim ng kontrol ng isang tao :D
  3. Natutunan namin kung ano ang kailangang i-log at kung ano ang hindi.
  4. Nalaman namin ang mga antas ng pag-log.
  5. Nakilala namin ang mga logging node.
  6. Tiningnan namin kung para saan ang appender at para saan ito.
  7. Na-configure namin ang log4j.proteties file nang sunud-sunod.

Mga karagdagang materyales

  1. JavaRush: Pag-log. I-unwind ang isang bola ng stectrace
  2. JavaRush: Magtala ng panayam
  3. Habr: Java logging. Hello mundo
  4. Habr: Java logging: ang kwento ng isang bangungot
  5. Youtube: Mga kurso sa Golovach. Pagtotroso. Bahagi 1 , Bahagi 2 , Bahagi 3 , Bahagi 4
  6. Log4j: dugtong
  7. Log4j: layout
Tingnan din ang aking iba pang mga artikulo:
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION