You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Better tracing spans
This commit is contained in:
@ -15,7 +15,7 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use mas_config::{ConfigurationSection, RootConfig};
|
use mas_config::{ConfigurationSection, RootConfig};
|
||||||
use rand::SeedableRng;
|
use rand::SeedableRng;
|
||||||
use tracing::info;
|
use tracing::{info, info_span};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub(super) struct Options {
|
pub(super) struct Options {
|
||||||
@ -40,6 +40,8 @@ impl Options {
|
|||||||
use Subcommand as SC;
|
use Subcommand as SC;
|
||||||
match &self.subcommand {
|
match &self.subcommand {
|
||||||
SC::Dump => {
|
SC::Dump => {
|
||||||
|
let _span = info_span!("cli.config.dump").entered();
|
||||||
|
|
||||||
let config: RootConfig = root.load_config()?;
|
let config: RootConfig = root.load_config()?;
|
||||||
|
|
||||||
serde_yaml::to_writer(std::io::stdout(), &config)?;
|
serde_yaml::to_writer(std::io::stdout(), &config)?;
|
||||||
@ -47,11 +49,15 @@ impl Options {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
SC::Check => {
|
SC::Check => {
|
||||||
|
let _span = info_span!("cli.config.check").entered();
|
||||||
|
|
||||||
let _config: RootConfig = root.load_config()?;
|
let _config: RootConfig = root.load_config()?;
|
||||||
info!(path = ?root.config, "Configuration file looks good");
|
info!(path = ?root.config, "Configuration file looks good");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
SC::Generate => {
|
SC::Generate => {
|
||||||
|
let _span = info_span!("cli.config.generate").entered();
|
||||||
|
|
||||||
// XXX: we should disallow SeedableRng::from_entropy
|
// XXX: we should disallow SeedableRng::from_entropy
|
||||||
let rng = rand_chacha::ChaChaRng::from_entropy();
|
let rng = rand_chacha::ChaChaRng::from_entropy();
|
||||||
let config = RootConfig::load_and_generate(rng).await?;
|
let config = RootConfig::load_and_generate(rng).await?;
|
||||||
|
@ -16,6 +16,7 @@ use anyhow::Context;
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use mas_config::DatabaseConfig;
|
use mas_config::DatabaseConfig;
|
||||||
use mas_storage::MIGRATOR;
|
use mas_storage::MIGRATOR;
|
||||||
|
use tracing::{info_span, Instrument};
|
||||||
|
|
||||||
use crate::util::database_from_config;
|
use crate::util::database_from_config;
|
||||||
|
|
||||||
@ -33,12 +34,14 @@ enum Subcommand {
|
|||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
pub async fn run(&self, root: &super::Options) -> anyhow::Result<()> {
|
pub async fn run(&self, root: &super::Options) -> anyhow::Result<()> {
|
||||||
|
let _span = info_span!("cli.database.migrate").entered();
|
||||||
let config: DatabaseConfig = root.load_config()?;
|
let config: DatabaseConfig = root.load_config()?;
|
||||||
let pool = database_from_config(&config).await?;
|
let pool = database_from_config(&config).await?;
|
||||||
|
|
||||||
// Run pending migrations
|
// Run pending migrations
|
||||||
MIGRATOR
|
MIGRATOR
|
||||||
.run(&pool)
|
.run(&pool)
|
||||||
|
.instrument(info_span!("db.migrate"))
|
||||||
.await
|
.await
|
||||||
.context("could not run migrations")?;
|
.context("could not run migrations")?;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ use mas_handlers::HttpClientFactory;
|
|||||||
use mas_http::HttpServiceExt;
|
use mas_http::HttpServiceExt;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use tower::{Service, ServiceExt};
|
use tower::{Service, ServiceExt};
|
||||||
use tracing::info;
|
use tracing::{info, info_span};
|
||||||
|
|
||||||
use crate::util::policy_factory_from_config;
|
use crate::util::policy_factory_from_config;
|
||||||
|
|
||||||
@ -74,6 +74,7 @@ impl Options {
|
|||||||
json: false,
|
json: false,
|
||||||
url,
|
url,
|
||||||
} => {
|
} => {
|
||||||
|
let _span = info_span!("cli.debug.http").entered();
|
||||||
let mut client = http_client_factory.client("cli-debug-http").await?;
|
let mut client = http_client_factory.client("cli-debug-http").await?;
|
||||||
let request = hyper::Request::builder()
|
let request = hyper::Request::builder()
|
||||||
.uri(url)
|
.uri(url)
|
||||||
@ -98,6 +99,7 @@ impl Options {
|
|||||||
json: true,
|
json: true,
|
||||||
url,
|
url,
|
||||||
} => {
|
} => {
|
||||||
|
let _span = info_span!("cli.debug.http").entered();
|
||||||
let mut client = http_client_factory
|
let mut client = http_client_factory
|
||||||
.client("cli-debug-http")
|
.client("cli-debug-http")
|
||||||
.await?
|
.await?
|
||||||
@ -122,6 +124,7 @@ impl Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SC::Policy => {
|
SC::Policy => {
|
||||||
|
let _span = info_span!("cli.debug.policy").entered();
|
||||||
let config: PolicyConfig = root.load_config()?;
|
let config: PolicyConfig = root.load_config()?;
|
||||||
info!("Loading and compiling the policy module");
|
info!("Loading and compiling the policy module");
|
||||||
let policy_factory = policy_factory_from_config(&config).await?;
|
let policy_factory = policy_factory_from_config(&config).await?;
|
||||||
|
@ -25,7 +25,7 @@ use mas_storage::{
|
|||||||
};
|
};
|
||||||
use oauth2_types::scope::Scope;
|
use oauth2_types::scope::Scope;
|
||||||
use rand::SeedableRng;
|
use rand::SeedableRng;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, info_span, warn};
|
||||||
|
|
||||||
use crate::util::{database_from_config, password_manager_from_config};
|
use crate::util::{database_from_config, password_manager_from_config};
|
||||||
|
|
||||||
@ -193,6 +193,9 @@ impl Options {
|
|||||||
|
|
||||||
match &self.subcommand {
|
match &self.subcommand {
|
||||||
SC::SetPassword { username, password } => {
|
SC::SetPassword { username, password } => {
|
||||||
|
let _span =
|
||||||
|
info_span!("cli.manage.set_password", user.username = %username).entered();
|
||||||
|
|
||||||
let database_config: DatabaseConfig = root.load_config()?;
|
let database_config: DatabaseConfig = root.load_config()?;
|
||||||
let passwords_config: PasswordsConfig = root.load_config()?;
|
let passwords_config: PasswordsConfig = root.load_config()?;
|
||||||
|
|
||||||
@ -221,6 +224,13 @@ impl Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SC::VerifyEmail { username, email } => {
|
SC::VerifyEmail { username, email } => {
|
||||||
|
let _span = info_span!(
|
||||||
|
"cli.manage.verify_email",
|
||||||
|
user.username = username,
|
||||||
|
user_email.email = email
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
|
|
||||||
let config: DatabaseConfig = root.load_config()?;
|
let config: DatabaseConfig = root.load_config()?;
|
||||||
let pool = database_from_config(&config).await?;
|
let pool = database_from_config(&config).await?;
|
||||||
let mut txn = pool.begin().await?;
|
let mut txn = pool.begin().await?;
|
||||||
@ -245,6 +255,8 @@ impl Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SC::ImportClients { update } => {
|
SC::ImportClients { update } => {
|
||||||
|
let _span = info_span!("cli.manage.import_clients").entered();
|
||||||
|
|
||||||
let config: RootConfig = root.load_config()?;
|
let config: RootConfig = root.load_config()?;
|
||||||
let pool = database_from_config(&config.database).await?;
|
let pool = database_from_config(&config.database).await?;
|
||||||
let encrypter = config.secrets.encrypter();
|
let encrypter = config.secrets.encrypter();
|
||||||
@ -303,6 +315,13 @@ impl Options {
|
|||||||
client_secret,
|
client_secret,
|
||||||
signing_alg,
|
signing_alg,
|
||||||
} => {
|
} => {
|
||||||
|
let _span = info_span!(
|
||||||
|
"cli.manage.add_oauth_upstream",
|
||||||
|
upstream_oauth_provider.issuer = issuer,
|
||||||
|
upstream_oauth_provider.client_id = client_id,
|
||||||
|
)
|
||||||
|
.entered();
|
||||||
|
|
||||||
let config: RootConfig = root.load_config()?;
|
let config: RootConfig = root.load_config()?;
|
||||||
let encrypter = config.secrets.encrypter();
|
let encrypter = config.secrets.encrypter();
|
||||||
let pool = database_from_config(&config.database).await?;
|
let pool = database_from_config(&config.database).await?;
|
||||||
|
@ -24,7 +24,7 @@ use mas_router::UrlBuilder;
|
|||||||
use mas_storage::MIGRATOR;
|
use mas_storage::MIGRATOR;
|
||||||
use mas_tasks::TaskQueue;
|
use mas_tasks::TaskQueue;
|
||||||
use tokio::signal::unix::SignalKind;
|
use tokio::signal::unix::SignalKind;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, info_span, warn, Instrument};
|
||||||
|
|
||||||
use crate::util::{
|
use crate::util::{
|
||||||
database_from_config, mailer_from_config, password_manager_from_config,
|
database_from_config, mailer_from_config, password_manager_from_config,
|
||||||
@ -45,6 +45,7 @@ pub(super) struct Options {
|
|||||||
impl Options {
|
impl Options {
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub async fn run(&self, root: &super::Options) -> anyhow::Result<()> {
|
pub async fn run(&self, root: &super::Options) -> anyhow::Result<()> {
|
||||||
|
let span = info_span!("cli.run.init").entered();
|
||||||
let config: RootConfig = root.load_config()?;
|
let config: RootConfig = root.load_config()?;
|
||||||
|
|
||||||
// Connect to the database
|
// Connect to the database
|
||||||
@ -55,6 +56,7 @@ impl Options {
|
|||||||
info!("Running pending migrations");
|
info!("Running pending migrations");
|
||||||
MIGRATOR
|
MIGRATOR
|
||||||
.run(&pool)
|
.run(&pool)
|
||||||
|
.instrument(info_span!("db.migrate"))
|
||||||
.await
|
.await
|
||||||
.context("could not run migrations")?;
|
.context("could not run migrations")?;
|
||||||
}
|
}
|
||||||
@ -186,6 +188,8 @@ impl Options {
|
|||||||
.with_signal(SignalKind::terminate())?
|
.with_signal(SignalKind::terminate())?
|
||||||
.with_signal(SignalKind::interrupt())?;
|
.with_signal(SignalKind::interrupt())?;
|
||||||
|
|
||||||
|
span.exit();
|
||||||
|
|
||||||
mas_listener::server::run_servers(servers, shutdown).await;
|
mas_listener::server::run_servers(servers, shutdown).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -17,6 +17,7 @@ use clap::Parser;
|
|||||||
use mas_storage::Clock;
|
use mas_storage::Clock;
|
||||||
use mas_templates::Templates;
|
use mas_templates::Templates;
|
||||||
use rand::SeedableRng;
|
use rand::SeedableRng;
|
||||||
|
use tracing::info_span;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub(super) struct Options {
|
pub(super) struct Options {
|
||||||
@ -38,6 +39,8 @@ impl Options {
|
|||||||
use Subcommand as SC;
|
use Subcommand as SC;
|
||||||
match &self.subcommand {
|
match &self.subcommand {
|
||||||
SC::Check { path } => {
|
SC::Check { path } => {
|
||||||
|
let _span = info_span!("cli.templates.check").entered();
|
||||||
|
|
||||||
let clock = Clock::default();
|
let clock = Clock::default();
|
||||||
// XXX: we should disallow SeedableRng::from_entropy
|
// XXX: we should disallow SeedableRng::from_entropy
|
||||||
let mut rng = rand_chacha::ChaChaRng::from_entropy();
|
let mut rng = rand_chacha::ChaChaRng::from_entropy();
|
||||||
|
@ -110,6 +110,7 @@ pub async fn templates_from_config(
|
|||||||
Templates::load(config.path.clone(), url_builder.clone()).await
|
Templates::load(config.path.clone(), url_builder.clone()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(name = "db.connect", skip_all, err(Debug))]
|
||||||
pub async fn database_from_config(config: &DatabaseConfig) -> Result<PgPool, anyhow::Error> {
|
pub async fn database_from_config(config: &DatabaseConfig) -> Result<PgPool, anyhow::Error> {
|
||||||
let mut options = match &config.options {
|
let mut options = match &config.options {
|
||||||
DatabaseConnectConfig::Uri { uri } => uri
|
DatabaseConnectConfig::Uri { uri } => uri
|
||||||
|
@ -86,6 +86,7 @@ impl SecretsConfig {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error when a key could not be imported
|
/// Returns an error when a key could not be imported
|
||||||
|
#[tracing::instrument(name = "secrets.load", skip_all, err(Debug))]
|
||||||
pub async fn key_store(&self) -> anyhow::Result<Keystore> {
|
pub async fn key_store(&self) -> anyhow::Result<Keystore> {
|
||||||
let mut keys = Vec::with_capacity(self.keys.len());
|
let mut keys = Vec::with_capacity(self.keys.len());
|
||||||
for item in &self.keys {
|
for item in &self.keys {
|
||||||
|
@ -100,10 +100,10 @@ impl Mailer {
|
|||||||
///
|
///
|
||||||
/// Will return `Err` if the email failed rendering or failed sending
|
/// Will return `Err` if the email failed rendering or failed sending
|
||||||
#[tracing::instrument(
|
#[tracing::instrument(
|
||||||
|
name = "email.verification.send",
|
||||||
skip_all,
|
skip_all,
|
||||||
fields(
|
fields(
|
||||||
email.to = %to,
|
email.to = %to,
|
||||||
email.from = %self.from,
|
|
||||||
user.id = %context.user().id,
|
user.id = %context.user().id,
|
||||||
user_email_verification.id = %context.verification().id,
|
user_email_verification.id = %context.verification().id,
|
||||||
user_email_verification.code = context.verification().code,
|
user_email_verification.code = context.verification().code,
|
||||||
@ -125,6 +125,7 @@ impl Mailer {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the connection failed
|
/// Returns an error if the connection failed
|
||||||
|
#[tracing::instrument(name = "email.test_connection", skip_all, err)]
|
||||||
pub async fn test_connection(&self) -> Result<(), crate::transport::Error> {
|
pub async fn test_connection(&self) -> Result<(), crate::transport::Error> {
|
||||||
self.transport.test_connection().await
|
self.transport.test_connection().await
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ impl PasswordManager {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the hashing failed
|
/// Returns an error if the hashing failed
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(name = "passwords.hash", skip_all)]
|
||||||
pub async fn hash<R: CryptoRng + RngCore + Send>(
|
pub async fn hash<R: CryptoRng + RngCore + Send>(
|
||||||
&self,
|
&self,
|
||||||
rng: R,
|
rng: R,
|
||||||
@ -82,13 +82,16 @@ impl PasswordManager {
|
|||||||
let rng = rand_chacha::ChaChaRng::from_rng(rng)?;
|
let rng = rand_chacha::ChaChaRng::from_rng(rng)?;
|
||||||
let hashers = self.hashers.clone();
|
let hashers = self.hashers.clone();
|
||||||
let default_hasher_version = self.default_hasher;
|
let default_hasher_version = self.default_hasher;
|
||||||
|
let span = tracing::Span::current();
|
||||||
|
|
||||||
let hashed = tokio::task::spawn_blocking(move || {
|
let hashed = tokio::task::spawn_blocking(move || {
|
||||||
let default_hasher = hashers
|
span.in_scope(move || {
|
||||||
.get(&default_hasher_version)
|
let default_hasher = hashers
|
||||||
.context("Default hasher not found")?;
|
.get(&default_hasher_version)
|
||||||
|
.context("Default hasher not found")?;
|
||||||
|
|
||||||
default_hasher.hash_blocking(rng, &password)
|
default_hasher.hash_blocking(rng, &password)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ impl PasswordManager {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the password hash verification failed
|
/// Returns an error if the password hash verification failed
|
||||||
#[tracing::instrument(skip_all, fields(%scheme))]
|
#[tracing::instrument(name = "passwords.verify", skip_all, fields(%scheme))]
|
||||||
pub async fn verify(
|
pub async fn verify(
|
||||||
&self,
|
&self,
|
||||||
scheme: SchemeVersion,
|
scheme: SchemeVersion,
|
||||||
@ -108,10 +111,13 @@ impl PasswordManager {
|
|||||||
hashed_password: String,
|
hashed_password: String,
|
||||||
) -> Result<(), anyhow::Error> {
|
) -> Result<(), anyhow::Error> {
|
||||||
let hashers = self.hashers.clone();
|
let hashers = self.hashers.clone();
|
||||||
|
let span = tracing::Span::current();
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let hasher = hashers.get(&scheme).context("Hashing scheme not found")?;
|
span.in_scope(move || {
|
||||||
hasher.verify_blocking(&hashed_password, &password)
|
let hasher = hashers.get(&scheme).context("Hashing scheme not found")?;
|
||||||
|
hasher.verify_blocking(&hashed_password, &password)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
@ -124,7 +130,7 @@ impl PasswordManager {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the password hash verification failed
|
/// Returns an error if the password hash verification failed
|
||||||
#[tracing::instrument(skip_all, fields(%scheme))]
|
#[tracing::instrument(name = "passwords.verify_and_upgrade", skip_all, fields(%scheme))]
|
||||||
pub async fn verify_and_upgrade<R: CryptoRng + RngCore + Send>(
|
pub async fn verify_and_upgrade<R: CryptoRng + RngCore + Send>(
|
||||||
&self,
|
&self,
|
||||||
rng: R,
|
rng: R,
|
||||||
|
@ -69,7 +69,7 @@ pub struct PolicyFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PolicyFactory {
|
impl PolicyFactory {
|
||||||
#[tracing::instrument(skip(source), err)]
|
#[tracing::instrument(name = "policy.load", skip(source), err)]
|
||||||
pub async fn load(
|
pub async fn load(
|
||||||
mut source: impl AsyncRead + std::marker::Unpin,
|
mut source: impl AsyncRead + std::marker::Unpin,
|
||||||
data: serde_json::Value,
|
data: serde_json::Value,
|
||||||
@ -108,7 +108,7 @@ impl PolicyFactory {
|
|||||||
authorization_grant_endpoint,
|
authorization_grant_endpoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to instanciate
|
// Try to instantiate
|
||||||
factory
|
factory
|
||||||
.instantiate()
|
.instantiate()
|
||||||
.await
|
.await
|
||||||
@ -117,7 +117,7 @@ impl PolicyFactory {
|
|||||||
Ok(factory)
|
Ok(factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self), err)]
|
#[tracing::instrument(name = "policy.instantiate", skip_all, err)]
|
||||||
pub async fn instantiate(&self) -> Result<Policy, InstanciateError> {
|
pub async fn instantiate(&self) -> Result<Policy, InstanciateError> {
|
||||||
let mut store = Store::new(&self.engine, ());
|
let mut store = Store::new(&self.engine, ());
|
||||||
let runtime = Runtime::new(&mut store, &self.module)
|
let runtime = Runtime::new(&mut store, &self.module)
|
||||||
@ -189,7 +189,14 @@ pub enum EvaluationError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Policy {
|
impl Policy {
|
||||||
#[tracing::instrument(skip(self, password))]
|
#[tracing::instrument(
|
||||||
|
name = "policy.evaluate.register",
|
||||||
|
skip_all,
|
||||||
|
fields(
|
||||||
|
data.username = username,
|
||||||
|
),
|
||||||
|
err,
|
||||||
|
)]
|
||||||
pub async fn evaluate_register(
|
pub async fn evaluate_register(
|
||||||
&mut self,
|
&mut self,
|
||||||
username: &str,
|
username: &str,
|
||||||
@ -234,7 +241,15 @@ impl Policy {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(
|
||||||
|
name = "policy.evaluate.authorization_grant",
|
||||||
|
skip_all,
|
||||||
|
fields(
|
||||||
|
data.authorization_grant.id = %authorization_grant.id,
|
||||||
|
data.user.id = %user.id,
|
||||||
|
),
|
||||||
|
err,
|
||||||
|
)]
|
||||||
pub async fn evaluate_authorization_grant(
|
pub async fn evaluate_authorization_grant(
|
||||||
&mut self,
|
&mut self,
|
||||||
authorization_grant: &AuthorizationGrant,
|
authorization_grant: &AuthorizationGrant,
|
||||||
|
@ -96,6 +96,12 @@ impl Templates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Load the templates from the given config
|
/// Load the templates from the given config
|
||||||
|
#[tracing::instrument(
|
||||||
|
name = "templates.load",
|
||||||
|
skip_all,
|
||||||
|
fields(%path),
|
||||||
|
err,
|
||||||
|
)]
|
||||||
pub async fn load(
|
pub async fn load(
|
||||||
path: Utf8PathBuf,
|
path: Utf8PathBuf,
|
||||||
url_builder: UrlBuilder,
|
url_builder: UrlBuilder,
|
||||||
@ -110,14 +116,17 @@ impl Templates {
|
|||||||
|
|
||||||
async fn load_(path: &Utf8Path, url_builder: UrlBuilder) -> Result<Tera, TemplateLoadingError> {
|
async fn load_(path: &Utf8Path, url_builder: UrlBuilder) -> Result<Tera, TemplateLoadingError> {
|
||||||
let path = path.to_owned();
|
let path = path.to_owned();
|
||||||
|
let span = tracing::Span::current();
|
||||||
|
|
||||||
// This uses blocking I/Os, do that in a blocking task
|
// This uses blocking I/Os, do that in a blocking task
|
||||||
let mut tera = tokio::task::spawn_blocking(move || {
|
let mut tera = tokio::task::spawn_blocking(move || {
|
||||||
let path = path.canonicalize_utf8()?;
|
span.in_scope(move || {
|
||||||
let path = format!("{path}/**/*.{{html,txt,subject}}");
|
let path = path.canonicalize_utf8()?;
|
||||||
|
let path = format!("{path}/**/*.{{html,txt,subject}}");
|
||||||
|
|
||||||
info!(%path, "Loading templates from filesystem");
|
info!(%path, "Loading templates from filesystem");
|
||||||
Tera::new(&path)
|
Tera::new(&path)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
@ -138,7 +147,13 @@ impl Templates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reload the templates on disk
|
/// Reload the templates on disk
|
||||||
pub async fn reload(&self) -> anyhow::Result<()> {
|
#[tracing::instrument(
|
||||||
|
name = "templates.reload",
|
||||||
|
skip_all,
|
||||||
|
fields(path = %self.path),
|
||||||
|
err,
|
||||||
|
)]
|
||||||
|
pub async fn reload(&self) -> Result<(), TemplateLoadingError> {
|
||||||
// Prepare the new Tera instance
|
// Prepare the new Tera instance
|
||||||
let new_tera = Self::load_(&self.path, self.url_builder.clone()).await?;
|
let new_tera = Self::load_(&self.path, self.url_builder.clone()).await?;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user