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

io.airlift.http.client.jetty.HttpRequestEvent Maven / Gradle / Ivy

The newest version!
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.airlift.http.client.jetty;

import com.google.common.annotations.VisibleForTesting;
import io.airlift.http.client.jetty.HttpClientLogger.RequestInfo;
import io.airlift.http.client.jetty.HttpClientLogger.ResponseInfo;
import jakarta.annotation.Nullable;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.http.HttpFields;

import java.time.Instant;
import java.util.Locale;
import java.util.Optional;

import static io.airlift.http.client.TraceTokenRequestFilter.TRACETOKEN_HEADER;
import static java.lang.Math.max;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

class HttpRequestEvent
{
    static final int NO_RESPONSE = -1;

    private final Instant timeStamp;
    private final String protocolVersion;
    private final String method;
    private final String requestUri;
    private final String traceToken;

    // Response-related fields can have the value of NO_RESPONSE for the requests
    // that didn't get any response (e.g., due to timeouts or other failures).
    private final long responseSize;
    private final int responseCode;
    private final long requestTotalTime;
    private final long requestQueueTime;
    private final long requestBeginToRequestEnd;
    private final long requestEndToResponseBegin;
    private final long responseBeginToResponseEnd;
    private final long timeToLastByte;
    private final Optional failureReason;

    private HttpRequestEvent(
            Instant timeStamp,
            String protocolVersion,
            String method,
            String requestUri,
            @Nullable String traceToken,
            long responseSize,
            int responseCode,
            long requestTotalTime,
            long requestQueueTime,
            long requestBeginToRequestEnd,
            long requestEndToResponseBegin,
            long responseBeginToResponseEnd,
            long timeToLastByte,
            Optional failureReason)
    {
        this.timeStamp = requireNonNull(timeStamp, "timeStamp is null");
        this.protocolVersion = requireNonNull(protocolVersion, "protocolVersion is null");
        this.method = requireNonNull(method, "method is null");
        this.requestUri = requireNonNull(requestUri, "requestUri is null");
        this.traceToken = traceToken;
        this.responseSize = responseSize;
        this.responseCode = responseCode;
        this.requestTotalTime = requestTotalTime;
        this.requestQueueTime = requestQueueTime;
        this.requestBeginToRequestEnd = requestBeginToRequestEnd;
        this.requestEndToResponseBegin = requestEndToResponseBegin;
        this.responseBeginToResponseEnd = responseBeginToResponseEnd;
        this.timeToLastByte = timeToLastByte;
        this.failureReason = requireNonNull(failureReason, "failureReason is null");
    }

    public Instant getTimeStamp()
    {
        return timeStamp;
    }

    public String getProtocolVersion()
    {
        return protocolVersion;
    }

    public String getMethod()
    {
        return method;
    }

    public String getRequestUri()
    {
        return requestUri;
    }

    public String getTraceToken()
    {
        return traceToken;
    }

    public long getResponseSize()
    {
        return responseSize;
    }

    public String getResponseCode()
    {
        return failureReason.orElseGet(() -> Integer.toString(responseCode));
    }

    public long getRequestTotalTime()
    {
        return requestTotalTime;
    }

    public long getRequestQueueTime()
    {
        return requestQueueTime;
    }

    public long getRequestBeginToRequestEnd()
    {
        return requestBeginToRequestEnd;
    }

    public long getRequestEndToResponseBegin()
    {
        return requestEndToResponseBegin;
    }

    public long getResponseBeginToResponseEnd()
    {
        return responseBeginToResponseEnd;
    }

    public long getTimeToLastByte()
    {
        return timeToLastByte;
    }

    static HttpRequestEvent createHttpRequestEvent(RequestInfo requestInfo, ResponseInfo responseInfo)
    {
        requireNonNull(requestInfo, "requestInfo is null");
        requireNonNull(responseInfo, "responseInfo is null");
        Request request = requestInfo.getRequest();
        Optional response = responseInfo.getResponse();

        String requestUri = null;
        if (request.getURI() != null) {
            requestUri = request.getURI().toString();
        }

        String method = request.getMethod();
        if (method != null) {
            method = method.toUpperCase(Locale.US);
        }

        long responseSize = NO_RESPONSE;
        int responseCode = NO_RESPONSE;
        if (response.isPresent()) {
            responseSize = responseInfo.getResponseSize();
            responseCode = response.get().getStatus();
        }

        long requestTotalTimeNanos = responseInfo.getResponseCompleteTimestamp() - requestInfo.getRequestCreatedTimestamp();
        long requestBeginToRequestEndNanos = requestInfo.getRequestEndTimestamp() - requestInfo.getRequestBeginTimestamp();
        long responseBeginTimeStamp = responseInfo.getResponseBeginTimestamp();
        long requestEndToResponseBeginNanos = 0;
        long responseBeginToResponseEndNanos = 0;
        // responseBeginTimeStamp is 0 if a response isn't received
        if (responseBeginTimeStamp != 0) {
            requestEndToResponseBeginNanos = responseBeginTimeStamp - requestInfo.getRequestEndTimestamp();
            responseBeginToResponseEndNanos = responseInfo.getResponseCompleteTimestamp() - responseBeginTimeStamp;
        }
        long timeToLastByte = max(responseInfo.getResponseTimestampMillis() - requestInfo.getRequestTimestampMillis(), 0L);

        return new HttpRequestEvent(
                Instant.ofEpochMilli(requestInfo.getRequestTimestampMillis()),
                request.getVersion().toString(),
                method,
                requestUri,
                getHeader(request, TRACETOKEN_HEADER),
                responseSize,
                responseCode,
                NANOSECONDS.toMillis(requestTotalTimeNanos),
                NANOSECONDS.toMillis(requestInfo.getRequestBeginTimestamp() - requestInfo.getRequestCreatedTimestamp()),
                NANOSECONDS.toMillis(requestBeginToRequestEndNanos),
                NANOSECONDS.toMillis(requestEndToResponseBeginNanos),
                NANOSECONDS.toMillis(responseBeginToResponseEndNanos),
                timeToLastByte,
                getFailureReason(responseInfo));
    }

    @VisibleForTesting
    static Optional getFailureReason(ResponseInfo responseInfo)
    {
        Optional failure = responseInfo.getFailureCause();

        if (!failure.isPresent()) {
            return Optional.empty();
        }

        String className = failure.get().getClass().getSimpleName().toUpperCase(Locale.US);

        if (className.endsWith("EXCEPTION")) {
            return Optional.of(className.substring(0, className.lastIndexOf("EXCEPTION")));
        }

        return Optional.of(className);
    }

    @Nullable
    private static String getHeader(Request request, String header)
    {
        requireNonNull(header, "header is null");
        HttpFields headers = request.getHeaders();
        if (headers != null) {
            return headers.get(header);
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy