feat: add log-file option (#383)

This commit is contained in:
sigoden 2024-05-11 17:13:31 +08:00 committed by GitHub
parent cb7d417fd3
commit 6b6d69a8ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 64 additions and 16 deletions

View file

@ -32,7 +32,7 @@ lazy_static = "1.4"
uuid = { version = "1.7", features = ["v4", "fast-rng"] }
urlencoding = "2.1"
xml-rs = "0.8"
log = "0.4"
log = { version = "0.4", features = ["std"] }
socket2 = "0.5"
async-stream = "0.3"
walkdir = "2.3"

View file

@ -73,6 +73,7 @@ Options:
--render-spa Serve SPA(Single Page Application)
--assets <path> Set the path to the assets directory for overriding the built-in assets
--log-format <format> Customize http log format
--log-file <file> Specify the file to save logs to, other than stdout/stderr
--compress <level> Set zip compress level [default: low] [possible values: none, low, medium, high]
--completions <shell> Print shell completion script for <shell> [possible values: bash, elvish, fish, powershell, zsh]
--tls-cert <path> Path to an SSL/TLS certificate to serve with HTTPS
@ -329,7 +330,7 @@ All options can be set using environment variables prefixed with `DUFS_`.
--config <file> DUFS_CONFIG=config.yaml
-b, --bind <addrs> DUFS_BIND=0.0.0.0
-p, --port <port> DUFS_PORT=5000
--path-prefix <path> DUFS_PATH_PREFIX=/static
--path-prefix <path> DUFS_PATH_PREFIX=/dufs
--hidden <value> DUFS_HIDDEN=tmp,*.log,*.lock
-a, --auth <rules> DUFS_AUTH="admin:admin@/:rw|@/"
-A, --allow-all DUFS_ALLOW_ALL=true
@ -342,9 +343,10 @@ All options can be set using environment variables prefixed with `DUFS_`.
--render-index DUFS_RENDER_INDEX=true
--render-try-index DUFS_RENDER_TRY_INDEX=true
--render-spa DUFS_RENDER_SPA=true
--assets <path> DUFS_ASSETS=/assets
--assets <path> DUFS_ASSETS=./assets
--log-format <format> DUFS_LOG_FORMAT=""
--compress <compress> DUFS_COMPRESS="low"
--log-file <file> DUFS_LOG_FILE=./dufs.log
--compress <compress> DUFS_COMPRESS=low
--tls-cert <path> DUFS_TLS_CERT=cert.pem
--tls-key <path> DUFS_TLS_KEY=key.pem
```
@ -380,6 +382,7 @@ render-try-index: true
render-spa: true
assets: ./assets/
log-format: '$remote_addr "$request" $status $http_user_agent'
log-file: ./dufs.log
compress: low
tls-cert: tests/data/cert.pem
tls-key: tests/data/key_pkcs1.pem

View file

@ -197,6 +197,15 @@ pub fn build_cli() -> Command {
.value_name("format")
.help("Customize http log format"),
)
.arg(
Arg::new("log-file")
.env("DUFS_LOG_FILE")
.hide_env(true)
.long("log-file")
.value_name("file")
.value_parser(value_parser!(PathBuf))
.help("Specify the file to save logs to, other than stdout/stderr"),
)
.arg(
Arg::new("compress")
.env("DUFS_COMPRESS")
@ -280,6 +289,7 @@ pub struct Args {
#[serde(deserialize_with = "deserialize_log_http")]
#[serde(rename = "log-format")]
pub http_logger: HttpLogger,
pub log_file: Option<PathBuf>,
pub compress: Compress,
pub tls_cert: Option<PathBuf>,
pub tls_key: Option<PathBuf>,
@ -392,6 +402,10 @@ impl Args {
args.http_logger = log_format.parse()?;
}
if let Some(log_file) = matches.get_one::<PathBuf>("log-file") {
args.log_file = Some(log_file.clone());
}
if let Some(compress) = matches.get_one::<Compress>("compress") {
args.compress = *compress;
}

View file

@ -1,8 +1,14 @@
use anyhow::{Context, Result};
use chrono::{Local, SecondsFormat};
use log::{Level, Metadata, Record};
use log::{LevelFilter, SetLoggerError};
use log::{Level, LevelFilter, Metadata, Record};
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::PathBuf;
use std::sync::Mutex;
struct SimpleLogger;
struct SimpleLogger {
file: Option<Mutex<File>>,
}
impl log::Log for SimpleLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
@ -12,10 +18,20 @@ impl log::Log for SimpleLogger {
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
let timestamp = Local::now().to_rfc3339_opts(SecondsFormat::Secs, true);
if record.level() < Level::Info {
eprintln!("{} {} - {}", timestamp, record.level(), record.args());
} else {
println!("{} {} - {}", timestamp, record.level(), record.args());
let text = format!("{} {} - {}", timestamp, record.level(), record.args());
match &self.file {
Some(file) => {
if let Ok(mut file) = file.lock() {
let _ = writeln!(file, "{text}");
}
}
None => {
if record.level() < Level::Info {
eprintln!("{text}");
} else {
println!("{text}");
}
}
}
}
}
@ -23,8 +39,23 @@ impl log::Log for SimpleLogger {
fn flush(&self) {}
}
static LOGGER: SimpleLogger = SimpleLogger;
pub fn init() -> Result<(), SetLoggerError> {
log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Info))
pub fn init(log_file: Option<PathBuf>) -> Result<()> {
let file = match log_file {
None => None,
Some(log_file) => {
let file = OpenOptions::new()
.create(true)
.append(true)
.open(&log_file)
.with_context(|| {
format!("Failed to open the log file at '{}'", log_file.display())
})?;
Some(Mutex::new(file))
}
};
let logger = SimpleLogger { file };
log::set_boxed_logger(Box::new(logger))
.map(|_| log::set_max_level(LevelFilter::Info))
.with_context(|| "Failed to init logger")?;
Ok(())
}

View file

@ -37,7 +37,6 @@ use tokio_rustls::{rustls::ServerConfig, TlsAcceptor};
#[tokio::main]
async fn main() -> Result<()> {
logger::init().map_err(|e| anyhow!("Failed to init logger, {e}"))?;
let cmd = build_cli();
let matches = cmd.get_matches();
if let Some(generator) = matches.get_one::<Shell>("completions") {
@ -46,6 +45,7 @@ async fn main() -> Result<()> {
return Ok(());
}
let mut args = Args::parse(matches)?;
logger::init(args.log_file.clone()).map_err(|e| anyhow!("Failed to init logger, {e}"))?;
let (new_addrs, print_addrs) = check_addrs(&args)?;
args.addrs = new_addrs;
let running = Arc::new(AtomicBool::new(true));