Search code examples
javaliteactiveweb

javalite Activeweb how to get response body string for logging purpose in HttpSupportFilter


How to get responseBody string for logging purpose in HttpSupportFilter?

Common log solution is create wrapper and insert it to the standar filter

If we use standar filter we cannot access activejdbc db connection layer

I tried to apply wrapper but it does not work, the string is still empty

public class HTTPLogFilter extends HttpSupportFilter {

    private static ThreadLocal<Long> start = new ThreadLocal<>();
    
    @Override
    public void before() {
        start.set(System.currentTimeMillis());
    }

    @Override
    public void after() {

        if(Configuration.HTTPLOGS_ENABLE) {

            Registry.instance().getStatisticsQueue().enqueue(
                    new QueryExecutionEvent(getRoute().getController().getClass().getName() +
                            "#" + getRoute().getActionName() + ":" + method(), System.currentTimeMillis() - start.get()));

            HttpLog httpLog = new HttpLog();

            String username ="TEST";

            Map request = new HashMap<String, Object>();
            request.put("requestUrl", url());
            request.put("contextPath", context());
            request.put("uriFullPath", uri());
            request.put("uriPath", path());
            request.put("method", method());
            request.put("requestHeaders", headers());
            request.put("requestParams", params());
            request.put("queryString", queryString());
            request.put("requestBody", getRequestString());

            Map response = new HashMap<String, Object>();
            response.put("responseHeaders", getResponseHeaders());
            try {
                // BUG ! this responseBody still empty
                response.put("responseBody", getHttpServletResponse().getWriter().toString());
            } catch (IOException e) {
                e.printStackTrace();
            }

            httpLog.setCreatedby(username);
            httpLog.setCreateddt(new Date());
            httpLog.setUsername(username);
            String remoteAddr = ipForwardedFor() != null ? ipForwardedFor() : remoteAddress();
            httpLog.setIpaddress(remoteAddr );
            httpLog.setUseragent(userAgent());
            httpLog.setControllername(getRoute().getController().getClass().getName() + "." + getRoute().getActionName());
            httpLog.setHttpmethod(method());
            httpLog.setHttpexceptions("");
            httpLog.setExecutiondt(new Date(start.get()));
            httpLog.setExecutiondur(System.currentTimeMillis() - start.get());
            httpLog.setHttpurl(url());
            httpLog.setHttprequest(JsonHelper.toJson(request));
            httpLog.setHttpresponse(JsonHelper.toJson(response));
            httpLog.setHttpstatuscode(getHttpServletResponse().getStatus());
            httpLog.saveIt();
        }
    }

}

Solution

  • generally, you are on the right path. It is my understanding that HttpLog is a model, and you want to store the request values that to database, correct?

    You write:

    if we use standar filter we cannot access activejdbc db connection layer

    So, the ActiveWeb filters have ordering, which is documented here: https://javalite.io/controller_filters#filter-ordering

    This means that if you want a database connection available in the HTTPLogFilter, you have to register the DBConnectionFilter before the HTTPLogFilter, example:

    public class AppControllerConfig extends AbstractControllerConfig {
        public void init(AppContext appContext) {
            add(new DBConnectionFilter(), new HTTPLogFilter());
        }
    }
    

    This way, the DBConnectionFilter.before() will be called before the HTTPLogFilter.before() and will open a DB connection accordingly.

    On the side note: you will be filling your database pretty quickly, and a recommendation is to simply log all this data to a log file and use a log analyzer like Splunk or Graylog.