0

I have a Spring Boot Java REST application with many APIs exposed to our clients and UI. I was tasked with implementing a Transaction logging framework that will capture the incoming transactions along with the response we send.

I have this working with Spring AOP and an Around inspect and I'm currently utilizing the HttpServletRequest and HttpServletResponse objects to obtain a lot of the data I need.

From my local system I am not having any issues capturing the server used since I'm connecting to my system directly. However, once I deployed my code I saw that the load balancer URL was being captured instead of the actual server name.

I am also using Eureka to discover the API by name as it's only a single application running on HAProxy.

Imagine this flow:

 /*
 UI -> https://my-lb-url/service-sidecar/createUser

 HAProxy directs traffic to -> my-lb-url/service-sidecar/ to one of below:
      my-server-1:12345
      my-server-2:12345
      my-server-3:12345


 Goal  : http://my-server-1:1235/createUser
 Actual: https://my-lb-url/createUser

Here is the code I am using to get the incoming URL.

 String url = httpRequest.getRequestURL().toString();
 if(httpRequest.getQueryString() != null){
      transaction.setApi(url + "?" + httpRequest.getQueryString());
 } else {
      transaction.setApi(url);
 }

Note:

I am not as familiar with HAProxy/Eurkea/etc. as I would like to be. If something stated above seems off or wrong then I apologize. Our system admin configured those and locked the developers out.


UPDATE

This is the new code I am using to construct the Request URL, but I am still seeing the output the same.

// Utility Class

public static String constructRequestURL(HttpServletRequest httpRequest) {

    StringBuilder url = new StringBuilder(httpRequest.getScheme());
    url.append("://").append(httpRequest.getServerName());

    int port = httpRequest.getServerPort();
    if(port != 80 && port != 443) {
        url.append(":").append(port);
    }
    url.append(httpRequest.getContextPath()).append(httpRequest.getServletPath());

    if(httpRequest.getPathInfo() != null) {
        url.append(httpRequest.getPathInfo());
    }
    if(httpRequest.getQueryString() != null) {
        url.append("?").append(httpRequest.getQueryString());
    }
    return url.toString();
}

// Service Class

transaction.setApi(CommonUtil.constructRequestURL(httpRequest));
wheeleruniverse
  • 1,511
  • 2
  • 20
  • 37
  • Is this running on the nodes itself? If so I'd say you should be able to get the host and port out of the request. – Thomas Oct 16 '18 at 13:23
  • Yes, we have a separate JVM running on each server and the application jar is copied to all of them and managed separately. -- I will try httpRequest.getServerName() and httpRequest.getServerPort() – wheeleruniverse Oct 16 '18 at 13:24
  • It didn't work as I am still seeing the same URL generated. I changed my code to create the URL based on these separate fields following the example code from this post: https://stackoverflow.com/questions/2222238/httpservletrequest-to-complete-url – wheeleruniverse Oct 16 '18 at 19:20

1 Answers1

0

I found a solution to this issue, but it's not the cleanest route and I would gladly take another suggestion if possible.

  1. I am autowiring the port number from my application.yml.
  2. I am running the "hostname" command on the Linux server that is hosting the application to determine the server fulfilling the request.

Now the URL stored in the Transaction Logs is accurate.

--

@Autowired
private int serverPort; 

/*
 * ... 
 */

private String constructRequestURL(HttpServletRequest httpRequest) {

    StringBuilder url = new StringBuilder(httpRequest.getScheme())
            .append("://").append(findHostnameFromServer()).append(":").append(serverPort)
            .append(httpRequest.getContextPath()).append(httpRequest.getServletPath());

    if(httpRequest.getPathInfo() != null) {
        url.append(httpRequest.getPathInfo());
    }
    if(httpRequest.getQueryString() != null) {
        url.append("?").append(httpRequest.getQueryString());
    }
    return url.toString();
}

private String findHostnameFromServer(){

    String hostname = null;
    LOGGER.info("Attempting to Find Hostname from Server...");
    try {
        Process process = Runtime.getRuntime().exec(new String[]{"hostname"});
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            hostname = reader.readLine();
        }

    } catch (IOException e) {
        LOGGER.error(CommonUtil.ERROR, e);
    }
    LOGGER.info("Found Hostname: {}", hostname);
    return hostname;
}
wheeleruniverse
  • 1,511
  • 2
  • 20
  • 37