From 85fcb2d239c724892296e87c54db2f0e04396b99 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Tue, 9 Jan 2018 17:48:44 +0800 Subject: [PATCH] Adds ability to disable indexing for in-memory and cassandra v2 storage This starts towards "firehose mode" by making it possible to disable indexing, notably on cassandra where SASI amplifies writes into the cluster. When enabled, only retrieval by ID is allowed. That said, someone can feel free to run the dependency linker if they like.. If 100% sampling is on, the dependency links will relate to actual service calls made. See #1869 --- .../http/ElasticsearchHttpStorage.java | 5 + .../elasticsearch/ElasticsearchStorage.java | 5 + .../cassandra/CassandraSpanConsumer.java | 33 ++-- .../storage/cassandra/CassandraSpanStore.java | 11 +- .../storage/cassandra/CassandraStorage.java | 5 + .../zipkin2/storage/cassandra/InsertSpan.java | 32 +-- .../storage/cassandra/InternalForTests.java | 6 + .../integration/ITCassandraStorage.java | 96 ++------- .../CassandraDependenciesTest.java | 2 +- .../CassandraEnsureSchemaTest.java | 2 +- .../CassandraSpanConsumerTest.java | 2 +- .../CassandraSpanStoreTest.java | 2 +- .../CassandraStrictTraceIdFalseTest.java | 57 ++++++ .../integrationV1/ITCassandraStorageV1.java | 121 ++++++++++++ .../java/zipkin2/storage/InMemoryStorage.java | 22 ++- .../java/zipkin2/storage/QueryRequest.java | 3 +- .../zipkin2/storage/StorageComponent.java | 12 ++ .../src/test/java/zipkin2/TestObjects.java | 6 +- .../zipkin2/storage/ITInMemoryStorage.java | 46 +++++ .../storage/ITIndexingEnabledFalse.java | 82 ++++++++ .../java/zipkin2/storage/ITSpanStore.java | 183 ++++++++++++++++++ .../zipkin2/storage/InMemoryStorageTest.java | 7 +- 22 files changed, 614 insertions(+), 126 deletions(-) rename zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/{integration => integrationV1}/CassandraDependenciesTest.java (97%) rename zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/{integration => integrationV1}/CassandraEnsureSchemaTest.java (97%) rename zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/{integration => integrationV1}/CassandraSpanConsumerTest.java (98%) rename zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/{integration => integrationV1}/CassandraSpanStoreTest.java (98%) create mode 100644 zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraStrictTraceIdFalseTest.java create mode 100644 zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/ITCassandraStorageV1.java create mode 100644 zipkin2/src/test/java/zipkin2/storage/ITInMemoryStorage.java create mode 100644 zipkin2/src/test/java/zipkin2/storage/ITIndexingEnabledFalse.java create mode 100644 zipkin2/src/test/java/zipkin2/storage/ITSpanStore.java diff --git a/zipkin-storage/elasticsearch-http/src/main/java/zipkin/storage/elasticsearch/http/ElasticsearchHttpStorage.java b/zipkin-storage/elasticsearch-http/src/main/java/zipkin/storage/elasticsearch/http/ElasticsearchHttpStorage.java index 5ef6442d7cb..6199ee96174 100644 --- a/zipkin-storage/elasticsearch-http/src/main/java/zipkin/storage/elasticsearch/http/ElasticsearchHttpStorage.java +++ b/zipkin-storage/elasticsearch-http/src/main/java/zipkin/storage/elasticsearch/http/ElasticsearchHttpStorage.java @@ -123,6 +123,11 @@ public final Builder indexReplicas(int indexReplicas) { return this; } + @Override public StorageComponent.Builder indexingEnabled(boolean indexingEnabled) { + delegate.indexingEnabled(indexingEnabled); + return this; + } + @Override public final ElasticsearchHttpStorage build() { return new ElasticsearchHttpStorage(delegate.build(), legacyReadsEnabled); } diff --git a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchStorage.java b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchStorage.java index c2383dc7e40..737977d14ff 100644 --- a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchStorage.java +++ b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchStorage.java @@ -60,6 +60,7 @@ public static Builder newBuilder(OkHttpClient client) { .hosts(Collections.singletonList("http://localhost:9200")) .maxRequests(64) .strictTraceId(true) + .indexingEnabled(true) .index("zipkin") .dateSeparator('-') .indexShards(5) @@ -177,6 +178,8 @@ public final Builder dateSeparator(char dateSeparator) { @Override public abstract Builder strictTraceId(boolean strictTraceId); + @Override public abstract Builder indexingEnabled(boolean indexingEnabled); + @Override public abstract ElasticsearchStorage build(); abstract IndexNameFormatter.Builder indexNameFormatterBuilder(); @@ -199,6 +202,8 @@ public final Builder dateSeparator(char dateSeparator) { public abstract boolean strictTraceId(); + abstract boolean indexingEnabled(); + abstract int indexShards(); abstract int indexReplicas(); diff --git a/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanConsumer.java b/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanConsumer.java index b25228fb2c0..e58b5cdad44 100644 --- a/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanConsumer.java +++ b/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanConsumer.java @@ -26,6 +26,7 @@ import zipkin2.Annotation; import zipkin2.Call; import zipkin2.Span; +import zipkin2.internal.Nullable; import zipkin2.storage.SpanConsumer; import zipkin2.storage.cassandra.internal.call.AggregateCall; @@ -36,21 +37,27 @@ class CassandraSpanConsumer implements SpanConsumer { // not final for testing = Long.getLong("zipkin2.storage.cassandra.internal.writtenNamesTtl", 60 * 60 * 1000); private final Session session; - private final boolean strictTraceId; + private final boolean strictTraceId, indexingEnabled; private final InsertSpan.Factory insertSpan; - private final InsertTraceByServiceSpan.Factory insertTraceByServiceSpan; - private final InsertServiceSpan.Factory insertServiceSpanName; + @Nullable final InsertTraceByServiceSpan.Factory insertTraceByServiceSpan; + @Nullable private final InsertServiceSpan.Factory insertServiceSpanName; CassandraSpanConsumer(CassandraStorage storage) { session = storage.session(); strictTraceId = storage.strictTraceId(); + indexingEnabled = storage.indexingEnabled(); // warns when schema problems exist Schema.readMetadata(session); - insertSpan = new InsertSpan.Factory(session, strictTraceId); - insertTraceByServiceSpan = new InsertTraceByServiceSpan.Factory(session, strictTraceId); - insertServiceSpanName = new InsertServiceSpan.Factory(session, WRITTEN_NAMES_TTL); + insertSpan = new InsertSpan.Factory(session, strictTraceId, indexingEnabled); + if (indexingEnabled) { + insertTraceByServiceSpan = new InsertTraceByServiceSpan.Factory(session, strictTraceId); + insertServiceSpanName = new InsertServiceSpan.Factory(session, WRITTEN_NAMES_TTL); + } else { + insertTraceByServiceSpan = null; + insertServiceSpanName = null; + } } /** @@ -77,6 +84,8 @@ public Call accept(List input) { spans.add(insertSpan.newInput(s, ts_uuid)); + if (!indexingEnabled) continue; + // Empty values allow for api queries with blank service or span name String service = s.localServiceName() != null ? s.localServiceName() : ""; String span = @@ -106,11 +115,13 @@ public Call accept(List input) { for (InsertSpan.Input span : spans) { calls.add(insertSpan.create(span)); } - for (InsertServiceSpan.Input serviceSpan : serviceSpans) { - calls.add(insertServiceSpanName.create(serviceSpan)); - } - for (InsertTraceByServiceSpan.Input serviceSpan : traceByServiceSpans) { - calls.add(insertTraceByServiceSpan.create(serviceSpan)); + if (indexingEnabled) { + for (InsertServiceSpan.Input serviceSpan : serviceSpans) { + calls.add(insertServiceSpanName.create(serviceSpan)); + } + for (InsertTraceByServiceSpan.Input serviceSpan : traceByServiceSpans) { + calls.add(insertTraceByServiceSpan.create(serviceSpan)); + } } return new StoreSpansCall(calls); } diff --git a/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanStore.java b/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanStore.java index cc24081a98c..4431442d54c 100644 --- a/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanStore.java +++ b/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanStore.java @@ -17,6 +17,7 @@ import com.datastax.driver.core.Session; import com.datastax.driver.core.utils.UUIDs; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -36,7 +37,7 @@ class CassandraSpanStore implements SpanStore { // not final for testing private final int maxTraceCols; private final int indexFetchMultiplier; - private final boolean strictTraceId; + private final boolean strictTraceId, indexingEnabled; private final SelectFromSpan.Factory spans; private final SelectDependencies.Factory dependencies; private final SelectSpanNames.Factory spanNames; @@ -50,6 +51,7 @@ class CassandraSpanStore implements SpanStore { // not final for testing maxTraceCols = storage.maxTraceCols(); indexFetchMultiplier = storage.indexFetchMultiplier(); strictTraceId = storage.strictTraceId(); + indexingEnabled = storage.indexingEnabled(); KeyspaceMetadata md = Schema.getKeyspaceMetadata(session); indexTtl = md.getTable(TABLE_TRACE_BY_SERVICE_SPAN).getOptions().getDefaultTimeToLive(); @@ -74,6 +76,8 @@ class CassandraSpanStore implements SpanStore { // not final for testing */ @Override public Call>> getTraces(QueryRequest request) { + if (!indexingEnabled) return Call.emptyList(); + return strictTraceId ? doGetTraces(request) : doGetTraces(request).map(new FilterTraces(request)); } @@ -85,7 +89,8 @@ Call>> doGetTraces(QueryRequest request) { final int traceIndexFetchSize = request.limit() * indexFetchMultiplier; List>> callsToIntersect = new ArrayList<>(); - List annotationKeys = CassandraUtil.annotationKeys(request); + List annotationKeys = + indexingEnabled ? CassandraUtil.annotationKeys(request) : Collections.emptyList(); for (String annotationKey : annotationKeys) { callsToIntersect.add(spanTable.newCall( request.serviceName(), @@ -174,10 +179,12 @@ Call>> newBucketedTraceIdCall(QueryRequest request, } @Override public Call> getServiceNames() { + if (!indexingEnabled) return Call.emptyList(); return serviceNames.clone(); } @Override public Call> getSpanNames(String serviceName) { + if (!indexingEnabled) return Call.emptyList(); return spanNames.create(serviceName); } diff --git a/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraStorage.java b/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraStorage.java index 96ec3f36de8..cfbc890946a 100644 --- a/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraStorage.java +++ b/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/CassandraStorage.java @@ -51,6 +51,7 @@ public interface SessionFactory { public static Builder newBuilder() { return new AutoValue_CassandraStorage.Builder() .strictTraceId(true) + .indexingEnabled(true) .keyspace(Schema.DEFAULT_KEYSPACE) .contactPoints("localhost") // Zipkin collectors can create out a lot of async requests in bursts @@ -67,6 +68,9 @@ public static abstract class Builder extends StorageComponent.Builder { /** {@inheritDoc} */ @Override public abstract Builder strictTraceId(boolean strictTraceId); + /** {@inheritDoc} */ + @Override public abstract Builder indexingEnabled(boolean indexingEnabled); + /** Override to control how sessions are created. */ public abstract Builder sessionFactory(SessionFactory sessionFactory); @@ -146,6 +150,7 @@ public final Builder maxConnections(int maxConnections) { abstract String keyspace(); abstract int indexFetchMultiplier(); abstract boolean strictTraceId(); + abstract boolean indexingEnabled(); abstract SessionFactory sessionFactory(); /** session and close are typically called from different threads */ diff --git a/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/InsertSpan.java b/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/InsertSpan.java index 032f5746d39..983fd1a7319 100644 --- a/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/InsertSpan.java +++ b/zipkin-storage/zipkin2_cassandra/src/main/java/zipkin2/storage/cassandra/InsertSpan.java @@ -18,6 +18,7 @@ import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSetFuture; import com.datastax.driver.core.Session; +import com.datastax.driver.core.querybuilder.Insert; import com.datastax.driver.core.querybuilder.QueryBuilder; import com.google.auto.value.AutoValue; import java.util.Collections; @@ -71,11 +72,11 @@ final class InsertSpan extends ResultSetFutureCall { static class Factory { final Session session; final PreparedStatement preparedStatement; - final boolean strictTraceId; + final boolean strictTraceId, indexingEnabled; - Factory(Session session, boolean strictTraceId) { + Factory(Session session, boolean strictTraceId, boolean indexingEnabled) { this.session = session; - this.preparedStatement = session.prepare(QueryBuilder.insertInto(TABLE_SPAN) + Insert insertQuery = QueryBuilder.insertInto(TABLE_SPAN) .value("trace_id", QueryBuilder.bindMarker("trace_id")) .value("trace_id_high", QueryBuilder.bindMarker("trace_id_high")) .value("ts_uuid", QueryBuilder.bindMarker("ts_uuid")) @@ -86,14 +87,20 @@ static class Factory { .value("ts", QueryBuilder.bindMarker("ts")) .value("duration", QueryBuilder.bindMarker("duration")) .value("l_ep", QueryBuilder.bindMarker("l_ep")) - .value("l_service", QueryBuilder.bindMarker("l_service")) .value("r_ep", QueryBuilder.bindMarker("r_ep")) .value("annotations", QueryBuilder.bindMarker("annotations")) .value("tags", QueryBuilder.bindMarker("tags")) .value("shared", QueryBuilder.bindMarker("shared")) - .value("debug", QueryBuilder.bindMarker("debug")) - .value("annotation_query", QueryBuilder.bindMarker("annotation_query"))); + .value("debug", QueryBuilder.bindMarker("debug")); + + if (indexingEnabled) { + insertQuery.value("l_service", QueryBuilder.bindMarker("l_service")); + insertQuery.value("annotation_query", QueryBuilder.bindMarker("annotation_query")); + } + + this.preparedStatement = session.prepare(insertQuery); this.strictTraceId = strictTraceId; + this.indexingEnabled = indexingEnabled; } Input newInput(zipkin2.Span span, UUID ts_uuid) { @@ -106,7 +113,7 @@ Input newInput(zipkin2.Span span, UUID ts_uuid) { } else { annotations = Collections.emptyList(); } - String annotation_query = CassandraUtil.annotationQuery(span); + String annotation_query = indexingEnabled ? CassandraUtil.annotationQuery(span): null; return new AutoValue_InsertSpan_Input( ts_uuid, traceIdHigh ? span.traceId().substring(0, 16) : null, @@ -178,15 +185,18 @@ Call create(Input span) { if (null != input.ts()) bound.setLong("ts", input.ts()); if (null != input.duration()) bound.setLong("duration", input.duration()); if (null != input.l_ep()) bound.set("l_ep", input.l_ep(), EndpointUDT.class); - if (null != input.l_ep()) bound.setString("l_service", input.l_ep().getService()); if (null != input.r_ep()) bound.set("r_ep", input.r_ep(), EndpointUDT.class); if (!input.annotations().isEmpty()) bound.setList("annotations", input.annotations()); if (!input.tags().isEmpty()) bound.setMap("tags", input.tags()); - if (null != input.annotation_query()) { - bound.setString("annotation_query", input.annotation_query()); - } if (input.shared()) bound.setBool("shared", true); if (input.debug()) bound.setBool("debug", true); + + if (factory.indexingEnabled) { + if (null != input.l_ep()) bound.setString("l_service", input.l_ep().getService()); + if (null != input.annotation_query()) { + bound.setString("annotation_query", input.annotation_query()); + } + } return factory.session.executeAsync(bound); } diff --git a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/InternalForTests.java b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/InternalForTests.java index 1a4fadf0528..5bd6c437edf 100644 --- a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/InternalForTests.java +++ b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/InternalForTests.java @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.Uninterruptibles; import java.util.List; import java.util.concurrent.TimeUnit; +import org.junit.rules.TestName; import zipkin.DependencyLink; import zipkin2.storage.SpanConsumer; @@ -74,6 +75,11 @@ public static void blockWhileInFlight(CassandraStorage storage) { } } + public static String keyspace(TestName testName) { + String result = testName.getMethodName().toLowerCase(); + return result.length() <= 48 ? result : result.substring(result.length() - 48); + } + public static void dropKeyspace(Session session, String keyspace) { session.execute("DROP KEYSPACE IF EXISTS " + keyspace); assertThat(session.getCluster().getMetadata().getKeyspace(keyspace)).isNull(); diff --git a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/ITCassandraStorage.java b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/ITCassandraStorage.java index dc9ce96bb08..73dd2fc8f47 100644 --- a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/ITCassandraStorage.java +++ b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/ITCassandraStorage.java @@ -13,111 +13,43 @@ */ package zipkin2.storage.cassandra.integration; -import com.datastax.driver.core.Session; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.experimental.runners.Enclosed; import org.junit.rules.TestName; import org.junit.runner.RunWith; +import zipkin2.storage.StorageComponent; import zipkin2.storage.cassandra.CassandraStorage; import zipkin2.storage.cassandra.CassandraStorageRule; -import zipkin2.storage.cassandra.InternalForTests; + +import static zipkin2.storage.cassandra.InternalForTests.dropKeyspace; +import static zipkin2.storage.cassandra.InternalForTests.keyspace; @RunWith(Enclosed.class) public class ITCassandraStorage { static CassandraStorageRule classRule() { - return new CassandraStorageRule("openzipkin/zipkin-cassandra:2.4.1", "test_zipkin3"); - } - - public static class DependenciesTest extends CassandraDependenciesTest { - @ClassRule public static CassandraStorageRule storage = classRule(); - @Rule public TestName testName = new TestName(); - - @Override protected String keyspace() { - return ITCassandraStorage.keyspace(testName); - } - - @Before @Override public void clear() { - InternalForTests.dropKeyspace(storage.session(), keyspace()); - } - - @Override protected CassandraStorage.Builder storageBuilder() { - return storage.computeStorageBuilder(); - } - } - - public static class SpanStoreTest extends CassandraSpanStoreTest { - @ClassRule public static CassandraStorageRule storage = classRule(); - @Rule public TestName testName = new TestName(); - - @Override protected String keyspace() { - return ITCassandraStorage.keyspace(testName); - } - - @Before @Override public void clear() { - InternalForTests.dropKeyspace(storage.session(), keyspace()); - } - - @Override protected CassandraStorage.Builder storageBuilder() { - return storage.computeStorageBuilder(); - } - } - - public static class SpanConsumerTest extends CassandraSpanConsumerTest { - @ClassRule public static CassandraStorageRule storage = classRule(); - @Rule public TestName testName = new TestName(); - - @Override protected String keyspace() { - return ITCassandraStorage.keyspace(testName); - } - - @Before public void clear() { - InternalForTests.dropKeyspace(storage.session(), keyspace()); - } - - @Override protected CassandraStorage.Builder storageBuilder() { - return storage.computeStorageBuilder(); - } + return new CassandraStorageRule("openzipkin/zipkin-cassandra:2.4.1", "test_cassandra3"); } - public static class EnsureSchemaTest extends CassandraEnsureSchemaTest { - @ClassRule public static CassandraStorageRule storage = classRule(); + public static class ITIndexingEnabledFalse extends zipkin2.storage.ITIndexingEnabledFalse { + @ClassRule public static CassandraStorageRule backend = classRule(); @Rule public TestName testName = new TestName(); - @Override protected String keyspace() { - return ITCassandraStorage.keyspace(testName); - } - - @Before public void clear() { - InternalForTests.dropKeyspace(storage.session(), keyspace()); - } + CassandraStorage storage; - @Override protected Session session() { - return storage.session(); + @Before public void connect() { + storage = backend.computeStorageBuilder().keyspace(keyspace(testName)) + .indexingEnabled(false).build(); } - } - - public static class StrictTraceIdFalseTest extends CassandraStrictTraceIdFalseTest { - @ClassRule public static CassandraStorageRule storage = classRule(); - @Rule public TestName testName = new TestName(); - @Override protected String keyspace() { - return ITCassandraStorage.keyspace(testName); + @Override protected StorageComponent storage() { + return storage; } @Before @Override public void clear() { - InternalForTests.dropKeyspace(storage.session(), keyspace()); - } - - @Override protected CassandraStorage.Builder storageBuilder() { - return storage.computeStorageBuilder(); + dropKeyspace(backend.session(), keyspace(testName)); } } - - static String keyspace(TestName testName){ - String result = testName.getMethodName().toLowerCase(); - return result.length() <= 48 ? result : result.substring(result.length() - 48); - } } diff --git a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraDependenciesTest.java b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraDependenciesTest.java similarity index 97% rename from zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraDependenciesTest.java rename to zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraDependenciesTest.java index 4260eafea60..f51b2c73955 100644 --- a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraDependenciesTest.java +++ b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraDependenciesTest.java @@ -11,7 +11,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package zipkin2.storage.cassandra.integration; +package zipkin2.storage.cassandra.integrationV1; import java.util.List; import org.junit.Before; diff --git a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraEnsureSchemaTest.java b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraEnsureSchemaTest.java similarity index 97% rename from zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraEnsureSchemaTest.java rename to zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraEnsureSchemaTest.java index 906e3b8e135..661bcbeb2af 100644 --- a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraEnsureSchemaTest.java +++ b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraEnsureSchemaTest.java @@ -11,7 +11,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package zipkin2.storage.cassandra.integration; +package zipkin2.storage.cassandra.integrationV1; import com.datastax.driver.core.KeyspaceMetadata; import com.datastax.driver.core.Session; diff --git a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraSpanConsumerTest.java b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraSpanConsumerTest.java similarity index 98% rename from zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraSpanConsumerTest.java rename to zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraSpanConsumerTest.java index 64026d8e96a..fe3002d2b33 100644 --- a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraSpanConsumerTest.java +++ b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraSpanConsumerTest.java @@ -11,7 +11,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package zipkin2.storage.cassandra.integration; +package zipkin2.storage.cassandra.integrationV1; import java.io.IOException; import java.util.stream.IntStream; diff --git a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraSpanStoreTest.java b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraSpanStoreTest.java similarity index 98% rename from zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraSpanStoreTest.java rename to zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraSpanStoreTest.java index 84a4ceca271..010e0672951 100644 --- a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integration/CassandraSpanStoreTest.java +++ b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraSpanStoreTest.java @@ -11,7 +11,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package zipkin2.storage.cassandra.integration; +package zipkin2.storage.cassandra.integrationV1; import java.util.ArrayList; import java.util.List; diff --git a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraStrictTraceIdFalseTest.java b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraStrictTraceIdFalseTest.java new file mode 100644 index 00000000000..894e7d77dd8 --- /dev/null +++ b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/CassandraStrictTraceIdFalseTest.java @@ -0,0 +1,57 @@ +/** + * Copyright 2015-2017 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin2.storage.cassandra.integrationV1; + +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import zipkin.Span; +import zipkin.internal.V2StorageComponent; +import zipkin.storage.StorageComponent; +import zipkin.storage.StrictTraceIdFalseTest; +import zipkin2.storage.cassandra.CassandraStorage; + +import static org.assertj.core.api.Assertions.assertThat; + +abstract class CassandraStrictTraceIdFalseTest extends StrictTraceIdFalseTest { + + abstract protected String keyspace(); + + private CassandraStorage storage; + private V2StorageComponent storageBeforeSwitch; + + @Before public void connect() { + storage = storageBuilder().strictTraceId(false).keyspace(keyspace()).build(); + storageBeforeSwitch = V2StorageComponent.create(storageBuilder().keyspace(keyspace()).build()); + } + + protected abstract CassandraStorage.Builder storageBuilder(); + + @Override protected final StorageComponent storage() { + return V2StorageComponent.create(storage); + } + + /** Ensures we can still lookup fully 128-bit traces when strict trace ID id disabled */ + @Test public void getTraces_128BitTraceId() { + getTraces_128BitTraceId(accept128BitTrace(storageBeforeSwitch)); + } + + /** Ensures data written before strict trace ID was enabled can be read */ + @Test public void getTrace_retrievesBy128BitTraceId_afterSwitch() { + List trace = accept128BitTrace(storageBeforeSwitch); + + assertThat(store().getRawTrace(trace.get(0).traceIdHigh, trace.get(0).traceId)) + .containsOnlyElementsOf(trace); + } +} diff --git a/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/ITCassandraStorageV1.java b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/ITCassandraStorageV1.java new file mode 100644 index 00000000000..c81f569fd7f --- /dev/null +++ b/zipkin-storage/zipkin2_cassandra/src/test/java/zipkin2/storage/cassandra/integrationV1/ITCassandraStorageV1.java @@ -0,0 +1,121 @@ +/** + * Copyright 2015-2017 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin2.storage.cassandra.integrationV1; + +import com.datastax.driver.core.Session; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.experimental.runners.Enclosed; +import org.junit.rules.TestName; +import org.junit.runner.RunWith; +import zipkin2.storage.cassandra.CassandraStorage; +import zipkin2.storage.cassandra.CassandraStorageRule; +import zipkin2.storage.cassandra.InternalForTests; + +import static zipkin2.storage.cassandra.InternalForTests.dropKeyspace; + +@RunWith(Enclosed.class) +public class ITCassandraStorageV1 { + + static CassandraStorageRule classRule() { + return new CassandraStorageRule("openzipkin/zipkin-cassandra:2.4.1", + "test_cassandra3_zipkinv1"); + } + + public static class DependenciesTest extends CassandraDependenciesTest { + @ClassRule public static CassandraStorageRule storage = classRule(); + @Rule public TestName testName = new TestName(); + + @Override protected String keyspace() { + return InternalForTests.keyspace(testName); + } + + @Before @Override public void clear() { + dropKeyspace(storage.session(), keyspace()); + } + + @Override protected CassandraStorage.Builder storageBuilder() { + return storage.computeStorageBuilder(); + } + } + + public static class SpanStoreTest extends CassandraSpanStoreTest { + @ClassRule public static CassandraStorageRule storage = classRule(); + @Rule public TestName testName = new TestName(); + + @Override protected String keyspace() { + return InternalForTests.keyspace(testName); + } + + @Before @Override public void clear() { + dropKeyspace(storage.session(), keyspace()); + } + + @Override protected CassandraStorage.Builder storageBuilder() { + return storage.computeStorageBuilder(); + } + } + + public static class SpanConsumerTest extends CassandraSpanConsumerTest { + @ClassRule public static CassandraStorageRule storage = classRule(); + @Rule public TestName testName = new TestName(); + + @Override protected String keyspace() { + return InternalForTests.keyspace(testName); + } + + @Before public void clear() { + dropKeyspace(storage.session(), keyspace()); + } + + @Override protected CassandraStorage.Builder storageBuilder() { + return storage.computeStorageBuilder(); + } + } + + public static class EnsureSchemaTest extends CassandraEnsureSchemaTest { + @ClassRule public static CassandraStorageRule storage = classRule(); + @Rule public TestName testName = new TestName(); + + @Override protected String keyspace() { + return InternalForTests.keyspace(testName); + } + + @Before public void clear() { + dropKeyspace(storage.session(), keyspace()); + } + + @Override protected Session session() { + return storage.session(); + } + } + + public static class StrictTraceIdFalseTest extends CassandraStrictTraceIdFalseTest { + @ClassRule public static CassandraStorageRule storage = classRule(); + @Rule public TestName testName = new TestName(); + + @Override protected String keyspace() { + return InternalForTests.keyspace(testName); + } + + @Before @Override public void clear() { + InternalForTests.dropKeyspace(storage.session(), keyspace()); + } + + @Override protected CassandraStorage.Builder storageBuilder() { + return storage.computeStorageBuilder(); + } + } +} diff --git a/zipkin2/src/main/java/zipkin2/storage/InMemoryStorage.java b/zipkin2/src/main/java/zipkin2/storage/InMemoryStorage.java index 4e87f18315f..810a3fa9ccb 100644 --- a/zipkin2/src/main/java/zipkin2/storage/InMemoryStorage.java +++ b/zipkin2/src/main/java/zipkin2/storage/InMemoryStorage.java @@ -72,7 +72,7 @@ public static Builder newBuilder() { } public static final class Builder extends StorageComponent.Builder { - boolean strictTraceId = true; + boolean strictTraceId = true, indexingEnabled = true; int maxSpanCount = 500000; /** {@inheritDoc} */ @@ -81,6 +81,11 @@ public static final class Builder extends StorageComponent.Builder { return this; } + @Override public Builder indexingEnabled(boolean indexingEnabled) { + this.indexingEnabled = indexingEnabled; + return this; + } + /** Eldest traces are removed to ensure spans in memory don't exceed this value */ public Builder maxSpanCount(int maxSpanCount) { if (maxSpanCount <= 0) throw new IllegalArgumentException("maxSpanCount <= 0"); @@ -122,12 +127,13 @@ public Builder maxSpanCount(int maxSpanCount) { } }; - final boolean strictTraceId; + final boolean strictTraceId, indexingEnabled; final int maxSpanCount; volatile int acceptedSpanCount; InMemoryStorage(Builder builder) { this.strictTraceId = builder.strictTraceId; + this.indexingEnabled = builder.indexingEnabled; this.maxSpanCount = builder.maxSpanCount; } @@ -151,6 +157,7 @@ public synchronized void clear() { traceIdToTraceIdTimeStamps.put(lowTraceId, traceIdTimeStamp); acceptedSpanCount++; + if (!indexingEnabled) continue; String spanName = span.name(); if (span.localServiceName() != null) { serviceToTraceIds.put(span.localServiceName(), lowTraceId); @@ -197,8 +204,10 @@ private int deleteOldestTrace() { Collection spans = spansByTraceIdTimeStamp.remove(traceIdTimeStamp); spansEvicted += spans.size(); } - for (String orphanedService : serviceToTraceIds.removeServiceIfTraceId(lowTraceId)) { - serviceToSpanNames.remove(orphanedService); + if (indexingEnabled) { + for (String orphanedService : serviceToTraceIds.removeServiceIfTraceId(lowTraceId)) { + serviceToSpanNames.remove(orphanedService); + } } return spansEvicted; } @@ -258,6 +267,8 @@ public synchronized List> getTraces() { } Set traceIdsDescendingByTimestamp(QueryRequest request) { + if (!indexingEnabled) return Collections.emptySet(); + Collection traceIdTimestamps = request.serviceName() != null ? traceIdTimestampsByServiceName(request.serviceName()) : spansByTraceIdTimeStamp.keySet(); @@ -292,11 +303,12 @@ Set traceIdsDescendingByTimestamp(QueryRequest request) { } @Override public synchronized Call> getServiceNames() { + if (!indexingEnabled) return Call.emptyList(); return Call.create(new ArrayList<>(serviceToTraceIds.keySet())); } @Override public synchronized Call> getSpanNames(String service) { - if (service.isEmpty()) return Call.emptyList(); + if (service.isEmpty() || !indexingEnabled) return Call.emptyList(); service = service.toLowerCase(Locale.ROOT); // service names are always lowercase! return Call.create(new ArrayList<>(serviceToSpanNames.get(service))); } diff --git a/zipkin2/src/main/java/zipkin2/storage/QueryRequest.java b/zipkin2/src/main/java/zipkin2/storage/QueryRequest.java index ac581cf4d03..8f1b0be8488 100644 --- a/zipkin2/src/main/java/zipkin2/storage/QueryRequest.java +++ b/zipkin2/src/main/java/zipkin2/storage/QueryRequest.java @@ -22,9 +22,9 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import zipkin2.internal.Nullable; import zipkin2.Annotation; import zipkin2.Span; +import zipkin2.internal.Nullable; /** * Invoking this request retrieves traces matching the below filters. @@ -39,7 +39,6 @@ */ @AutoValue public abstract class QueryRequest { - /** * When present, corresponds to {@link zipkin2.Endpoint#serviceName} and constrains all other * parameters. diff --git a/zipkin2/src/main/java/zipkin2/storage/StorageComponent.java b/zipkin2/src/main/java/zipkin2/storage/StorageComponent.java index 02329a2d393..c1746946a73 100644 --- a/zipkin2/src/main/java/zipkin2/storage/StorageComponent.java +++ b/zipkin2/src/main/java/zipkin2/storage/StorageComponent.java @@ -73,6 +73,18 @@ public static abstract class Builder { */ public abstract Builder strictTraceId(boolean strictTraceId); + /** + * False is an attempt to disable indexing, leaving only {@link SpanStore#getTrace(String)} + * supported. For example, query requests will be disabled. + * + * The use case is typically to support 100% sampled data, or when traces are searched using + * alternative means such as a logging index. + * + *

