58. Span lifecycle

您可以通过brave.Tracer在 Span 上执行以下操作:

  • start:开始 Span 时,将分配其名称并记录开始时间戳。

  • close:Span 已完成(记录了 Span 的结束时间),并且,如果对 Span 进行了采样,则可以进行收集(例如,到 Zipkin)。

  • continue:创建了一个新的 span 实例。它是 continue 的副本。

  • detach:Span 不会停止或关闭。它只会从当前线程中删除。

  • 用显式父创建:您可以创建一个新 Span 并为其设置一个明确的父级。

Tip

Spring Cloud Sleuth 为您创建一个Tracer的实例。为了使用它,您可以对其进行自动接线。

58.1 创建和整理 Span

您可以使用Tracer手动创建 Span,如以下示例所示:

// Start a span. If there was a span present in this thread it will become
// the `newSpan`'s parent.
Span newSpan = this.tracer.nextSpan().name("calculateTax");
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(newSpan.start())) {
	// ...
	// You can tag a span
	newSpan.tag("taxValue", taxValue);
	// ...
	// You can log an event on a span
	newSpan.annotate("taxCalculated");
}
finally {
	// Once done remember to finish the span. This will allow collecting
	// the span to send it to Zipkin
	newSpan.finish();
}

在前面的示例中,我们可以看到如何创建 Span 的新实例。如果此线程中已经有一个 Span,它将成为新 Span 的父级。

Tip

创建 Span 后,请始终保持清洁。另外,请始终完成要发送给 Zipkin 的所有 Span。

Tip

如果您的 Span 包含的名称大于 50 个字符,则该名称将被截断为 50 个字符。您的姓名必须明确明确。知名人士会导致延迟问题,有时甚至会引发 exceptions。

58.2 连续 Span

有时,您不想创建一个新 Span,但想 continue 一个 Span。这种情况的示例如下:

  • AOP :如果在达到宽高比之前已经创建了一个 Span,则您可能不想创建一个新的 Span。

  • Hystrix :执行 Hystrix 命令很可能是当前处理的逻辑部分。实际上,它仅仅是技术实现细节,您不一定要在跟踪中将其反映为一个单独的实体。

要 continueSpan,可以使用brave.Tracer,如以下示例所示:

// let's assume that we're in a thread Y and we've received
// the `initialSpan` from thread X
Span continuedSpan = this.tracer.toSpan(newSpan.context());
try {
	// ...
	// You can tag a span
	continuedSpan.tag("taxValue", taxValue);
	// ...
	// You can log an event on a span
	continuedSpan.annotate("taxCalculated");
}
finally {
	// Once done remember to flush the span. That means that
	// it will get reported but the span itself is not yet finished
	continuedSpan.flush();
}

58.3 使用显式父级创建 Span

您可能要开始一个新的 Span 并提供该 Span 的显式父项。假定范围的父级在一个线程中,而您想在另一个线程中开始一个新的范围。在《Brave 传说》中,每当您调用nextSpan()时,它都会参考当前范围内的范围创建一个范围。您可以将范围放在范围中,然后调用nextSpan(),如以下示例所示:

// let's assume that we're in a thread Y and we've received
// the `initialSpan` from thread X. `initialSpan` will be the parent
// of the `newSpan`
Span newSpan = null;
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(initialSpan)) {
	newSpan = this.tracer.nextSpan().name("calculateCommission");
	// ...
	// You can tag a span
	newSpan.tag("commissionValue", commissionValue);
	// ...
	// You can log an event on a span
	newSpan.annotate("commissionCalculated");
}
finally {
	// Once done remember to finish the span. This will allow collecting
	// the span to send it to Zipkin. The tags and events set on the
	// newSpan will not be present on the parent
	if (newSpan != null) {
		newSpan.finish();
	}
}

Tip

创建这样的 Span 后,必须完成它。否则,不会报告(例如,向 Zipkin 报告)。