Plynulá ťažba dreva Flogger

1. Prehľad

V tomto tutoriáli si povieme niečo o Flogger frameworke, plynulom logovaní API pre Java navrhnutom spoločnosťou Google.

2. Prečo používať Flogger?

Prečo potrebujeme so sebou ešte jeden framework na protokolovanie, ktorý je momentálne na trhu, ako sú Log4j a Logback?

Ukázalo sa, že Flogger má oproti iným rámcom niekoľko výhod - poďme sa na to pozrieť.

2.1. Čitateľnosť

Plynulá povaha Floggerovho rozhrania API prispieva k lepšej čitateľnosti.

Pozrime sa na príklad, keď chceme správu prihlásiť každých desať iterácií.

Pri tradičnom rámci ťažby dreva by sme videli niečo ako:

int i = 0; // ... if (i% 10 == 0) {logger.info ("Tento protokol zobrazuje každých 10 iterácií"); i ++; }

Ale teraz, s Floggerom, sa dá vyššie uvedené zjednodušiť na:

logger.atInfo (). every (10) .log ("Tento protokol zobrazuje každých 10 iterácií");

Aj keď by sa dalo tvrdiť, že verzia záznamu nástroja Flogger vyzerá o niečo podrobnejšie ako tradičné verzie, umožňuje vyššiu funkčnosť a v konečnom dôsledku vedie k čitateľnejším a výraznejším výpisom z denníka.

2.2. Výkon

Protokolovanie objektov je optimalizované, pokiaľ sa vyhýbame volaniu natiahnuť na prihlásených objektoch:

User user = new User (); logger.atInfo (). log ("Užívateľ je:% s", užívateľ);

Ak sa prihlásime, ako je uvedené vyššie, back-end má možnosť optimalizovať protokolovanie. Na druhej strane, ak zavoláme natiahnuť priamo alebo zreťaziť reťazce, potom sa táto príležitosť stratí:

logger.atInfo (). log ("Tento užívateľ je:% s", user.toString ()); logger.atInfo (). log ("Tento užívateľ je:% s" + užívateľ);

2.3. Rozšíriteľnosť

Rámec Flogger už pokrýva väčšinu základných funkcií, ktoré by sme od rámca protokolovania očakávali.

Existujú však prípady, kedy by sme museli túto funkcionalitu doplniť. V týchto prípadoch je možné rozšíriť API.

V súčasnosti to vyžaduje samostatnú podpornú triedu. Mohli by sme napríklad rozšíriť Flogger API napísaním a UserLogger trieda:

logger.at (INFO) .forUserId (id) .wSUsername (meno používateľa) .log ("Správa:% s", param);

To by mohlo byť užitočné v prípadoch, keď chceme správu dôsledne formátovať. The UserLogger by potom poskytla implementáciu pre vlastné metódy forUserId (ID reťazca) a withUsername (String username).

Urobiť toto, the UserLogger triedy bude musieť predĺžiť AbstractLogger triedy a zabezpečiť implementáciu pre API. Ak sa pozrieme na FluentLogger, je to iba záznamník bez ďalších metód, môžeme preto Začnite skopírovaním tejto triedy tak, ako je, a potom vytvorte tento základ pridaním metód.

2.4. Účinnosť

Tradičné rámce vo veľkej miere využívajú varargy. Tieto metódy si vyžadujú nový Objekt [] alokovať a vyplniť skôr, ako sa dá metóda vyvolať. Všetky základné zadané typy musia byť navyše automaticky označené.

To všetko stojí ďalšie bajtkódy a latencia na mieste hovoru. Je to obzvlášť poľutovaniahodné ak výpis z protokolu nie je skutočne povolený. Cena sa stáva zrejmejšou v protokoloch na úrovni ladenia, ktoré sa často objavujú v slučkách. Flogger sa týchto nákladov zbavuje tým, že sa úplne vyhne varargom.

Flogger tento problém obchádza využitím plynulého reťazca hovorov, z ktorého je možné zostaviť protokolovacie príkazy. To umožňuje, aby rámec mal iba malý počet prepísaní protokolu log metódou, a teda byť schopný vyhnúť sa veciam, ako sú varargy a automatický box. To znamená, že API môže obsahovať rôzne nové funkcie bez kombinatorickej explózie.

Typický rámec protokolovania by mal tieto metódy:

úroveň (reťazec, objekt) úroveň (reťazec, objekt ...)

kde úrovni môže byť jeden z približne siedmich mien na úrovni protokolu (ťažké napríklad), ako aj mať metódu kanonického protokolu, ktorá akceptuje ďalšiu úroveň protokolu:

denník (úroveň, objekt ...)

Okrem toho zvyčajne existujú varianty metód, ktoré majú príčinu (a Hoditeľné inštancia), ktorá je spojená s príkazom log:

úroveň (Throwable, String, Object) úroveň (Throwable, String, Object ...)

Je zrejmé, že API spája tri záujmy do jedného volania metódy:

  1. Pokúša sa určiť úroveň protokolu (výber metódy)
  2. Pokúšam sa pripojiť metaúdaje k výpisu z denníka (Hádzateľné príčina)
  3. A tiež uvedenie správy a argumentov protokolu.

