tracing
This commit is contained in:
12
rust/Cargo.lock
generated
12
rust/Cargo.lock
generated
@@ -1225,6 +1225,7 @@ dependencies = [
|
||||
"opentelemetry",
|
||||
"opentelemetry-semantic-conventions",
|
||||
"thrift",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1270,6 +1271,8 @@ dependencies = [
|
||||
"rand",
|
||||
"regex",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1318,6 +1321,7 @@ dependencies = [
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-log",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
@@ -1667,9 +1671,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.3"
|
||||
version = "0.101.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0"
|
||||
checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
@@ -1808,9 +1812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.8"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
@@ -11,10 +11,18 @@ path = "src/main.rs"
|
||||
opt-level = 0
|
||||
lto = "off"
|
||||
|
||||
[dependencies]
|
||||
opentelemetry = "0.20"
|
||||
tracing-opentelemetry = "0.20"
|
||||
opentelemetry-jaeger = "0.19"
|
||||
[dependencies.opentelemetry]
|
||||
version = "0.20"
|
||||
|
||||
[dependencies.tracing-opentelemetry]
|
||||
version = "0.20"
|
||||
|
||||
[dependencies.tracing-log]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.opentelemetry-jaeger]
|
||||
version = "0.19"
|
||||
features = ["rt-tokio"]
|
||||
|
||||
[dependencies.http]
|
||||
version = "0.2"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::{extract::State, middleware::Next, response::IntoResponse};
|
||||
use tracing::Instrument;
|
||||
|
||||
use hyper::Request;
|
||||
|
||||
@@ -11,28 +12,33 @@ pub enum Config {
|
||||
Disabled { assume_user: String },
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(state, request, next))]
|
||||
#[tracing::instrument(name = "check_auth", skip(state, request, next))]
|
||||
pub async fn authorize<B>(
|
||||
State(state): State<AppState>,
|
||||
mut request: Request<B>,
|
||||
next: Next<B>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let current_user = match state.auth_config {
|
||||
let current_user = async {
|
||||
let user = match state.auth_config {
|
||||
Config::Disabled { assume_user } => {
|
||||
match models::user::User::find_by_name(&state.database_pool, &assume_user).await? {
|
||||
let user =
|
||||
match models::user::User::find_by_name(&state.database_pool, &assume_user)
|
||||
.await?
|
||||
{
|
||||
Some(user) => user,
|
||||
None => {
|
||||
return Err(Error::Request(RequestError::AuthenticationUserNotFound {
|
||||
username: assume_user,
|
||||
}))
|
||||
}
|
||||
}
|
||||
};
|
||||
tracing::info!(?user, "auth disabled, requested user exists");
|
||||
user
|
||||
}
|
||||
Config::Enabled => {
|
||||
let Some(username) = request.headers().get("x-auth-username") else {
|
||||
return Err(Error::Request(RequestError::AuthenticationHeaderMissing));
|
||||
};
|
||||
|
||||
let username = username
|
||||
.to_str()
|
||||
.map_err(|error| {
|
||||
@@ -42,16 +48,25 @@ pub async fn authorize<B>(
|
||||
})?
|
||||
.to_string();
|
||||
|
||||
match models::user::User::find_by_name(&state.database_pool, &username).await? {
|
||||
let user = match models::user::User::find_by_name(&state.database_pool, &username)
|
||||
.await?
|
||||
{
|
||||
Some(user) => user,
|
||||
None => {
|
||||
tracing::warn!(username, "auth rejected, user not found");
|
||||
return Err(Error::Request(RequestError::AuthenticationUserNotFound {
|
||||
username,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
tracing::info!(?user, "auth successful");
|
||||
user
|
||||
}
|
||||
};
|
||||
Ok(user)
|
||||
}
|
||||
.instrument(tracing::debug_span!("authorize"))
|
||||
.await?;
|
||||
|
||||
request.extensions_mut().insert(current_user);
|
||||
Ok(next.run(request).await)
|
||||
|
||||
69
rust/src/cmd.rs
Normal file
69
rust/src/cmd.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
|
||||
#[derive(ValueEnum, Clone, Copy, Debug)]
|
||||
pub enum BoolArg {
|
||||
True,
|
||||
False,
|
||||
}
|
||||
|
||||
impl From<BoolArg> for bool {
|
||||
fn from(arg: BoolArg) -> bool {
|
||||
match arg {
|
||||
BoolArg::True => true,
|
||||
BoolArg::False => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
#[arg(long)]
|
||||
pub database_url: String,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = BoolArg::False)]
|
||||
pub enable_opentelemetry: BoolArg,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = BoolArg::False)]
|
||||
pub enable_tokio_console: BoolArg,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub command: Command,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum Command {
|
||||
Serve(Serve),
|
||||
#[command(subcommand)]
|
||||
Admin(Admin),
|
||||
Migrate,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct Serve {
|
||||
#[arg(long, default_value_t = 3000)]
|
||||
pub port: u16,
|
||||
#[arg(long)]
|
||||
pub bind: String,
|
||||
#[arg(long, name = "USERNAME")]
|
||||
pub disable_auth_and_assume_user: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum Admin {
|
||||
#[command(subcommand)]
|
||||
User(UserCommand),
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum UserCommand {
|
||||
Create(UserCreate),
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct UserCreate {
|
||||
#[arg(long)]
|
||||
pub username: String,
|
||||
#[arg(long)]
|
||||
pub fullname: String,
|
||||
}
|
||||
@@ -3,6 +3,7 @@ use uuid::Uuid;
|
||||
use std::fmt;
|
||||
|
||||
pub mod auth;
|
||||
pub mod cmd;
|
||||
pub mod error;
|
||||
pub mod htmx;
|
||||
pub mod models;
|
||||
|
||||
107
rust/src/main.rs
107
rust/src/main.rs
@@ -1,57 +1,11 @@
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::pin::Pin;
|
||||
use std::process::ExitCode;
|
||||
use std::str::FromStr;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use packager::{auth, cmd, models, routing, sqlite, telemetry, AppState, ClientState, Error};
|
||||
|
||||
use packager::{auth, models, routing, sqlite, telemetry, AppState, ClientState, Error};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
#[arg(long)]
|
||||
database_url: String,
|
||||
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Command {
|
||||
Serve(Serve),
|
||||
#[command(subcommand)]
|
||||
Admin(Admin),
|
||||
Migrate,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Serve {
|
||||
#[arg(long, default_value_t = 3000)]
|
||||
port: u16,
|
||||
#[arg(long)]
|
||||
bind: String,
|
||||
#[arg(long, name = "USERNAME")]
|
||||
disable_auth_and_assume_user: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Admin {
|
||||
#[command(subcommand)]
|
||||
User(UserCommand),
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum UserCommand {
|
||||
Create(UserCreate),
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct UserCreate {
|
||||
#[arg(long)]
|
||||
username: String,
|
||||
#[arg(long)]
|
||||
fullname: String,
|
||||
}
|
||||
use clap::Parser;
|
||||
|
||||
struct MainResult(Result<(), Error>);
|
||||
|
||||
@@ -75,15 +29,29 @@ impl From<Error> for MainResult {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> MainResult {
|
||||
telemetry::init_tracing();
|
||||
let args = Args::parse();
|
||||
let args = cmd::Args::parse();
|
||||
telemetry::init_tracing(
|
||||
if args.enable_opentelemetry.into() {
|
||||
telemetry::OpenTelemetryConfig::Enabled
|
||||
} else {
|
||||
telemetry::OpenTelemetryConfig::Disabled
|
||||
},
|
||||
if args.enable_tokio_console.into() {
|
||||
telemetry::TokioConsoleConfig::Enabled
|
||||
} else {
|
||||
telemetry::TokioConsoleConfig::Disabled
|
||||
},
|
||||
args,
|
||||
|args| -> Pin<Box<dyn std::future::Future<Output = MainResult>>> {
|
||||
Box::pin(async move {
|
||||
match args.command {
|
||||
Command::Serve(serve_args) => {
|
||||
cmd::Command::Serve(serve_args) => {
|
||||
if let Err(e) = sqlite::migrate(&args.database_url).await {
|
||||
return <_ as Into<Error>>::into(e).into();
|
||||
}
|
||||
|
||||
let database_pool = match sqlite::init_database_pool(&args.database_url).await {
|
||||
let database_pool =
|
||||
match sqlite::init_database_pool(&args.database_url).await {
|
||||
Ok(pool) => pool,
|
||||
Err(e) => return <_ as Into<Error>>::into(e).into(),
|
||||
};
|
||||
@@ -91,7 +59,9 @@ async fn main() -> MainResult {
|
||||
let state = AppState {
|
||||
database_pool,
|
||||
client_state: ClientState::new(),
|
||||
auth_config: if let Some(assume_user) = serve_args.disable_auth_and_assume_user {
|
||||
auth_config: if let Some(assume_user) =
|
||||
serve_args.disable_auth_and_assume_user
|
||||
{
|
||||
auth::Config::Disabled { assume_user }
|
||||
} else {
|
||||
auth::Config::Enabled
|
||||
@@ -105,7 +75,10 @@ async fn main() -> MainResult {
|
||||
let addr = SocketAddr::from((
|
||||
IpAddr::from_str(&serve_args.bind)
|
||||
.map_err(|error| {
|
||||
format!("error parsing bind address {}: {}", &serve_args.bind, error)
|
||||
format!(
|
||||
"error parsing bind address {}: {}",
|
||||
&serve_args.bind, error
|
||||
)
|
||||
})
|
||||
.unwrap(),
|
||||
serve_args.port,
|
||||
@@ -120,10 +93,11 @@ async fn main() -> MainResult {
|
||||
return <hyper::Error as Into<Error>>::into(e).into();
|
||||
}
|
||||
}
|
||||
Command::Admin(admin_command) => match admin_command {
|
||||
Admin::User(cmd) => match cmd {
|
||||
UserCommand::Create(user) => {
|
||||
let database_pool = match sqlite::init_database_pool(&args.database_url).await {
|
||||
cmd::Command::Admin(admin_command) => match admin_command {
|
||||
cmd::Admin::User(cmd) => match cmd {
|
||||
cmd::UserCommand::Create(user) => {
|
||||
let database_pool =
|
||||
match sqlite::init_database_pool(&args.database_url).await {
|
||||
Ok(pool) => pool,
|
||||
Err(e) => return <_ as Into<Error>>::into(e).into(),
|
||||
};
|
||||
@@ -137,11 +111,11 @@ async fn main() -> MainResult {
|
||||
)
|
||||
.await
|
||||
.map_err(|error| match error {
|
||||
models::Error::Query(models::QueryError::Duplicate { description: _ }) => {
|
||||
Error::Command(packager::CommandError::UserExists {
|
||||
models::Error::Query(models::QueryError::Duplicate {
|
||||
description: _,
|
||||
}) => Error::Command(packager::CommandError::UserExists {
|
||||
username: user.username.clone(),
|
||||
})
|
||||
}
|
||||
}),
|
||||
_ => Error::Model(error),
|
||||
}) {
|
||||
Ok(id) => id,
|
||||
@@ -157,7 +131,7 @@ async fn main() -> MainResult {
|
||||
}
|
||||
},
|
||||
},
|
||||
Command::Migrate => {
|
||||
cmd::Command::Migrate => {
|
||||
if let Err(e) = sqlite::migrate(&args.database_url).await {
|
||||
return <_ as Into<Error>>::into(e).into();
|
||||
}
|
||||
@@ -165,6 +139,9 @@ async fn main() -> MainResult {
|
||||
println!("Migrations successfully applied");
|
||||
}
|
||||
}
|
||||
|
||||
MainResult(Ok(()))
|
||||
})
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ use crate::Context;
|
||||
use futures::{TryFutureExt, TryStreamExt};
|
||||
use uuid::Uuid;
|
||||
|
||||
use tracing::Instrument;
|
||||
|
||||
pub struct Inventory {
|
||||
pub categories: Vec<Category>,
|
||||
}
|
||||
@@ -12,6 +14,7 @@ impl Inventory {
|
||||
#[tracing::instrument]
|
||||
pub async fn load(ctx: &Context, pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<Self, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let categories = async {
|
||||
let mut categories = sqlx::query_as!(
|
||||
DbCategoryRow,
|
||||
"SELECT
|
||||
@@ -33,6 +36,11 @@ impl Inventory {
|
||||
category.populate_items(ctx, pool).await?;
|
||||
}
|
||||
|
||||
Ok::<_, Error>(categories)
|
||||
}
|
||||
.instrument(tracing::info_span!("packager::query", "query"))
|
||||
.await?;
|
||||
|
||||
Ok(Self { categories })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
use axum::{
|
||||
error_handling::HandleErrorLayer,
|
||||
http::header::HeaderMap,
|
||||
http::StatusCode,
|
||||
middleware,
|
||||
routing::{get, post},
|
||||
Router,
|
||||
BoxError, Router,
|
||||
};
|
||||
|
||||
use std::time::Duration;
|
||||
use tower::{timeout::TimeoutLayer, ServiceBuilder};
|
||||
|
||||
use crate::{AppState, Error, RequestError, TopLevelPage};
|
||||
|
||||
use super::auth;
|
||||
@@ -39,6 +44,13 @@ pub fn router(state: AppState) -> Router {
|
||||
})
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
"/slow",
|
||||
get(|| async {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
"Ok"
|
||||
}),
|
||||
)
|
||||
.route("/debug", get(debug))
|
||||
.merge(
|
||||
// thse are routes that require authentication
|
||||
@@ -119,6 +131,15 @@ pub fn router(state: AppState) -> Router {
|
||||
auth::authorize,
|
||||
)),
|
||||
)
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(HandleErrorLayer::new(|_: BoxError| async {
|
||||
tracing::warn!("request timeout");
|
||||
StatusCode::REQUEST_TIMEOUT
|
||||
}))
|
||||
.layer(TimeoutLayer::new(Duration::from_millis(500))),
|
||||
)
|
||||
// .propagate_x_request_id()
|
||||
.fallback(|| async {
|
||||
Error::Request(RequestError::NotFound {
|
||||
message: "no route found".to_string(),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::time;
|
||||
|
||||
use tracing::Instrument;
|
||||
|
||||
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||
use sqlx::ConnectOptions;
|
||||
pub use sqlx::{Pool, Sqlite};
|
||||
@@ -28,10 +30,13 @@ pub async fn migrate(url: &str) -> Result<(), StartError> {
|
||||
.connect_with(
|
||||
SqliteConnectOptions::from_str(url)?
|
||||
.pragma("foreign_keys", "0")
|
||||
.log_statements(log::LevelFilter::Debug),
|
||||
.log_statements(log::LevelFilter::Warn),
|
||||
)
|
||||
.await?;
|
||||
|
||||
sqlx::migrate!().run(&pool).await?;
|
||||
async { sqlx::migrate!().run(&pool).await }
|
||||
.instrument(tracing::info_span!("packager::query", "migration"))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::time::Duration;
|
||||
|
||||
use axum::Router;
|
||||
use http::Request;
|
||||
use tower_http::{classify::ServerErrorsFailureClass, trace::TraceLayer};
|
||||
use tracing::{Level, Span};
|
||||
use tracing::Span;
|
||||
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::{
|
||||
filter::{LevelFilter, Targets},
|
||||
fmt::{format::Format, Layer},
|
||||
@@ -16,13 +19,31 @@ use tracing_subscriber::{
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use opentelemetry::global;
|
||||
use opentelemetry::{global, runtime::Tokio};
|
||||
|
||||
pub fn otel_init(f: impl FnOnce() -> ()) {
|
||||
f()
|
||||
pub enum OpenTelemetryConfig {
|
||||
Enabled,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
pub fn init_tracing() {
|
||||
pub enum TokioConsoleConfig {
|
||||
Enabled,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
pub async fn init_tracing<Func, T>(
|
||||
opentelemetry_config: OpenTelemetryConfig,
|
||||
tokio_console_config: TokioConsoleConfig,
|
||||
args: crate::cmd::Args,
|
||||
f: Func,
|
||||
) -> T
|
||||
where
|
||||
Func: FnOnce(crate::cmd::Args) -> Pin<Box<dyn Future<Output = T>>>,
|
||||
T: std::process::Termination,
|
||||
{
|
||||
let mut shutdown_functions: Vec<Box<dyn FnOnce() -> Result<(), Box<dyn std::error::Error>>>> =
|
||||
vec![];
|
||||
|
||||
// default is the Full format, there is no way to specify this, but it can be
|
||||
// overridden via builder methods
|
||||
let stdout_format = Format::default()
|
||||
@@ -37,53 +58,81 @@ pub fn init_tracing() {
|
||||
.with_writer(io::stdout);
|
||||
|
||||
let stdout_filter = Targets::new()
|
||||
.with_default(LevelFilter::OFF)
|
||||
.with_default(LevelFilter::WARN)
|
||||
.with_targets(vec![
|
||||
(env!("CARGO_PKG_NAME"), Level::DEBUG),
|
||||
// this is for axum requests
|
||||
("request", Level::DEBUG),
|
||||
// required for tokio-console as by the docs
|
||||
// ("tokio", Level::TRACE),
|
||||
// ("runtime", Level::TRACE),
|
||||
(env!("CARGO_PKG_NAME"), LevelFilter::DEBUG),
|
||||
("request", LevelFilter::DEBUG),
|
||||
("runtime", LevelFilter::OFF),
|
||||
("sqlx", LevelFilter::TRACE),
|
||||
]);
|
||||
|
||||
let stdout_layer = stdout_layer.with_filter(stdout_filter);
|
||||
|
||||
let console_layer = console_subscriber::Builder::default().spawn();
|
||||
let console_layer = match tokio_console_config {
|
||||
TokioConsoleConfig::Enabled => Some(console_subscriber::Builder::default().spawn()),
|
||||
TokioConsoleConfig::Disabled => None,
|
||||
};
|
||||
|
||||
let opentelemetry_layer = match opentelemetry_config {
|
||||
OpenTelemetryConfig::Enabled => {
|
||||
global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new());
|
||||
// Sets up the machinery needed to export data to Jaeger
|
||||
// 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"))
|
||||
.install_simple()
|
||||
.with_max_packet_size(20_000)
|
||||
.with_auto_split_batch(true)
|
||||
.install_batch(Tokio)
|
||||
.unwrap();
|
||||
|
||||
let opentelemetry_filter = Targets::new()
|
||||
.with_default(LevelFilter::OFF)
|
||||
let opentelemetry_filter = {
|
||||
Targets::new()
|
||||
.with_default(LevelFilter::DEBUG)
|
||||
.with_targets(vec![
|
||||
(env!("CARGO_PKG_NAME"), Level::DEBUG),
|
||||
// this is for axum requests
|
||||
("request", Level::DEBUG),
|
||||
// required for tokio-console as by the docs
|
||||
// ("tokio", Level::TRACE),
|
||||
// ("runtime", Level::TRACE),
|
||||
]);
|
||||
(env!("CARGO_PKG_NAME"), LevelFilter::DEBUG),
|
||||
("request", LevelFilter::DEBUG),
|
||||
("runtime", LevelFilter::OFF),
|
||||
("sqlx", LevelFilter::DEBUG),
|
||||
])
|
||||
};
|
||||
|
||||
let opentelemetry = tracing_opentelemetry::layer()
|
||||
.with_tracer(tracer)
|
||||
.with_filter(opentelemetry_filter);
|
||||
let opentelemetry_layer = tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
// .with_filter(opentelemetry_filter);
|
||||
|
||||
shutdown_functions.push(Box::new(|| {
|
||||
println!("shutting down otel");
|
||||
global::shutdown_tracer_provider();
|
||||
Ok(())
|
||||
}));
|
||||
|
||||
println!("set up otel");
|
||||
|
||||
Some(opentelemetry_layer)
|
||||
}
|
||||
OpenTelemetryConfig::Disabled => None,
|
||||
};
|
||||
|
||||
let registry = Registry::default()
|
||||
.with(console_layer)
|
||||
.with(opentelemetry)
|
||||
.with(opentelemetry_layer)
|
||||
// just an example, you can actuall pass Options here for layers that might be
|
||||
// set/unset at runtime
|
||||
.with(Some(stdout_layer))
|
||||
.with(None::<Layer<_>>);
|
||||
|
||||
tracing::subscriber::set_global_default(registry).unwrap();
|
||||
|
||||
tracing::debug!("tracing setup finished");
|
||||
|
||||
tracing_log::log_tracer::Builder::new().init().unwrap();
|
||||
|
||||
let result = f(args).await;
|
||||
|
||||
for shutdown_func in shutdown_functions {
|
||||
shutdown_func().unwrap();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
struct Latency(Duration);
|
||||
|
||||
@@ -7,12 +7,17 @@ use uuid::Uuid;
|
||||
pub struct Inventory;
|
||||
|
||||
impl Inventory {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory",
|
||||
fields(component = "Inventory")
|
||||
)]
|
||||
pub fn build(
|
||||
active_category: Option<&models::inventory::Category>,
|
||||
categories: &Vec<models::inventory::Category>,
|
||||
edit_item_id: Option<Uuid>,
|
||||
) -> Markup {
|
||||
tracing::info!("building inventory HTML component");
|
||||
html!(
|
||||
div id="pkglist-item-manager" {
|
||||
div ."p-8" ."grid" ."grid-cols-4" ."gap-5" {
|
||||
@@ -37,7 +42,11 @@ impl Inventory {
|
||||
pub struct InventoryCategoryList;
|
||||
|
||||
impl InventoryCategoryList {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory_category_list",
|
||||
fields(component = "InventoryCategoryList")
|
||||
)]
|
||||
pub fn build(
|
||||
active_category: Option<&models::inventory::Category>,
|
||||
categories: &Vec<models::inventory::Category>,
|
||||
@@ -144,7 +153,11 @@ impl InventoryCategoryList {
|
||||
pub struct InventoryItemList;
|
||||
|
||||
impl InventoryItemList {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory_item_list",
|
||||
fields(component = "InventoryItemList")
|
||||
)]
|
||||
pub fn build(edit_item_id: Option<Uuid>, items: &Vec<models::inventory::Item>) -> Markup {
|
||||
let biggest_item_weight: i64 = items.iter().map(|item| item.weight).max().unwrap_or(1);
|
||||
html!(
|
||||
@@ -320,7 +333,11 @@ impl InventoryItemList {
|
||||
pub struct InventoryNewItemFormName;
|
||||
|
||||
impl InventoryNewItemFormName {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory_new_item_form_name",
|
||||
fields(component = "InventoryNewItemFormName")
|
||||
)]
|
||||
pub fn build(value: Option<&str>, error: bool) -> Markup {
|
||||
html!(
|
||||
div
|
||||
@@ -368,7 +385,11 @@ impl InventoryNewItemFormName {
|
||||
pub struct InventoryNewItemFormWeight;
|
||||
|
||||
impl InventoryNewItemFormWeight {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory_new_item_form_weight",
|
||||
fields(component = "InventoryNewItemFormWeight")
|
||||
)]
|
||||
pub fn build() -> Markup {
|
||||
html!(
|
||||
div
|
||||
@@ -411,7 +432,11 @@ impl InventoryNewItemFormWeight {
|
||||
pub struct InventoryNewItemFormCategory;
|
||||
|
||||
impl InventoryNewItemFormCategory {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory_new_item_form_category",
|
||||
fields(component = "InventoryNewItemFormCategory")
|
||||
)]
|
||||
pub fn build(
|
||||
active_category: Option<&models::inventory::Category>,
|
||||
categories: &Vec<models::inventory::Category>,
|
||||
@@ -452,7 +477,11 @@ impl InventoryNewItemFormCategory {
|
||||
pub struct InventoryNewItemForm;
|
||||
|
||||
impl InventoryNewItemForm {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory_new_item_form",
|
||||
fields(component = "InventoryNewItemForm")
|
||||
)]
|
||||
pub fn build(
|
||||
active_category: Option<&models::inventory::Category>,
|
||||
categories: &Vec<models::inventory::Category>,
|
||||
@@ -499,7 +528,11 @@ impl InventoryNewItemForm {
|
||||
pub struct InventoryNewCategoryForm;
|
||||
|
||||
impl InventoryNewCategoryForm {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory_new_category_form",
|
||||
fields(component = "InventoryNewCategoryForm")
|
||||
)]
|
||||
pub fn build() -> Markup {
|
||||
html!(
|
||||
form
|
||||
@@ -554,7 +587,11 @@ impl InventoryNewCategoryForm {
|
||||
pub struct InventoryItem;
|
||||
|
||||
impl InventoryItem {
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(
|
||||
target = "packager::html::build",
|
||||
name = "build_inventory_item",
|
||||
fields(component = "InventoryItem")
|
||||
)]
|
||||
pub fn build(_state: &ClientState, item: &models::inventory::InventoryItem) -> Markup {
|
||||
html!(
|
||||
div ."p-8" {
|
||||
|
||||
Reference in New Issue
Block a user