/**
* Copyright 2015-2016 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 zipkin.junit;
import java.io.IOException;
import java.util.List;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import zipkin.Codec;
import zipkin.DependencyLink;
import zipkin.Span;
import zipkin.internal.Nullable;
import zipkin.internal.Util;
import zipkin.storage.QueryRequest;
import zipkin.storage.SpanStore;
/**
* Implements the span store interface by forwarding requests over http.
*/
final class HttpSpanStore implements SpanStore {
private final OkHttpClient client;
private final HttpUrl baseUrl;
HttpSpanStore(OkHttpClient client, HttpUrl baseUrl) {
this.client = client;
this.baseUrl = baseUrl;
}
@Override
public List<List<Span>> getTraces(QueryRequest request) {
HttpUrl.Builder url = baseUrl.newBuilder("/api/v1/traces");
maybeAddQueryParam(url, "serviceName", request.serviceName);
maybeAddQueryParam(url, "spanName", request.spanName);
maybeAddQueryParam(url, "annotationQuery", request.toAnnotationQuery());
maybeAddQueryParam(url, "minDuration", request.minDuration);
maybeAddQueryParam(url, "maxDuration", request.maxDuration);
maybeAddQueryParam(url, "endTs", request.endTs);
maybeAddQueryParam(url, "lookback", request.lookback);
maybeAddQueryParam(url, "limit", request.limit);
Response response = call(new Request.Builder().url(url.build()).build());
return Codec.JSON.readTraces(responseBytes(response));
}
@Override
public List<Span> getTrace(long traceId) {
return getTrace(0L, traceId);
}
@Override public List<Span> getTrace(long traceIdHigh, long traceIdLow) {
return getTrace(traceIdHigh, traceIdLow, false);
}
@Override
public List<Span> getRawTrace(long traceId) {
return getRawTrace(0L, traceId);
}
@Override public List<Span> getRawTrace(long traceIdHigh, long traceIdLow) {
return getTrace(traceIdHigh, traceIdLow, true);
}
private List<Span> getTrace(long traceIdHigh, long traceIdLow, boolean raw) {
String traceIdHex = Util.toLowerHex(traceIdHigh, traceIdLow);
Response response = call(new Request.Builder()
.url(baseUrl.resolve(String.format("/api/v1/trace/%s%s", traceIdHex, raw ? "?raw" : "")))
.build());
if (response.code() == 404) {
return null;
}
return Codec.JSON.readSpans(responseBytes(response));
}
@Override
public List<String> getServiceNames() {
Response response = call(new Request.Builder()
.url(baseUrl.resolve("/api/v1/services")).build());
return Codec.JSON.readStrings(responseBytes(response));
}
@Override
public List<String> getSpanNames(String serviceName) {
Response response = call(new Request.Builder()
.url(baseUrl.resolve("/api/v1/spans?serviceName=" + serviceName)).build());
return Codec.JSON.readStrings(responseBytes(response));
}
@Override
public List<DependencyLink> getDependencies(long endTs, @Nullable Long lookback) {
HttpUrl.Builder url = baseUrl.newBuilder("/api/v1/dependencies?endTs=" + endTs);
if (lookback != null) url.addQueryParameter("lookback", lookback.toString());
Response response = call(new Request.Builder().url(url.build()).build());
return Codec.JSON.readDependencyLinks(responseBytes(response));
}
Response call(Request request) {
try {
return client.newCall(request).execute();
} catch (IOException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
void maybeAddQueryParam(HttpUrl.Builder builder, String name, @Nullable Object value) {
if (value != null) builder.addQueryParameter(name, value.toString());
}
byte[] responseBytes(Response response) {
if (response.code() != 200) throw new RuntimeException("unexpected response: " + response);
try {
return response.body().bytes();
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}