Search in sources :

Example 1 with Aggregation

use of zipkin.storage.elasticsearch.http.internal.client.Aggregation in project zipkin by openzipkin.

the class ElasticsearchHttpSpanStore method getTraces.

@Override
public void getTraces(QueryRequest request, Callback<List<List<Span>>> callback) {
    long beginMillis = request.endTs - request.lookback;
    long endMillis = request.endTs;
    SearchRequest.Filters filters = new SearchRequest.Filters();
    filters.addRange("timestamp_millis", beginMillis, endMillis);
    if (request.serviceName != null) {
        filters.addNestedTerms(asList("annotations.endpoint.serviceName", "binaryAnnotations.endpoint.serviceName"), request.serviceName);
    }
    if (request.spanName != null) {
        filters.addTerm("name", request.spanName);
    }
    for (String annotation : request.annotations) {
        Map<String, String> nestedTerms = new LinkedHashMap<>();
        nestedTerms.put("annotations.value", annotation);
        if (request.serviceName != null) {
            nestedTerms.put("annotations.endpoint.serviceName", request.serviceName);
        }
        filters.addNestedTerms(nestedTerms);
    }
    for (Map.Entry<String, String> kv : request.binaryAnnotations.entrySet()) {
        // In our index template, we make sure the binaryAnnotation value is indexed as string,
        // meaning non-string values won't even be indexed at all. This means that we can only
        // match string values here, which happens to be exactly what we want.
        Map<String, String> nestedTerms = new LinkedHashMap<>();
        nestedTerms.put("binaryAnnotations.key", kv.getKey());
        nestedTerms.put("binaryAnnotations.value", kv.getValue());
        if (request.serviceName != null) {
            nestedTerms.put("binaryAnnotations.endpoint.serviceName", request.serviceName);
        }
        filters.addNestedTerms(nestedTerms);
    }
    if (request.minDuration != null) {
        filters.addRange("duration", request.minDuration, request.maxDuration);
    }
    // We need to filter to traces that contain at least one span that matches the request,
    // but the zipkin API is supposed to order traces by first span, regardless of if it was
    // filtered or not. This is not possible without either multiple, heavyweight queries
    // or complex multiple indexing, defeating much of the elegance of using elasticsearch for this.
    // So we fudge and order on the first span among the filtered spans - in practice, there should
    // be no significant difference in user experience since span start times are usually very
    // close to each other in human time.
    Aggregation traceIdTimestamp = Aggregation.terms("traceId", request.limit).addSubAggregation(Aggregation.min("timestamp_millis")).orderBy("timestamp_millis", "desc");
    List<String> indices = indexNameFormatter.indexNamePatternsForRange(beginMillis, endMillis);
    SearchRequest esRequest = SearchRequest.forIndicesAndType(indices, SPAN).filters(filters).addAggregation(traceIdTimestamp);
    HttpCall<List<String>> traceIdsCall = search.newCall(esRequest, BodyConverters.SORTED_KEYS);
    // When we receive span results, we need to group them by trace ID
    Callback<List<Span>> successCallback = new Callback<List<Span>>() {

        @Override
        public void onSuccess(List<Span> input) {
            List<List<Span>> traces = GroupByTraceId.apply(input, strictTraceId, true);
            // Due to tokenization of the trace ID, our matches are imprecise on Span.traceIdHigh
            for (Iterator<List<Span>> trace = traces.iterator(); trace.hasNext(); ) {
                List<Span> next = trace.next();
                if (next.get(0).traceIdHigh != 0 && !request.test(next)) {
                    trace.remove();
                }
            }
            callback.onSuccess(traces);
        }

        @Override
        public void onError(Throwable t) {
            callback.onError(t);
        }
    };
    // Fire off the query to get spans once we have trace ids
    traceIdsCall.submit(new Callback<List<String>>() {

        @Override
        public void onSuccess(@Nullable List<String> traceIds) {
            if (traceIds == null || traceIds.isEmpty()) {
                callback.onSuccess(Collections.emptyList());
                return;
            }
            SearchRequest request = SearchRequest.forIndicesAndType(indices, SPAN).terms("traceId", traceIds);
            search.newCall(request, BodyConverters.SPANS).submit(successCallback);
        }

        @Override
        public void onError(Throwable t) {
            callback.onError(t);
        }
    });
}
Also used : SearchRequest(zipkin.storage.elasticsearch.http.internal.client.SearchRequest) Span(zipkin.Span) LinkedHashMap(java.util.LinkedHashMap) Aggregation(zipkin.storage.elasticsearch.http.internal.client.Aggregation) Callback(zipkin.storage.Callback) List(java.util.List) Arrays.asList(java.util.Arrays.asList) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Aggregations

Arrays.asList (java.util.Arrays.asList)1 LinkedHashMap (java.util.LinkedHashMap)1 List (java.util.List)1 Map (java.util.Map)1 Span (zipkin.Span)1 Callback (zipkin.storage.Callback)1 Aggregation (zipkin.storage.elasticsearch.http.internal.client.Aggregation)1 SearchRequest (zipkin.storage.elasticsearch.http.internal.client.SearchRequest)1