Refer to implementation docs for the impact of this parameter. Operations that use indexes + * should return empty as opposed to throwing an exception. + */ + public abstract Builder indexingEnabled(boolean indexingEnabled); + public abstract StorageComponent build(); } } diff --git a/zipkin2/src/test/java/zipkin2/TestObjects.java b/zipkin2/src/test/java/zipkin2/TestObjects.java index 1facaccaabe..ee56f25fff4 100644 --- a/zipkin2/src/test/java/zipkin2/TestObjects.java +++ b/zipkin2/src/test/java/zipkin2/TestObjects.java @@ -56,9 +56,9 @@ public static long midnightUTC(long epochMillis) { .kind(Span.Kind.CLIENT) .localEndpoint(FRONTEND) .remoteEndpoint(BACKEND) - .timestamp(1472470996199000L) - .duration(207000L) - .addAnnotation(1472470996238000L, "foo") + .timestamp((TODAY - 207) * 1000L) + .duration(207 * 1000L) + .addAnnotation((TODAY - 100) * 1000L, "foo") .putTag("http.path", "/api") .putTag("clnt/finagle.version", "6.45.0") .build(); diff --git a/zipkin2/src/test/java/zipkin2/storage/ITInMemoryStorage.java b/zipkin2/src/test/java/zipkin2/storage/ITInMemoryStorage.java new file mode 100644 index 00000000000..6193a2a9d32 --- /dev/null +++ b/zipkin2/src/test/java/zipkin2/storage/ITInMemoryStorage.java @@ -0,0 +1,46 @@ +/** + * Copyright 2015-2017 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin2.storage; + +import java.io.IOException; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; + +@RunWith(Enclosed.class) +public class ITInMemoryStorage { + + public static class ITSpanStore extends zipkin2.storage.ITSpanStore { + InMemoryStorage storage = InMemoryStorage.newBuilder().build(); + + @Override protected InMemoryStorage storage() { + return storage; + } + + @Override public void clear() throws IOException { + // no need.. the test rule does this + } + } + + public static class ITIndexingEnabledFalse extends zipkin2.storage.ITIndexingEnabledFalse { + InMemoryStorage storage = InMemoryStorage.newBuilder().indexingEnabled(false).build(); + + @Override protected InMemoryStorage storage() { + return storage; + } + + @Override public void clear() throws IOException { + // no need.. the test rule does this + } + } +} diff --git a/zipkin2/src/test/java/zipkin2/storage/ITIndexingEnabledFalse.java b/zipkin2/src/test/java/zipkin2/storage/ITIndexingEnabledFalse.java new file mode 100644 index 00000000000..6494d6736af --- /dev/null +++ b/zipkin2/src/test/java/zipkin2/storage/ITIndexingEnabledFalse.java @@ -0,0 +1,82 @@ +/** + * Copyright 2015-2017 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin2.storage; + +import java.io.IOException; +import org.junit.Before; +import org.junit.Test; +import zipkin2.Span; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static zipkin2.TestObjects.CLIENT_SPAN; +import static zipkin2.storage.ITSpanStore.requestBuilder; + +/** + * Base test for when {@link StorageComponent.Builder#indexingEnabled(boolean) indexingEnabled == + * false}. + * + *

Subtypes should create a connection to a real backend, even if that backend is in-process. + */ +public abstract class ITIndexingEnabledFalse { + + /** Should maintain state between multiple calls within a test. */ + protected abstract StorageComponent storage(); + + protected SpanStore store() { + return storage().spanStore(); + } + + /** Clears store between tests. */ + @Before public abstract void clear() throws Exception; + + @Test public void getTraces_indexDataReturnsNothing() throws Exception { + accept(CLIENT_SPAN); + + assertThat(store().getTraces(requestBuilder() + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .serviceName(CLIENT_SPAN.localServiceName()) + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .spanName(CLIENT_SPAN.name()) + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .annotationQuery(CLIENT_SPAN.tags()) + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .minDuration(CLIENT_SPAN.duration()) + .build()).execute()).isEmpty(); + } + + @Test public void getSpanNames_isEmpty() throws Exception { + accept(CLIENT_SPAN); + + assertThat(store().getSpanNames(CLIENT_SPAN.name()).execute()).isEmpty(); + } + + @Test public void getServiceNames_isEmpty() throws Exception { + accept(CLIENT_SPAN); + + assertThat(store().getServiceNames().execute()).isEmpty(); + } + + protected void accept(Span... spans) throws IOException { + storage().spanConsumer().accept(asList(spans)).execute(); + } +} diff --git a/zipkin2/src/test/java/zipkin2/storage/ITSpanStore.java b/zipkin2/src/test/java/zipkin2/storage/ITSpanStore.java new file mode 100644 index 00000000000..9208cf60a39 --- /dev/null +++ b/zipkin2/src/test/java/zipkin2/storage/ITSpanStore.java @@ -0,0 +1,183 @@ +/** + * Copyright 2015-2017 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin2.storage; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.junit.Before; +import org.junit.Test; +import zipkin2.Endpoint; +import zipkin2.Span; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static zipkin2.TestObjects.CLIENT_SPAN; +import static zipkin2.TestObjects.DAY; +import static zipkin2.TestObjects.TODAY; + +/** + * Base test for {@link SpanStore}. + * + *

Subtypes should create a connection to a real backend, even if that backend is in-process. + */ +public abstract class ITSpanStore { + + /** Should maintain state between multiple calls within a test. */ + protected abstract StorageComponent storage(); + + protected SpanStore store() { + return storage().spanStore(); + } + + /** Clears store between tests. */ + @Before public abstract void clear() throws Exception; + + @Test public void getTraces_filteringMatchesMostRecentTraces() throws Exception { + List endpoints = IntStream.rangeClosed(1, 10) + .mapToObj(i -> Endpoint.newBuilder().serviceName("service" + i).ip("127.0.0.1").build()) + .collect(Collectors.toList()); + + long gapBetweenSpans = 100; + Span[] earlySpans = + IntStream.rangeClosed(1, 10).mapToObj(i -> Span.newBuilder().name("early") + .traceId(Integer.toHexString(i)).id(Integer.toHexString(i)) + .timestamp((TODAY - i) * 1000).duration(1L) + .localEndpoint(endpoints.get(i - 1)).build()).toArray(Span[]::new); + + Span[] lateSpans = IntStream.rangeClosed(1, 10).mapToObj(i -> Span.newBuilder().name("late") + .traceId(Integer.toHexString(i + 10)).id(Integer.toHexString(i + 10)) + .timestamp((TODAY + gapBetweenSpans - i) * 1000).duration(1L) + .localEndpoint(endpoints.get(i - 1)).build()).toArray(Span[]::new); + + accept(earlySpans); + accept(lateSpans); + + List[] earlyTraces = + Stream.of(earlySpans).map(Collections::singletonList).toArray(List[]::new); + List[] lateTraces = + Stream.of(lateSpans).map(Collections::singletonList).toArray(List[]::new); + + assertThat(store().getTraces(requestBuilder().build()).execute()) + .hasSize(20); + + assertThat(store().getTraces(requestBuilder() + .limit(10).build()).execute()) + .containsExactly(lateTraces); + + assertThat(store().getTraces(requestBuilder() + .endTs(TODAY + gapBetweenSpans).lookback(gapBetweenSpans).build()).execute()) + .containsExactly(lateTraces); + + assertThat(store().getTraces(requestBuilder() + .endTs(TODAY).build()).execute()) + .containsExactly(earlyTraces); + } + + @Test public void getTraces_localServiceName() throws Exception { + accept(CLIENT_SPAN); + + assertThat(store().getTraces(requestBuilder() + .serviceName(CLIENT_SPAN.localServiceName() + 1) + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .serviceName(CLIENT_SPAN.localServiceName()) + .build()).execute()).flatExtracting(l -> l).contains(CLIENT_SPAN); + } + + @Test public void getTraces_spanName() throws Exception { + accept(CLIENT_SPAN); + + assertThat(store().getTraces(requestBuilder() + .spanName(CLIENT_SPAN.name() + 1) + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .spanName(CLIENT_SPAN.name()) + .build()).execute()).flatExtracting(l -> l).contains(CLIENT_SPAN); + } + + @Test public void getTraces_tags() throws Exception { + accept(CLIENT_SPAN); + + assertThat(store().getTraces(requestBuilder() + .annotationQuery(Collections.singletonMap("foo", "bar")) + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .annotationQuery(CLIENT_SPAN.tags()) + .build()).execute()).flatExtracting(l -> l).contains(CLIENT_SPAN); + } + + @Test public void getTraces_minDuration() throws Exception { + accept(CLIENT_SPAN); + + assertThat(store().getTraces(requestBuilder() + .minDuration(CLIENT_SPAN.duration() + 1) + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .minDuration(CLIENT_SPAN.duration()) + .build()).execute()).flatExtracting(l -> l).contains(CLIENT_SPAN); + } + + @Test public void getTraces_maxDuration() throws Exception { + accept(CLIENT_SPAN); + + assertThat(store().getTraces(requestBuilder() + .minDuration(CLIENT_SPAN.duration() - 2) + .maxDuration(CLIENT_SPAN.duration() - 1) + .build()).execute()).isEmpty(); + + assertThat(store().getTraces(requestBuilder() + .minDuration(CLIENT_SPAN.duration()) + .maxDuration(CLIENT_SPAN.duration()) + .build()).execute()).flatExtracting(l -> l).contains(CLIENT_SPAN); + } + + @Test public void getSpanNames() throws Exception { + assertThat(store().getSpanNames(CLIENT_SPAN.localServiceName()).execute()) + .isEmpty(); + + accept(CLIENT_SPAN); + + assertThat(store().getSpanNames(CLIENT_SPAN.localServiceName() + 1).execute()) + .isEmpty(); + + assertThat(store().getSpanNames(CLIENT_SPAN.localServiceName()).execute()) + .contains(CLIENT_SPAN.name()); + } + + @Test public void getServiceNames_includesLocalServiceName() throws Exception { + assertThat(store().getServiceNames().execute()) + .isEmpty(); + + accept(CLIENT_SPAN); + + assertThat(store().getServiceNames().execute()) + .contains(CLIENT_SPAN.localServiceName()); + } + + protected void accept(Span... spans) throws IOException { + storage().spanConsumer().accept(asList(spans)).execute(); + } + + static QueryRequest.Builder requestBuilder() { + return QueryRequest.newBuilder().endTs(TODAY + DAY).lookback(DAY * 2).limit(100); + } +} diff --git a/zipkin2/src/test/java/zipkin2/storage/InMemoryStorageTest.java b/zipkin2/src/test/java/zipkin2/storage/InMemoryStorageTest.java index f8d67c27068..a5f6337535a 100644 --- a/zipkin2/src/test/java/zipkin2/storage/InMemoryStorageTest.java +++ b/zipkin2/src/test/java/zipkin2/storage/InMemoryStorageTest.java @@ -23,13 +23,13 @@ import zipkin2.DependencyLink; import zipkin2.Endpoint; import zipkin2.Span; -import zipkin2.TestObjects; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static zipkin2.TestObjects.CLIENT_SPAN; import static zipkin2.TestObjects.TODAY; +import static zipkin2.storage.ITSpanStore.requestBuilder; public class InMemoryStorageTest { InMemoryStorage storage = InMemoryStorage.newBuilder().build(); @@ -122,9 +122,4 @@ public class InMemoryStorageTest { "root" ); } - - static QueryRequest.Builder requestBuilder() { - return QueryRequest.newBuilder().endTs(TODAY + TestObjects.DAY).lookback( - TestObjects.DAY * 2).limit(100); - } }