zipkin2.storage.cassandra.CassandraUtil Maven / Gradle / Ivy
/*
* Copyright The OpenZipkin Authors
* SPDX-License-Identifier: Apache-2.0
*/
package zipkin2.storage.cassandra;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import zipkin2.Annotation;
import zipkin2.Call;
import zipkin2.Span;
import zipkin2.internal.DateUtil;
import zipkin2.internal.Nullable;
import zipkin2.internal.RecyclableBuffers;
import zipkin2.storage.QueryRequest;
import static zipkin2.internal.RecyclableBuffers.SHORT_STRING_LENGTH;
final class CassandraUtil {
static final Logger LOG = LoggerFactory.getLogger(CassandraUtil.class);
/**
* Time window covered by a single bucket of the {@link Schema#TABLE_TRACE_BY_SERVICE_SPAN} and
* {@link Schema#TABLE_TRACE_BY_SERVICE_REMOTE_SERVICE}, in seconds. Default: 1 day
*/
private static final long DURATION_INDEX_BUCKET_WINDOW_SECONDS =
Long.getLong("zipkin.store.cassandra.internal.durationIndexBucket", 24 * 60 * 60);
public static int durationIndexBucket(long ts_micro) {
// if the window constant has microsecond precision, the division produces negative getValues
return (int) (ts_micro / (DURATION_INDEX_BUCKET_WINDOW_SECONDS * 1_000_000));
}
/**
* Returns a set of annotation getValues and tags joined on equals, delimited by ░
*
* 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 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;
char delimiter = '░'; // as very unlikely to be in the query
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 tag : span.tags().entrySet()) {
if (tag.getValue().length() > SHORT_STRING_LENGTH) continue;
result.append(tag.getKey()).append(delimiter); // search is possible by key alone
result.append(tag.getKey()).append('=').append(tag.getValue()).append(delimiter);
}
return result.length() == 1 ? null : result.toString();
}
static List annotationKeys(QueryRequest request) {
Set annotationKeys = new LinkedHashSet<>();
for (Map.Entry e : request.annotationQuery().entrySet()) {
if (e.getValue().isEmpty()) {
annotationKeys.add(e.getKey());
} else {
annotationKeys.add(e.getKey() + "=" + e.getValue());
}
}
return new ArrayList<>(annotationKeys);
}
static Call.Mapper