Skip to content

Commit

Permalink
fix(dgw): size-based log rotation
Browse files Browse the repository at this point in the history
Set a maximum size of 3 MB for each file and a maximum of 10 log files.
With this change, Devolutions Gateway should never consume more than
30 MB for its logs.

Issue: DGW-34
  • Loading branch information
CBenoit committed Mar 4, 2023
1 parent 8546e0e commit 76dc347
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 20 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ default-members = [
[profile.production]
inherits = "release"
lto = true

[patch.crates-io]
tracing-appender = { git = "https://github.com/CBenoit/tracing", rev = "454313f66da3a662" }
2 changes: 1 addition & 1 deletion devolutions-gateway/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl Conf {
let log_file = conf_file
.log_file
.clone()
.unwrap_or_else(|| Utf8PathBuf::from("gateway.log"))
.unwrap_or_else(|| Utf8PathBuf::from("gateway"))
.pipe_ref(|path| normalize_data_path(path, &data_dir));

let jrl_file = conf_file
Expand Down
9 changes: 8 additions & 1 deletion devolutions-gateway/src/http/middlewares/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ impl LogMiddleware {
uri
};

let span = if uri.len() > 512 {
// Truncate long URI to keep log readable and prevent fast growing log file
info_span!("request", request_id = %operation_id, %method, uri = %&uri[..512])
} else {
info_span!("request", request_id = %operation_id, %method, %uri)
};

async move {
let start_time = Instant::now();

Expand All @@ -42,7 +49,7 @@ impl LogMiddleware {

Ok(ctx)
}
.instrument(info_span!("request", request_id = %operation_id, %method, %uri))
.instrument(span)
.await
}
}
31 changes: 18 additions & 13 deletions devolutions-gateway/src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ use tokio::fs;
use tokio::time::{sleep, Duration};
use tracing::metadata::LevelFilter;
use tracing_appender::non_blocking::WorkerGuard;
use tracing_appender::rolling;
use tracing_subscriber::filter::Directive;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{fmt, EnvFilter};

const MAX_BYTES_PER_LOG_FILE: u64 = 3_000_000; // 3 MB
const MAX_LOG_FILES: usize = 10;

pub struct LoggerGuard {
_file_guard: WorkerGuard,
_stdio_guard: WorkerGuard,
Expand All @@ -26,7 +30,7 @@ impl<'a> LogPathCfg<'a> {
if path.is_dir() {
Ok(Self {
folder: path,
prefix: "gateway.log",
prefix: "gateway",
})
} else {
Ok(Self {
Expand All @@ -38,15 +42,16 @@ impl<'a> LogPathCfg<'a> {
}

pub fn init(path: &Utf8Path, filtering_directive: Option<&str>) -> anyhow::Result<LoggerGuard> {
let (file_layer, file_guard) = {
let cfg = LogPathCfg::from_path(path)?;

let file_appender = tracing_appender::rolling::daily(cfg.folder, cfg.prefix);
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let file_layer = fmt::layer().with_writer(non_blocking).with_ansi(false);

(file_layer, guard)
};
let log_cfg = LogPathCfg::from_path(path)?;
let file_appender = rolling::Builder::new()
.rotation(rolling::Rotation::max_bytes(MAX_BYTES_PER_LOG_FILE))
.filename_prefix(log_cfg.prefix)
.filename_suffix("log")
.max_log_files(MAX_LOG_FILES)
.build(log_cfg.folder)
.context("Couldn’t create file appender")?;
let (file_non_blocking, file_guard) = tracing_appender::non_blocking(file_appender);
let file_layer = fmt::layer().with_writer(file_non_blocking).with_ansi(false);

let (non_blocking_stdio, stdio_guard) = tracing_appender::non_blocking(std::io::stdout());
let stdio_layer = fmt::layer().with_writer(non_blocking_stdio);
Expand Down Expand Up @@ -83,7 +88,7 @@ pub fn init(path: &Utf8Path, filtering_directive: Option<&str>) -> anyhow::Resul
#[instrument]
pub async fn log_deleter_task(prefix: &Utf8Path) -> anyhow::Result<()> {
const TASK_INTERVAL: Duration = Duration::from_secs(60 * 60 * 24); // once per day
const MAX_AGE: Duration = Duration::from_secs(60 * 60 * 24 * 10); // 10 days
const MAX_AGE: Duration = Duration::from_secs(60 * 60 * 24 * 90); // 90 days

debug!("Task started");

Expand All @@ -94,7 +99,7 @@ pub async fn log_deleter_task(prefix: &Utf8Path) -> anyhow::Result<()> {
Ok(mut read_dir) => {
while let Ok(Some(entry)) = read_dir.next_entry().await {
match entry.file_name().to_str() {
Some(file_name) if file_name.starts_with(cfg.prefix) => {
Some(file_name) if file_name.starts_with(cfg.prefix) && file_name.contains("log") => {
debug!(file_name, "Found a log file");
match entry
.metadata()
Expand Down Expand Up @@ -143,7 +148,7 @@ pub async fn find_latest_log_file(prefix: &Utf8Path) -> anyhow::Result<std::path

while let Ok(Some(entry)) = read_dir.next_entry().await {
match entry.file_name().to_str() {
Some(file_name) if file_name.starts_with(cfg.prefix) => {
Some(file_name) if file_name.starts_with(cfg.prefix) && file_name.contains("log") => {
debug!(file_name, "Found a log file");
match entry.metadata().await.and_then(|metadata| metadata.modified()) {
Ok(modified) if modified > most_recent_time => {
Expand Down

0 comments on commit 76dc347

Please sign in to comment.