Compare commits

...

3 commits

Author SHA1 Message Date
eff094e856
tracing: extract request info into tags
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
2024-11-26 20:23:26 +01:00
fbbd753312
WIP: Add otel tracing 2024-11-26 20:23:26 +01:00
35ab2b31c5
WIP: Initial dropshot server
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
2024-11-26 20:23:25 +01:00
5 changed files with 1805 additions and 19 deletions

1675
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -20,9 +20,16 @@ clap = { version = "4.5.21", features = [
"wrap_help",
"string",
] }
dropshot = "0.13.0"
http = "1.1.0"
schemars = "0.8.21"
serde = "1.0.215"
slog = "2.7.0"
slog-async = "2.8.0"
tokio = { version = "1.41.1", features = ["full"] }
tracing = "0.1.40"
tracing-chrome = "0.7.2"
tracing-slog = { git = "https://github.com/oxidecomputer/tracing-slog", default-features = false }
tracing-subscriber = { version = "0.3.18", default-features = false, features = [
"std",
"ansi",

View file

@ -7,10 +7,22 @@ license = "MPL-2.0"
[dependencies]
anyhow.workspace = true
clap.workspace = true
dropshot.workspace = true
http.workspace = true
schemars.workspace = true
serde.workspace = true
slog.workspace = true
slog-async.workspace = true
tokio.workspace = true
tracing.workspace = true
tracing-chrome.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true
tracing-slog.workspace = true
tracing-opentelemetry = "0.28.0"
opentelemetry_sdk = { version = "0.27.0", features = ["rt-tokio"] }
opentelemetry-otlp = { version = "0.27.0", features = ["http-proto", "hyper-client", "opentelemetry-http", "trace"] }
opentelemetry = "0.27.0"
opentelemetry-semantic-conventions = "0.27.0"
[[bin]]
name = "patagia-controller"

View file

@ -1,24 +1,130 @@
use anyhow::Result;
use anyhow::{anyhow, Result};
use clap::Parser;
use tokio::time::{sleep, Duration};
use dropshot::endpoint;
use dropshot::ApiDescription;
use dropshot::ConfigDropshot;
use dropshot::HttpError;
use dropshot::HttpResponseOk;
use dropshot::RequestContext;
use dropshot::ServerBuilder;
use opentelemetry::{trace::TracerProvider as _, KeyValue};
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::{
trace::{RandomIdGenerator, Sampler},
Resource,
};
use opentelemetry_semantic_conventions::{
attribute::{SERVICE_NAME, SERVICE_VERSION},
SCHEMA_URL,
};
use schemars::JsonSchema;
use serde::Serialize;
use slog::Drain;
use tracing_opentelemetry::OpenTelemetryLayer;
use tracing_slog::TracingSlogDrain;
use tracing_subscriber::prelude::*;
use std::net::SocketAddr;
use std::str::FromStr;
use std::sync::Arc;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Cli {}
/// Represents a project in our API.
#[derive(Serialize, JsonSchema)]
struct VersionInfo {
name: String,
version: String,
}
/// Fetch version info.
#[endpoint {
method = GET,
path = "/version",
}]
#[tracing::instrument(
skip(rqctx),
fields(
http.method=rqctx.request.method().as_str(),
http.path=rqctx.request.uri().path(),
http.remote_ip=rqctx.request.remote_addr().ip().to_string(),
request_id = rqctx.request_id,
),
err(Debug),
)]
async fn api_version(
rqctx: RequestContext<Arc<()>>,
) -> Result<HttpResponseOk<VersionInfo>, HttpError> {
let ver = VersionInfo {
name: env!("CARGO_PKG_NAME").to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
tracing::info!("Someone made a request to /version");
Ok(HttpResponseOk(ver))
}
#[tokio::main]
async fn main() -> Result<()> {
let _args = Cli::parse();
let fmt_layer = tracing_subscriber::fmt::layer();
let mut config_dropshot = ConfigDropshot::default();
config_dropshot.bind_address = SocketAddr::from_str("0.0.0.0:9474").unwrap();
config_dropshot.request_body_max_bytes = 1024 * 1024;
// Adapt the Dropshot logger to tracing
let dropshot_logger = {
let level_drain = slog::LevelFilter(TracingSlogDrain, slog::Level::Debug).fuse();
let async_drain = slog_async::Async::new(level_drain).build().fuse();
slog::Logger::root(async_drain, slog::o!())
};
let otlp_exporter = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.with_endpoint("https://localhost:4317")
.build()
.map_err(|e| anyhow!("Error creating OTLP exporter: {:?}", e))?;
let resource = Resource::from_schema_url(
[
KeyValue::new(SERVICE_NAME, env!("CARGO_PKG_NAME")),
KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")),
],
SCHEMA_URL,
);
let tracer_provider = opentelemetry_sdk::trace::TracerProvider::builder()
.with_config(
opentelemetry_sdk::trace::Config::default()
.with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
1.0,
))))
.with_id_generator(RandomIdGenerator::default())
.with_resource(resource),
)
.with_batch_exporter(otlp_exporter, opentelemetry_sdk::runtime::Tokio)
.build();
let tracer = tracer_provider.tracer("patagia-controller");
tracing_subscriber::registry()
.with(tracing_subscriber::EnvFilter::from_default_env())
.with(fmt_layer)
.with(OpenTelemetryLayer::new(tracer))
.init();
tracing::info!("Patagia Controller");
sleep(Duration::from_secs(3)).await;
Ok(())
let mut api = ApiDescription::new();
api.register(api_version).unwrap();
ServerBuilder::new(api, Arc::new(()), dropshot_logger)
.config(config_dropshot)
.start()
.map_err(|e| anyhow!("Error starting server: {:?}", e))?
.await
.map_err(|e| anyhow!(e))
}

View file

@ -1,18 +1,16 @@
set shell := ["/usr/bin/env", "bash", "-euo", "pipefail", "-c"]
export OTEL_SERVICE_NAME := "my-program"
[private]
default:
@just --choose
# Run
run $RUST_LOG="debug":
nix run
# Run controller
run-controller $RUST_LOG="debug":
cargo run --package patagia-controller
# Run local development
dev:
watchexec --clear --restart --stop-signal INT --debounce 300ms -- just run
# Run controller local development
dev-controller:
watchexec --clear --restart --stop-signal INT --debounce 300ms -- just run-controller
# Run all tests
check: