Vår - Logg innkommende forespørsler

1. Introduksjon

I denne raske opplæringen skal vi vise det grunnleggende om å logge innkommende forespørsler ved hjelp av Spring's loggingsfilter. Hvis du nettopp har kommet i gang med logging, kan du sjekke ut denne artikkelen om logging, samt SLF4J-artikkelen.

2. Maven-avhengigheter

Loggavhengighet vil ganske enkelt være den samme som i intro artikkelen; la oss bare legge til vår her:

 org.springframework spring-core 5.2.2.RELEASE 

Den siste versjonen finner du her for vårkjernen.

3. Grunnleggende nettkontroller

La oss først og fremst definere en kontroller som skal brukes i vårt eksempel:

@RestController offentlig klasse TaxiFareController {@GetMapping ("/ taxifare / get /") offentlig RateCard getTaxiFare () {returner nytt RateCard (); } @PostMapping ("/ taxifare / calc /") public String calcTaxiFare (@RequestBody @Valid TaxiRide taxiRide) {// returner beregnet billettpris}}

4. Tilpasset forespørsellogging

Spring gir en mekanisme for å konfigurere brukerdefinerte avlyttere til å utføre handlinger før og etter forespørsler på nettet.

Blant våren forespørsel interceptors, er en av de bemerkelsesverdige grensesnittene HandlerInterceptor, som kan brukes til å logge innkommende forespørsel ved å implementere følgende metoder:

  1. preHandle () - denne metoden utføres før selve kontrollertjenestemetoden
  2. afterCompletion () - denne metoden utføres etter at kontrolleren er klar til å sende svaret

Videre gir Spring standard implementering av HandlerInterceptor grensesnitt i form av HandlerInterceptorAdaptor klasse som kan utvides av brukeren.

La oss lage vår egen avlytter - ved å utvide HandlerInterceptorAdaptor som:

@Komponent offentlig klasse TaxiFareRequestInterceptor utvider HandlerInterceptorAdapter {@Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) {return true; } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {//}}

Til slutt konfigurerer vi TaxiRideRequestInterceptor inne i MVC-livssyklus for å fange opp pre- og etterbehandling av kontrollermetodeanropninger som er kartlagt til stien / taxifare definert i TaxiFareController klasse.

@Configuration offentlig klasse TaxiFareMVCConfig implementerer WebMvcConfigurer {@Autowired private TaxiFareRequestInterceptor taxiFareRequestInterceptor; @Override public void addInterceptors (InterceptorRegistry registry) {registry.addInterceptor (taxiFareRequestInterceptor) .addPathPatterns ("/ ** / taxifare / ** /"); }}

Avslutningsvis, WebMvcConfigurer legger til TaxiFareRequestInterceptor inne i våren MVC livssyklus ved å påkalle addInterceptors () metode.

Den største utfordringen er å få kopiene av forespørselen og svarets nyttelast for loggføring, og likevel legge igjen den forespurte nyttelasten til servletten for å behandle den.

Hovedproblemet med leseforespørselen er at så snart inngangsstrømmen leses for første gang, er den merket som forbrukt og kan ikke leses igjen.

Søknaden kaster et unntak etter å ha lest forespørselsstrømmen:

{"tidsstempel": 1500645243383, "status": 400, "error": "Dårlig forespørsel", "unntak": "org.springframework.http.converter. HttpMessageNotReadableException", "message": "Kunne ikke lese dokumentet: Stream stengt ; nestet unntak er java.io.IOException: Stream closed "," path ":" / rest-log / taxifare / calcute / "}

For å overvinne dette problemet, kan vi utnytte caching for å lagre forespørselsstrømmen og bruke den til logging.

Spring gir få nyttige klasser som ContentCachingRequestWrapper og ContentCachingResponseWrapper som kan brukes til å cache forespørselsdataene for loggingsformål.

La oss justere vår preHandle () av TaxiRideRequestInterceptor klasse for å cache forespørselsobjektet ved hjelp av ContentCachingRequestWrapper klasse.

@ Override offentlig boolsk preHandle (HttpServletRequest-forespørsel, HttpServletResponse-svar, Objektbehandler) {HttpServletRequest requestCacheWrapperObject = nytt ContentCachingRequestWrapper (forespørsel); requestCacheWrapperObject.getParameterMap (); // Les inputStream fra requestCacheWrapperObject og logg den return true; }

Som vi kan se, har vi lagret forespørselsobjektet ved hjelp av ContentCachingRequestWrapper klasse som kan brukes til å lese nyttelastdata for logging uten å forstyrre det faktiske forespørselsobjektet:

requestCacheWrapperObject.getContentAsByteArray ();

Begrensning

  • ContentCachingRequestWrapper klasse støtter bare følgende:
Content-Type: application / x-www-form-urlencoded Method-Type: POST
  • Vi må påberope oss følgende metode for å sikre at forespørselsdata lagres i hurtigbuffer ContentCachingRequestWrapper før du bruker den:
requestCacheWrapperObject.getParameterMap ();

5. Innebygd vårlogging

Spring gir en innebygd løsning for å logge nyttelast. Vi kan bruke ferdige filtre ved å koble til vårapplikasjonen ved hjelp av konfigurasjon.

AbstractRequestLoggingFilter er et filter som gir grunnleggende funksjoner for logging. Underklasser bør overstyre beforeRequest () og afterRequest () metoder for å utføre selve loggingen rundt forespørselen.

Spring framework gir tre konkrete implementeringsklasser som kan brukes til å logge innkommende forespørsel. Disse tre klassene er:

  • CommonsRequestLoggingFilter
  • Log4jNestedDiagnosticContextFilter (utfaset)
  • ServletContextRequestLoggingFilter

La oss nå gå videre til CommonsRequestLoggingFilter og konfigurer den til å fange innkommende forespørsel om logging.

5.1. Konfigurer Spring Boot Application

Spring Boot-applikasjonen kan konfigureres ved å legge til en bønnedefinisjon for å aktivere forespørsellogging:

@Configuration public class RequestLoggingFilterConfig {@Bean public CommonsRequestLoggingFilter logFilter () {CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter (); filter.setIncludeQueryString (true); filter.setIncludePayload (true); filter.setMaxPayloadLength (10000); filter.setIncludeHeaders (false); filter.setAfterMessagePrefix ("FORESPØRSEL DATA:"); returfilter; }}

Dette loggfilteret krever også at loggnivået er satt til DEBUG. Vi kan aktivere DEBUG-modus ved å legge til elementet nedenfor i logback.xml:

En annen måte å aktivere DEBUG-nivåloggen er å legge til følgende i application.properties:

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

5.2. Konfigurer tradisjonell webapplikasjon

I vårens standardapplikasjon, Filter kan stilles inn enten via XML-konfigurasjon eller Java-konfigurasjon. La oss sette opp CommonsRequestLoggingFilter ved hjelp av konvensjonell Java-basert konfigurasjon.

Som vi vet, inkludererPayload attributt av CommonsRequestLoggingFilter er satt til false som standard. Vi trenger en tilpasset klasse for å overstyre verdien av attributtet for å aktivere det inkludererPayload før du injiserer i beholderen ved hjelp av Java-konfigurasjon:

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

Nå må vi injisere CustomeRequestLoggingFilter ved hjelp av Java-basert nettinitialisering:

offentlig klasse CustomWebAppInitializer implementerer WebApplicationInitializer {public void onStartup (ServletContext container) {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext (); context.setConfigLocation ("com.baeldung"); container.addListener (ny ContextLoaderListener (kontekst)); ServletRegistration.Dynamic dispatcher = container.addServlet ("dispatcher", ny DispatcherServlet (kontekst)); dispatcher.setLoadOnStartup (1); dispatcher.addMapping ("/"); container.addFilter ("customRequestLoggingFilter", CustomeRequestLoggingFilter.class) .addMappingForServletNames (null, false, "dispatcher"); }}

6. Eksempel i aksjon

Nå kan vi koble opp en Spring Boot med kontekst og se i handling at logging av innkommende forespørsler fungerer som forventet:

@Test offentlig ugyldig givenRequest_whenFetchTaxiFareRateCard_thanOK () {TestRestTemplate testRestTemplate = ny TestRestTemplate (); TaxiRide taxiRide = ny TaxiRide (true, 10l); String fare = testRestTemplate.postForObject (URL + "beregne /", taxiRide, String.class); assertThat (fare, equalTo ("200")); }

7. Konklusjon

I denne artikkelen viste vi hvordan du implementerer grunnleggende nettforespørsellogging ved hjelp av avlyttere; vi viste også begrensningene og utfordringene med denne løsningen.

Så viste vi den innebygde filterklassen som gir klar til bruk og enkel loggingsmekanisme.

Som alltid er implementeringen av eksemplet og kodebiter tilgjengelig på GitHub.


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