io.convergence_platform.services.observability.RequestLog Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of service-lib Show documentation
Show all versions of service-lib Show documentation
Holds the common functionality needed by all Convergence Platform-based services written in Java.
The newest version!
package io.convergence_platform.services.observability;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.convergence_platform.common.dto.RequestValidationFailureDTO;
import io.convergence_platform.common.dto.RequestValidationFieldFailureDTO;
import io.convergence_platform.common.exceptions.ManagedApiException;
import io.convergence_platform.common.helpers.ConvergenceHelpers;
import io.convergence_platform.common.responses.ApiResponse;
import io.convergence_platform.common.responses.Errors;
import io.convergence_platform.common.responses.HttpErrors;
import io.convergence_platform.common.responses.ListApiResponse;
import io.convergence_platform.services.constants.IServiceInfo;
import jakarta.servlet.http.HttpServletRequest;
import java.util.*;
public class RequestLog {
public static final String REQUEST_ID_HEADER = "X-CONVERGENCE-REQUEST-ID";
public static final String PARENT_REQUEST_ID_HEADER = "X-CONVERGENCE-PARENT-REQUEST-ID";
public static final String CALLER_SERVICE_HEADER = "X-CONVERGENCE-CALLER-SERVICE";
public static final String CALLER_SERVICE_HASH_HEADER = "X-CONVERGENCE-CALLER-SERVICE-HASH";
public static final String CALLER_SERVICE_VERSION_HEADER = "X-CONVERGENCE-CALLER-SERVICE-VERSION";
@JsonProperty("request_identifier")
public String requestIdentifier;
@JsonProperty("parent_request_identifier")
public String parentRequestIdentifier;
@JsonProperty("caller_service")
public LogEntryServiceInfo callerService;
@JsonProperty("receiver_service")
public LogEntryServiceInfo receiverService;
@JsonProperty("start_timestamp")
public long startTimestamp;
@JsonProperty("end_timestamp")
public long endTimestamp;
@JsonProperty("headers")
public Map headers;
@JsonProperty("url")
public String url;
@JsonProperty("parameters")
public Object[] parameters;
@JsonProperty("log_entries")
public List logEntries = new ArrayList<>();
@JsonProperty("response")
public Object response;
private RequestLog() {
}
public static RequestLog initialize(String requestType, HttpServletRequest httpRequest, IServiceInfo serviceInfo, boolean isBehindGateway, Object... parameters) {
if (isBehindGateway) {
validateBehindGatewayHeaders(httpRequest);
}
RequestLog result = new RequestLog();
result.startTimestamp = System.currentTimeMillis();
result.headers = loadRequestHeaders(httpRequest);
result.requestIdentifier = getRequestIDFromHeader(httpRequest, result, requestType, isBehindGateway);
result.parentRequestIdentifier = loadParentIdentifier(httpRequest, result.headers, requestType);
result.callerService = loadCallerService(result.headers);
result.receiverService = loadCurrentService(serviceInfo);
result.url = getRequestURI(httpRequest);
result.parameters = parameters;
result.headers.remove(REQUEST_ID_HEADER.toLowerCase());
result.headers.remove(PARENT_REQUEST_ID_HEADER.toLowerCase());
result.headers.remove(CALLER_SERVICE_HEADER.toLowerCase());
result.headers.remove(CALLER_SERVICE_HASH_HEADER.toLowerCase());
result.headers.remove(CALLER_SERVICE_VERSION_HEADER.toLowerCase());
return result;
}
private static void validateBehindGatewayHeaders(HttpServletRequest httpRequest) {
List missingHeaders = new ArrayList<>();
if (ConvergenceHelpers.getGatewayHeaderFromRequest(REQUEST_ID_HEADER, httpRequest) == null)
missingHeaders.add(REQUEST_ID_HEADER);
if (ConvergenceHelpers.getGatewayHeaderFromRequest(CALLER_SERVICE_HEADER, httpRequest) == null)
missingHeaders.add(CALLER_SERVICE_HEADER);
if (ConvergenceHelpers.getGatewayHeaderFromRequest(CALLER_SERVICE_HASH_HEADER, httpRequest) == null)
missingHeaders.add(CALLER_SERVICE_HASH_HEADER);
if (ConvergenceHelpers.getGatewayHeaderFromRequest(CALLER_SERVICE_VERSION_HEADER, httpRequest) == null)
missingHeaders.add(CALLER_SERVICE_VERSION_HEADER);
if (!missingHeaders.isEmpty()) {
RequestValidationFailureDTO details = new RequestValidationFailureDTO();
for (String header : missingHeaders) {
RequestValidationFieldFailureDTO missingHeader = new RequestValidationFieldFailureDTO();
missingHeader.field = header;
missingHeader.location = "header";
missingHeader.messages.add("Request is missing header.");
details.errors.add(missingHeader);
}
throw new ManagedApiException(HttpErrors.GATEWAY_ERROR, Errors.INVALID_DATA, "The request input was invalid, missing the mandatory API gateway headers.", details);
}
}
private static String getRequestIDFromHeader(HttpServletRequest request, RequestLog result, String requestType, boolean isBehindGateway) {
UUID requestId = ConvergenceHelpers.getRequestIdFromRequest(request, true);
if (!isBehindGateway) {
if (requestId != null) {
throw new ManagedApiException(HttpErrors.BAD_REQUEST, Errors.INVALID_DATA, "The request has unexpected request ID header.");
}
requestId = UUID.randomUUID();
}
return requestType.toLowerCase() + "_" + requestId.toString();
}
private static String getRequestURI(HttpServletRequest request) {
StringBuilder requestURL = new StringBuilder(request.getRequestURI());
String queryString = request.getQueryString();
if (queryString == null) {
return requestURL.toString();
} else {
return requestURL.append('?').append(queryString).toString();
}
}
@JsonIgnore
public String getRawRequestID() {
String result= requestIdentifier;
if (result.contains("_")) {
result = result.substring(result.lastIndexOf("_") + 1);
}
return result;
}
private static LogEntryServiceInfo loadCurrentService(IServiceInfo serviceInfo) {
LogEntryServiceInfo result = new LogEntryServiceInfo();
result.name = serviceInfo.getServiceName();
result.hash = serviceInfo.getServiceVersionHash();
result.version = serviceInfo.getServiceVersion();
return result;
}
private static LogEntryServiceInfo loadCallerService(Map headers) {
LogEntryServiceInfo result = new LogEntryServiceInfo();
result.name = headers.get(CALLER_SERVICE_HEADER);
result.hash = headers.get(CALLER_SERVICE_HASH_HEADER);
result.version = headers.get(CALLER_SERVICE_VERSION_HEADER);
return result;
}
private static String loadParentIdentifier(HttpServletRequest httpRequest, Map headers, String requestType) {
UUID content = ConvergenceHelpers.getParentRequestIdFromRequest(httpRequest);
if (content != null) {
return content.toString();
}
return null;
}
private static Map loadRequestHeaders(HttpServletRequest httpRequest) {
var names = httpRequest.getHeaderNames();
Map result = new HashMap<>();
while (names.hasMoreElements()) {
String header = names.nextElement();
String value = httpRequest.getHeader(header);
result.put(header.toLowerCase(), value);
}
return result;
}
public void finish(ApiResponse response) {
this.endTimestamp = System.currentTimeMillis();
this.response = response;
}
public void finish(ListApiResponse response) {
this.endTimestamp = System.currentTimeMillis();
this.response = response;
}
public void info(String message, Object... arguments) {
addLogEntry("info", message, arguments);
}
public void error(String message, Object... arguments) {
addLogEntry("error", message, arguments);
}
public void warning(String message, Object... arguments) {
addLogEntry("warning", message, arguments);
}
public void debug(String message, Object... arguments) {
addLogEntry("debug", message, arguments);
}
private void addLogEntry(String level, String message, Object[] arguments) {
LogEntry entry = new LogEntry();
entry.timestamp = System.currentTimeMillis();
entry.level = level;
entry.message = message;
entry.arguments = arguments;
entry.type = "log_entry";
entry.threadID = Thread.currentThread().getId();
synchronized (this) {
this.logEntries.add(entry);
}
}
public void exception(Exception ex) {
}
}