物流服务
此服务负责在从结账服务请求时提供物流信息,包括价格和追踪信息。
物流服务主要使用 Tonic、Reqwest 和 OpenTelemetry 库/组件构建。其他子依赖项包含在 Cargo.toml
中。
根据您的框架和运行时,您可能需要参考Rust文档以作为补充。您可以在报价请求中找到异步和同步跨度的示例,以及跟踪 ID。
build.rs
支持在无 Docker 的情况下进行开发,只需安装 Rust。否则,考虑使用 docker compose
进行构建以编辑/评估所需的更改。
链路追踪
初始化追踪
OpenTelemetry SDK 在 main
函数中进行初始化。
fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
global::set_text_map_propagator(TraceContextPropagator::new());
let os_resource = OsResourceDetector.detect(Duration::from_secs(0));
let process_resource = ProcessResourceDetector.detect(Duration::from_secs(0));
let sdk_resource = SdkProvidedResourceDetector.detect(Duration::from_secs(0));
let env_resource = EnvResourceDetector::new().detect(Duration::from_secs(0));
let telemetry_resource = TelemetryResourceDetector.detect(Duration::from_secs(0));
opentelemetry_otlp::new_pipeline()
.tracing()
.with_exporter(
opentelemetry_otlp::new_exporter()
.tonic()
.with_endpoint(format!(
"{}{}",
env::var("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT")
.unwrap_or_else(|_| "http://otelcol:4317".to_string()),
"/v1/traces"
)), // TODO: assume this ^ is true from config when opentelemetry crate > v0.17.0
// https://github.com/open-telemetry/opentelemetry-rust/pull/806 includes the environment variable.
)
.with_trace_config(
sdktrace::config()
.with_resource(os_resource.merge(&process_resource).merge(&sdk_resource).merge(&env_resource).merge(&telemetry_resource)),
)
.install_batch(opentelemetry::runtime::Tokio)
}
此示例中,我们创建了一些资源探测器并配置了追踪导出器。这段代码将初始化 OpenTelemetry SDK,并设置了采样器和追踪配置。可以参考 Rust 文档了解更多详细信息。
添加 gRPC 仪表板
此服务接收 gRPC 请求,并在中间件中进行仪表板记录。
在同一线程中启动根跨度,并将其引用传递给另一个闭包,在闭包中调用 quoteservice
。
let tracer = global::tracer("shippingservice");
let mut span = tracer.span_builder("oteldemo.ShippingService/GetQuote").with_kind(SpanKind::Server).start_with_context(&tracer, &parent_cx);
span.set_attribute(semcov::trace::RPC_SYSTEM.string(RPC_SYSTEM_GRPC));
span.add_event("Processing get quote request".to_string(), vec![]);
let cx = Context::current_with_span(span);
let q = match create_quote_from_count(itemct)
.with_context(cx.clone())
.await
//-> create_quote_from_count()...
let f = match request_quote(count).await {
Ok(float) => float,
Err(err) => {
let msg = format!("{}", err);
return Err(tonic::Status::unknown(msg));
}
};
Ok(get_active_span(|span| {
let q = create_quote_from_float(f);
span.add_event(
"Received Quote".to_string(),
vec![KeyValue::new("app.shipping.cost.total", format!("{}", q))],
);
span.set_attribute(KeyValue::new("app.shipping.items.count", count as i64));
span.set_attribute(KeyValue::new("app.shipping.cost.total", format!("{}", q)));
q
}))
//<- create_quote_from_count()...
cx.span().set_attribute(semcov::trace::RPC_GRPC_STATUS_CODE.i64(RPC_GRPC_STATUS_CODE_OK));
注意我们在根跨度周围创建了一个上下文,并将其克隆到异步函数 create_quote_from_count()
中。在 create_quote_from_count()
完成后,我们可以根据需要向根跨度添加其他属性。
您还可以注意到此示例中对跨度设置的属性和类似的传播的事件
。使用任何有效的跨度指针(附加到上下文)都可以操作OpenTelemetry API。
添加 HTTP 仪表板
对于通过 reqwest
客户端发送的出站 HTTP 调用到 quoteservice
,也会生成一个子客户端跨度,与相应的 quoteservice
服务器跨度配对。跟踪工具的实施在客户端中间件中完成,使用了可用的 reqwest-middleware
、reqwest-tracing
和 tracing-opentelemetry
库。
let reqwest_client = reqwest::Client::new();
let client = ClientBuilder::new(reqwest_client)
.with(TracingMiddleware::<SpanBackendWithUrl>::new())
.build();
添加跨度属性
只要您在相同的线程上,或在跨度拥有线程中传递的上下文中,或在作用域中存在 ContextGuard
,都可以使用 get_active_span
获取一个活跃的跨度。您可以在演示中找到这些情况的示例,其中 shipping_service
中提供了同步/异步运行时的上下文。您应该查阅 quote.rs
或上面的示例以查看传递给异步运行时的上下文。
以下是 shiporder
中的一个片段,其中保持了上下文和跨度。这在我们的同步运行时中是合适的。
let parent_cx =
global::get_text_map_propagator(|prop| prop.extract(&MetadataMap(request.metadata())));
// 在这个例子中,生成追踪ID非常简单
//我们将会在这个函数中创建一个跨度和相关的事件。
let tracer = global::tracer("shippingservice");
let mut span = tracer
.span_builder("oteldemo.ShippingService/ShipOrder").with_kind(SpanKind::Server).start_with_context(&tracer, &parent_cx);
您必须在具有上下文的跨度中使用 set_attribute
添加属性,然后使用包含键和值的 KeyValue
对象。
let tid = create_tracking_id();
span.set_attribute(KeyValue::new("app.shipping.tracking.id", tid.clone()));
info!("Tracking ID Created: {}", tid);
添加跨度事件
使用 span 对象的 add_event
方法可以添加跨度事件。服务器路由(同步的 ShipOrderRequest
和异步的 GetQuoteRequest
)都有跨度事件。此处没有包含属性,但是属性的添加非常简单。
添加跨度事件:
let tid = create_tracking_id();
span.set_attribute(KeyValue::new("app.shipping.tracking.id", tid.clone()));
info!("Tracking ID Created: {}", tid);
指标
待定
日志
待定