Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Rust getting started #6515

Merged
merged 24 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d421127
Fix Rust getting started
cijothomas Mar 11, 2025
aa39bbe
Merge branch 'main' into cijothomas/rust-start-1
cijothomas Mar 12, 2025
7ba99af
Results from /fix:all
opentelemetrybot Mar 12, 2025
1f5ec0f
[ja] translate contributing/blog into ja (#6521)
Msksgm Mar 12, 2025
56dde5d
[ja] fix drift of content/ja/docs/demo/feature-flags (#6527)
Msksgm Mar 12, 2025
9c3caaf
blog: fix slack channel name up-to-date (#6531)
ymotongpoo Mar 12, 2025
a6cd8a7
Update community members (#6518)
opentelemetrybot Mar 12, 2025
254b762
[ja] translated contributing/pr-checks into ja (#6529)
Msksgm Mar 12, 2025
d30549f
docs: translated demo/requirements into ja (#6522)
tko-cactus Mar 12, 2025
bc6304e
[ja] translate SDK configurations (#6532)
ymotongpoo Mar 13, 2025
8b9d175
[ja] translated contributing/development into ja (#6536)
Msksgm Mar 13, 2025
e85131c
[ja] translated contributing/acknowledgements into ja (#6539)
Msksgm Mar 13, 2025
00235cd
Updated description/ details for Purview.Telemetry.SourceGenerator in…
kieronlanning Mar 14, 2025
8cf79ed
Add docs for @WithSpan params. (#6543)
breedx-splk Mar 14, 2025
69398c8
Auto-update registry versions (ec0219561e3dbe276f9d3bd3b41468ad0744d9…
opentelemetrybot Mar 14, 2025
a2a8520
Update opentelemetry-java-instrumentation version to v2.14.0 (#6545)
opentelemetrybot Mar 14, 2025
90e8c07
[ja] translate platform/android and platform/faas (#6535)
ymotongpoo Mar 14, 2025
e21c2d9
[CI] cSpell config tweak (#6547)
chalin Mar 14, 2025
c246d00
Add video link to what-is-opentelemetry page (#6550)
chalin Mar 14, 2025
e7d04ea
Results from /fix:all
cijothomas Mar 14, 2025
660e2a4
[ja] fix drift of content/ja/docs/demo/feature-flags (#6527)
Msksgm Mar 12, 2025
2e11966
Results from /fix:all
cijothomas Mar 14, 2025
0dcaefc
[ja] fix drift of content/ja/docs/demo/feature-flags (#6527)
Msksgm Mar 12, 2025
36a5320
Merge branch 'main' into cijothomas/rust-start-1
cijothomas Mar 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 125 additions & 116 deletions content/en/docs/languages/rust/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,74 +28,88 @@ For more elaborate examples, see [examples](/docs/languages/rust/examples/).

### Dependencies

To begin, create a file `Cargo.toml` in a new directory and add the following
content:
To begin, create an executable using `cargo new dice_server` in a new directory and add the following
content to the `Cargo.toml` file:

```toml
[package]
name = "dice_server"
version = "0.1.0"
edition = "2021"
publish = false

[[bin]]
name = "dice_server"
path = "dice_server.rs"
doc = false

[dependencies]
hyper = { version = "0.14", features = ["full"] }
tokio = { version = "1.29", features = ["full"] }
rand = { version = "0.8" }
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"
```

### Create and launch an HTTP Server

In that same folder, create a file called `dice_server.rs` and add the following
code to the file:
Modify `main.rs` to the following:

```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, Method, StatusCode};
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 std::{convert::Infallible, net::SocketAddr};
use tokio::net::TcpListener;

async fn handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
let mut response = Response::new(Body::empty());
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") => {
let random_number = rand::thread_rng().gen_range(1..7);
*response.body_mut() = Body::from(random_number.to_string());
}
_ => {
*response.status_mut() = StatusCode::NOT_FOUND;
}
};

Ok(response)
(&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() {
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));

let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(handle)) });

let server = Server::bind(&addr).serve(make_svc);
let listener = TcpListener::bind(addr).await?;

println!("Listening on {addr}");
if let Err(e) = server.await {
eprintln!("server error: {e}");
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);
}
});
}
}

```

Build and run the application with the following command, then open
<http://localhost:8080/rolldice> in your web browser to ensure it is working.

```console
$ cargo run --bin dice_server
$ cargo run
...
Listening on 127.0.0.1:8080
```
Expand All @@ -114,125 +128,120 @@ opentelemetry_sdk = "{{% version-from-registry otel-rust-sdk %}}"
opentelemetry-stdout = { version = "{{% version-from-registry exporter-rust-stdout %}}", features = ["trace"] }
```

Update the `dice_server.rs` file with code to initialize a tracer and to emit
Update the `main.rs` file with code to initialize a tracer and to emit
spans when the `handle` function is called:

```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Server, StatusCode};
use rand::Rng;
use std::{convert::Infallible, net::SocketAddr};
use opentelemetry::global::ObjectSafeSpan;
use opentelemetry::trace::{SpanKind, Status};
use opentelemetry::{global, trace::Tracer};
use opentelemetry_sdk::propagation::TraceContextPropagator;
use opentelemetry_sdk::trace::TracerProvider;
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 handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
let mut response = Response::new(Body::empty());
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(),
))))
}

let tracer = global::tracer("dice_server");
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);
.start(tracer);

match (req.method(), req.uri().path()) {
(&Method::GET, "/rolldice") => {
let random_number = rand::thread_rng().gen_range(1..7);
*response.body_mut() = Body::from(random_number.to_string());
span.set_status(Status::Ok);
}
(&Method::GET, "/rolldice") => roll_dice(req).await,
_ => {
*response.status_mut() = StatusCode::NOT_FOUND;
span.set_status(Status::error("Not Found"));
span.set_status(Status::Ok);
Ok(Response::builder()
.status(404)
.body(Full::new(Bytes::from("Not Found")))
.unwrap())
}
};
}
}

Ok(response)
fn get_tracer() -> &'static BoxedTracer {
static TRACER: OnceLock<BoxedTracer> = OnceLock::new();
TRACER.get_or_init(|| global::tracer("dice_server"))
}

fn init_tracer() {
global::set_text_map_propagator(TraceContextPropagator::new());
let provider = TracerProvider::builder()
fn init_tracer_provider() {
let provider = SdkTracerProvider::builder()
.with_simple_exporter(SpanExporter::default())
.build();
global::set_tracer_provider(provider);
}

#[tokio::main]
async fn main() {
init_tracer();
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));

let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(handle)) });
let listener = TcpListener::bind(addr).await?;
init_tracer_provider();

let server =
Server::bind(&addr).serve(make_svc);

println!("Listening on {addr}");
if let Err(e) = server.await {
eprintln!("server error: {e}");
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);
}
});
}
}
```

Start your server again:

```sh
$ cargo run --bin dice_server
$ cargo run
...
Listening on 127.0.0.1:8080
```

When you send a request to the server at <http://localhost:8080/rolldice>,
you'll see a span being emitted to the console (output is pretty printed for
convenience):

```json
{
"resourceSpans": [
{
"resource": {
"attributes": [
{
"key": "service.name",
"value": {
"stringValue": "unknown_service"
}
}
]
},
"scopeSpans": [
{
"scope": {
"name": "dice_server"
},
"spans": [
{
"attributes": [],
"droppedAttributesCount": 0,
"droppedEventsCount": 0,
"droppedLinksCount": 0,
"endTimeUnixNano": 1691076354768034000,
"kind": 2,
"name": "GET /rolldice",
"parentSpanId": "",
"spanId": "27e1d7d8e44a63c5",
"startTimeUnixNano": 1691076354768025000,
"status": {
"code": 2
},
"traceId": "adfe9d364ee19610adde517d722167ca"
}
]
}
]
}
]
}
you'll see a span being emitted to the console:

```txt
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
```

## What next?
Expand Down
2 changes: 1 addition & 1 deletion data/registry/exporter-rust-stdout.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ createdAt: 2024-01-19
package:
registry: crates
name: opentelemetry-stdout
version: 0.27.0
version: 0.28.0
2 changes: 1 addition & 1 deletion data/registry/otel-rust-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ createdAt: 2020-02-04
package:
registry: crates
name: opentelemetry_sdk
version: 0.22.1
version: 0.28.0
2 changes: 1 addition & 1 deletion data/registry/otel-rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ createdAt: 2020-02-04
package:
registry: crates
name: opentelemetry
version: 0.22.0
version: 0.28.0
Loading