sysmaster/backport-feature-use-our-own-file-logger.patch
huyubiao 8936fa02c5 sync patches from upstream,change the path of the unit,modify permissions for some directories and files
(cherry picked from commit ce9ff469b57f60130621bc293783bd3ac1fc92f2)
2023-08-05 18:15:53 +08:00

284 lines
8.7 KiB
Diff

From f70fcf7c4389ee9eb81f62e8b763e095ed50aea9 Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Tue, 27 Jun 2023 20:15:04 +0800
Subject: [PATCH] feature: use our own file logger
This implements a simple file logger which supports log rorating. we set
the log file mode to 600 forcely
---
libs/basic/Cargo.toml | 1 +
libs/basic/src/logger.rs | 203 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 202 insertions(+), 2 deletions(-)
diff --git a/libs/basic/Cargo.toml b/libs/basic/Cargo.toml
index 7557d37..6ee7162 100644
--- a/libs/basic/Cargo.toml
+++ b/libs/basic/Cargo.toml
@@ -21,6 +21,7 @@ lazy_static = "1.4.0"
bitflags = "1.3.2"
pkg-config = "0.3"
rand = "0.4.6"
+time = {version = "=0.3.10", features = ["formatting", "macros"] }
[dev-dependencies]
libtests = { path = "../libtests" }
diff --git a/libs/basic/src/logger.rs b/libs/basic/src/logger.rs
index 56def43..3bf579b 100644
--- a/libs/basic/src/logger.rs
+++ b/libs/basic/src/logger.rs
@@ -11,6 +11,14 @@
// See the Mulan PSL v2 for more details.
//!
+use std::{
+ fs::{File, OpenOptions},
+ io::Write,
+ os::unix::prelude::OpenOptionsExt,
+ path::{Path, PathBuf},
+ sync::Mutex,
+};
+
use log::{LevelFilter, Log};
use log4rs::{
append::{
@@ -27,6 +35,7 @@ use log4rs::{
encode::pattern::PatternEncoder,
};
use nix::libc;
+use time::UtcOffset;
/// sysmaster log parttern:
///
@@ -83,6 +92,174 @@ impl log::Log for SysLogger {
fn flush(&self) {}
}
+struct FileLogger {
+ level: log::Level,
+ file_path: PathBuf,
+ #[allow(dead_code)]
+ file_mode: u32,
+ file_number: u32,
+ max_size: u32,
+ file: Mutex<File>,
+}
+
+impl log::Log for FileLogger {
+ fn enabled(&self, metadata: &log::Metadata) -> bool {
+ metadata.level() <= self.level
+ }
+
+ fn log(&self, record: &log::Record) {
+ if !self.enabled(record.metadata()) {
+ return;
+ }
+ let current_size: u32;
+ {
+ let mut file = self.file.lock().unwrap();
+ self.write(
+ &mut file,
+ record.module_path().unwrap(),
+ record.args().to_string(),
+ );
+ current_size = file.metadata().unwrap().len() as u32;
+ /* file is automatically unlocked. */
+ }
+ if current_size > self.max_size {
+ self.rotate();
+ let file = self.file.lock().unwrap();
+ let _ = file.set_len(0);
+ }
+ }
+
+ fn flush(&self) {
+ let mut file = self.file.lock().unwrap();
+ let _ = file.flush();
+ }
+}
+
+impl FileLogger {
+ fn file_open(file_path: &PathBuf, file_mode: u32) -> File {
+ OpenOptions::new()
+ .write(true)
+ .create(true)
+ .append(true)
+ .mode(file_mode)
+ .open(file_path)
+ .unwrap()
+ }
+
+ fn mv_file_in_dir(src: &str, dst: Option<&str>, dir: &Path) {
+ let src = dir.join(src);
+ if dst.is_none() {
+ let _ = std::fs::remove_file(src);
+ return;
+ }
+ let dst = dir.join(dst.unwrap());
+ let _ = std::fs::rename(src, dst);
+ }
+
+ fn cp_file_in_dir(src: &str, dst: &str, dir: &Path) {
+ let src = dir.join(src);
+ let dst = dir.join(dst);
+ let _ = std::fs::copy(src, dst);
+ }
+
+ fn new(
+ level: log::Level,
+ file_path: PathBuf,
+ file_mode: u32,
+ max_size: u32,
+ file_number: u32,
+ ) -> Self {
+ let file = Self::file_open(&file_path, file_mode);
+ Self {
+ level,
+ file_path,
+ file_mode,
+ file_number,
+ max_size: max_size * 1024,
+ file: Mutex::new(file),
+ }
+ }
+
+ fn write(&self, file: &mut File, module: &str, msg: String) {
+ let now = time::OffsetDateTime::now_utc().to_offset(UtcOffset::UTC);
+ let format =
+ time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
+ let now = now.format(&format).unwrap();
+
+ /* 1. Write time */
+ if let Err(e) = file.write(format!("{now} ").as_bytes()) {
+ println!("Failed to log time message: {e}");
+ return;
+ }
+
+ /* 2. Write module */
+ if let Err(e) = file.write((module.to_string() + " ").as_bytes()) {
+ println!("Failed to log module message: {e}");
+ return;
+ }
+
+ /* 3. Write message */
+ if let Err(e) = file.write((msg + "\n").as_bytes()) {
+ println!("Failed to log message: {e}");
+ return;
+ }
+ }
+
+ fn rotate(&self) {
+ let dir = self.file_path.parent().unwrap();
+ let file_name = self
+ .file_path
+ .file_name()
+ .unwrap()
+ .to_string_lossy()
+ .to_string();
+ let file_name_dot = String::from(&file_name) + ".";
+ let mut num_list: Vec<usize> = Vec::new();
+
+ for de in dir.read_dir().unwrap() {
+ let de = match de {
+ Err(_) => continue,
+ Ok(v) => v,
+ };
+ if !de.file_type().unwrap().is_file() {
+ continue;
+ }
+ let de_file_name = de.file_name().to_string_lossy().to_string();
+ let rotated_num = de_file_name.trim_start_matches(&file_name_dot);
+ let rotated_num = match rotated_num.parse::<usize>() {
+ Err(_) => {
+ continue;
+ }
+ Ok(v) => v,
+ };
+ num_list.push(rotated_num);
+ }
+
+ num_list.sort();
+
+ /* 1. delete surplus rotated file */
+ /* We only keep (file_number - 1) rotated files, because we will generate a new one later. */
+ let file_number = self.file_number as usize;
+ for i in file_number - 1..num_list.len() {
+ let src = String::from(&file_name_dot) + &num_list[i].to_string();
+ Self::mv_file_in_dir(&src, None, dir);
+ }
+
+ let end = std::cmp::min(num_list.len(), file_number);
+ /* 2. {sysmaster.log.1, sysmaster.log.2, ...} => {sysmaster.log.2, sysmaster.log.3, ...} */
+ for i in (0..end).rev() {
+ let src = String::from(&file_name_dot) + &num_list[i].to_string();
+ let dst = String::from(&file_name_dot) + &(num_list[i] + 1).to_string();
+ Self::mv_file_in_dir(&src, Some(&dst), dir);
+ }
+
+ /* 3. **copy** sysmaster.log => sysmaster.log.1 */
+ let src = String::from(&file_name);
+ let dst = String::from(&file_name_dot) + "1";
+ Self::cp_file_in_dir(&src, &dst, dir);
+ }
+}
+
fn append_log(
app_name: &str,
level: LevelFilter,
@@ -96,6 +273,17 @@ fn append_log(
log::set_max_level(level);
return;
}
+ if target == "file" {
+ log::set_max_level(level);
+ let _ = log::set_boxed_logger(Box::new(FileLogger::new(
+ log::Level::Debug,
+ PathBuf::from(file_path),
+ 0o600,
+ file_size,
+ file_number,
+ )));
+ return;
+ }
let config = build_log_config(app_name, level, target, file_path, file_size, file_number);
let logger = log4rs::Logger::new(config);
log::set_max_level(level);
@@ -173,6 +361,17 @@ pub fn init_log(
log::set_max_level(level);
return;
}
+ if target == "file" {
+ let _ = log::set_boxed_logger(Box::new(FileLogger::new(
+ log::Level::Debug,
+ PathBuf::from(&file_path),
+ 0o600,
+ file_size,
+ file_number,
+ )));
+ log::set_max_level(level);
+ return;
+ }
let config = build_log_config(app_name, level, target, file_path, file_size, file_number);
let r = log4rs::init_config(config);
if let Err(e) = r {
@@ -190,7 +389,7 @@ fn build_log_config(
) -> Config {
let mut target = target;
/* If the file is configured to None, use console forcely. */
- if (file_path.is_empty() || file_size == 0 || file_number == 0) && target == "file" {
+ if (file_path.is_empty() || file_size == 0 || file_number == 0) && target == "rolling_file" {
println!(
"LogTarget is configured to `file`, but configuration is invalid, changing the \
LogTarget to `console`, file: {file_path}, file_size: {file_size}, file_number: \
@@ -206,7 +405,7 @@ fn build_log_config(
.target(Target::Stdout)
.build(),
),
- "file" => {
+ "rolling_file" => {
let pattern = file_path.to_string() + ".{}";
let policy = Box::new(CompoundPolicy::new(
Box::new(SizeTrigger::new(file_size as u64 * 1024)),
--
2.33.0