この記事は ZOZO #4 Advent Calendar 2021 17日目の記事になります。
今回はマイクロサービスのdatadogの分散トレースに挑戦したのでそれについて記載しようと思います。
構成は以下になります。
処理の流れは以下になります。
- Classic ASPからJava API【A】の登録APIを呼ぶ
- Java API【A】はDynamoDBに処理開始のレコードを登録する
- Java API【A】はKinesis Data Streams(以下、KDS)に登録情報を渡す
- Java API【B】はKDSから情報を取り出し、処理を行う
- Java API【B】はDynamoDBにレコードを処理完了に更新する
これにdatadogを仕込み、一連の処理をトレースします。
はじめにJava API【A】の登録APIでTraceを作成します。
public record Trace(TraceId traceId, DdCarrier ddCarrier) {
public static Trace convert(String traceId) {
Tracer tracer = GlobalTracer.get();
Map<String, String> ddMap = new HashMap<>();
tracer.inject(
tracer.activeSpan().context(),
Format.Builtin.TEXT_MAP_INJECT,
new TextMapInjectAdapter(ddMap));
return new Trace(new TraceId(traceId), new DdCarrier(ddMap));
}
}
作成されたTraceをKDSに渡し、Java API【A】の登録APIの返却値として以下を返却します。
- x-datadog-trace-id
- x-datadog-sampling-priority
- x-datadog-parent-id
Java API【B】はKDSを経由してdatadogのパラメータを受け取ります。
受け取ったパラメータを元にSpanを作成し、登録APIのtraceと紐付けます。
また、Java API【A】の参照APIもClassic ASPを経由して同じ様に対応します。
Tracer tracer = GlobalTracer.get();
SpanBuilder spanBuilder =
new SpanBuilder()
.generate(
tracer,
"処理API",
traceId,
datadogTraceId,
datadogParentId,
datadogSamplingPriority);
Span span = spanBuilder.start();
try (Scope scope = tracer.scopeManager().activate(span)) {
// 処理
} catch (Exception e) {
span.setTag(DDTags.ERROR_MSG, e.getMessage());
span.setTag(DDTags.ERROR_STACK, Arrays.toString(e.getStackTrace()));
throw e;
} finally {
span.finish();
}
public class SpanBuilder {
public Tracer.SpanBuilder generate(
Tracer tracer,
String operationName,
String traceId,
String datadogTraceId,
String datadogParentId,
String datadogSamplingPriority) {
Tracer.SpanBuilder spanBuilder =
tracer
.buildSpan(operationName)
.withTag("trace-id", traceId)
.withTag("datadog-trace-id", datadogTraceId)
.withTag("datadog-sampling-priority", datadogSamplingPriority)
.withTag("datadog-parent-id", datadogParentId);
Map<String, String> ddCarrier = new HashMap<>();
ddCarrier.put("x-datadog-trace-id", datadogTraceId);
ddCarrier.put("x-datadog-sampling-priority", datadogSamplingPriority);
ddCarrier.put("x-datadog-parent-id", datadogParentId);
SpanContext spanContext =
tracer.extract(Format.Builtin.TEXT_MAP_EXTRACT, new TextMapExtractAdapter(ddCarrier));
return spanBuilder.asChildOf(spanContext);
}
}
これにより、以下のように一気通貫で処理をトレースすることができます。
処理の流れが追いやすくなり、エラーなどが発生した際も原因の特定がしやすくなりました。
明日は @EnKUMA の記事になります。
読んでいただきありがとうございました。