/** * Returns the value of calling {@link ServletRuntime#isAsyncRequest(HttpServletRequest)} on the {@link * ServletRuntime} returned by {@link #getServletRuntime(ServletRequest)}. This method is here to allow * easy overriding by subclasses if needed, where {@link ServletRuntime} is not in scope. * * @param request The request to inspect to see if it's part of an async servlet request or not. * * @return the value of calling {@link ServletRuntime#isAsyncRequest(HttpServletRequest)} on the {@link * ServletRuntime} returned by {@link #getServletRuntime(ServletRequest)}. */ protected boolean isAsyncRequest(HttpServletRequest request) { return getServletRuntime(request).isAsyncRequest(request); }
@Override @SuppressWarnings("RedundantThrows") public void init(FilterConfig filterConfig) throws ServletException { this.userIdHeaderKeysFromInitParam = initializeUserIdHeaderKeys(filterConfig); this.tagAndNamingStrategy = initializeTagAndNamingStrategy(filterConfig); this.tagAndNamingAdapter = initializeTagAndNamingAdapter(filterConfig); }
/** * @return {@link #getZipkinHttpTagStrategy()} (i.e. the default tag and naming strategy is the Zipkin tag strategy). */ protected HttpTagAndSpanNamingStrategy<HttpServletRequest, HttpServletResponse> getDefaultTagStrategy() { return getZipkinHttpTagStrategy(); }
private RequestTracingFilter getBasicFilter() { RequestTracingFilter filter = new RequestTracingFilter(); try { filter.init(filterConfigMock); filter.tagAndNamingStrategy = tagAndNamingStrategy; filter.tagAndNamingAdapter = tagAndNamingAdapterMock; } catch (ServletException e) { throw new RuntimeException(e); } return filter; }
@Bean public RequestTracingFilter requestTracingFilter() { return new RequestTracingFilter(); }
@Test public void getServletRuntime_returns_value_of_ServletRuntime_determineServletRuntime_method_and_caches_result() { // given Class<? extends ServletRuntime> expectedServletRuntimeClass = ServletRuntime.determineServletRuntime(requestMock.getClass(), ASYNC_LISTENER_CLASSNAME).getClass(); RequestTracingFilter filter = getBasicFilter(); assertThat(filter.servletRuntime).isNull(); // when ServletRuntime result = filter.getServletRuntime(requestMock); // then assertThat(result.getClass()).isEqualTo(expectedServletRuntimeClass); assertThat(filter.servletRuntime).isSameAs(result); }
/** * Delegates to {@link * ServletRuntime#setupTracingCompletionWhenAsyncRequestCompletes(HttpServletRequest, HttpServletResponse, * TracingState, HttpTagAndSpanNamingStrategy, HttpTagAndSpanNamingAdapter)}, with the {@link ServletRuntime} * retrieved via {@link #getServletRuntime(ServletRequest)}. This method is here to allow easy overriding by * subclasses if needed, where {@link ServletRuntime} is not in scope. * * @param asyncRequest The async servlet request (guaranteed to be async since this method will only be called when * {@link #isAsyncRequest(HttpServletRequest)} returns true). * @param asyncResponse The servlet response object - needed for span tagging. * @param originalRequestTracingState The {@link TracingState} that was generated when this request started, and * which should be completed when the given async servlet request finishes. * @param tagAndNamingStrategy The {@link HttpTagAndSpanNamingStrategy} that should be used for final span name * and tagging. * @param tagAndNamingAdapter The {@link HttpTagAndSpanNamingAdapter} that should be used by * {@code tagAndNamingStrategy} for final span name and tagging. */ protected void setupTracingCompletionWhenAsyncRequestCompletes( HttpServletRequest asyncRequest, HttpServletResponse asyncResponse, TracingState originalRequestTracingState, HttpTagAndSpanNamingStrategy<HttpServletRequest, HttpServletResponse> tagAndNamingStrategy, HttpTagAndSpanNamingAdapter<HttpServletRequest,HttpServletResponse> tagAndNamingAdapter ) { getServletRuntime(asyncRequest).setupTracingCompletionWhenAsyncRequestCompletes( asyncRequest, asyncResponse, originalRequestTracingState, tagAndNamingStrategy, tagAndNamingAdapter ); }
/** * The dispatcher type {@code javax.servlet.DispatcherType.ASYNC} introduced in Servlet 3.0 means a filter can be * invoked in more than one thread over the course of a single request. This method should return {@code true} if * the filter is currently executing within an asynchronous dispatch. * * @param request the current request * * @deprecated This method is no longer used to determine whether this filter should execute, and will be removed * in a future update. It remains here only to prevent breaking impls that overrode the method. */ @Deprecated protected boolean isAsyncDispatch(HttpServletRequest request) { return getServletRuntime(request).isAsyncDispatch(request); }
@Before public void beforeMethod() { servlet2Runtime = new Servlet2Runtime(); servlet3Runtime = new Servlet3Runtime(); requestMock = mock(HttpServletRequest.class); responseMock = mock(HttpServletResponse.class); }
@Test public void doFilter_should_not_explode_if_request_and_response_are_HttpServletRequests_and_HttpServletResponses( ) throws IOException, ServletException { // expect getBasicFilter().doFilter( mock(HttpServletRequest.class), mock(HttpServletResponse.class), mock(FilterChain.class) ); // No explosion no problem }
@Test public void skipDispatch_should_return_false() { // given: filter RequestTracingFilter filter = getBasicFilter(); // when: skipDispatchIsCalled boolean result = filter.skipDispatch(requestMock); // then: the result should be false assertThat(result).isFalse(); }
@Test public void getServletRuntime_uses_cached_value_if_possible() { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); ServletRuntime servletRuntimeMock = mock(ServletRuntime.class); filterSpy.servletRuntime = servletRuntimeMock; // when ServletRuntime result = filterSpy.getServletRuntime(mock(HttpServletRequest.class)); // then assertThat(result).isSameAs(servletRuntimeMock); }
@Override public void onComplete(AsyncEvent event) { completeRequestSpan(event); }
@Override public @Nullable String getRequestUriPathTemplate( @Nullable HttpServletRequest request, @Nullable HttpServletResponse response ) { return HttpSpanFactory.determineUriPathTemplate(request); }
/** * Attempts to pull a valid ID for the user making the request. * * @return The HTTP Header value of the user ID if it exists, null otherwise. The request's headers will be inspected for the user ID using the given list of userIdHeaderKeys * in list order - the first one found that is not null/empty will be returned. */ public static String getUserIdFromHttpServletRequest(HttpServletRequest servletRequest, List<String> userIdHeaderKeys) { if (servletRequest == null) return null; return HttpRequestTracingUtils.getUserIdFromRequestWithHeaders(new RequestWithHeadersServletAdapter(servletRequest), userIdHeaderKeys); }
@After public void afterMethod() { resetTracing(); }
@After public void afterMethod() { resetTracing(); }
@Bean public RequestTracingFilter requestTracingFilter() { return new RequestTracingFilter(); }
@Test(expected = ServletException.class) public void doFilter_should_explode_if_request_is_not_HttpServletRequest() throws IOException, ServletException { // expect getBasicFilter().doFilter(mock(ServletRequest.class), mock(HttpServletResponse.class), mock(FilterChain.class)); fail("Expected ServletException but no exception was thrown"); }
@Test(expected = ServletException.class) public void doFilter_should_explode_if_response_is_not_HttpServletResponse() throws IOException, ServletException { // expect getBasicFilter().doFilter(mock(HttpServletRequest.class), mock(ServletResponse.class), mock(FilterChain.class)); fail("Expected ServletException but no exception was thrown"); }