入门
本页面将向您展示如何开始使用 OpenTelemetry 的 Rust SDK。
您将学习如何为简单的 Rust 应用程序进行插装,以便 追踪 可以输出到控制台。
先决条件
请确保您已在本地安装以下软件
示例应用程序
以下示例使用了一个基本的 hyper 应用程序。如果您不使用 hyper,也没关系 — 您也可以将 OpenTelemetry Rust 用于其他 HTTP 实现,例如 Actix Web 和 Tide。有关支持的框架的库的完整列表,请参阅 注册表。
有关更详细的示例,请参阅 示例。
依赖项
首先,在新的目录中创建一个名为 cargo new dice_server 的可执行文件,并将以下内容添加到 Cargo.toml 文件中
[package]
name = "dice_server"
version = "0.1.0"
edition = "2021"
[dependencies]
hyper = { version = "1", features = ["full"] }
tokio = { version = "1", features = ["full"] }
http-body-util = "0.1"
hyper-util = { version = "0.1", features = ["full"] }
rand = "0.9.0"
创建并启动 HTTP 服务器
修改 main.rs 文件为以下内容
use std::convert::Infallible;
use std::net::SocketAddr;
use http_body_util::Full;
use hyper::body::Bytes;
use hyper::server::conn::http1;
use hyper::service::service_fn;
use hyper::Method;
use hyper::{Request, Response};
use hyper_util::rt::TokioIo;
use rand::Rng;
use tokio::net::TcpListener;
async fn roll_dice(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
let random_number = rand::rng().random_range(1..=6);
Ok(Response::new(Full::new(Bytes::from(
random_number.to_string(),
))))
}
async fn handle(req: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
match (req.method(), req.uri().path()) {
(&Method::GET, "/rolldice") => roll_dice(req).await,
_ => Ok(Response::builder()
.status(404)
.body(Full::new(Bytes::from("Not Found")))
.unwrap()),
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
let listener = TcpListener::bind(addr).await?;
loop {
let (stream, _) = listener.accept().await?;
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(handle))
.await
{
eprintln!("Error serving connection: {:?}", err);
}
});
}
}
使用以下命令构建并运行应用程序,然后在 Web 浏览器中打开 https://:8080/rolldice 以确保其正常工作。
$ cargo run
...
Listening on 127.0.0.1:8080
仪表
要将 OpenTelemetry 添加到您的应用程序中,请更新 Cargo.toml 文件,添加 OpenTelemetry Rust SDK opentelemetry 和 OpenTelemetry Stdout Exporter opentelemetry-stdout 的依赖项
opentelemetry = "0.28.0"
opentelemetry_sdk = "0.28.0"
opentelemetry-stdout = { version = "0.28.0", features = ["trace"] }
更新 main.rs 文件,添加代码以初始化一个追踪器,并在调用 handle 函数时发出 span
use std::convert::Infallible;
use std::net::SocketAddr;
use std::sync::OnceLock;
use http_body_util::Full;
use hyper::body::Bytes;
use hyper::server::conn::http1;
use hyper::service::service_fn;
use hyper::Method;
use hyper::{Request, Response};
use hyper_util::rt::TokioIo;
use opentelemetry::global::{self, BoxedTracer};
use opentelemetry::trace::{Span, SpanKind, Status, Tracer};
use opentelemetry_sdk::trace::SdkTracerProvider;
use opentelemetry_stdout::SpanExporter;
use rand::Rng;
use tokio::net::TcpListener;
async fn roll_dice(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
let random_number = rand::rng().random_range(1..=6);
Ok(Response::new(Full::new(Bytes::from(
random_number.to_string(),
))))
}
async fn handle(req: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
let tracer = get_tracer();
let mut span = tracer
.span_builder(format!("{} {}", req.method(), req.uri().path()))
.with_kind(SpanKind::Server)
.start(tracer);
match (req.method(), req.uri().path()) {
(&Method::GET, "/rolldice") => roll_dice(req).await,
_ => {
span.set_status(Status::Ok);
Ok(Response::builder()
.status(404)
.body(Full::new(Bytes::from("Not Found")))
.unwrap())
}
}
}
fn get_tracer() -> &'static BoxedTracer {
static TRACER: OnceLock<BoxedTracer> = OnceLock::new();
TRACER.get_or_init(|| global::tracer("dice_server"))
}
fn init_tracer_provider() {
let provider = SdkTracerProvider::builder()
.with_simple_exporter(SpanExporter::default())
.build();
global::set_tracer_provider(provider);
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
let listener = TcpListener::bind(addr).await?;
init_tracer_provider();
loop {
let (stream, _) = listener.accept().await?;
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(handle))
.await
{
eprintln!("Error serving connection: {:?}", err);
}
});
}
}
再次启动您的服务器
$ cargo run
...
Listening on 127.0.0.1:8080
当您向服务器发送请求 https://:8080/rolldice 时,您将在控制台中看到一个 span 被发出
Spans
Resource
-> telemetry.sdk.version=String(Static("0.28.0"))
-> service.name=String(Static("unknown_service"))
-> telemetry.sdk.language=String(Static("rust"))
-> telemetry.sdk.name=String(Static("opentelemetry"))
Span #0
Instrumentation Scope
Name : "dice_server"
Name : GET /rolldice
TraceId : 9f03de7cf14780bd54b95d7095332107
SpanId : 9faed88b3f9ed699
TraceFlags : TraceFlags(1)
ParentSpanId: 0000000000000000
Kind : Server
Start time: 2025-03-11 00:47:26.687497
End time: 2025-03-11 00:47:26.687653
Status: Unset
下一步?
更多信息