use clap::Parser; use config::AppConfig; use slog::{Drain, OwnedKVList, Record}; #[derive(Parser, Debug)] #[command(name = "gitserver")] #[command(version)] struct Args { #[arg(long, default_value = "info")] log_level: String, } #[tokio::main] async fn main() -> anyhow::Result<()> { let args = Args::parse(); let cfg = AppConfig::load(); let log = build_logger(&args.log_level); let http_handle = tokio::spawn(git::http::run_http(cfg.clone(), log.clone())); let ssh_handle = tokio::spawn(git::ssh::run_ssh(cfg, log.clone())); tokio::select! { result = http_handle => { match result { Ok(Ok(())) => slog::info!(log, "HTTP server stopped"), Ok(Err(e)) => slog::error!(log, "HTTP server error: {}", e), Err(e) => slog::error!(log, "HTTP server task panicked: {}", e), } } result = ssh_handle => { match result { Ok(Ok(())) => slog::info!(log, "SSH server stopped"), Ok(Err(e)) => slog::error!(log, "SSH server error: {}", e), Err(e) => slog::error!(log, "SSH server task panicked: {}", e), } } _ = tokio::signal::ctrl_c() => { slog::info!(log, "received shutdown signal"); } } slog::info!(log, "shutting down"); Ok(()) } fn build_logger(level: &str) -> slog::Logger { let level_filter = match level { "trace" => 0usize, "debug" => 1usize, "info" => 2usize, "warn" => 3usize, "error" => 4usize, _ => 2usize, }; struct StderrDrain(usize); impl Drain for StderrDrain { type Ok = (); type Err = (); #[inline] fn log(&self, record: &Record, _logger: &OwnedKVList) -> Result<(), ()> { let slog_level = match record.level() { slog::Level::Trace => 0, slog::Level::Debug => 1, slog::Level::Info => 2, slog::Level::Warning => 3, slog::Level::Error => 4, slog::Level::Critical => 5, }; if slog_level < self.0 { return Ok(()); } let _ = eprintln!( "{} [{}] {}:{} - {}", chrono::Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ"), record.level().to_string(), record .file() .rsplit_once('/') .map(|(_, s)| s) .unwrap_or(record.file()), record.line(), record.msg(), ); Ok(()) } } let drain = StderrDrain(level_filter); let drain = std::sync::Mutex::new(drain); let drain = slog::Fuse::new(drain); slog::Logger::root(drain, slog::o!()) }