More logging configuration
This commit is contained in:
parent
23fa73ad20
commit
b94859b88a
|
@ -1143,6 +1143,15 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchit"
|
name = "matchit"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -1585,6 +1594,15 @@ dependencies = [
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.28"
|
version = "0.6.28"
|
||||||
|
@ -2360,12 +2378,16 @@ version = "0.3.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
"tracing-serde",
|
"tracing-serde",
|
||||||
|
|
|
@ -7,8 +7,9 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
tracing-subscriber = { version = "0.3.16", features = [ "tracing-log", "json" ] }
|
tracing-subscriber = { version = "0.3.16", features = [ "tracing-log", "json", "env-filter" ] }
|
||||||
tracing-log = "0.1.3"
|
tracing-log = "0.1.3"
|
||||||
|
tracing-appender = "0.2.2"
|
||||||
|
|
||||||
uuid = { version = "1.3.1", features = [ "v4", "fast-rng" ] }
|
uuid = { version = "1.3.1", features = [ "v4", "fast-rng" ] }
|
||||||
sqlx = { version = "0.6.3", features = [ "runtime-tokio-rustls", "sqlite" ] }
|
sqlx = { version = "0.6.3", features = [ "runtime-tokio-rustls", "sqlite" ] }
|
||||||
|
@ -53,5 +54,4 @@ rand = "0.8.5"
|
||||||
bcrypt = "0.14.0"
|
bcrypt = "0.14.0"
|
||||||
bitflags = "2.2.1"
|
bitflags = "2.2.1"
|
||||||
ldap3 = "0.11.1"
|
ldap3 = "0.11.1"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
tracing-appender = "0.2.2"
|
|
|
@ -59,15 +59,52 @@ pub enum DatabaseConfig {
|
||||||
Sqlite(SqliteDbConfig),
|
Sqlite(SqliteDbConfig),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Default)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum LogFormat {
|
||||||
|
Human,
|
||||||
|
#[default]
|
||||||
|
Json,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Default)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum RollPeriod {
|
||||||
|
Minutely,
|
||||||
|
Hourly,
|
||||||
|
#[default]
|
||||||
|
Daily,
|
||||||
|
Never,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
pub struct LogConfig {
|
||||||
|
/// The minimum level of logging
|
||||||
|
#[serde(deserialize_with = "serialize_log_level", default = "default_log_level")]
|
||||||
|
pub level: Level,
|
||||||
|
/// The path of the logging file
|
||||||
|
#[serde(default = "default_log_path")]
|
||||||
|
pub path: String,
|
||||||
|
/// The format of the produced logs
|
||||||
|
#[serde(default)]
|
||||||
|
pub format: LogFormat,
|
||||||
|
/// The roll period of the file
|
||||||
|
#[serde(default)]
|
||||||
|
pub roll_period: RollPeriod,
|
||||||
|
#[serde(default)]
|
||||||
|
pub extra_logging: bool,
|
||||||
|
pub env_filter: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
#[derive(Deserialize, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub listen_address: String,
|
pub listen_address: String,
|
||||||
pub listen_port: String,
|
pub listen_port: String,
|
||||||
url: Option<String>,
|
url: Option<String>,
|
||||||
|
pub registry_path: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub extra_logging: bool,
|
pub extra_logging: bool,
|
||||||
#[serde(deserialize_with = "serialize_log_level", default = "default_log_level")]
|
pub log: LogConfig,
|
||||||
pub log_level: Level,
|
|
||||||
pub ldap: Option<LdapConnectionConfig>,
|
pub ldap: Option<LdapConnectionConfig>,
|
||||||
pub database: DatabaseConfig,
|
pub database: DatabaseConfig,
|
||||||
pub storage: StorageConfig,
|
pub storage: StorageConfig,
|
||||||
|
@ -123,6 +160,10 @@ fn default_log_level() -> Level {
|
||||||
Level::INFO
|
Level::INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_log_path() -> String {
|
||||||
|
"orca.log".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize_log_level<'de, D>(deserializer: D) -> Result<Level, D::Error>
|
fn serialize_log_level<'de, D>(deserializer: D) -> Result<Level, D::Error>
|
||||||
where D: Deserializer<'de> {
|
where D: Deserializer<'de> {
|
||||||
let s = String::deserialize(deserializer)?.to_lowercase();
|
let s = String::deserialize(deserializer)?.to_lowercase();
|
||||||
|
|
129
src/main.rs
129
src/main.rs
|
@ -8,8 +8,9 @@ mod config;
|
||||||
mod auth;
|
mod auth;
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ use tracing::{debug, info};
|
||||||
|
|
||||||
use app_state::AppState;
|
use app_state::AppState;
|
||||||
use database::Database;
|
use database::Database;
|
||||||
use tracing_subscriber::filter;
|
use tracing_subscriber::{filter, EnvFilter};
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
use crate::storage::StorageDriver;
|
use crate::storage::StorageDriver;
|
||||||
|
@ -70,48 +71,103 @@ async fn change_request_paths<B>(mut request: Request<B>, next: Next<B>) -> Resu
|
||||||
Ok(next.run(request).await)
|
Ok(next.run(request).await)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn path_relative_to(registry_path: &str, other_path: &str) -> PathBuf {
|
||||||
|
let other = PathBuf::from(other_path);
|
||||||
|
|
||||||
|
if other.is_absolute() {
|
||||||
|
other
|
||||||
|
} else {
|
||||||
|
PathBuf::from(registry_path).join(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
let mut config = Config::new()
|
let mut config = Config::new()
|
||||||
.expect("Failure to parse config!");
|
.expect("Failure to parse config!");
|
||||||
|
|
||||||
let mut logging_guards = Vec::new();
|
// Create registry directory if it doesn't exist
|
||||||
|
if !Path::new(&config.registry_path).exists() {
|
||||||
|
fs::create_dir_all(&config.registry_path)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a tracing subscriber
|
let mut logging_guards = Vec::new();
|
||||||
if !config.extra_logging {
|
{
|
||||||
let sqlite_config = match &config.database {
|
let logc = &config.log;
|
||||||
DatabaseConfig::Sqlite(sqlite) => sqlite,
|
|
||||||
|
// Create log directory if it doesn't exist
|
||||||
|
let log_path = path_relative_to(&config.registry_path, &logc.path);
|
||||||
|
if !log_path.exists() {
|
||||||
|
fs::create_dir_all(&log_path)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a rolling file appender depending on the config
|
||||||
|
let file_appender = match logc.roll_period {
|
||||||
|
config::RollPeriod::Minutely => tracing_appender::rolling::minutely(log_path, "orca.log"),
|
||||||
|
config::RollPeriod::Hourly => tracing_appender::rolling::hourly(log_path, "orca.log"),
|
||||||
|
config::RollPeriod::Daily => tracing_appender::rolling::daily(log_path, "orca.log"),
|
||||||
|
config::RollPeriod::Never => tracing_appender::rolling::never(log_path, "orca.log"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = Path::new(&sqlite_config.path);
|
// Create non blocking loggers
|
||||||
let path = path.parent().unwrap();
|
|
||||||
|
|
||||||
// create file writer
|
|
||||||
let file_appender = tracing_appender::rolling::never(path, "orca.log");
|
|
||||||
|
|
||||||
//let (syslog_nb, _syslog_guard) = tracing_appender::non_blocking(syslog);
|
|
||||||
let (file_appender_nb, _file_guard) = tracing_appender::non_blocking(file_appender);
|
let (file_appender_nb, _file_guard) = tracing_appender::non_blocking(file_appender);
|
||||||
let (stdout_nb, _stdout_guard) = tracing_appender::non_blocking(std::io::stdout());
|
let (stdout_nb, _stdout_guard) = tracing_appender::non_blocking(std::io::stdout());
|
||||||
|
|
||||||
logging_guards.push(_file_guard);
|
logging_guards.push(_file_guard);
|
||||||
logging_guards.push(_stdout_guard);
|
logging_guards.push(_stdout_guard);
|
||||||
|
|
||||||
// only allow logs from the registry
|
// TODO: Is there a way for this to be less ugly?
|
||||||
tracing_subscriber::registry()
|
// Get json or text layers
|
||||||
.with(tracing_subscriber::fmt::layer()
|
let (json_a, json_b, plain_a, plain_b) = match logc.format {
|
||||||
.with_writer(file_appender_nb)
|
config::LogFormat::Json => (
|
||||||
.with_writer(stdout_nb)
|
Some(
|
||||||
//.json()
|
tracing_subscriber::fmt::layer()
|
||||||
|
.with_writer(file_appender_nb)
|
||||||
|
.json()
|
||||||
|
),
|
||||||
|
Some(
|
||||||
|
tracing_subscriber::fmt::layer()
|
||||||
|
.with_writer(stdout_nb)
|
||||||
|
.json()
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
None
|
||||||
|
),
|
||||||
|
config::LogFormat::Human => (
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Some(
|
||||||
|
tracing_subscriber::fmt::layer()
|
||||||
|
.with_writer(file_appender_nb)
|
||||||
|
),
|
||||||
|
Some(
|
||||||
|
tracing_subscriber::fmt::layer()
|
||||||
|
.with_writer(stdout_nb)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.with(filter::Targets::new()
|
};
|
||||||
.with_target("orca_registry", config.log_level)
|
|
||||||
|
// Change filter to only log orca_registry or everything
|
||||||
|
let targets_filter = if logc.extra_logging {
|
||||||
|
filter::Targets::new()
|
||||||
|
.with_default(logc.level)
|
||||||
|
} else {
|
||||||
|
filter::Targets::new()
|
||||||
|
.with_target("orca_registry", logc.level)
|
||||||
.with_default(LevelFilter::INFO)
|
.with_default(LevelFilter::INFO)
|
||||||
)
|
};
|
||||||
.init();
|
|
||||||
} else {
|
// Get env filter if specified
|
||||||
// allow all logs from any crates
|
let env_filter = if let Some(env_filter) = &logc.env_filter {
|
||||||
tracing_subscriber::fmt()
|
Some(EnvFilter::from_str(env_filter).unwrap())
|
||||||
.with_max_level(config.log_level)
|
} else { None };
|
||||||
|
|
||||||
|
tracing_subscriber::registry()
|
||||||
|
.with(json_a)
|
||||||
|
.with(json_b)
|
||||||
|
.with(plain_a)
|
||||||
|
.with(plain_b)
|
||||||
|
.with(targets_filter)
|
||||||
|
.with(env_filter)
|
||||||
.init();
|
.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,11 +176,13 @@ async fn main() -> anyhow::Result<()> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a database file if it doesn't exist already
|
// Create a database file if it doesn't exist already
|
||||||
if !Path::new(&sqlite_config.path).exists() {
|
let sqlite_path = path_relative_to(&config.registry_path, &sqlite_config.path);
|
||||||
|
debug!("sqlite path: {:?}", sqlite_path);
|
||||||
|
if !Path::new(&sqlite_path).exists() {
|
||||||
File::create(&sqlite_config.path).await?;
|
File::create(&sqlite_config.path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let connection_options = SqliteConnectOptions::from_str(&format!("sqlite://{}", &sqlite_config.path))?
|
let connection_options = SqliteConnectOptions::from_str(&format!("sqlite://{}", sqlite_path.as_os_str().to_str().unwrap()))?
|
||||||
.journal_mode(SqliteJournalMode::Wal);
|
.journal_mode(SqliteJournalMode::Wal);
|
||||||
let pool = SqlitePoolOptions::new()
|
let pool = SqlitePoolOptions::new()
|
||||||
.max_connections(15)
|
.max_connections(15)
|
||||||
|
@ -155,13 +213,11 @@ async fn main() -> anyhow::Result<()> {
|
||||||
let app_addr = SocketAddr::from_str(&format!("{}:{}", config.listen_address, config.listen_port))?;
|
let app_addr = SocketAddr::from_str(&format!("{}:{}", config.listen_address, config.listen_port))?;
|
||||||
|
|
||||||
let tls_config = config.tls.clone();
|
let tls_config = config.tls.clone();
|
||||||
|
let registry_path = config.registry_path.clone();
|
||||||
let state = Arc::new(AppState::new(pool, storage_driver, config, auth_driver));
|
let state = Arc::new(AppState::new(pool, storage_driver, config, auth_driver));
|
||||||
|
|
||||||
//let auth_middleware = axum::middleware::from_fn_with_state(state.clone(), auth::require_auth);
|
|
||||||
let auth_middleware = axum::middleware::from_fn_with_state(state.clone(), auth::check_auth);
|
let auth_middleware = axum::middleware::from_fn_with_state(state.clone(), auth::check_auth);
|
||||||
let path_middleware = axum::middleware::from_fn(change_request_paths);
|
let path_middleware = axum::middleware::from_fn(change_request_paths);
|
||||||
|
|
||||||
//let debug_middleware = axum::middleware::from_fn(extreme_debug_middleware);
|
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/token", routing::get(api::auth::auth_basic_get)
|
.route("/token", routing::get(api::auth::auth_basic_get)
|
||||||
|
@ -190,7 +246,6 @@ async fn main() -> anyhow::Result<()> {
|
||||||
.layer(auth_middleware) // require auth for ALL v2 routes
|
.layer(auth_middleware) // require auth for ALL v2 routes
|
||||||
)
|
)
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
//.layer(debug_middleware)
|
|
||||||
.layer(TraceLayer::new_for_http());
|
.layer(TraceLayer::new_for_http());
|
||||||
|
|
||||||
let layered_app = NormalizePathLayer::trim_trailing_slash().layer(path_middleware.layer(app));
|
let layered_app = NormalizePathLayer::trim_trailing_slash().layer(path_middleware.layer(app));
|
||||||
|
@ -199,7 +254,9 @@ async fn main() -> anyhow::Result<()> {
|
||||||
Some(tls) if tls.enable => {
|
Some(tls) if tls.enable => {
|
||||||
info!("Starting https server, listening on {}", app_addr);
|
info!("Starting https server, listening on {}", app_addr);
|
||||||
|
|
||||||
let config = RustlsConfig::from_pem_file(&tls.cert, &tls.key).await?;
|
let cert_path = path_relative_to(®istry_path, &tls.cert);
|
||||||
|
let key_path = path_relative_to(®istry_path, &tls.key);
|
||||||
|
let config = RustlsConfig::from_pem_file(&cert_path, &key_path).await?;
|
||||||
|
|
||||||
axum_server::bind_rustls(app_addr, config)
|
axum_server::bind_rustls(app_addr, config)
|
||||||
.serve(layered_app.into_make_service())
|
.serve(layered_app.into_make_service())
|
||||||
|
|
Loading…
Reference in New Issue