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

io.jaegertracing.analytics.tracequality.MinimumClientVersion Maven / Gradle / Ivy

package io.jaegertracing.analytics.tracequality;

import io.jaegertracing.analytics.ModelRunner;
import io.jaegertracing.analytics.gremlin.GraphCreator;
import io.jaegertracing.analytics.model.Span;
import io.prometheus.client.Counter;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Vertex;

/**
 * Emits a passing score if the version number of a client is higher than the ones specified and a failing score
 * otherwise.
 */
public class MinimumClientVersion implements ModelRunner {

    static final String VERSION_TAG = "jaeger.version";
    static final String MISSING_VERSION = "none";

    public static class Builder implements Serializable {
        private String javaVersion = "1.0.0";
        private String nodeVersion = "3.17.1";
        private String goVersion = "2.22.0";
        private String pythonVersion = "4.0.0";

        private Builder() {}

        public  MinimumClientVersion build() {
            return new MinimumClientVersion(this);
        }

        public Builder withJavaVersion(String javaVersion) {
            this.javaVersion = javaVersion;
            return this;
        }

        public Builder withNodeVersion(String nodeVersion) {
            this.nodeVersion = nodeVersion;
            return this;
        }

        public Builder withGoVersion(String goVersion) {
            this.goVersion = goVersion;
            return this;
        }

        public Builder withPythonVersion(String pythonVersion) {
            this.pythonVersion = pythonVersion;
            return this;
        }
    }

    public static Builder builder() {
        return new Builder();
    }

    private MinimumClientVersion(Builder builder) {
        languageToMinVersion = Collections.unmodifiableMap(new HashMap() {{
            put("go", builder.goVersion);
            put("python", builder.pythonVersion);
            put("node", builder.nodeVersion);
            put("java", builder.javaVersion);
        }});

    }

    private final Map languageToMinVersion;

    private static final Counter counter = Counter.build()
        .name("trace_quality_minimum_client_version_total")
        .help("The service emitted spans with Jaeger client version")
        .labelNames("pass", "service", "version")
        .create()
        .register();

    @Override
    public void runWithMetrics(Graph graph) {
        Iterator vertices = graph.vertices();
        while (vertices.hasNext()) {
            Vertex vertex = vertices.next();
            Span span = GraphCreator.toSpan(vertex);
            String jaegerVersion = span.tags.get(VERSION_TAG);
            if (jaegerVersion == null || jaegerVersion.isEmpty()) {
                jaegerVersion = MISSING_VERSION;
            }
            boolean result = computeScore(span);
            counter.labels(Boolean.toString(result), span.serviceName, jaegerVersion)
                .inc();
        }
    }

    public boolean computeScore(Span span) {
        String version = span.tags.get(VERSION_TAG);
        if (version == null || version.isEmpty()) {
            return false;
        }

        String[] languageVersion = version.toLowerCase().split("-");
        if (languageVersion.length != 2
                || languageToMinVersion.get(languageVersion[0]) == null
                || !languageVersion[1].matches("[0-9]+(\\.[0-9]+)*")) {
            return false;
        }

        if (isGreaterThanOrEqualTo(languageToMinVersion.get(languageVersion[0]), languageVersion[1])) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Compares two semantic version strings
     *
     * @param left  semantic version string
     * @param right semantic version string
     * @return true if right is greater than or equal to left
     * false for all other cases
     */
    boolean isGreaterThanOrEqualTo(String left, String right) {
        String[] leftParts = left.split("\\.");
        String[] rightParts = right.split("\\.");

        int length = Math.min(leftParts.length, rightParts.length);
        try {
            for (int i = 0; i < length; i++) {
                int leftPart = Integer.parseInt(leftParts[i]);
                int rightPart = Integer.parseInt(rightParts[i]);
                if (leftPart < rightPart) {
                    return true;
                }
                if (leftPart > rightPart) {
                    return false;
                }
            }
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy