All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.convergence_platform.services.observability.RequestLog Maven / Gradle / Ivy

Go to download

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) {

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy