Tavasz - Bejövő kérések naplózása

1. Bemutatkozás

Ebben a gyors bemutatóban bemutatjuk a bejövő kérések naplózásának alapjait a Spring naplózási szűrője segítségével. Ha még csak most kezdi a naplózást, olvassa el ezt a naplózási bevezető cikket, valamint az SLF4J cikket.

2. Maven-függőségek

A naplózási függőségek egyszerűen megegyeznek az intro cikkben szereplőkkel; tegyük egyszerűen ide a Tavaszt:

 org.springframework rugós mag 5.2.2.FELHASZNÁLÁS 

A legfrissebb verzió itt található a rugós maghoz.

3. Alapvető webvezérlő

Először is definiáljunk egy vezérlőt, amelyet a példánkban használunk:

@RestController public class TaxiFareController {@GetMapping ("/ taxifare / get /") public RateCard getTaxiFare () {return new RateCard (); } @PostMapping ("/ taxifare / calc /") public String calcTaxiFare (@RequestBody @Valid TaxiRide taxiRide) {// adja vissza a kiszámított viteldíjat}}

4. Egyedi kérelem naplózása

A Spring mechanizmust biztosít a felhasználó által meghatározott elfogók konfigurálására a webes kérések előtti és utáni műveletek végrehajtására.

A tavaszi kérést elfogók között az egyik figyelemre méltó felület a HandlerInterceptor, amely a bejövő kérelem naplózására használható a következő módszerek végrehajtásával:

