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

zipkin2.storage.StrictTraceId Maven / Gradle / Ivy

There is a newer version: 3.4.2
Show newest version
/*
 * Copyright The OpenZipkin Authors
 * SPDX-License-Identifier: Apache-2.0
 */
package zipkin2.storage;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import zipkin2.Call.Mapper;
import zipkin2.Span;
import zipkin2.internal.FilterTraces;

/**
 * Storage implementation often need to re-check query results when {@link
 * StorageComponent.Builder#strictTraceId(boolean) strict trace ID} is disabled.
 */
public final class StrictTraceId {

  public static Mapper, List> filterSpans(String traceId) {
    return new FilterSpans(traceId);
  }

  /**
   * Filters the mutable input client-side when there's a clash on lower 64-bits of a trace ID.
   *
   * @see FilterTraces
   */
  public static Mapper>, List>> filterTraces(QueryRequest request) {
    return new FilterTracesIfClashOnLowerTraceId(request);
  }

  static final class FilterTracesIfClashOnLowerTraceId
    implements Mapper>, List>> {
    final QueryRequest request;

    FilterTracesIfClashOnLowerTraceId(QueryRequest request) {
      this.request = request;
    }

    @Override public List> map(List> input) {
      if (hasClashOnLowerTraceId(input)) {
        return FilterTraces.create(request).map(input);
      }
      return input;
    }

    @Override public String toString() {
      return "FilterTracesIfClashOnLowerTraceId{request=" + request + "}";
    }
  }

  /** Returns true if any trace clashes on the right-most 16 characters of the trace ID */
  // Concretely, Netflix have a special index template for a multi-tag, "fit.sessionId". If we
  // blindly filtered without seeing if we had to, a match that works on the server side would
  // fail client side. Normally, we wouldn't special case like this, but not filtering unless
  // necessary is also more efficient.
  static boolean hasClashOnLowerTraceId(List> input) {
    int traceCount = input.size();
    if (traceCount <= 1) return false;

    // NOTE: It is probably more efficient to do clever sorting and peeking here, but the call site
    // is query side, which is not in the critical path of user code. A set is much easier to grok.
    Set traceIdLows = new LinkedHashSet<>();
    boolean clash = false;
    for (List spans : input) {
      String traceId = lowerTraceId(spans.get(0).traceId());
      if (!traceIdLows.add(traceId)) {
        clash = true;
        break;
      }
    }
    return clash;
  }

  static String lowerTraceId(String traceId) {
    return traceId.length() == 16 ? traceId : traceId.substring(16);
  }

  static final class FilterSpans implements Mapper, List> {
    final String traceId;

    FilterSpans(String traceId) {
      this.traceId = traceId;
    }

    @Override public List map(List input) {
      Iterator i = input.iterator();
      while (i.hasNext()) {
        Span next = i.next();
        if (!next.traceId().equals(traceId)) i.remove();
      }
      return input;
    }

    @Override public String toString() {
      return "FilterSpans{traceId=" + traceId + "}";
    }
  }

  /**
   * Returns a function that filters its mutable input when it contains a trace not matching the
   * specified trace IDs.
   *
   * 

Make sure the input IDs are unique and {@link Span#normalizeTraceId(String) normalized}. */ public static Mapper>, List>> filterTraces(Iterable traceIds) { return new FilterTracesByIds(traceIds); } static final class FilterTracesByIds implements Mapper>, List>> { final Set traceIds; FilterTracesByIds(Iterable sanitizedIds) { traceIds = new LinkedHashSet<>(); for (String traceId : sanitizedIds) { traceIds.add(traceId); } } @Override public List> map(List> input) { Iterator> i = input.iterator(); while (i.hasNext()) { // Not using removeIf as that's java 8+ List next = i.next(); if (!traceIds.contains(next.get(0).traceId())) { i.remove(); } } return input; } @Override public String toString() { return "FilterTracesByIds{traceIds=" + traceIds + "}"; } } StrictTraceId() { } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy