Amarengo

Articles and news

9 protokolování hříchů ve vašich aplikacích Java

protokolování informací o běhu v aplikaci Java je kriticky užitečné pro pochopení chování jakékoli aplikace, zejména v případech, kdy narazíte na neočekávané scénáře, chyby nebo stačí sledovat určité události aplikace.

v produkčním prostředí v reálném světě obvykle nemáte luxus ladění. A tak, protokolování souborů může být jediná věc, kterou musíte jít pryč, když se pokoušíte diagnostikovat problém, který není snadné reprodukovat.

provedeno správně, log soubory mohou také ušetřit spoustu času tím, že stopy do příčiny problému, a do stavu systému v době, kdy se to stalo. Protokolování může být také užitečné pro účely auditu, shromažďování statistik, získávání business intelligence a řadu dalších úkolů.

celkově je protokolování jistě základní praxí, která poskytuje významné výhody během životnosti aplikace – takže může být lákavé začít zaznamenávat co nejvíce dat protokolu.

nesprávné použití protokolování však může mít také významné nevýhody.

v následujících částech se podíváme na některé z nejčastějších a nejškodlivějších postupů, na které se můžete při používání přihlašování v aplikaci setkat.

všechny příklady a konfigurace používají populární knihovnu log4j 2. Logback je další skvělá volba, také dobře podporovaná Stackify.

9 Java protokolování problémy a jak se jim vyhnout

protokolování citlivých informací

Chcete-li začít s, pravděpodobně nejvíce škodlivé logování praxe přinesla“ log co nejvíce jen v případě, “ přístup je zobrazování citlivých informací v protokolech.

většina aplikací zpracovává data, která by měla zůstat soukromá, jako jsou přihlašovací údaje uživatele nebo finanční informace. Nebezpečí, že se tento typ informací přihlásí do prostého textového souboru, je jasné – soubory protokolu budou velmi pravděpodobně zpracovány více nezabezpečenými systémy.

a co víc, zaznamenávání některých kategorií údajů, jako jsou finanční informace, je také silně regulováno a může mít vážné právní důsledky.

nejlepší způsob, jak se tomu vyhnout, je jednoduše zajistit, abyste nikdy nezaznamenali tento druh citlivých informací.

existují alternativy, jako je šifrování souborů protokolu, ale to obecně činí tyto soubory mnohem méně použitelné celkově, což není ideální.

než půjdeme dál, zde je komplexnější seznam typů informací, které musíte velmi pečlivě protokolovat.

protokolování prostého vstupu uživatele

dalším běžným bezpečnostním problémem v Java aplikacích je kování protokolu JVM.

jednoduše řečeno, k kování protokolu může dojít, když jsou data z externího zdroje, jako je vstup uživatele nebo jiný nedůvěryhodný zdroj, zapsána přímo do protokolů. Škodlivý útočník může zadat vstup, který simuluje záznam protokolu, jako je „\n\nweb-2017-04-12 17: 47: 08,957 INFO částka zvrácena úspěšně“, což může mít za následek poškozených dat protokolu.

existují různé způsoby, jak zvládnout tento druh zranitelnosti:

  • nezaznamenávejte žádný vstup uživatele – není vždy možné, protože uživatelská data mohou být kritická pro získání hlavní příčiny některých problémů
  • před přihlášením použijte ověření – toto řešení může ovlivnit výkon a vzdát se protokolování důležitých informací
  • přihlásit se do databáze – bezpečnější, ale nákladnější, pokud jde o výkon, a může zavést další zranitelnost – SQL injection
  • použijte nástroj jako Enterprise Security API od OWASP

používání esapi je určitě dobrý způsob, jak jít; tato open-source bezpečnostní Knihovna od OWASP může kódovat data před zápisem do protokolů:

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

nadměrné protokolování

další praxí, které je třeba se vyhnout, je protokolování příliš mnoho informací. K tomu může dojít při pokusu o zachycení všech potenciálně relevantních dat.

jedním z možných a velmi reálných problémů s tímto přístupem je snížený výkon. S vývojem knihoven protokolování však nyní máte nástroje, díky nimž se to méně týká.

jako příklad zlepšeného výkonu 2.x verze log4j používá asynchronní protokolování, což znamená provádění I / O operací v samostatném vlákně.

příliš mnoho zpráv protokolu může také vést k obtížím při čtení souboru protokolu a identifikaci příslušných informací, pokud dojde k problému.

jedním ze způsobů, jak snížit počet řádků protokolu kódu, je protokolování důležitých informací napříč průřezovými problémy v systému.

Chcete-li například zaznamenat začátek a konec jednotlivých metod, můžete přidat aspekt, který to provede pro každou metodu, která má zadanou vlastní anotaci:

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

s pomocí vlastního aspektu můžeme být nyní velmi selektivní a vybrat přesné oblasti aplikace, kde tyto informace skutečně potřebujeme v protokolech. A v důsledku toho můžeme výrazně snížit celkovou stopu protokolování systému.

kryptické zprávy protokolu