  1. preHandle () - ezt a módszert a tényleges vezérlőszolgáltatási módszer előtt hajtják végre
  2. afterCompletion () - ezt a módszert akkor hajtják végre, miután a vezérlő készen áll a válasz küldésére

Ezenkívül a Spring biztosítja a HandlerInterceptor interfész formájában HandlerInterceptorAdaptor osztály, amelyet a felhasználó kibővíthet.

Hozzunk létre saját elfogót - kiterjesztéssel HandlerInterceptorAdaptor mint:

A @Component public class TaxiFareRequestInterceptor kiterjeszti a HandlerInterceptorAdaptert {@Orride public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) {return true; } @Orride public void afterCompletion (HttpServletRequest kérés, HttpServletResponse válasz, Objektumkezelő, Kivétel ex) {//}}

Végül konfiguráljuk a TaxiRideRequestInterceptor az MVC életciklusán belül, hogy rögzítse az útvonalhoz leképezett vezérlő metódusok előzetes és utólagos feldolgozását / taxifare -ban meghatározott TaxiFareController osztály.

A @Configuration nyilvános osztály TaxiFareMVCConfig hajtja végre a WebMvcConfigurer {@Autowired private TaxiFareRequestInterceptor taxiFareRequestInterceptor; @Orride public void addInterceptors (InterceptorRegistry registry) {register.addInterceptor (taxiFareRequestInterceptor) .addPathPatterns ("/ ** / taxifare / ** /"); }}

Összegzésképpen: WebMvcConfigurer hozzáteszi a TaxiFareRequestInterceptor belül az MVC életciklusa meghívással addInterceptors () módszer.

A legnagyobb kihívás az, hogy megszerezzük a kérelem és a válasz hasznos terhelésének másolatait a naplózáshoz, és a szervlet számára továbbra is a kért hasznos terhet hagyjuk feldolgozásra.

Az olvasási kérelem fő kérdése, hogy amint a bemeneti adatfolyamot először olvassák el, elfogyasztottként jelölik meg, és nem olvasható újra.

Az alkalmazás kivételt vet a kérésfolyam elolvasása után:

{"időbélyeg": 1500645243383, "status": 400, "error": "Bad Request", "kivétel": "org.springframework.http.converter .HttpMessageNotReadableException", "message": "Nem sikerült elolvasni a dokumentumot: A patak bezárult ; beágyazott kivétel a java.io.IOException: Stream closed "," path ":" / rest-log / taxifare / calc / "}

Ennek a problémának a leküzdésére, kihasználhatjuk a gyorsítótárat a kérelemfolyam tárolására és naplózáshoz.

A Spring néhány hasznos osztályt kínál, mint például a ContentCachingRequestWrapper és a ContentCachingResponseWrapper, amelyek felhasználhatók a kérési adatok gyorsítótárazásához naplózás céljából.

Állítsuk be preHandle () nak,-nek TaxiRideRequestInterceptor osztály a kérelemobjektum gyorsítótárazásával ContentCachingRequestWrapper osztály.

@Orride public boolean preHandle (HttpServletRequest kérés, HttpServletResponse válasz, Objektumkezelő) {HttpServletRequest requestCacheWrapperObject = new ContentCachingRequestWrapper (kérés); requestCacheWrapperObject.getParameterMap (); // Az inputStream beolvasása a requestCacheWrapperObject fájlból és naplózása a true true értékkel; }

Mint láthatjuk, a kérelemobjektumot gyorsítótáraztuk a használatával ContentCachingRequestWrapper osztály, amellyel a tényleges kérelemobjektum megzavarása nélkül olvasható a hasznos adatok a naplózáshoz:

requestCacheWrapperObject.getContentAsByteArray ();

Korlátozás

  • ContentCachingRequestWrapper osztály csak a következőket támogatja:
Tartalom-típus: application / x-www-form-urlencoded Módszer-típus: POST
  • A következő módszert kell használnunk annak biztosítására, hogy a kérelem adatai gyorsítótárban legyenek ContentCachingRequestWrapper használata előtt:
requestCacheWrapperObject.getParameterMap ();

5. Tavaszi beépített kérelem naplózása

A Spring beépített megoldást kínál a hasznos terhek naplózására. Kész szűrőket használhatunk, ha konfigurációt használva csatlakoztatjuk a Spring alkalmazást.

AbstractRequestLoggingFilter egy szűrő, amely biztosítja a naplózás alapfunkcióit. Az alosztályoknak felül kell írniuk a beforeRequest () és afterRequest () módszerek a kérelem körüli tényleges naplózás végrehajtására.

A Spring framework három konkrét megvalósítási osztályt kínál, amelyek felhasználhatók a beérkező kérések naplózására. Ez a három osztály a következő:

  • CommonsRequestLoggingFilter
  • Log4jNestedDiagnosticContextFilter (elavult)
  • ServletContextRequestLoggingFilter

Most térjünk át a CommonsRequestLoggingFilter és konfigurálja a bejövő naplózási kérelem rögzítésére.

5.1. Konfigurálja a Spring Boot alkalmazást

A Spring Boot alkalmazás konfigurálható egy babdefiníció hozzáadásával a kérelem naplózásának engedélyezéséhez:

@Configuration public class RequestLoggingFilterConfig {@Bean public CommonsRequestLoggingFilter logFilter () {CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter (); filter.setIncludeQueryString (true); filter.setIncludePayload (true); filter.setMaxPayloadLength (10000); filter.setIncludeHeaders (hamis); filter.setAfterMessagePrefix ("ADATKÉRÉS:"); visszatérő szűrő; }}

Ez a naplózási szűrő megköveteli, hogy a naplószint DEBUG legyen. Engedélyezhetjük a DEBUG módot az alábbi elem hozzáadásával logback.xml:

A DEBUG szintű napló engedélyezésének másik módja az alábbiak hozzáadása alkalmazás.tulajdonságok:

logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter = DEBUG

5.2. Konfigurálja a hagyományos webalkalmazást

A szokásos tavaszi webalkalmazásban Szűrő beállítható XML vagy Java konfigurációval. Állítsuk be a CommonsRequestLoggingFilter hagyományos Java alapú konfigurációval.

Mint tudjuk, a includePayload attribútuma CommonsRequestLoggingFilter alapértelmezés szerint hamis értékre van állítva. Szükségünk lenne egy egyedi osztályra, amely felülbírálja az attribútum értékét az engedélyezéshez includePayload mielőtt a Java konfigurációval befecskendezne a tartályba:

public class CustomeRequestLoggingFilter kiterjeszti a CommonsRequestLoggingFilter {public CustomeRequestLoggingFilter () {super.setIncludeQueryString (true); super.setIncludePayload (true); super.setMaxPayloadLength (10000); }}

Most be kell adnunk a CustomeRequestLoggingFilter Java alapú webes inicializáló használatával:

public class CustomWebAppInitializer implementálja a WebApplicationInitializer {public void onStartup (ServletContext container) {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext (); context.setConfigLocation ("com.baeldung"); container.addListener (új ContextLoaderListener (context)); ServletRegistration.Dynamic diszpécser = container.addServlet ("diszpécser", új DispatcherServlet (kontextus)); diszpécser.setLoadOnStartup (1); diszpécser.addMapping ("/"); container.addFilter ("customRequestLoggingFilter", CustomeRequestLoggingFilter.class) .addMappingForServletNames (null, hamis, "diszpécser"); }}

6. Példa a cselekvésben

Most összekapcsolhatjuk a tavaszi rendszerindítást kontextussal, és működés közben láthatjuk, hogy a beérkező kérések naplózása a várt módon működik:

@Test public void givenRequest_whenFetchTaxiFareRateCard_thanOK () {TestRestTemplate testRestTemplate = new TestRestTemplate (); TaxiRide taxiRide = új TaxiRide (igaz, 10l); String viteldíj = testRestTemplate.postForObject (URL + "kiszámítja /", taxiRide, String.osztály); assertThat (viteldíj, egyenlőTo ("200")); }

7. Következtetés

Ebben a cikkben bemutattuk, hogyan lehet megvalósítani az internetes kérések naplózását elfogók segítségével; megmutattuk ennek a megoldásnak a korlátait és kihívásait is.

Ezután bemutattuk a beépített szűrőosztályt, amely használatra kész és egyszerű naplózási mechanizmust biztosít.

Mint mindig, a példa és a kódrészletek megvalósítása elérhető a GitHubon.