This commit is contained in:
aOK 2023-10-25 11:09:13 +03:00
parent 3a6d29b4cb
commit 7928ec9588
5 changed files with 177 additions and 0 deletions

32
Cargo.toml Normal file
View file

@ -0,0 +1,32 @@
[package]
name = "pred"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
axum = { version = "0.6.20", features = ["macros", "headers"] }
reqwest = "0.11"
tokio = { version = "1", features = ["full"] }
select = "0.5"
dotenvy = "~0"
cfg-if = "~1"
# -- Tracing
tracing-subscriber = { version = "0.3.16", features = ["env-filter", "json", "std"], optional = true }
tracing = { version = "~0", features = ["log", "log-always"] }
opentelemetry = {version ="0.20.0", features = ["rt-tokio"], optional = true }
opentelemetry-otlp = { version = "0.13.0", optional = true }
tracing-opentelemetry = { version = "0.21.0", optional = true }
tracing-log = { version = "~0", optional = true, features = ["env_logger"] }
tracing-bunyan-formatter = { version = "0.3.9", optional = true }
# Misc
thiserror = "~1"
log = "~0"
[features]
default = ["tracing", "bunyan"]
tracing = ["tracing-log", "tracing-subscriber", "tracing-opentelemetry", "opentelemetry", "opentelemetry-otlp"]
bunyan = ["tracing-bunyan-formatter"]

29
src/error.rs Normal file
View file

@ -0,0 +1,29 @@
use opentelemetry::trace::TraceError;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
TraceErr(String),
SetGlobalDefaultErr(String)
}
impl From<tracing::subscriber::SetGlobalDefaultError> for Error {
fn from(_: tracing::subscriber::SetGlobalDefaultError) -> Self {
Error::SetGlobalDefaultErr("Set global err".to_string())
}
}
impl From<TraceError> for Error {
fn from(_: TraceError) -> Self {
Error::TraceErr("Trace err".to_string())
}
}
impl core::fmt::Display for Error {
fn fmt(
&self,
fmt: &mut core::fmt::Formatter,
) -> core::result::Result<(), core::fmt::Error> {
write!(fmt, "{self:?}")
}
}

47
src/main.rs Normal file
View file

@ -0,0 +1,47 @@
// use crate::observability;
mod observability;
mod error;
use axum::{response::Html, routing::get, Router};
use tracing::debug;
#[tokio::main]
async fn main() -> error::Result<()> {
// Set up a tracing subscriber with JSON formatting
tracing_log::LogTracer::builder()
.ignore_crate("sqlx")
.with_max_level(log::LevelFilter::Info)
.init()
.expect("could not initialize log tracer");
match observability::configure_observability().await {
Ok(_) => {
tracing::debug!("tracing configured");
}
Err(err) => {
tracing::error!("error configuring tracing: {}", err);
return Err(err);
}
};
// build our application with a route
let app = Router::new().route("/", get(handler));
// run it
debug!("listening on 0.0.0.0:3000");
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.expect("server failed");
Ok(())
}
#[tracing::instrument]
async fn handler() -> Html<&'static str> {
Html("<h1>Hello, World!</h1>")
}

1
src/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod observability;

68
src/observability.rs Executable file
View file

@ -0,0 +1,68 @@
use opentelemetry_otlp::WithExportConfig;
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
use crate::error::Result;
use tracing::debug;
const OTEL_EXPORTER_OTLP_ENDPOINT_ENV_VAR: &str = "OTEL_EXPORTER_OTLP_ENDPOINT";
const OTEL_EXPORTER_OTLP_ENDPOINT_DEFAULT: &str = "http://localhost:4317";
const OBSERVABILITY_SERVICE_NAME_ENV_VAR: &str = "OBSERVABILITY_SERVICE_NAME";
const OBSERVABILITY_SERVICE_NAME_DEFAULT: &str = "pred";
#[tracing::instrument]
pub async fn configure_observability() -> Result<()> {
debug!("{:<12} - configure_observability", "fn");
let otel_exporter_endpoint =
dotenvy::var(OTEL_EXPORTER_OTLP_ENDPOINT_ENV_VAR).unwrap_or_else(|_| {
tracing::warn!(
"{} Env var not set, using default",
OTEL_EXPORTER_OTLP_ENDPOINT_DEFAULT
);
OTEL_EXPORTER_OTLP_ENDPOINT_DEFAULT.to_string()
});
let observability_service_name = dotenvy::var(OBSERVABILITY_SERVICE_NAME_ENV_VAR)
.unwrap_or_else(|_| OBSERVABILITY_SERVICE_NAME_DEFAULT.to_string());
let tracer = opentelemetry_otlp::new_pipeline()
.tracing()
.with_exporter(
opentelemetry_otlp::new_exporter()
.tonic()
.with_endpoint(otel_exporter_endpoint),
)
.with_trace_config(opentelemetry::sdk::trace::config().with_resource(
opentelemetry::sdk::Resource::new(vec![opentelemetry::KeyValue::new(
"service.name",
observability_service_name.clone(),
)]),
))
.install_batch(opentelemetry::runtime::Tokio)?;
// Create a tracing layer with the configured tracer
let telemetry_layer = tracing_opentelemetry::layer().with_tracer(tracer);
let filter = tracing_subscriber::EnvFilter::from_default_env();
cfg_if::cfg_if! {
if #[cfg(feature="bunyan")] {
// Create a new formatting layer to print bunyan formatted logs to stdout, pipe into bunyan to view
let formatting_layer = BunyanFormattingLayer::new(observability_service_name, std::io::stdout);
let subscriber = tracing_subscriber::Registry::default()
.with(filter)
.with(telemetry_layer)
.with(JsonStorageLayer)
.with(formatting_layer);
} else {
let subscriber = tracing_subscriber::Registry::default()
.with_filter(filter)
.with_writer(std::io::stdout)
.with(telemetry_layer);
}
}
Ok(tracing::subscriber::set_global_default(subscriber)?)
}