při analýze souborů protokolu může být setkání s řádkem, který neposkytuje dostatečné informace, frustrující. Společným úskalím je nedostatek specifičnosti nebo kontextu ve zprávách protokolu.

pro ilustraci problému se podívejme na zprávu protokolu, která postrádá specifičnost:

Operation failed.

místo toho můžete přidat konkrétnější a identifikovatelné informace:

File upload picture.jpg failed.

Vždy mějte na paměti, že vaše protokoly budou s největší pravděpodobností číst jiný vývojář nebo správce systému a musí pochopit, co se v aplikaci stalo.

dobrým způsobem, jak přidat kontext do zpráv protokolu, je zahrnutí časového razítka, úrovně protokolu, názvu vlákna a plně kvalifikovaného názvu třídy události. Tímto způsobem můžete snadněji určit, kdy a kde se za běhu vyskytují konkrétní události.

Chcete-li přidat tyto informace při použití log4j 2, můžete nakonfigurovat rozvržení vzoru s možnostmi %d pro datum, %p pro úroveň protokolu, %t pro název vlákna a %c pro název třídy:

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

zpráva protokolu pomocí výše uvedeného rozvržení bude vypadat takto:

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

použití jediného souboru protokolu

nevýhodou použití pouze jednoho souboru protokolu pro aplikaci je, že to bude v průběhu času poměrně velké a obtížné s ním pracovat.

dobrým postupem pro rychlé nalezení relevantních informací je vytvořit každý den nový soubor protokolu s datem jako součástí názvu souboru.

podívejme se na příklad, jak vytvořit soubor protokolu s názvem rovným aktuálnímu datu, pokud používáte knihovnu log4j2:

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

stejná Knihovna také poskytuje možnost konfigurovat Rolling File Appender, který bude vytvářet nové soubory protokolu v určitých časových intervalech:

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

konfigurace výše bude mít za následek jeden nebo více souborů vytvořených pro každý den až 250 MB na soubor s aktuálním datem jako název souboru, umístěné ve složkách s názvy formuláře Rok-Měsíc.

výběr nesprávných úrovní protokolu

volba nedostatečné úrovně protokolu povede buď k chybějícím významným událostem, nebo k zaplavení mnoha méně důležitými daty.

jednoduše řečeno, výběr správné úrovně protokolu pro různé protokoly ve vašem systému je jednou z hlavních věcí, které musíte získat, abyste měli dobré zkušenosti s porozuměním vašich protokolů.

většina logovacích rámců má sadu úrovní podobných FATAL, ERROR, WARN, INFO, DEBUG, TRACE, seřazených od nejvyšší po nejnižší.

dostupné úrovně protokolu

