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

io.helidon.webclient.metrics.WebClientMetric Maven / Gradle / Ivy

There is a newer version: 4.1.4
Show newest version
/*
 * Copyright (c) 2020, 2024 Oracle and/or its affiliates.
 *
 * 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.helidon.webclient.metrics;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;

import io.helidon.common.config.Config;
import io.helidon.http.Method;
import io.helidon.metrics.api.MeterRegistry;
import io.helidon.metrics.api.Metrics;
import io.helidon.webclient.api.WebClientServiceRequest;
import io.helidon.webclient.api.WebClientServiceResponse;
import io.helidon.webclient.spi.WebClientService;

abstract class WebClientMetric implements WebClientService {

    private static final int ERROR_STATUS_CODE = 400;

    private final MeterRegistry registry;
    private final Set methods;
    private final String nameFormat;
    private final String description;
    private final boolean success;
    private final boolean errors;

    WebClientMetric(Builder builder) {
        this.registry = Metrics.globalRegistry();
        this.methods = builder.methods;
        this.nameFormat = builder.nameFormat;
        this.description = builder.description;
        this.success = builder.success;
        this.errors = builder.errors;
    }

    static Builder builder(WebClientMetricType clientMetricType) {
        return new Builder(clientMetricType);
    }

    @Override
    public String type() {
        return "metrics";
    }

    MeterRegistry meterRegistry() {
        return registry;
    }

    Set methods() {
        return methods;
    }

    String nameFormat() {
        return nameFormat;
    }

    String description() {
        return description;
    }

    boolean measureSuccess() {
        return success;
    }

    boolean measureErrors() {
        return errors;
    }

    boolean shouldContinueOnSuccess(Method method, int status) {
        return handlesMethod(method) && measureSuccess() && status < ERROR_STATUS_CODE;
    }

    boolean shouldContinueOnError(Method method) {
        return handlesMethod(method) && measureErrors();
    }

    boolean shouldContinueOnError(Method method, int status) {
        if (status >= ERROR_STATUS_CODE) {
            return shouldContinueOnError(method);
        }
        return false;
    }

    Metadata createMetadata(WebClientServiceRequest request, WebClientServiceResponse response) {
        String name;
        if (response == null) {
            name = createName(request);
        } else {
            name = createName(request, response);
        }
        Metadata.Builder builder = Metadata.builder().withName(name);
        if (description != null) {
            builder = builder.withDescription(description);
        }
        return builder.build();
    }

    String createName(WebClientServiceRequest request, WebClientServiceResponse response) {
        return String.format(nameFormat(), request.method().text(), request.uri().host(), response.status().code());
    }

    String createName(WebClientServiceRequest request) {
        return String.format(nameFormat(), request.method().text(), request.uri().host());
    }

    boolean handlesMethod(Method method) {
        return methods().isEmpty() || methods().contains(method.text());
    }

    /**
     * Client metric builder.
     */
    public static final class Builder implements io.helidon.common.Builder {

        private final WebClientMetricType type;
        private Set methods = Collections.emptySet();
        private String nameFormat;
        private String description;
        private boolean success = true;
        private boolean errors = true;

        private Builder(WebClientMetricType type) {
            this.type = type;
        }

        /**
         * Adds metric supported methods.
         *
         * @param methods metric supported methods
         * @return updated builder instance
         */
        public Builder methods(String... methods) {
            this.methods = Arrays.stream(methods).map(String::toUpperCase).collect(Collectors.toSet());
            return this;
        }

        /**
         * Adds metric supported methods.
         *
         * @param methods metric supported methods
         * @return updated builder instance
         */
        public Builder methods(Method... methods) {
            this.methods = Arrays.stream(methods)
                                 .map(Method::text)
                                 .map(String::toUpperCase)
                                 .collect(Collectors.toSet());
            return this;
        }

        /**
         * Adds metric supported methods.
         *
         * @param methods metric supported methods
         * @return updated builder instance
         */
        public Builder methods(Collection methods) {
            this.methods = methods.stream()
                                  .map(String::toUpperCase)
                                  .collect(Collectors.toSet());
            return this;
        }

        /**
         * Sets name format of the metric.
         *
         * @param nameFormat format of the metric
         * @return updated builder instance
         */
        public Builder nameFormat(String nameFormat) {
            this.nameFormat = nameFormat;
            return this;
        }

        /**
         * Sets the description of the metric.
         *
         * @param description metric description
         * @return updated builder instance
         */
        public Builder description(String description) {
            this.description = description;
            return this;
        }

        /**
         * Sets value if this metric should cover successful requests.
         *
         * @param success handle success
         * @return updated builder instance
         */
        public Builder success(boolean success) {
            this.success = success;
            return this;
        }

        /**
         * Sets value if this metric should cover unsuccessful requests.
         *
         * @param errors handle errors
         * @return updated builder instance
         */
        public Builder errors(boolean errors) {
            this.errors = errors;
            return this;
        }

        /**
         * Configure a metric from configuration.
         * The following configuration key are used:
         * 
         * 
         * 
         *     
         *     
         *     
         * 
         * 
         *     
         *     
         *     
         * 
         * 
         *     
         *     
         *     
         * 
         * 
         *     
         *     
         *     
         * 
         * 
         *     
         *     
         *     
         * 
         * 
Client Metric configuration options
keydefaultdescription
errors{@code true}Whether this metric triggers for error states
success{@code true}Whether this metric triggers for successful executions
name-format{@code client.success.method.hostname.status}A string format used to construct a metric name. The format gets three parameters: the method name, * the hostname and the response code (if applicable)
description Description of this metric.
* * @param config configuration to configure this metric * @return updated builder instance */ public Builder config(Config config) { config.get("methods").asList(String.class).ifPresent(this::methods); config.get("errors").asBoolean().ifPresent(this::errors); config.get("success").asBoolean().ifPresent(this::success); config.get("name-format").asString().ifPresent(this::nameFormat); config.get("description").asString().ifPresent(this::description); return this; } @Override public WebClientMetric build() { return type.createInstance(this); } } record Metadata(String name, String description) { static Builder builder() { return new Builder(); } static class Builder { private String name; private String description; Builder withName(String name) { this.name = name; return this; } Builder withDescription(String description) { this.description = description; return this; } Metadata build() { return new Metadata(name, description); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy