From 8b9ac4b0954529df5c343317ee5223307224303c Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Sun, 25 Jun 2023 15:00:41 +0800
Subject: [PATCH] feature: use LogFileSize and LogFileNumber to rotate the log
 and make __um_obj_create() accept LogFileSize/LogFileNumber

---
 core/bin/plugin/mod.rs   | 61 ++++++++++++++++------------
 core/bin/unit/manager.rs | 25 ++++++++----
 core/lib/unit/umif.rs    |  6 ++-
 libs/basic/src/logger.rs | 88 +++++++++++++++++++++++++++++++---------
 4 files changed, 125 insertions(+), 55 deletions(-)

diff --git a/core/bin/plugin/mod.rs b/core/bin/plugin/mod.rs
index 9b19336..a8f6f24 100644
--- a/core/bin/plugin/mod.rs
+++ b/core/bin/plugin/mod.rs
@@ -475,33 +475,44 @@ impl Plugin {
         unit_type: UnitType,
         target: &str,
         file: &str,
+        file_size: u32,
+        file_number: u32,
     ) -> Result<Box<dyn UnitManagerObj>> {
-        match self.get_lib(unit_type) {
-            Ok(dy_lib) => {
-                #[allow(clippy::type_complexity)]
-                let sym: Result<
-                    Symbol<
-                        fn(level: LevelFilter, target: &str, file: &str) -> *mut dyn UnitManagerObj,
-                    >,
-                > = unsafe {
-                    dy_lib
-                        .lib
-                        .get(b"__um_obj_create")
-                        .map_err(|e| Error::PluginLoad { msg: e.to_string() })
-                };
-                if let Ok(fun) = sym {
-                    let boxed_raw = fun(log::max_level(), target, file);
-                    Ok(unsafe { Box::from_raw(boxed_raw) })
-                } else {
-                    Err(Error::PluginLoad {
-                        msg: format!("The library of {:?} is {:?}", unit_type, sym.err()),
-                    })
-                }
+        let dy_lib = match self.get_lib(unit_type) {
+            Err(_) => {
+                return Err(Error::PluginLoad {
+                    msg: format!("create um, the {unit_type:?} plugin is not exist"),
+                });
             }
-            Err(_) => Err(Error::PluginLoad {
-                msg: format!("create um, the {unit_type:?} plugin is not exist"),
-            }),
-        }
+            Ok(v) => v,
+        };
+
+        type FnType = fn(
+            level: LevelFilter,
+            target: &str,
+            file: &str,
+            file_size: u32,
+            file_number: u32,
+        ) -> *mut dyn UnitManagerObj;
+
+        #[allow(clippy::type_complexity)]
+        let sym: Result<Symbol<FnType>> = unsafe {
+            dy_lib
+                .lib
+                .get(b"__um_obj_create")
+                .map_err(|e| Error::PluginLoad { msg: e.to_string() })
+        };
+        let fun = match sym {
+            Err(_) => {
+                return Err(Error::PluginLoad {
+                    msg: format!("The library of {:?} is {:?}", unit_type, sym.err()),
+                })
+            }
+            Ok(v) => v,
+        };
+
+        let boxed_raw = fun(log::max_level(), target, file, file_size, file_number);
+        Ok(unsafe { Box::from_raw(boxed_raw) })
     }
 
     fn get_lib(&self, unit_type: UnitType) -> Result<Arc<Lib>> {
diff --git a/core/bin/unit/manager.rs b/core/bin/unit/manager.rs
index 492f3f4..f548817 100644
--- a/core/bin/unit/manager.rs
+++ b/core/bin/unit/manager.rs
@@ -1408,15 +1408,24 @@ mod unit_submanager {
 
         fn new_sub(&self, unit_type: UnitType) -> Option<Box<dyn UnitManagerObj>> {
             let um = self.um();
-            let target = um.get_log_target();
-            let file = um.get_log_file();
-            let ret = Plugin::get_instance().create_um_obj(unit_type, target, file);
-            if ret.is_err() {
-                log::info!("create um_obj is not found, type {:?}!", unit_type);
-                return None;
-            }
+            log::info!(
+                "Creating UnitManagerObj for {:?} by __um_obj_create()",
+                unit_type
+            );
+            let sub = match Plugin::get_instance().create_um_obj(
+                unit_type,
+                um.get_log_target(),
+                um.get_log_file(),
+                um.get_log_file_size(),
+                um.get_log_file_number(),
+            ) {
+                Err(_) => {
+                    log::info!("__um_obj_create() of {:?} is not found", unit_type);
+                    return None;
+                }
+                Ok(v) => v,
+            };
 
-            let sub = ret.unwrap();
             let reli = um.reliability();
             sub.attach_um(um);
             sub.attach_reli(reli);
diff --git a/core/lib/unit/umif.rs b/core/lib/unit/umif.rs
index c41c211..a000a3d 100644
--- a/core/lib/unit/umif.rs
+++ b/core/lib/unit/umif.rs
@@ -250,9 +250,11 @@ macro_rules! declure_umobj_plugin {
         pub fn __um_obj_create(
             level: LevelFilter,
             target: &str,
-            file: &str,
+            file_path: &str,
+            file_size: u32,
+            file_number: u32,
         ) -> *mut dyn $crate::unit::UnitManagerObj {
-            logger::init_log_for_subum($name, level, target, file);
+            logger::init_log_for_subum($name, level, target, file_path, file_size, file_number);
             let construcotr: fn() -> $unit_type = $constructor;
             let obj = construcotr();
             let boxed: Box<dyn $crate::unit::UnitManagerObj> = Box::new(obj);
diff --git a/libs/basic/src/logger.rs b/libs/basic/src/logger.rs
index 2f24d25..0bc15bb 100644
--- a/libs/basic/src/logger.rs
+++ b/libs/basic/src/logger.rs
@@ -15,7 +15,12 @@ use log::{LevelFilter, Log};
 use log4rs::{
     append::{
         console::{ConsoleAppender, Target},
-        file::FileAppender,
+        rolling_file::{
+            policy::compound::{
+                roll::fixed_window::FixedWindowRoller, trigger::size::SizeTrigger, CompoundPolicy,
+            },
+            RollingFileAppender,
+        },
         Append,
     },
     config::{Appender, Config, Logger, Root},
@@ -78,13 +83,20 @@ impl log::Log for SysLogger {
     fn flush(&self) {}
 }
 
-fn append_log(app_name: &str, level: LevelFilter, target: &str, file_path: Option<&str>) {
+fn append_log(
+    app_name: &str,
+    level: LevelFilter,
+    target: &str,
+    file_path: &str,
+    file_size: u32,
+    file_number: u32,
+) {
     if target == "syslog" {
         let _ = log::set_boxed_logger(Box::new(SysLogger));
         log::set_max_level(level);
         return;
     }
-    let config = build_log_config(app_name, level, target, file_path);
+    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);
     let _ = log::set_boxed_logger(Box::new(LogPlugin(logger)));
@@ -99,12 +111,18 @@ fn append_log(app_name: &str, level: LevelFilter, target: &str, file_path: Optio
 /// target: log target
 ///
 /// file_path: file path if the target is set to file
-pub fn init_log_for_subum(app_name: &str, level: LevelFilter, target: &str, file: &str) {
-    let file = if file.is_empty() { None } else { Some(file) };
+pub fn init_log_for_subum(
+    app_name: &str,
+    level: LevelFilter,
+    target: &str,
+    file_path: &str,
+    file_size: u32,
+    file_number: u32,
+) {
     /* We should avoid calling init_log here, or we will get many "attempted
      * to set a logger after the logging system was already initialized" error
      * message. */
-    append_log(app_name, level, target, file);
+    append_log(app_name, level, target, file_path, file_size, file_number);
 }
 
 /// Init and set the log target to console
@@ -113,7 +131,7 @@ pub fn init_log_for_subum(app_name: &str, level: LevelFilter, target: &str, file
 ///
 /// level: maximum log level
 pub fn init_log_to_console(app_name: &str, level: LevelFilter) {
-    init_log(app_name, level, "console", None);
+    init_log(app_name, level, "console", "", 0, 0);
 }
 
 /// Init and set the log target to file
@@ -123,8 +141,14 @@ pub fn init_log_to_console(app_name: &str, level: LevelFilter) {
 /// level: maximum log level
 ///
 /// file_path: log to which file
-pub fn init_log_to_file(app_name: &str, level: LevelFilter, file_path: &str) {
-    init_log(app_name, level, "file", Some(file_path));
+pub fn init_log_to_file(
+    app_name: &str,
+    level: LevelFilter,
+    file_path: &str,
+    file_size: u32,
+    file_number: u32,
+) {
+    init_log(app_name, level, "file", file_path, file_size, file_number);
 }
 
 /// Init and set the logger
@@ -136,13 +160,20 @@ pub fn init_log_to_file(app_name: &str, level: LevelFilter, file_path: &str) {
 /// target: log target
 ///
 /// file_path: file path if the target is set to file
-pub fn init_log(app_name: &str, level: LevelFilter, target: &str, file_path: Option<&str>) {
+pub fn init_log(
+    app_name: &str,
+    level: LevelFilter,
+    target: &str,
+    file_path: &str,
+    file_size: u32,
+    file_number: u32,
+) {
     if target == "syslog" {
         let _ = log::set_boxed_logger(Box::new(SysLogger));
         log::set_max_level(level);
         return;
     }
-    let config = build_log_config(app_name, level, target, file_path);
+    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 {
         println!("{e}");
@@ -153,12 +184,18 @@ fn build_log_config(
     app_name: &str,
     level: LevelFilter,
     target: &str,
-    file: Option<&str>,
+    file_path: &str,
+    file_size: u32,
+    file_number: u32,
 ) -> Config {
     let mut target = target;
     /* If the file is configured to None, use console forcely. */
-    if file.is_none() && target == "file" {
-        println!("LogTarget is configured to `file`, but LogFile is not configured, changing the LogTarget to `console`");
+    if (file_path.is_empty() || file_size == 0 || file_number == 0) && target == "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: \
+             {file_number}"
+        );
         target = "console";
     }
     let encoder = Box::new(PatternEncoder::new(LOG_PATTERN));
@@ -169,12 +206,23 @@ fn build_log_config(
                 .target(Target::Stdout)
                 .build(),
         ),
-        "file" => Box::new(
-            FileAppender::builder()
-                .encoder(encoder)
-                .build(file.unwrap())
-                .unwrap(),
-        ),
+        "file" => {
+            let pattern = file_path.to_string() + &".{}";
+            let policy = Box::new(CompoundPolicy::new(
+                Box::new(SizeTrigger::new(file_size as u64 * 1024)),
+                Box::new(
+                    FixedWindowRoller::builder()
+                        .build(&pattern, file_number)
+                        .unwrap(),
+                ),
+            ));
+            Box::new(
+                RollingFileAppender::builder()
+                    .encoder(encoder)
+                    .build(file_path, policy)
+                    .unwrap(),
+            )
+        }
         _ => Box::new(
             ConsoleAppender::builder()
                 .encoder(encoder)
-- 
2.33.0

