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));
I found a solution to this issue, but it's not the cleanest route and I would gladly take another suggestion if possible.
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;
}