.
This commit is contained in:
1467
Cargo.lock
generated
1467
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
39
Cargo.toml
39
Cargo.toml
@@ -8,11 +8,11 @@ name = "packager"
|
||||
path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
jaeger = ["dep:opentelemetry", "dep:tracing-opentelemetry", "dep:opentelemetry-jaeger", "tokio/tracing"]
|
||||
opentelemetry = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:tracing-opentelemetry", "tokio/tracing"]
|
||||
prometheus = ["dep:axum-prometheus"]
|
||||
tokio-console = ["dep:console-subscriber"]
|
||||
|
||||
default = ["jaeger", "prometheus", "tokio-console"]
|
||||
default = ["opentelemetry", "prometheus", "tokio-console"]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
@@ -24,23 +24,22 @@ lto = "off"
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.opentelemetry]
|
||||
version = "0.20"
|
||||
version = "0.22"
|
||||
optional = true
|
||||
|
||||
[dependencies.opentelemetry_sdk]
|
||||
version = "0.22"
|
||||
optional = true
|
||||
|
||||
[dependencies.tracing-opentelemetry]
|
||||
version = "0.21"
|
||||
version = "0.23"
|
||||
optional = true
|
||||
|
||||
[dependencies.tracing-log]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.opentelemetry-jaeger]
|
||||
version = "0.19"
|
||||
features = ["rt-tokio"]
|
||||
optional = true
|
||||
version = "0.2"
|
||||
|
||||
[dependencies.http]
|
||||
version = "0.2"
|
||||
version = "1.1"
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
@@ -50,19 +49,19 @@ version = "4"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.axum]
|
||||
version = "0.6"
|
||||
features = ["headers", "macros"]
|
||||
version = "0.7"
|
||||
features = ["macros"]
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1"
|
||||
features = ["macros", "rt-multi-thread"]
|
||||
|
||||
[dependencies.console-subscriber]
|
||||
version = "0.1"
|
||||
version = "0.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.hyper]
|
||||
version = "0.14"
|
||||
version = "1.3"
|
||||
features = ["full"]
|
||||
|
||||
[dependencies.tower]
|
||||
@@ -70,7 +69,7 @@ version = "0.4"
|
||||
features = ["timeout"]
|
||||
|
||||
[dependencies.tower-http]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
features = ["trace", "request-id"]
|
||||
|
||||
[dependencies.tracing]
|
||||
@@ -84,7 +83,7 @@ version = "0.3"
|
||||
features = ["json", "env-filter"]
|
||||
|
||||
[dependencies.maud]
|
||||
version = "0.25"
|
||||
version = "0.26"
|
||||
features = [
|
||||
"axum",
|
||||
]
|
||||
@@ -123,14 +122,14 @@ features = ["derive"]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.axum-prometheus]
|
||||
version = "0.4"
|
||||
version = "0.6"
|
||||
optional = true
|
||||
|
||||
[dependencies.metrics]
|
||||
version = "0.21"
|
||||
version = "0.22"
|
||||
|
||||
[dependencies.sha2]
|
||||
version = "0.10"
|
||||
|
||||
[dependencies.base64]
|
||||
version = "0.21"
|
||||
version = "0.22"
|
||||
|
||||
37
src/auth.rs
37
src/auth.rs
@@ -1,9 +1,11 @@
|
||||
use axum::{extract::State, middleware::Next, response::IntoResponse};
|
||||
use axum::{
|
||||
extract::{Request, State},
|
||||
middleware::Next,
|
||||
response::IntoResponse,
|
||||
};
|
||||
use futures::FutureExt;
|
||||
use tracing::Instrument;
|
||||
|
||||
use hyper::Request;
|
||||
|
||||
use crate::models::user::User;
|
||||
|
||||
use super::models;
|
||||
@@ -16,11 +18,21 @@ pub enum Config {
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "check_auth", skip(state, request, next))]
|
||||
pub async fn authorize<B>(
|
||||
pub async fn authorize(
|
||||
State(state): State<AppState>,
|
||||
mut request: Request<B>,
|
||||
next: Next<B>,
|
||||
mut request: Request,
|
||||
next: Next,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
// We must not access `request` inside the async block above, otherwise there will be
|
||||
// errors like the following:
|
||||
//
|
||||
// the trait `tower::Service<http::Request<axum::body::Body>>` is not implemented for
|
||||
// `FromFn<fn(State<AppState>, Request<Body>, Next) -> impl Future<Output =
|
||||
// Result<impl IntoResponse, Error>> {authorize}, AppState, Route, _>
|
||||
//
|
||||
// I am honestly not sure about the reason
|
||||
let username_header = request.headers().get("x-auth-username");
|
||||
|
||||
let user = async {
|
||||
let auth: Result<Result<User, AuthError>, Error> = match state.auth_config {
|
||||
Config::Disabled { assume_user } => {
|
||||
@@ -35,7 +47,7 @@ pub async fn authorize<B>(
|
||||
};
|
||||
Ok(user)
|
||||
}
|
||||
Config::Enabled => match request.headers().get("x-auth-username") {
|
||||
Config::Enabled => match username_header {
|
||||
None => Ok(Err(AuthError::AuthenticationHeaderMissing)),
|
||||
Some(username) => match username.to_str() {
|
||||
Err(e) => Ok(Err(AuthError::AuthenticationHeaderInvalid {
|
||||
@@ -54,7 +66,6 @@ pub async fn authorize<B>(
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
auth
|
||||
}
|
||||
.instrument(tracing::debug_span!("authorize"))
|
||||
@@ -72,15 +83,17 @@ pub async fn authorize<B>(
|
||||
format!("packager_auth_{}_total", {
|
||||
match auth {
|
||||
Ok(_) => "success".to_string(),
|
||||
Err(ref e) => format!("failure_{}", e.to_prom_metric_name()),
|
||||
Err(ref e) => {
|
||||
format!("failure_{}", e.to_prom_metric_name())
|
||||
}
|
||||
}
|
||||
}),
|
||||
1,
|
||||
&match &auth {
|
||||
Ok(user) => vec![("username", user.username.clone())],
|
||||
Err(e) => e.to_prom_labels(),
|
||||
}
|
||||
);
|
||||
)
|
||||
.increment(1);
|
||||
auth
|
||||
})
|
||||
})
|
||||
@@ -89,5 +102,5 @@ pub async fn authorize<B>(
|
||||
.await??;
|
||||
|
||||
request.extensions_mut().insert(user);
|
||||
Ok(next.run(request).await)
|
||||
Ok::<http::Response<axum::body::Body>, Error>(next.run(request).await)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ pub struct Args {
|
||||
#[arg(long)]
|
||||
pub database_url: String,
|
||||
|
||||
#[cfg(feature = "jaeger")]
|
||||
#[cfg(feature = "opentelemetry")]
|
||||
#[arg(long, value_enum, default_value_t = BoolArg::False)]
|
||||
pub enable_opentelemetry: BoolArg,
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ pub mod route {
|
||||
|
||||
use crate::{models::user::User, AppState};
|
||||
use axum::{
|
||||
body::{BoxBody, HttpBody},
|
||||
body::Body,
|
||||
extract::{Path, Query, State},
|
||||
http::HeaderMap,
|
||||
response::Response,
|
||||
@@ -160,7 +160,7 @@ pub mod route {
|
||||
headers: HeaderMap,
|
||||
path: Path<Self::UrlParams>,
|
||||
form: Form<Self::Form>,
|
||||
) -> Result<Response<BoxBody>, crate::Error>;
|
||||
) -> Result<Response<Body>, crate::Error>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -176,7 +176,7 @@ pub mod route {
|
||||
headers: HeaderMap,
|
||||
query: Query<Self::QueryParams>,
|
||||
path: Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error>;
|
||||
) -> Result<Response<Body>, crate::Error>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -191,7 +191,7 @@ pub mod route {
|
||||
state: State<AppState>,
|
||||
headers: HeaderMap,
|
||||
path: Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error>;
|
||||
) -> Result<Response<Body>, crate::Error>;
|
||||
|
||||
async fn save(
|
||||
user: Extension<User>,
|
||||
@@ -199,14 +199,14 @@ pub mod route {
|
||||
headers: HeaderMap,
|
||||
path: Path<Self::UrlParams>,
|
||||
form: Form<Self::UpdateForm>,
|
||||
) -> Result<Response<BoxBody>, crate::Error>;
|
||||
) -> Result<Response<Body>, crate::Error>;
|
||||
|
||||
async fn cancel(
|
||||
user: Extension<User>,
|
||||
state: State<AppState>,
|
||||
headers: HeaderMap,
|
||||
path: Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error>;
|
||||
) -> Result<Response<Body>, crate::Error>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -222,14 +222,14 @@ pub mod route {
|
||||
headers: HeaderMap,
|
||||
params: Self::UrlParams,
|
||||
value: bool,
|
||||
) -> Result<Response<BoxBody>, crate::Error>;
|
||||
) -> Result<Response<Body>, crate::Error>;
|
||||
|
||||
async fn set_true(
|
||||
Extension(user): Extension<User>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error> {
|
||||
) -> Result<Response<Body>, crate::Error> {
|
||||
<Self as ToggleFallback>::set(user, state, headers, path, true).await
|
||||
}
|
||||
|
||||
@@ -238,15 +238,11 @@ pub mod route {
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error> {
|
||||
) -> Result<Response<Body>, crate::Error> {
|
||||
<Self as ToggleFallback>::set(user, state, headers, path, false).await
|
||||
}
|
||||
|
||||
fn router<B>() -> axum::Router<AppState, B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
<B as HttpBody>::Data: Send,
|
||||
<B as HttpBody>::Error: std::error::Error + Sync + Send;
|
||||
fn router() -> axum::Router<AppState>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -267,13 +263,13 @@ pub mod route {
|
||||
ctx: &crate::Context,
|
||||
state: AppState,
|
||||
params: Self::UrlParams,
|
||||
) -> Result<Response<BoxBody>, crate::Error>;
|
||||
) -> Result<Response<Body>, crate::Error>;
|
||||
|
||||
async fn on(
|
||||
Extension(user): Extension<User>,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error> {
|
||||
) -> Result<Response<Body>, crate::Error> {
|
||||
let (ctx, state, params) = <Self as ToggleHtmx>::set(user, state, path, true).await?;
|
||||
<Self as ToggleHtmx>::response(&ctx, state, params).await
|
||||
}
|
||||
@@ -282,25 +278,16 @@ pub mod route {
|
||||
Extension(user): Extension<User>,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error> {
|
||||
) -> Result<Response<Body>, crate::Error> {
|
||||
let (ctx, state, params) = <Self as ToggleHtmx>::set(user, state, path, false).await?;
|
||||
<Self as ToggleHtmx>::response(&ctx, state, params).await
|
||||
}
|
||||
|
||||
fn router<B>() -> axum::Router<AppState, B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
<B as HttpBody>::Data: Send,
|
||||
<B as HttpBody>::Error: std::error::Error + Sync + Send;
|
||||
fn router() -> axum::Router<AppState>;
|
||||
}
|
||||
|
||||
pub trait Toggle: ToggleHtmx + ToggleFallback {
|
||||
fn router<B>() -> axum::Router<AppState, B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
<B as HttpBody>::Data: Send,
|
||||
<B as HttpBody>::Error: std::error::Error + Sync + Send,
|
||||
{
|
||||
fn router() -> axum::Router<AppState> {
|
||||
axum::Router::new()
|
||||
.merge(<Self as ToggleHtmx>::router())
|
||||
.merge(<Self as ToggleFallback>::router())
|
||||
@@ -318,14 +305,10 @@ pub mod route {
|
||||
state: State<AppState>,
|
||||
headers: HeaderMap,
|
||||
path: Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error>;
|
||||
) -> Result<Response<Body>, crate::Error>;
|
||||
}
|
||||
|
||||
pub trait Router: Create + Delete {
|
||||
fn router<B>() -> axum::Router<AppState, B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
<B as HttpBody>::Data: Send,
|
||||
<B as HttpBody>::Error: std::error::Error + Sync + Send;
|
||||
fn router() -> axum::Router<AppState>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ pub mod list;
|
||||
pub use list::List;
|
||||
|
||||
use axum::{
|
||||
body::{BoxBody, HttpBody},
|
||||
body::Body,
|
||||
extract::{Form, Path, State as StateExtractor},
|
||||
http::HeaderMap,
|
||||
response::{IntoResponse, Redirect, Response},
|
||||
@@ -653,7 +653,7 @@ impl route::Create for Todo {
|
||||
headers: HeaderMap,
|
||||
Path((trip_id,)): Path<Self::UrlParams>,
|
||||
Form(form): Form<Self::Form>,
|
||||
) -> Result<Response<BoxBody>, crate::Error> {
|
||||
) -> Result<Response<Body>, crate::Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
// method output is not required as we reload the whole trip todos anyway
|
||||
let _todo_item = <Self as crud::Create>::create(
|
||||
@@ -700,7 +700,7 @@ impl route::Delete for Todo {
|
||||
StateExtractor(state): StateExtractor<AppState>,
|
||||
_headers: HeaderMap,
|
||||
Path((trip_id, todo_id)): Path<Self::UrlParams>,
|
||||
) -> Result<Response<BoxBody>, crate::Error> {
|
||||
) -> Result<Response<Body>, crate::Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
let deleted = <Self as crud::Delete>::delete(
|
||||
&ctx,
|
||||
@@ -737,12 +737,7 @@ impl route::Delete for Todo {
|
||||
}
|
||||
|
||||
impl route::Router for Todo {
|
||||
fn router<B>() -> axum::Router<AppState, B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
<B as HttpBody>::Data: Send,
|
||||
<B as HttpBody>::Error: std::error::Error + Sync + Send,
|
||||
{
|
||||
fn router() -> axum::Router<AppState> {
|
||||
axum::Router::new()
|
||||
.route("/new", axum::routing::post(<Self as route::Create>::create))
|
||||
.route(
|
||||
@@ -972,7 +967,7 @@ impl route::ToggleFallback for StateUpdate {
|
||||
headers: HeaderMap,
|
||||
(trip_id, todo_id): (Uuid, Uuid),
|
||||
value: bool,
|
||||
) -> Result<Response<BoxBody>, crate::Error> {
|
||||
) -> Result<Response<Body>, crate::Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
<Self as crud::Toggle>::set(
|
||||
&ctx,
|
||||
@@ -988,12 +983,7 @@ impl route::ToggleFallback for StateUpdate {
|
||||
Ok(Redirect::to(get_referer(&headers)?).into_response())
|
||||
}
|
||||
|
||||
fn router<B>() -> axum::Router<AppState, B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
<B as HttpBody>::Data: Send,
|
||||
<B as HttpBody>::Error: std::error::Error + Sync + Send,
|
||||
{
|
||||
fn router() -> axum::Router<AppState> {
|
||||
axum::Router::new()
|
||||
.route(Self::URL_TRUE, post(Self::set_true))
|
||||
.route(Self::URL_FALSE, post(Self::set_false))
|
||||
@@ -1023,7 +1013,7 @@ impl route::ToggleHtmx for StateUpdate {
|
||||
ctx: &Context,
|
||||
state: AppState,
|
||||
(trip_id, todo_id): Self::UrlParams,
|
||||
) -> Result<Response<BoxBody>, crate::Error> {
|
||||
) -> Result<Response<Body>, crate::Error> {
|
||||
let todo_item = Todo::find(
|
||||
ctx,
|
||||
&state.database_pool,
|
||||
@@ -1047,12 +1037,7 @@ impl route::ToggleHtmx for StateUpdate {
|
||||
.into_response())
|
||||
}
|
||||
|
||||
fn router<B>() -> axum::Router<AppState, B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
<B as HttpBody>::Data: Send,
|
||||
<B as HttpBody>::Error: std::error::Error + Sync + Send,
|
||||
{
|
||||
fn router() -> axum::Router<AppState> {
|
||||
axum::Router::new()
|
||||
.route(Self::URL_TRUE, post(Self::on))
|
||||
.route(Self::URL_FALSE, post(Self::off))
|
||||
|
||||
21
src/main.rs
21
src/main.rs
@@ -6,6 +6,7 @@ use std::str::FromStr;
|
||||
use packager::{
|
||||
auth, cli, models, routing, sqlite, telemetry, AppState, ClientState, Error, StartError,
|
||||
};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
struct MainResult(Result<(), Error>);
|
||||
|
||||
@@ -41,7 +42,7 @@ async fn main() -> MainResult {
|
||||
};
|
||||
|
||||
telemetry::tracing::init(
|
||||
#[cfg(feature = "jaeger")]
|
||||
#[cfg(feature = "opentelemetry")]
|
||||
if args.enable_opentelemetry.into() {
|
||||
telemetry::tracing::OpenTelemetryConfig::Enabled
|
||||
} else {
|
||||
@@ -117,19 +118,19 @@ async fn main() -> MainResult {
|
||||
|
||||
tracing::debug!("listening on {}", addr);
|
||||
|
||||
if let Err(e) = axum::Server::try_bind(&addr)
|
||||
.map_err(|e| {
|
||||
axum::serve(
|
||||
TcpListener::bind(&addr).await.map_err(|e| {
|
||||
Error::Start(StartError::BindError {
|
||||
addr,
|
||||
message: e.to_string(),
|
||||
})
|
||||
})?
|
||||
.serve(app.into_make_service())
|
||||
.await
|
||||
{
|
||||
return Err(<hyper::Error as Into<Error>>::into(e));
|
||||
}
|
||||
Ok(())
|
||||
})?,
|
||||
app,
|
||||
)
|
||||
.await
|
||||
// Error = Infallible
|
||||
.unwrap();
|
||||
unreachable!()
|
||||
});
|
||||
|
||||
// now we wait for all tasks. none of them are supposed to finish
|
||||
|
||||
@@ -325,7 +325,7 @@ impl InventoryItem {
|
||||
weight: u32,
|
||||
) -> Result<Uuid, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let weight = i64::try_from(weight).unwrap();
|
||||
let weight = i64::from(weight);
|
||||
|
||||
let id_param = id.to_string();
|
||||
crate::execute_returning_uuid!(
|
||||
|
||||
@@ -1036,28 +1036,6 @@ impl Trip {
|
||||
ctx: &Context,
|
||||
pool: &sqlite::Pool,
|
||||
) -> Result<(), Error> {
|
||||
struct Row {
|
||||
id: String,
|
||||
name: String,
|
||||
active: i32,
|
||||
}
|
||||
|
||||
impl TryFrom<Row> for TripType {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(row: Row) -> Result<Self, Self::Error> {
|
||||
Ok(TripType {
|
||||
id: Uuid::try_parse(&row.id)?,
|
||||
name: row.name,
|
||||
active: match row.active {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let id = self.id.to_string();
|
||||
let types = crate::query_all!(
|
||||
@@ -1066,7 +1044,7 @@ impl Trip {
|
||||
component: sqlite::Component::Trips,
|
||||
},
|
||||
pool,
|
||||
Row,
|
||||
TripTypeRow,
|
||||
TripType,
|
||||
"
|
||||
SELECT
|
||||
@@ -1406,6 +1384,28 @@ pub struct TripType {
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
struct TripTypeRow {
|
||||
id: String,
|
||||
name: String,
|
||||
active: i32,
|
||||
}
|
||||
|
||||
impl TryFrom<TripTypeRow> for TripType {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(row: TripTypeRow) -> Result<Self, Self::Error> {
|
||||
Ok(TripType {
|
||||
id: Uuid::try_parse(&row.id)?,
|
||||
name: row.name,
|
||||
active: match row.active {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TripsType {
|
||||
#[tracing::instrument]
|
||||
pub async fn all(ctx: &Context, pool: &sqlite::Pool) -> Result<Vec<Self>, Error> {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use axum::{
|
||||
error_handling::HandleErrorLayer,
|
||||
http::header::HeaderMap,
|
||||
http::StatusCode,
|
||||
http::{header::HeaderMap, StatusCode},
|
||||
middleware,
|
||||
routing::{get, post},
|
||||
BoxError, Router,
|
||||
|
||||
@@ -137,7 +137,7 @@ pub fn sqlx_query(
|
||||
("query_type", classification.query_type.to_string()),
|
||||
("query_component", classification.component.to_string()),
|
||||
]);
|
||||
metrics::counter!("packager_database_queries_total", 1, &labels);
|
||||
metrics::counter!("packager_database_queries_total", &labels).increment(1);
|
||||
}
|
||||
|
||||
// This does not work, as the query*! macros expect a string literal for the query, so
|
||||
|
||||
@@ -4,11 +4,10 @@ use axum::routing::get;
|
||||
use axum::Router;
|
||||
|
||||
use axum_prometheus::{Handle, MakeDefaultHandle, PrometheusMetricLayerBuilder};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
use crate::{Error, StartError};
|
||||
|
||||
pub struct LabelBool(bool);
|
||||
|
||||
/// Serves metrics on the specified `addr`.
|
||||
///
|
||||
/// You will get two outputs back: Another router, and a task that you have
|
||||
@@ -25,19 +24,19 @@ pub fn prometheus_server(
|
||||
let app = Router::new().route("/metrics", get(|| async move { metric_handle.render() }));
|
||||
|
||||
let task = async move {
|
||||
if let Err(e) = axum::Server::try_bind(&addr)
|
||||
.map_err(|e| {
|
||||
axum::serve(
|
||||
TcpListener::bind(addr).await.map_err(|e| {
|
||||
Error::Start(StartError::BindError {
|
||||
message: e.to_string(),
|
||||
addr,
|
||||
message: e.to_string(),
|
||||
})
|
||||
})?
|
||||
.serve(app.into_make_service())
|
||||
.await
|
||||
{
|
||||
return Err(<hyper::Error as Into<Error>>::into(e));
|
||||
}
|
||||
Ok(())
|
||||
})?,
|
||||
app,
|
||||
)
|
||||
.await
|
||||
// Error = Infallible
|
||||
.unwrap();
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
(router.layer(prometheus_layer), task)
|
||||
|
||||
@@ -22,8 +22,10 @@ use tracing::Instrument;
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
#[cfg(feature = "jaeger")]
|
||||
use opentelemetry::{global, runtime::Tokio};
|
||||
#[cfg(feature = "opentelemetry")]
|
||||
use opentelemetry::{global, trace::TracerProvider as _};
|
||||
#[cfg(feature = "opentelemetry")]
|
||||
use opentelemetry_sdk::trace::TracerProvider;
|
||||
|
||||
pub enum OpenTelemetryConfig {
|
||||
Enabled,
|
||||
@@ -64,17 +66,8 @@ fn get_stdout_layer<
|
||||
stdout_layer.boxed()
|
||||
}
|
||||
|
||||
trait Forwarder {
|
||||
type Config;
|
||||
|
||||
fn build(
|
||||
config: Self::Config,
|
||||
shutdown_functions: &mut Vec<ShutdownFunction>,
|
||||
) -> Option<Box<dyn tracing_subscriber::Layer<dyn tracing::Subscriber>>>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "jaeger")]
|
||||
fn get_jaeger_layer<
|
||||
#[cfg(feature = "opentelemetry")]
|
||||
fn get_opentelemetry_layer<
|
||||
T: tracing::Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
|
||||
>(
|
||||
config: &OpenTelemetryConfig,
|
||||
@@ -82,16 +75,20 @@ fn get_jaeger_layer<
|
||||
) -> Option<impl tracing_subscriber::Layer<T>> {
|
||||
match config {
|
||||
OpenTelemetryConfig::Enabled => {
|
||||
global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new());
|
||||
// Sets up the machinery needed to export data to Jaeger
|
||||
global::set_text_map_propagator(
|
||||
opentelemetry_sdk::propagation::TraceContextPropagator::new(),
|
||||
);
|
||||
// Sets up the machinery needed to export data to an opentelemetry endpoint.
|
||||
// There are other OTel crates that provide pipelines for the vendors
|
||||
// mentioned earlier.
|
||||
let tracer = opentelemetry_jaeger::new_agent_pipeline()
|
||||
.with_service_name(env!("CARGO_PKG_NAME"))
|
||||
.with_max_packet_size(50_000)
|
||||
.with_auto_split_batch(true)
|
||||
.install_batch(Tokio)
|
||||
.unwrap();
|
||||
let provider = TracerProvider::builder()
|
||||
// .with_service_name()
|
||||
// .with_max_packet_size(50_000)
|
||||
// .with_auto_split_batch(true)
|
||||
// .install_batch(Tokio)
|
||||
.build();
|
||||
|
||||
let tracer = provider.tracer(env!("CARGO_PKG_NAME"));
|
||||
|
||||
let opentelemetry_filter = {
|
||||
Targets::new()
|
||||
@@ -122,7 +119,7 @@ fn get_jaeger_layer<
|
||||
type ShutdownFunction = Box<dyn FnOnce() -> Result<(), Box<dyn std::error::Error>>>;
|
||||
|
||||
pub async fn init<Func, T>(
|
||||
#[cfg(feature = "jaeger")] opentelemetry_config: OpenTelemetryConfig,
|
||||
#[cfg(feature = "opentelemetry")] opentelemetry_config: OpenTelemetryConfig,
|
||||
#[cfg(feature = "tokio-console")] tokio_console_config: TokioConsoleConfig,
|
||||
args: crate::cli::Args,
|
||||
f: Func,
|
||||
@@ -131,12 +128,12 @@ where
|
||||
Func: FnOnce(crate::cli::Args) -> Pin<Box<dyn Future<Output = T>>>,
|
||||
T: std::process::Termination,
|
||||
{
|
||||
// mut is dependent on features (it's only required when jaeger is set), so
|
||||
// mut is dependent on features (it's only required when opentelemetry is set), so
|
||||
// let's just disable the lint
|
||||
#[cfg(feature = "jaeger")]
|
||||
#[cfg(feature = "opentelemetry")]
|
||||
let mut shutdown_functions: Vec<ShutdownFunction> = vec![];
|
||||
|
||||
#[cfg(not(feature = "jaeger"))]
|
||||
#[cfg(not(feature = "opentelemetry"))]
|
||||
let shutdown_functions: Vec<ShutdownFunction> = vec![];
|
||||
|
||||
#[cfg(feature = "tokio-console")]
|
||||
@@ -147,16 +144,17 @@ where
|
||||
|
||||
let stdout_layer = get_stdout_layer();
|
||||
|
||||
#[cfg(feature = "jaeger")]
|
||||
let jaeger_layer = get_jaeger_layer(&opentelemetry_config, &mut shutdown_functions);
|
||||
#[cfg(feature = "opentelemetry")]
|
||||
let opentelemetry_layer =
|
||||
get_opentelemetry_layer(&opentelemetry_config, &mut shutdown_functions);
|
||||
|
||||
let registry = Registry::default();
|
||||
|
||||
#[cfg(feature = "tokio-console")]
|
||||
let registry = registry.with(console_layer);
|
||||
|
||||
#[cfg(feature = "jaeger")]
|
||||
let registry = registry.with(jaeger_layer);
|
||||
#[cfg(feature = "opentelemetry")]
|
||||
let registry = registry.with(opentelemetry_layer);
|
||||
// just an example, you can actuall pass Options here for layers that might be
|
||||
// set/unset at runtime
|
||||
|
||||
|
||||
Reference in New Issue
Block a user