use of zipkin2.storage.QueryRequest in project zipkin by openzipkin.
the class CassandraUtilTest method annotationKeys_emptyRequest.
@Test
public void annotationKeys_emptyRequest() {
QueryRequest request = QueryRequest.newBuilder().endTs(System.currentTimeMillis()).limit(10).serviceName("test").lookback(86400000L).build();
assertThat(CassandraUtil.annotationKeys(request)).isEmpty();
}
use of zipkin2.storage.QueryRequest in project zipkin by openzipkin.
the class CassandraUtilTest method annotationKeys.
@Test
public void annotationKeys() {
QueryRequest request = QueryRequest.newBuilder().endTs(System.currentTimeMillis()).limit(10).lookback(86400000L).serviceName("service").parseAnnotationQuery("error and http.method=GET").build();
assertThat(CassandraUtil.annotationKeys(request)).containsExactly("error", "http.method=GET");
}
use of zipkin2.storage.QueryRequest in project zipkin by openzipkin.
the class ITEnsureSchema method worksWithOldSchema.
/**
* This tests we don't accidentally rely on new indexes such as autocomplete tags
*/
@Test
void worksWithOldSchema(TestInfo testInfo) throws Exception {
String testSuffix = testSuffix(testInfo);
Schema.applyCqlFile(storage.keyspace, session(), "/zipkin2-schema.cql");
Schema.applyCqlFile(storage.keyspace, session(), "/zipkin2-schema-indexes-original.cql");
// Ensure the storage component is functional before proceeding
CheckResult check = storage.check();
if (!check.ok()) {
throw new AssertionError("Could not connect to storage: " + check.error().getMessage(), check.error());
}
List<Span> trace = newTrace(testSuffix);
accept(trace);
assertGetTraceReturns(trace.get(0).traceId(), trace);
assertThat(storage.autocompleteTags().getValues("environment").execute()).isEmpty();
String serviceName = trace.get(0).localServiceName();
assertThat(storage.serviceAndSpanNames().getRemoteServiceNames(serviceName).execute()).isEmpty();
QueryRequest request = requestBuilder().serviceName(serviceName).remoteServiceName(appendSuffix(BACKEND.serviceName(), testSuffix)).build();
// Make sure there's an error if a query will return incorrectly vs returning invalid results
assertThatThrownBy(() -> storage.spanStore().getTraces(request)).isInstanceOf(IllegalArgumentException.class).hasMessage("remoteService=" + trace.get(1).remoteServiceName() + " unsupported due to missing table remote_service_by_service");
}
use of zipkin2.storage.QueryRequest in project zipkin by openzipkin.
the class CassandraSpanStore method getTraces.
/**
* This fans out into a number of requests corresponding to query input. In simplest case, there
* is less than a day of data queried, and only one expression. This implies one call to fetch
* trace IDs and another to retrieve the span details.
*
* <p>The amount of backend calls increase in dimensions of query complexity, days of data, and
* limit of traces requested. For example, a query like "http.path=/foo and error" will be two
* select statements for the expression, possibly follow-up calls for pagination (when over 5K
* rows match). Once IDs are parsed, there's one call for each 5K rows of span data. This means
* "http.path=/foo and error" is minimally 3 network calls, the first two in parallel.
*/
@Override
public Call<List<List<Span>>> getTraces(QueryRequest request) {
if (!searchEnabled)
return Call.emptyList();
TimestampRange timestampRange = timestampRange(request);
// If we have to make multiple queries, over fetch on indexes as they don't return distinct
// (trace id, timestamp) rows. This mitigates intersection resulting in < limit traces
final int traceIndexFetchSize = request.limit() * indexFetchMultiplier;
List<Call<Map<String, Long>>> callsToIntersect = new ArrayList<>();
List<String> annotationKeys = CassandraUtil.annotationKeys(request);
for (String annotationKey : annotationKeys) {
if (spanTable == null) {
throw new IllegalArgumentException(request.annotationQueryString() + " query unsupported due to missing annotation_query index");
}
callsToIntersect.add(spanTable.newCall(request.serviceName(), annotationKey, timestampRange, traceIndexFetchSize));
}
// Bucketed calls can be expensive when service name isn't specified. This guards against abuse.
if (request.remoteServiceName() != null || request.spanName() != null || request.minDuration() != null || callsToIntersect.isEmpty()) {
callsToIntersect.add(newBucketedTraceIdCall(request, timestampRange, traceIndexFetchSize));
}
if (callsToIntersect.size() == 1) {
return callsToIntersect.get(0).map(traceIdsSortedByDescTimestamp()).flatMap(spans.newFlatMapper(request));
}
// We achieve the AND goal, by intersecting each of the key sets.
IntersectKeySets intersectedTraceIds = new IntersectKeySets(callsToIntersect);
// @xxx the sorting by timestamp desc is broken here^
return intersectedTraceIds.flatMap(spans.newFlatMapper(request));
}
use of zipkin2.storage.QueryRequest in project zipkin by openzipkin.
the class CassandraUtil method annotationQuery.
/**
* Returns a set of annotation getValues and tags joined on equals, delimited by ░
*
* <p>Values over {@link RecyclableBuffers#SHORT_STRING_LENGTH} are not considered. Zipkin's
* {@link QueryRequest#annotationQuery()} are equals match. Not all values are lookup values. For
* example, {@code sql.query} isn't something that is likely to be looked up by value and indexing
* that could add a potentially kilobyte partition key on {@link Schema#TABLE_SPAN}
*
* @see QueryRequest#annotationQuery()
*/
@Nullable
static String annotationQuery(Span span) {
if (span.annotations().isEmpty() && span.tags().isEmpty())
return null;
// as very unlikely to be in the query
char delimiter = '░';
StringBuilder result = new StringBuilder().append(delimiter);
for (Annotation a : span.annotations()) {
if (a.value().length() > SHORT_STRING_LENGTH)
continue;
result.append(a.value()).append(delimiter);
}
for (Map.Entry<String, String> tag : span.tags().entrySet()) {
if (tag.getValue().length() > SHORT_STRING_LENGTH)
continue;
// search is possible by key alone
result.append(tag.getKey()).append(delimiter);
result.append(tag.getKey()).append('=').append(tag.getValue()).append(delimiter);
}
return result.length() == 1 ? null : result.toString();
}
Aggregations