Amarengo

Articles and news

9 rejestrowanie grzechów w aplikacjach Java

rejestrowanie informacji runtime w aplikacji Java jest niezwykle przydatne do zrozumienia zachowania dowolnej aplikacji, szczególnie w przypadku napotkania nieoczekiwanych scenariuszy, błędów lub po prostu konieczności śledzenia określonych zdarzeń aplikacji.

w rzeczywistym środowisku produkcyjnym zwykle nie masz luksusu debugowania. Tak więc rejestrowanie plików może być jedyną rzeczą, z której musisz zrezygnować, próbując zdiagnozować problem, który nie jest łatwy do odtworzenia.

poprawnie wykonane pliki dziennika mogą również zaoszczędzić dużo czasu, dostarczając wskazówek dotyczących przyczyny problemu i stanu systemu w momencie, gdy to się stało. Ponadto rejestrowanie może być przydatne do celów audytu, zbierania statystyk, wydobywania business intelligence i wielu innych zadań.

ogólnie rzecz biorąc, rejestrowanie danych jest z pewnością podstawową praktyką, która zapewnia znaczące korzyści w okresie użytkowania aplikacji – więc może być kuszące, aby rozpocząć rejestrowanie jak największej ilości danych dziennika.

jednak niewłaściwe korzystanie z logowania może mieć również znaczące wady.

w poniższych sekcjach przyjrzymy się niektórym z najczęstszych i najbardziej szkodliwych praktyk, na które można napotkać podczas logowania się do aplikacji.

wszystkie przykłady i konfiguracja korzystają z popularnej biblioteki log4j 2. Logback to kolejna świetna opcja, również dobrze wspierana przez Stackify.

9 problemy z logowaniem w Javie i jak ich uniknąć

rejestrowanie poufnych informacji

na początek, prawdopodobnie najbardziej szkodliwa praktyka rejestrowania wprowadzona przez podejście „log as much as possible just in case” wyświetla poufne informacje w dziennikach.

większość aplikacji obsługuje dane, które powinny pozostać prywatne, takie jak poświadczenia użytkownika lub informacje finansowe. Niebezpieczeństwo zalogowania tego typu informacji do zwykłego pliku tekstowego jest oczywiste-pliki dziennika będą najprawdopodobniej przetwarzane przez wiele niezabezpieczonych systemów.

co więcej, rejestrowanie niektórych kategorii danych, takich jak informacje finansowe, jest również mocno regulowane i może mieć poważne konsekwencje prawne.

najlepszym sposobem, aby tego uniknąć, jest po prostu upewnienie się, że nigdy nie rejestrujesz tego rodzaju poufnych informacji.

istnieją alternatywy, takie jak szyfrowanie plików dziennika, ale to ogólnie sprawia, że te pliki są o wiele mniej użyteczne, co nie jest idealne.

zanim przejdziemy dalej, oto bardziej obszerna lista rodzajów informacji, które trzeba być bardzo ostrożnym logowania.

rejestrowanie zwykłego wejścia użytkownika

Innym częstym problemem bezpieczeństwa w aplikacjach Java jest fałszowanie dziennika JVM.

Mówiąc najprościej, fałszowanie logów może się zdarzyć, gdy dane z zewnętrznego źródła, takiego jak dane wejściowe użytkownika lub inne niezaufane źródło, zostaną zapisane bezpośrednio do dzienników. Złośliwy atakujący może wprowadzić dane wejściowe, które symuluje wpis dziennika, taki jak „\n\nweb – 2017-04-12 17:47:08,957 kwota informacji odwrócona pomyślnie”, co może spowodować uszkodzenie danych dziennika.

istnieją różne sposoby radzenia sobie z tego rodzaju luką:

  • nie rejestruj żadnych danych wejściowych użytkownika – nie zawsze jest to możliwe, ponieważ dane użytkownika mogą być krytyczne dla uzyskania głównej przyczyny niektórych problemów
  • użyj walidacji przed zalogowaniem – To rozwiązanie może wpłynąć na wydajność, a także zrezygnować z rejestrowania ważnych informacji
  • Zaloguj się do bazy danych – bardziej bezpieczne, ale kosztowne pod względem wydajności i może wprowadzić kolejną lukę – SQL injection
  • użyj narzędzia takiego jak Enterprise API bezpieczeństwa od OWASP

używanie esapi jest zdecydowanie dobrym sposobem; ta otwarta biblioteka bezpieczeństwa OWASP może kodować dane przed zapisaniem ich do dzienników:

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

nadmierne rejestrowanie

inną praktyką, której należy unikać, jest rejestrowanie zbyt wielu informacji. Może się to zdarzyć w celu przechwycenia wszystkich potencjalnie istotnych danych.

jednym z możliwych i bardzo realnych problemów z tym podejściem jest zmniejszona wydajność. Jednak wraz z rozwojem bibliotek rejestrowania masz teraz narzędzia, które sprawią, że stanie się to mniej problemem.

jako przykład poprawy wydajności, 2.x wersja log4j używa asynchronicznego logowania, co oznacza wykonywanie operacji We / Wy w osobnym wątku.

zbyt wiele komunikatów dziennika może również prowadzić do trudności w odczytaniu pliku dziennika i zidentyfikowaniu istotnych informacji, gdy wystąpi problem.

jednym ze sposobów zmniejszenia liczby wierszy dziennika kodu jest rejestrowanie ważnych informacji w systemie.

na przykład, jeśli chcesz zalogować początek i koniec poszczególnych metod, możesz dodać aspekt, który zrobi to dla każdej metody, która ma określoną niestandardową adnotację:

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

z pomocą niestandardowego aspektu możemy teraz być bardzo selektywni i wybrać dokładne obszary aplikacji, w których faktycznie potrzebujemy tych informacji w dziennikach. W rezultacie możemy znacznie zmniejszyć ogólny ślad rejestrowania systemu.

tajemnicze komunikaty dziennika

podczas analizowania plików dziennika napotkanie linii, która nie dostarcza wystarczających informacji, może być frustrujące. Częstą pułapką jest brak specyfiki lub kontekstu w komunikatach dziennika.

aby zilustrować problem, rzućmy okiem na komunikat dziennika pozbawiony specyfiki:

Operation failed.

zamiast tego możesz dodać bardziej szczegółowe i możliwe do zidentyfikowania informacje:

File upload picture.jpg failed.

zawsze należy pamiętać, że dzienniki z pewnością będą odczytywane przez innego programistę lub administratora systemu i muszą zrozumieć, co się stało w aplikacji.

dobrym sposobem na dodanie kontekstu w komunikatach dziennika jest włączenie znacznika czasu, poziomu dziennika, nazwy wątku i w pełni kwalifikowanej nazwy klasy zdarzenia. W ten sposób można łatwiej zidentyfikować, kiedy i gdzie występują określone zdarzenia w czasie wykonywania.

aby dodać te informacje podczas używania log4j 2, możesz skonfigurować układ wzorca z opcjami %d Dla daty, % p dla poziomu dziennika, % t dla nazwy wątku i % c dla nazwy klasy:

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

komunikat dziennika korzystający z powyższego układu będzie wyglądał następująco:

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

używanie pojedynczego pliku dziennika

minusem używania tylko jednego pliku dziennika dla aplikacji jest to, że z czasem stanie się on dość duży i trudny do pracy.

dobrą praktyką szybkiego znajdowania istotnych informacji jest tworzenie nowego pliku dziennika każdego dnia, z datą jako częścią nazwy pliku.

przyjrzyjmy się przykładowi, jak utworzyć plik dziennika o nazwie równej bieżącej dacie, jeśli korzystasz z biblioteki log4j2:

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

ta sama biblioteka zapewnia również możliwość skonfigurowania aplikatora Rolling File, który będzie tworzyć nowe pliki dziennika w określonych odstępach czasu:

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

powyższa konfiguracja spowoduje utworzenie jednego lub więcej plików na każdy dzień do 250 MB na plik z bieżącą datą jako nazwą pliku, umieszczonych w folderach z nazwami formularza Rok-Miesiąc.

wybranie nieprawidłowego poziomu dziennika

wybranie nieodpowiedniego poziomu dziennika spowoduje brak istotnych zdarzeń lub zalanie wieloma mniej ważnymi danymi.

Mówiąc najprościej, wybór odpowiedniego poziomu dziennika dla różnych dzienników w systemie jest jedną z podstawowych rzeczy, których potrzebujesz, aby uzyskać dobre doświadczenie w zrozumieniu dzienników.

