blob: fc5dcb2815ac585df6d4b3b6b7f2e6279e55de40 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.solr.util.tracing;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import io.opentracing.mock.MockSpan;
import io.opentracing.mock.MockTracer;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.util.TimeSource;
import org.apache.solr.util.TimeOut;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestDistributedTracing extends SolrCloudTestCase {
private static final String COLLECTION = "collection1";
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@BeforeClass
public static void beforeTest() throws Exception {
configureCluster(4)
.addConfig("config", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
.withSolrXml(TEST_PATH().resolve("solr-tracing.xml"))
.configure();
CollectionAdminRequest.setClusterProperty(ZkStateReader.SAMPLE_PERCENTAGE, "100.0")
.process(cluster.getSolrClient());
waitForSampleRateUpdated(1.0);
CollectionAdminRequest
.createCollection(COLLECTION, "config", 2, 2)
.setPerReplicaState(SolrCloudTestCase.USE_PER_REPLICA_STATE)
.process(cluster.getSolrClient());
cluster.waitForActiveCollection(COLLECTION, 2, 4);
}
private static void waitForSampleRateUpdated(double rate) throws TimeoutException, InterruptedException {
TimeOut timeOut = new TimeOut(1, TimeUnit.MINUTES, TimeSource.NANO_TIME);
timeOut.waitFor("Waiting for sample rate is updated", () ->
Math.abs(GlobalTracer.get().getSampleRate() - rate) < 0.001
&& GlobalTracer.get().tracer instanceof MockTracer);
}
private List<MockSpan> getFinishedSpans() {
return ((MockTracer)GlobalTracer.get().tracer).finishedSpans();
}
@Test
public void test() throws IOException, SolrServerException, TimeoutException, InterruptedException {
CloudSolrClient cloudClient = cluster.getSolrClient();
List<MockSpan> allSpans = getFinishedSpans();
cloudClient.add(COLLECTION, sdoc("id", "1"));
List<MockSpan> finishedSpans = getRecentSpans(allSpans);
finishedSpans.removeIf(x ->
!x.tags().get("http.url").toString().endsWith("/update"));
assertEquals(2, finishedSpans.size());
assertOneSpanIsChildOfAnother(finishedSpans);
cloudClient.add(COLLECTION, sdoc("id", "2"));
finishedSpans = getRecentSpans(allSpans);
finishedSpans.removeIf(x ->
!x.tags().get("http.url").toString().endsWith("/update"));
assertEquals(2, finishedSpans.size());
assertOneSpanIsChildOfAnother(finishedSpans);
cloudClient.add(COLLECTION, sdoc("id", "3"));
cloudClient.add(COLLECTION, sdoc("id", "4"));
cloudClient.commit(COLLECTION);
getRecentSpans(allSpans);
cloudClient.query(COLLECTION, new SolrQuery("*:*"));
finishedSpans = getRecentSpans(allSpans);
finishedSpans.removeIf(x ->
!x.tags().get("http.url").toString().endsWith("/select"));
// one from client to server, 2 for execute query, 2 for fetching documents
assertEquals(5, finishedSpans.size());
assertEquals(1, finishedSpans.stream().filter(s -> s.parentId() == 0).count());
long parentId = finishedSpans.stream()
.filter(s -> s.parentId() == 0)
.collect(Collectors.toList())
.get(0).context().spanId();
for (MockSpan span: finishedSpans) {
if (span.parentId() != 0 && parentId != span.parentId()) {
fail("All spans must belong to single span, but:"+finishedSpans);
}
}
CollectionAdminRequest.setClusterProperty(ZkStateReader.SAMPLE_PERCENTAGE, "0.0")
.process(cluster.getSolrClient());
waitForSampleRateUpdated(0);
getRecentSpans(allSpans);
cloudClient.add(COLLECTION, sdoc("id", "5"));
finishedSpans = getRecentSpans(allSpans);
assertEquals(0, finishedSpans.size());
}
private void assertOneSpanIsChildOfAnother(List<MockSpan> finishedSpans) {
MockSpan child = finishedSpans.get(0);
MockSpan parent = finishedSpans.get(1);
if (child.parentId() == 0) {
MockSpan temp = parent;
parent = child;
child = temp;
}
assertEquals(child.parentId(), parent.context().spanId());
}
private List<MockSpan> getRecentSpans(List<MockSpan> allSpans) {
List<MockSpan> result = new ArrayList<>(getFinishedSpans());
result.removeAll(allSpans);
allSpans.clear();
allSpans.addAll(getFinishedSpans());
return result;
}
}