@Override public O serve(ServiceRequestContext ctx, I req) throws Exception { final TraceData traceData = getTraceData(ctx, req); final String method = req instanceof RpcRequest ? ((RpcRequest) req).method() : ctx.method(); final ServerRequestAdapter requestAdapter = new InternalServerRequestAdapter(method, traceData); final ServerSpan serverSpan = serverInterceptor.openSpan(requestAdapter); final boolean sampled; if (serverSpan != null) { ctx.onEnter(() -> serverInterceptor.setSpan(serverSpan)); ctx.onExit(serverInterceptor::clearSpan); sampled = serverSpan.getSample(); } else { sampled = false; } try { final O res = delegate().serve(ctx, req); if (sampled) { ctx.requestLogFuture() .thenAcceptBoth( res.closeFuture(), (log, unused) -> closeSpan(ctx, serverSpan, log, res)) .exceptionally(CompletionActions::log); } return res; } finally { serverInterceptor.clearSpan(); } }
/** Returns the server-side annotations that should be added to a Zipkin span. */ protected List<KeyValueAnnotation> annotations(ServiceRequestContext ctx, RequestLog req, O res) { final List<KeyValueAnnotation> annotations = new ArrayList<>(5); final StringBuilder uriBuilder = new StringBuilder(); uriBuilder.append(req.scheme().uriText()); uriBuilder.append("://"); uriBuilder.append(req.host()); uriBuilder.append(ctx.path()); if (req.method() != null) { uriBuilder.append('#'); uriBuilder.append(req.method()); } annotations.add(KeyValueAnnotation.create("server.uri", uriBuilder.toString())); if (ctx.remoteAddress() != null) { annotations.add(KeyValueAnnotation.create("server.remote", ctx.remoteAddress().toString())); } if (ctx.localAddress() != null) { annotations.add(KeyValueAnnotation.create("server.local", ctx.localAddress().toString())); } final CompletableFuture<?> f = res.closeFuture(); if (f.isDone()) { // Need to use a callback because CompletableFuture does not have a getter for the cause of // failure. // The callback will be invoked immediately because the future is done already. f.handle( voidFunction( (result, cause) -> { final String resultText = cause == null ? "success" : "failure"; annotations.add(KeyValueAnnotation.create("server.result", resultText)); if (cause != null) { annotations.add(KeyValueAnnotation.create("server.cause", cause.toString())); } })) .exceptionally(CompletionActions::log); } return annotations; }