diff --git a/zipkin-java-server/src/main/java/io/zipkin/server/ZipkinQueryApiV1.java b/zipkin-java-server/src/main/java/io/zipkin/server/ZipkinQueryApiV1.java index f44048b57ba..68add998bf7 100644 --- a/zipkin-java-server/src/main/java/io/zipkin/server/ZipkinQueryApiV1.java +++ b/zipkin-java-server/src/main/java/io/zipkin/server/ZipkinQueryApiV1.java @@ -13,37 +13,42 @@ */ package io.zipkin.server; -import io.zipkin.Codec; -import io.zipkin.QueryRequest; -import io.zipkin.Span; -import io.zipkin.SpanStore; -import io.zipkin.internal.Util.Serializer; +import static io.zipkin.internal.Util.writeJsonList; + import java.util.Arrays; import java.util.Collections; import java.util.List; + import javax.inject.Inject; -import okio.Buffer; + import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; -import static io.zipkin.internal.Util.writeJsonList; +import io.zipkin.Codec; +import io.zipkin.QueryRequest; +import io.zipkin.Span; +import io.zipkin.SpanStore; +import io.zipkin.internal.Util.Serializer; +import okio.Buffer; /** * Implements the json api used by {@code zipkin-web}. * * See com.twitter.zipkin.query.ZipkinQueryController */ -@Controller +@RestController @RequestMapping("/api/v1") public class ZipkinQueryApiV1 { - static final Serializer> TRACE_TO_JSON = writeJsonList(Codec.JSON::writeSpan); + static final Serializer> TRACE_TO_JSON = writeJsonList( + Codec.JSON::writeSpan); static final Serializer>> TRACES_TO_JSON = writeJsonList(TRACE_TO_JSON); private final SpanStore spanStore; @@ -54,41 +59,38 @@ public class ZipkinQueryApiV1 { } @RequestMapping(value = "/dependencies", method = RequestMethod.GET) - @ResponseBody - public List getDependencies(@RequestParam(value = "startTs", required = false, defaultValue = "0") long startTs, - @RequestParam(value = "endTs", required = true) long endTs) { + public List getDependencies( + @RequestParam(value = "startTs", required = false, defaultValue = "0") long startTs, + @RequestParam(value = "endTs", required = true) long endTs) { return Arrays.asList(); } @RequestMapping(value = "/services", method = RequestMethod.GET) - @ResponseBody public List getServiceNames() { - return spanStore.getServiceNames(); + return this.spanStore.getServiceNames(); } @RequestMapping(value = "/spans", method = RequestMethod.GET) - @ResponseBody - public List getSpanNames(@RequestParam(value = "serviceName", required = true) String serviceName) { - return spanStore.getSpanNames(serviceName); + public List getSpanNames( + @RequestParam(value = "serviceName", required = true) String serviceName) { + return this.spanStore.getSpanNames(serviceName); } - @RequestMapping(value = "/traces", method = RequestMethod.GET) - @ResponseBody - public ResponseEntity getTraces(@RequestParam(value = "serviceName", required = true) String serviceName, - @RequestParam(value = "spanName", defaultValue = "all") String spanName, - @RequestParam(value = "annotationQuery") String annotationQuery, - @RequestParam(value = "endTs") Long endTs, - @RequestParam(value = "limit") Integer limit) { - QueryRequest.Builder builder = new QueryRequest.Builder() - .serviceName(serviceName) - .spanName(spanName.equals("all") ? null : spanName) - .endTs(endTs) - .limit(limit); + @RequestMapping(value = "/traces", method = RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE) + public byte[] getTraces( + @RequestParam(value = "serviceName", required = true) String serviceName, + @RequestParam(value = "spanName", defaultValue = "all") String spanName, + @RequestParam(value = "annotationQuery") String annotationQuery, + @RequestParam(value = "endTs") Long endTs, + @RequestParam(value = "limit") Integer limit) { + QueryRequest.Builder builder = new QueryRequest.Builder().serviceName(serviceName) + .spanName(spanName.equals("all") ? null : spanName).endTs(endTs).limit(limit); if (annotationQuery != null && !annotationQuery.isEmpty()) { for (String ann : annotationQuery.split(" and ")) { if (ann.indexOf('=') == -1) { builder.addAnnotation(ann); - } else { + } + else { String[] keyValue = ann.split("="); if (keyValue.length < 2 || keyValue[1] == null) { builder.addAnnotation(ann); @@ -97,18 +99,32 @@ public ResponseEntity getTraces(@RequestParam(value = "serviceName", req } } } - return ResponseEntity.ok(TRACES_TO_JSON.apply(spanStore.getTraces(builder.build()))); + return TRACES_TO_JSON.apply(this.spanStore.getTraces(builder.build())); } - @RequestMapping(value = "/trace/{traceId}", method = RequestMethod.GET) - @ResponseBody - public ResponseEntity getTrace(@PathVariable String traceId) { + @RequestMapping(value = "/trace/{traceId}", method = RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE) + public byte[] getTrace(@PathVariable String traceId) { long id = new Buffer().writeUtf8(traceId).readHexadecimalUnsignedLong(); - List> traces = spanStore.getTracesByIds(Collections.singletonList(id)); + List> traces = this.spanStore + .getTracesByIds(Collections.singletonList(id)); if (traces.isEmpty()) { - return new ResponseEntity(HttpStatus.NOT_FOUND); + throw new TraceNotFoundException(traceId, id); } - return ResponseEntity.ok(TRACE_TO_JSON.apply(traces.get(0))); + return TRACE_TO_JSON.apply(traces.get(0)); + } + + @ExceptionHandler(TraceNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public void notFound() { } + +} + +class TraceNotFoundException extends RuntimeException { + + public TraceNotFoundException(String traceId, long id) { + super("Cannot find trace for id=" + traceId + ", long value=" + id); + } + }