public static void onExitServlet()

in apm-agent-plugins/apm-servlet-plugin/src/main/java/co/elastic/apm/agent/servlet/ServletApiAdvice.java [171:298]


    public static <HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> void onExitServlet(
        ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> adapter,
        Object servletRequest,
        Object servletResponse,
        @Nullable Object transactionOrScopeOrSpan,
        @Nullable Throwable t,
        Object thiz) {

        Tracer tracer = GlobalTracer.get();

        Transaction<?> transaction = null;
        Scope scope = null;
        Span<?> span = null;
        if (transactionOrScopeOrSpan instanceof Transaction<?>) {
            transaction = (Transaction<?>) transactionOrScopeOrSpan;
        } else if (transactionOrScopeOrSpan instanceof Scope) {
            scope = (Scope) transactionOrScopeOrSpan;
        } else if (transactionOrScopeOrSpan instanceof Span<?>) {
            span = (Span<?>) transactionOrScopeOrSpan;
        }

        excluded.remove();
        if (scope != null) {
            scope.close();
        }
        HttpServletRequest httpServletRequest = adapter.asHttpServletRequest(servletRequest);
        HttpServletResponse httpServletResponse = adapter.asHttpServletResponse(servletResponse);
        if (adapter.isInstanceOfHttpServlet(thiz) && httpServletRequest != null) {
            Transaction<?> currentTransaction = tracer.currentTransaction();
            if (currentTransaction != null) {
                TransactionNameUtils.setTransactionNameByServletClass(adapter.getMethod(httpServletRequest), thiz.getClass(), currentTransaction.getAndOverrideName(PRIORITY_LOW_LEVEL_FRAMEWORK));

                String userName = ServletTransactionHelper.getUserFromPrincipal(adapter.getUserPrincipal(httpServletRequest));
                if (userName != null) {
                    ServletTransactionHelper.setUsernameIfUnset(userName, currentTransaction.getContext());
                }
            }
        }
        if (transaction != null &&
            httpServletRequest != null &&
            httpServletResponse != null) {

            if (adapter.getAttribute(httpServletRequest, ServletTransactionHelper.ASYNC_ATTRIBUTE) != null) {
                // HttpServletRequest.startAsync was invoked on this httpServletRequest.
                // The transaction should be handled from now on by the other thread committing the response
                transaction.deactivate();
            } else {
                // this is not an async httpServletRequest, so we can end the transaction immediately
                if (transaction.isSampled() && tracer.getConfig(CoreConfiguration.class).isCaptureHeaders()) {
                    final Response resp = transaction.getContext().getResponse();
                    for (String headerName : adapter.getHeaderNames(httpServletResponse)) {
                        resp.addHeader(headerName, adapter.getHeaders(httpServletResponse, headerName));
                    }
                }
                // httpServletRequest.getParameterMap() may allocate a new map, depending on the servlet container implementation
                // so only call this method if necessary
                final String contentTypeHeader = adapter.getHeader(httpServletRequest, "Content-Type");
                final Map<String, String[]> parameterMap;
                if (transaction.isSampled() && servletTransactionHelper.captureParameters(adapter.getMethod(httpServletRequest), contentTypeHeader)) {
                    parameterMap = adapter.getParameterMap(httpServletRequest);
                } else {
                    parameterMap = null;
                }

                Throwable t2 = null;
                boolean overrideStatusCodeOnThrowable = true;
                if (t == null) {
                    final int size = requestExceptionAttributes.size();
                    for (int i = 0; i < size; i++) {
                        String attributeName = requestExceptionAttributes.get(i);
                        Object throwable = adapter.getAttribute(httpServletRequest, attributeName);
                        // We don't check tracer.getConfig(CoreConfiguration.class).isAvoidTouchingExceptions() here,
                        // because in that case the corrupt pointer is already stored in the request attributes
                        // In that case we already lost, because the GC will complain about the broken pointer
                        // when the request attributes entry is GCed
                        if (throwable instanceof Throwable) {
                            t2 = (Throwable) throwable;

                            // elastic exception can be removed as it's not needed after transaction end
                            if (attributeName.equals(ELASTIC_EXCEPTION)) {
                                adapter.removeAttribute(httpServletRequest, attributeName);
                            }

                            if (!attributeName.equals(JAVAX_ERROR_EXCEPTION) && !attributeName.equals(JAKARTA_ERROR_EXCEPTION)) {
                                overrideStatusCodeOnThrowable = false;
                            }
                            break;
                        }
                    }
                    if (t2 == null) {
                        t2 = transaction.getPendingTransactionException();
                        if(t2 != null) {
                            overrideStatusCodeOnThrowable = false;
                        }
                    }
                }

                ServletContext servletContext = adapter.getServletContext(httpServletRequest);
                String servletPath = adapter.getServletPath(httpServletRequest);
                String pathInfo = adapter.getPathInfo(httpServletRequest);
                if ((servletPath == null || servletPath.isEmpty()) && servletContext != null) {
                    String contextPath = adapter.getContextPath(servletContext);
                    String requestURI = adapter.getRequestURI(httpServletRequest);
                    servletPath = servletTransactionHelper.normalizeServletPath(requestURI, contextPath, servletPath, pathInfo);
                }

                servletTransactionHelper.onAfter(
                    transaction, t == null ? t2 : t,
                    adapter.isCommitted(httpServletResponse),
                    adapter.getStatus(httpServletResponse),
                    overrideStatusCodeOnThrowable,
                    adapter.getMethod(httpServletRequest),
                    parameterMap,
                    servletPath,
                    pathInfo,
                    contentTypeHeader,
                    true);
            }
        }
        if (span != null) {
            servletPathTL.remove();
            pathInfoTL.remove();
            span.captureException(t)
                .withOutcome(t != null ? Outcome.FAILURE : Outcome.SUCCESS)
                .deactivate()
                .end();
        }
    }