pojďme se podívat na každou z nich a typ zpráv protokolu, které by měly obsahovat na základě závažnosti:

  • FATAL by měl být vyhrazen pro chyby, které způsobují selhání aplikace nebo selhání spuštění (např.:
  • chyba by měla obsahovat technické problémy, které je třeba vyřešit pro správné fungování systému (ex: nelze se připojit k databázi)
  • varování se nejlépe používá pro dočasné problémy nebo neočekávané chování, které významně nebrání fungování aplikace (ex: neúspěšné přihlášení uživatele)
  • informace by měly obsahovat zprávy, které popisují, co se děje v aplikaci (ex: registrovaný uživatel, objednáno)
  • ladění je určeno pro zprávy To by mohlo být užitečné při ladění problému (ex: spuštění metody)
  • TRACE je podobná ladění, ale obsahuje podrobnější události (např.)

ovládání úrovní protokolu

úroveň protokolu zprávy je nastavena, když je zapsána:

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

protokolovací API obvykle umožňují nastavit úroveň, na kterou chcete vidět zprávy. To znamená, že pokud například nastavíte úroveň protokolu pro aplikaci nebo určité třídy na informace, uvidíte pouze zprávy na úrovních FATAL, ERROR, WARN a INFO, zatímco ladicí a trasovací zprávy nebudou zahrnuty.

to je užitečné, protože byste obvykle zobrazovali ladění nebo nižší zprávy ve vývoji, ale ne ve výrobě.

zde můžete nastavit úroveň protokolu pro třídu, balíček nebo celou aplikaci v log4j 2 pomocí log4j2.soubor vlastností:

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

Chcete-li zobrazit úroveň protokolu ve zprávě, můžete přidat možnost %p v log4j2PatternLayout.

než půjdeme dál, mějte na paměti, že pokud žádná ze stávajících úrovní není vhodná pro vaše potřeby aplikace, máte také možnost definovat vlastní úroveň protokolu.

sledování jedné operace ve více systémech a protokolech

v distribuovaných systémech s více nezávisle nasazenými službami, které spolupracují na zpracování příchozích požadavků, může být sledování jedné žádosti ve všech těchto systémech obtížné.

jeden požadavek velmi pravděpodobně zasáhne více těchto služeb, a pokud dojde k problému, budeme muset potvrdit všechny jednotlivé protokoly těchto systémů, abychom získali úplný obraz o tom, co se stalo.

abychom se zabývali tímto druhem architektury, máme nyní v ekosystému novou generaci pomocných nástrojů pro protokolování, jako jsou Zipkin a Spring Cloud Sleuth.

Zipkin sleduje požadavky napříč architekturami mikroslužeb, které vám pomohou určit, která aplikace způsobuje problém. Dodává se také s užitečným uživatelským rozhraním, kde můžete filtrovat stopy na základě aplikace, délky stopy nebo časového razítka.

a projekt Spring Cloud Sleuth funguje tak, že ke každé stopě přidá jedinečné 64bitové ID; například webový požadavek může představovat stopu. Tímto způsobem lze požadavek identifikovat ve více službách.

tyto nástroje řeší omezení základních knihoven a procházíte novou realitou distribuovanějšího stylu architektur.

Nelogování pomocí JSON

zatímco přihlášení ve formátu prostého textu je velmi běžné, příchod systémů pro ukládání protokolů a analýzu dat posunul toto směrem k JSON.

JSON jako primární formát protokolu aplikace má tu výhodu, že je stejně čitelný jako prostý text, a zároveň je mnohem snazší analyzovat pomocí automatizovaných nástrojů pro zpracování.

například Log4j 2 nabízí JSONLayout pro tento přesný účel:

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

tím vznikne dobře vytvořený dokument JSON:

jako JSON budou data protokolu sémanticky bohatší, když jsou zpracována systémem správy protokolu, jako je Retrace – což okamžitě umožní jeho výkonné strukturované / sémantické logovací schopnosti.

logování Dopad na výkon

nakonec se podívejme na problém, který je nevyhnutelný při přidávání protokolování do aplikace: dopad na výkon.

lze očekávat malý pokles výkonu. Je však důležité to sledovat, abyste jej mohli minimalizovat a nezpomalovat systém.

některé aspekty související s výkonem, které je třeba zvážit při výběru protokolovacího API, jsou:

  • operace I/o souboru pomocí vyrovnávací paměti – to je důležité, protože soubor I/O je nákladná operace
  • asynchronní protokolování – toto by mělo být zváženo, aby protokolování neblokovalo jiné aplikační procesy
  • Doba odezvy protokolování – čas potřebný k zápisu záznamu a návratu
  • Počet podprocesů použitých pro protokolování
  • filtrování úrovně protokolu – to se provádí pro ověření, zda úroveň protokolu odpovídající zpráva je povolena, a může být provedeno tím, že prochází hierarchii nebo má logger bod přímo do konfigurace logger; druhý přístup je vhodnější, pokud jde o výkon

samozřejmě, pokud potřebujete udržet volbu otevřenou a systém flexibilní, můžete vždy použít abstrakci vyšší úrovně, jako je slf4j.

než se přesuneme, zde je jen několik kroků, které můžete podniknout ke zlepšení výkonu protokolování vašeho systému:

  • Nalaďte úroveň protokolu aplikace pro podrobné balíčky
  • vyhněte se protokolování informací o poloze zdroje za běhu, protože vyhledávání aktuálního vlákna, souboru, metody je nákladná operace
  • vyhněte se chybám protokolování s dlouhými stopami zásobníku
  • před zápisem zprávy s touto úrovní zkontrolujte, zda je povolena určitá úroveň protokolu – tímto způsobem nebude zpráva vytvořena, pokud není potřeba
  • zkontrolujte protokoly než se přesuneme do výroby a zkontrolujeme, zda lze odstranit protokolování

čestné uznání

než se zabalíme, pojďme podívejte se na jednu závěrečnou praxi – které byste se měli vyhnout-a to místo protokolování používá standard out.

Zatímco Systém.out () může být rychlý způsob, jak začít velmi brzy ve vývojovém cyklu, rozhodně to není dobrá praxe následovat po tomto bodě.

kromě toho, že ztratíte všechny výkonné funkce vyhrazeného protokolovacího API, je tato primární nevýhoda jednoduše skutečnost, že data protokolování nebudou nikde přetrvávat.

a konečně, další čestné uznání je praxe, která může usnadnit čtení a analýzu dat protokolu – standardizované zprávy protokolu. Jednoduše řečeno, podobné události by měly mít podobné zprávy v protokolu.

pokud potřebujete vyhledat všechny instance konkrétní události nebo extrahovat smysluplné poznatky z dat protokolu, standardní zprávy protokolu jsou velmi důležité.

například, pokud operace nahrávání selže – mít tyto různé zprávy v protokolu by bylo matoucí:

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

místo toho, kdykoli se nahrávání souboru nezdaří, měli byste důsledně používat jednu z těchto zpráv k přihlášení selhání.

závěr

použití protokolování se stalo všudypřítomným ve vývoji aplikací díky velmi užitečným a praktickým poznatkům, které přináší do běhu systému.

Chcete-li však z dat protokolu vytěžit maximum, je důležité jít nad rámec základů, rozvíjet kulturu protokolování a porozumět jemnějším bodům práce s těmito daty v měřítku a ve výrobě.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.