Tento prístup rýchlo znásobuje počet rôznych metód protokolovania potrebných na uspokojenie týchto nezávislých záujmov.

Teraz vidíme, prečo je dôležité mať v reťazci dve metódy:

logger.atInfo (). withCause (e) .log ("Správa:% s", arg);

Poďme sa teraz pozrieť na to, ako to môžeme použiť v našej kódovej základni.

3. Závislosti

Nastavenie Floggeru je celkom jednoduché. Musíme len dodať šibač a flogger-system-backend k nášmu pom:

  com.google.flogger flogger 0.4 com.google.flogger flogger-system-backend 0.4 runtime 

Po nastavení týchto závislostí teraz môžeme pokračovať v skúmaní API, ktoré máme k dispozícii.

4. Skúmanie Fluent API

Najskôr vyhlásime a statický napríklad pre náš záznamník:

súkromný statický konečný záznamník údajov FluentLogger = FluentLogger.forEnclosingClass ();

A teraz môžeme začať s prihlásením. Začneme niečím jednoduchým:

int výsledok = 45/3; logger.atInfo (). log ("Výsledok je% d", výsledok);

Správy v denníku môžu používať ktorýkoľvek z jazykov Java printf špecifikátory formátu, ako napr %SD alebo % 016x.

4.1. Vyhýbajte sa práci na stránkach protokolu

Tvorcovia programu Flogger odporúčajú, aby sme sa vyhli práci na stránkach denníka.

Povedzme, že máme nasledujúcu dlhodobú metódu na zhrnutie súčasného stavu komponentu:

public static String collectSummaries () {longRunningProcess (); int položky = 110; int s = 30; return String.format ("% d doposiaľ uplynulo.% d položiek čakajúcich na spracovanie", s, položky); }

Je lákavé zavolať collectSummaries priamo v našom výpise z denníka:

logger.atFine (). log ("statistics =% s", collectSummaries ());

Bez ohľadu na nakonfigurované úrovne protokolu alebo rýchlosť obmedzujúcu však collectSummaries metóda bude teraz volaná zakaždým.

V jadre rámca protokolovania je dosiahnutie toho, aby náklady na vyhlásenia so zakázaným protokolovaním boli skutočne bezplatné. To zase znamená, že viac z nich môže zostať neporušených v kóde bez poškodenia. Písanie výpisu z denníka, ako sme to robili práve teraz, túto výhodu berie.

Namiesto toho by sme mali použiť LazyArgs.lazy metóda:

logger.atFine (). log ("statistics =% s", LazyArgs.lazy (() -> collectSummaries ()));

Teraz sa na stránke denníka takmer nijako nepracuje Iba vytvorenie inštancie pre výraz lambda. Flogger vyhodnotí túto lambdu, iba ak má v úmysle správu skutočne prihlásiť.

Aj keď je povolené strážiť výpisy z denníka pomocou je umožnené:

if (logger.atFine (). isEnabled ()) {logger.atFine (). log ("summaries =% s", collectSummaries ()); }

To nie je potrebné a mali by sme sa tomu vyhnúť, pretože tieto kontroly za nás robí Flogger. Tento prístup tiež stráži iba protokolové vyhlásenia podľa úrovne a nepomáha pri protokolových výpisoch s obmedzenou rýchlosťou.

4.2. Riešenie výnimiek

Čo tak výnimky, ako ich zvládneme?

Flogger prichádza s withStackTrace metóda, ktorú môžeme použiť na prihlásenie a Hoditeľné inštancia:

skúsiť {int výsledok = 45/0; } catch (RuntimeException re) {logger.atInfo (). withStackTrace (StackSize.FULL) .withCause (re) .log ("Správa"); }

Kde withStackTrace berie ako argument StackSize enum s konštantnými hodnotami MALÉ, STREDNÉ, VEĽKÉ alebo PLNÉ. Stopa zásobníka vygenerovaná withStackTrace () sa zobrazí ako LogSiteStackTrace výnimka v predvolenom nastavení java.util.logovanie backend. Iné backendy sa však môžu rozhodnúť, že to budú riešiť inak.

4.3. Konfigurácia protokolovania a úrovne

Doteraz sme to používali logger.atInfo vo väčšine našich príkladov, ale Flogger podporuje mnoho ďalších úrovní. Pozrime sa na tieto, ale najskôr si predstavíme, ako nakonfigurovať možnosti protokolovania.

Na konfiguráciu protokolovania používame LoggerConfig trieda.

Napríklad, keď chceme nastaviť úroveň protokolovania na FINE:

LoggerConfig.of (logger) .setLevel (Level.FINE);

A Flogger podporuje rôzne úrovne protokolovania:

logger.atInfo (). log ("informačná správa"); logger.atWarning (). log ("Varovná správa"); logger.atSevere (). log ("závažná správa"); logger.atFine (). log ("Dobrá správa"); logger.atFiner (). log ("Jemnejšia správa"); logger.atFinest (). log ("Najlepšia správa"); logger.atConfig (). log ("Správa o konfigurácii");

