はじめに
Googleの分散トレースモニタリングのCloudTraceはOpenCensusをベースというかその元になっているので、同様に非同期処理であってもちゃんとトレーシング出来ます。
なので、CloudTasksを使って非同期処理を今回実装したのですが、マニュアルとかにやり方が書いてなくて少し嵌ったのでメモ。
やり方
まずはCloudTasksをJavaで実行するコード。これは基本的にはチュートリアル通りです。
try ( var client = CloudTasksClient.create()) {
var queuePath = QueueName.of(projectId, locationId, queueId).toString();
var traceparent = getTraceparent();
var taskBuilder = Task.newBuilder()
.setHttpRequest(HttpRequest.newBuilder()
.putHeaders("traceparent", traceparent)
.setUrl("http://locahost:9000")
.setHttpMethod(HttpMethod.GET)
.build());
// Send create task request.
var task = client.createTask(queuePath, taskBuilder.build());
logger.debug("task-create", $("taskid", task.getName()));
}
ポイントはHTTPヘッダにtraceparent
を使っていることです。以前の記事にも書きましたが、これでコンテキストを伝搬してやらないと、リクエスト自体は反映されるものの一連のリクエストとしてCloudTrace側で認識できません。
そのため、以下のようなコードで現在のSpanからtraceparent
を生成します。
private static final Setter<Map<String, String>> setter = new Setter<Map<String, String>>() {
@Override
public void put(Map<String, String> carrier, String key, String value) {
carrier.put(key, value);
}
};
public String getTraceparent() {
var traceContextFormat = new TraceContextFormat();
var current = Tracing.getTracer().getCurrentSpan().getContext();
var carrier = new LinkedHashMap<String, String>();
traceContextFormat.inject(
SpanContext.create(current.getTraceId(), current.getSpanId(), current.getTraceOptions(), current.getTracestate()),
carrier,
setter);
var traceparent = carrier.get("traceparent");
return traceparent;
}
前提としてopencensus-api
を依存に入れておく必要があります。
traceparent
のメインはTraceContextFormat
とSetter<Map<String, String>>
です。こいつにSpanのトレースIDやスパンIDを渡す事で下記のフォーマットで変換してくれます。
自前で、作っても良いのですが微妙にフォーマットがめんどくさいので既存のコードを使わない理由も特にないでしょう。
これで、以下のように非同期処理もちゃんとトレースされました。