Większość frameworków logowania ma zestaw poziomów podobnych do FATAL, ERROR, WARN, INFO, DEBUG, TRACE, uporządkowanych od najwyższego do najniższego.

dostępne poziomy logów

przyjrzyjmy się każdemu z nich i rodzajowi komunikatów logów, które powinny zawierać w oparciu o dotkliwość:

  • krytyczny powinien być zarezerwowany dla błędów, które powodują awarię lub niepowodzenie uruchomienia aplikacji (np.:
  • błąd powinien zawierać problemy techniczne, które należy rozwiązać dla prawidłowego funkcjonowania systemu (np. nie można połączyć się z bazą danych)
  • WARN jest najlepiej używany do tymczasowych problemów lub nieoczekiwanych zachowań, które nie utrudniają znacząco funkcjonowania aplikacji (np. nieudane logowanie użytkownika)
  • informacje powinny zawierać komunikaty opisujące, co dzieje się w aplikacji (np. zarejestrowany użytkownik, złożone zamówienie)
  • debugowanie jest przeznaczone dla wiadomości, które mogą być przydatne w debugowaniu problemu (np.:
  • TRACE jest podobny do debugowania, ale zawiera bardziej szczegółowe zdarzenia(np.)

kontrolowanie poziomów dziennika

poziom dziennika wiadomości jest ustawiany podczas pisania:

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

interfejsy API logowania zazwyczaj pozwalają ustawić poziom, do którego mają być wyświetlane wiadomości. Oznacza to, że jeśli ustawisz poziom dziennika dla aplikacji lub niektórych klas na przykład na INFO, zobaczysz tylko wiadomości na poziomach FATAL, ERROR, WARN i INFO, podczas gdy komunikaty debugowania i śledzenia nie będą uwzględniane.

jest to pomocne, ponieważ zwykle pokazujesz komunikaty debugowania lub niższe w fazie rozwoju, ale nie w fazie produkcji.

oto jak można ustawić poziom dziennika dla klasy, pakietu lub całej aplikacji w log4j 2, używając log4j2.Plik Właściwości:

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

rootLogger.level=debug

aby wyświetlić poziom dziennika w wiadomości, możesz dodać opcję %p w log4j2PatternLayout.

zanim przejdziemy dalej, pamiętaj, że jeśli żaden z istniejących poziomów nie jest odpowiedni dla Twoich potrzeb aplikacji, masz również możliwość zdefiniowania niestandardowego poziomu dziennika.

śledzenie pojedynczej operacji w wielu systemach i dzienniki

w systemach rozproszonych z wieloma niezależnie wdrożonymi usługami, które współpracują ze sobą w celu przetwarzania przychodzących żądań, śledzenie pojedynczego żądania we wszystkich tych systemach może być trudne.

pojedyncze żądanie najprawdopodobniej trafi do wielu z tych usług, a jeśli wystąpi problem, będziemy musieli potwierdzić wszystkie pojedyncze dzienniki tych systemów, aby uzyskać pełny obraz tego, co się stało.

aby rozwiązać ten rodzaj architektury, mamy teraz nową generację narzędzi pomocniczych do logowania w ekosystemie, takich jak Zipkin i Spring Cloud Sleuth.

Zipkin śledzi żądania w architekturach mikroserwisów, aby pomóc ci zidentyfikować, która aplikacja jest przyczyną problemu. Jest również wyposażony w pomocny interfejs użytkownika, w którym można filtrować ślady na podstawie aplikacji, długości śladu lub znacznika czasu.

a projekt Spring Cloud Sleuth działa poprzez dodanie unikalnego 64-bitowego identyfikatora do każdego śladu; na przykład żądanie sieciowe może stanowić ślad. W ten sposób żądanie można zidentyfikować w wielu usługach.

te narzędzia rozwiązują ograniczenia podstawowych bibliotek i poruszają się po nowych realiach bardziej rozproszonego stylu architektur.

brak logowania za pomocą JSON

podczas gdy logowanie w formacie tekstowym jest bardzo powszechne, pojawienie się systemów przechowywania dzienników i analizy danych przesunęło to w kierunku JSON.

JSON jako podstawowy format dziennika aplikacji ma tę zaletę, że jest tak samo czytelny jak zwykły tekst, a jednocześnie znacznie łatwiejszy do przeanalizowania przez zautomatyzowane narzędzia przetwarzania.

na przykład Log4j 2 oferuje JSONLayout do tego celu:

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

stworzy to dobrze uformowany dokument JSON:

jako JSON, dane dziennika będą semantycznie bogatsze, gdy będą przetwarzane przez system zarządzania logami, taki jak Retrace – co natychmiast umożliwi jego potężne możliwości rejestrowania strukturalnego/semantycznego.

wpływ logowania na wydajność

na koniec rozważmy problem, który jest nieunikniony podczas dodawania logowania do aplikacji: wpływ na wydajność.

należy się spodziewać niewielkiego spadku wydajności. Ważne jest jednak, aby śledzić to, aby zminimalizować to i nie spowolnić systemu.

niektóre aspekty związane z wydajnością, które należy wziąć pod uwagę przy wyborze logowania API to:

  • operacje We/Wy pliku przy użyciu bufora – jest to krytyczne, ponieważ We/Wy pliku jest kosztowną operacją
  • asynchroniczne logowanie – należy to wziąć pod uwagę, aby logowanie nie blokowało innych procesów aplikacji
  • czas reakcji logowania – czas potrzebny na napisanie wpisu dziennika i zwrócenie
  • liczby wątków używanych do logowania
  • filtrowanie poziomu dziennika – służy do weryfikacji, czy poziom dziennika odpowiadający wiadomości jest włączony i można to zrobić, przechodząc przez hierarchię lub kierując Rejestrator bezpośrednio do konfiguracji rejestratora; to drugie podejście jest preferowane w odniesieniu do wydajności

oczywiście, jeśli chcesz zachować otwarty wybór, a system elastyczny, zawsze możesz użyć abstrakcji wyższego poziomu, takiej jak slf4j.

zanim je przeniesiemy, oto kilka kroków, które możesz podjąć, aby poprawić wydajność rejestrowania systemu:

  • dostroić poziom dziennika aplikacji dla obszernych pakietów
  • unikaj rejestrowania informacji o lokalizacji źródła w czasie wykonywania, ponieważ przeglądanie bieżącego wątku, pliku, metody jest kosztowną operacją
  • unikaj rejestrowania błędów z długimi śladami stosu
  • sprawdź, czy dany poziom dziennika jest włączony przed napisaniem wiadomości z tym poziomem – w ten sposób wiadomość nie zostanie zbudowana, jeśli nie jest potrzebna
  • przejrzyj logi przed przejściem do produkcji, aby sprawdzić, czy można usunąć jakiekolwiek logowanie

wyróżnienia

zanim skończymy, zróbmy spójrz na jedną ostatnią praktykę, której powinieneś unikać – a mianowicie używanie standardowego wyjścia zamiast logowania.

Podczas Gdy System.out() może być szybkim sposobem na rozpoczęcie bardzo wcześnie w cyklu rozwojowym, zdecydowanie nie jest to dobra praktyka do naśladowania po tym punkcie.

poza tym, że tracisz wszystkie potężne funkcje dedykowanego API rejestrowania, tym głównym minusem jest po prostu fakt, że dane logowania nie będą nigdzie utrzymywane.

wreszcie kolejną wyróżnieniem jest praktyka, która może znacznie ułatwić czytanie i analizowanie danych dziennika-standaryzowane komunikaty dziennika. Mówiąc najprościej, podobne zdarzenia powinny mieć podobne wiadomości w dzienniku.

jeśli chcesz wyszukać wszystkie wystąpienia tego konkretnego zdarzenia lub wydobyć znaczące informacje z danych dziennika, standardowe komunikaty dziennika są dość ważne.

na przykład, jeśli operacja przesyłania nie powiedzie się-posiadanie tych różnych wiadomości w dzienniku byłoby mylące:

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

zamiast tego, gdy przesyłanie pliku nie powiedzie się, należy konsekwentnie używać jednego z tych komunikatów do rejestrowania awarii.

wniosek

korzystanie z logowania stało się wszechobecne w tworzeniu aplikacji, ze względu na bardzo przydatne i praktyczne spostrzeżenia, które wnosi do działania systemu.

jednak, aby w pełni wykorzystać dane dziennika, ważne jest, aby wyjść poza podstawy, rozwinąć kulturę rejestrowania i zrozumieć drobniejsze Punkty pracy z tymi danymi na skalę iw produkcji.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.