4.4. Miera obmedzenia

Čo tak otázka obmedzenia sadzieb? Ako postupujeme v prípade, keď nechceme zaznamenávať každú iteráciu?

Flogger nám prichádza na pomoc s každý (int n) metóda:

IntStream.range (0, 100) .forEach (hodnota -> {logger.atInfo (). Every (40) .log ("Tento protokol zobrazuje každých 40 iterácií =>% d", hodnota);});

Po spustení vyššie uvedeného kódu dostaneme nasledujúci výstup:

18. septembra 2019 17:04:02 com.baeldung.flogger.FloggerUnitTest lambda $ givenAnInterval_shouldLogAfterEveryTInterval $ 0 INFO: Tento denník zobrazuje každých 40 iterácií => 0 [CONTEXT ratelimit_count = 40] 18. septembra 2019 17:04:02 com. baeldung.flogger.FloggerUnitTest lambda $ givenAnInterval_shouldLogAfterEveryTInterval $ 0 INFO: Tento protokol zobrazuje každých 40 iterácií => 40 [CONTEXT ratelimit_count = 40] 18. sep 2019, 17:04:02 com.baeldung.flogger.FloggerUnitTestInterval $ $ protokol zobrazuje každých 40 iterácií => 80 [CONTEXT ratelimit_count = 40]

Čo ak sa chceme prihlásiť každých 10 sekúnd? Potom, môžeme použiť atMostEvery (int n, jednotka TimeUnit):

IntStream.range (0, 1_000_0000) .forEach (hodnota -> {logger.atInfo (). AtMostEvery (10, TimeUnit.SECONDS) .log ("Tento protokol zobrazuje [každých 10 sekúnd] =>% d", hodnota); });

Výsledkom bude teraz:

18. septembra 2019 17:08:06 com.baeldung.flogger.FloggerUnitTest lambda $ givenATimeInterval_shouldLogAfterEveryTimeInterval $ 1 INFO: Tento protokol zobrazuje [každých 10 sekúnd] => 0 [KONTEXT ratelimit_period = "10 SEKUND"] 18. septembra 2019 5:08 : 16:00 com.baeldung.flogger.FloggerUnitTest lambda $ givenATimeInterval_shouldLogAfterEveryTimeInterval $ 1 INFO: Tento denník zobrazuje [každých 10 sekúnd] => 3545373 [CONTEXT ratelimit_period = "10 SEKUND [preskočených: 3545372]"]] 18. septembra 2019 5:08:26 PM com.baeldung.flogger.FloggerUnitTest lambda $ givenATimeInterval_shouldLogAfterEveryTimeInterval $ 1 INFO: Tento protokol zobrazuje [každých 10 sekúnd] => 7236301 [CONTEXT ratelimit_period = "10 SEKUND [preskočené: 3690927]"]]

5. Používanie Floggeru s inými backendmi

Takže, čo keby sme chceli pridajte Flogger do našej existujúcej aplikácie, ktorá už používa povedzme Slf4j alebo Log4j napríklad? To by mohlo byť užitočné v prípadoch, keď by sme chceli využiť výhody našich existujúcich konfigurácií. Flogger podporuje viac backendov, ako uvidíme.

5.1 Flogger so Slf4j

Konfigurácia koncového zariadenia Slf4j je jednoduchá. Najprv musíme pridať flogger-slf4j-backend závislosť na našom pom:

 com.google.flogger flogger-slf4j-backend 0.4 

Ďalej musíme spoločnosti Flogger povedať, že by sme chceli použiť iný back-end ako ten predvolený. Robíme to registráciou továrne Flogger prostredníctvom vlastností systému:

System.setProperty ("flogger.backend_factory", "com.google.common.flogger.backend.slf4j.Slf4jBackendFactory # getInstance");

A teraz bude naša aplikácia využívať existujúcu konfiguráciu.

5.1 Flogger s protokolom Log4j

Pri konfigurácii back-endu Log4j postupujeme podobne. Pridajme flogger-log4j-backend závislosť na našom pom:

 com.google.flogger flogger-log4j-backend 0.4 com.sun.jmx jmxri com.sun.jdmk jmxtools javax.jms jms log4j log4j 1.2.17 log4j apache-log4j-extras 1.2.17 

Tiež musíme zaregistrovať back-endovú továreň Flogger pre Log4j:

System.setProperty ("flogger.backend_factory", "com.google.common.flogger.backend.log4j.Log4jBackendFactory # getInstance");

A to je všetko, naša aplikácia je teraz nastavená na používanie existujúcich konfigurácií Log4j!

6. Záver

V tomto tutoriáli sme videli, ako používať rámec Flogger ako alternatívu k tradičným rámcom protokolovania. Videli sme niekoľko výkonných funkcií, z ktorých môžeme ťažiť pri používaní rámca.

Tiež sme videli, ako môžeme využiť naše existujúce konfigurácie registráciou rôznych koncových zariadení, ako sú Slf4j a Log4j.

Ako obvykle je zdrojový kód tohto tutoriálu k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found