1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 use std::io::Write;
16 use std::path::Path;
17 use std::sync::{Arc, Mutex};
18 use std::time::SystemTime;
19
20 use hdc::config;
21
22 // #[derive(Default)]
23
24 pub struct LoggerMeta {
25 stdout_require: bool,
26 run_in_server: bool, // scrolling dump only by server
27 current_size: usize,
28 log_file: std::path::PathBuf,
29 log_level: log::LevelFilter,
30 }
31
32 impl Default for LoggerMeta {
defaultnull33 fn default() -> Self {
34 Self {
35 stdout_require: Default::default(),
36 run_in_server: Default::default(),
37 current_size: Default::default(),
38 log_file: Default::default(),
39 log_level: log::LevelFilter::Debug,
40 }
41 }
42 }
43
44 type LoggerMeta_ = Arc<Mutex<LoggerMeta>>;
45
46 struct HostLoggerMeta {}
47 impl HostLoggerMeta {
get_instancenull48 fn get_instance() -> LoggerMeta_ {
49 static mut LOGGER_META: Option<LoggerMeta_> = None;
50 unsafe {
51 LOGGER_META
52 .get_or_insert_with(|| Arc::new(Mutex::new(LoggerMeta::default())))
53 .clone()
54 }
55 }
56
initnull57 fn init(run_in_server: bool, spawned_server: bool, log_level: log::LevelFilter) {
58 let instance = Self::get_instance();
59 let Ok(mut meta) = instance.lock() else {
60 println!("init lock error");
61 return;
62 };
63 meta.log_level = log_level;
64 if run_in_server && !spawned_server {
65 meta.stdout_require = true;
66 }
67 meta.run_in_server = run_in_server;
68 meta.log_file = Path::new(&std::env::temp_dir())
69 .join(config::LOG_FILE_NAME.to_string() + config::LOG_TAIL_NAME);
70 if run_in_server {
71 Self::dump_log_file(config::LOG_BAK_NAME, meta.log_level);
72 if let Err(err) = std::fs::File::create(&meta.log_file) {
73 println!("File::create failed, {}, {err}", meta.log_file.display());
74 }
75 }
76 }
77
write_lognull78 fn write_log(content: String) {
79 let instance = Self::get_instance();
80 let mut meta = instance.lock().unwrap();
81 if meta.run_in_server && meta.current_size > config::LOG_FILE_SIZE {
82 meta.current_size = 0;
83 Self::dump_log_file(config::LOG_CACHE_NAME, meta.log_level);
84 std::fs::File::create(&meta.log_file).unwrap();
85 }
86 meta.current_size += content.len();
87 if let Ok(mut f) = std::fs::File::options().append(true).open(&meta.log_file) {
88 writeln!(&mut f, "{}", content).unwrap();
89 }
90 if meta.stdout_require {
91 println!("{}", content);
92 }
93 }
94
dump_log_filenull95 fn dump_log_file(file_type: &str, log_level: log::LevelFilter) {
96 let file_path = Path::new(&std::env::temp_dir())
97 .join(config::LOG_FILE_NAME.to_string() + config::LOG_TAIL_NAME);
98 let ts = humantime::format_rfc3339_millis(SystemTime::now())
99 .to_string()
100 .replace(':', "");
101 let file_cache_path = if log_level == log::LevelFilter::Trace {
102 Path::new(&std::env::temp_dir())
103 .join(file_type.to_string() + &ts[..19] + config::LOG_TAIL_NAME)
104 } else {
105 Path::new(&std::env::temp_dir()).join(file_type.to_string() + config::LOG_TAIL_NAME)
106 };
107 if file_path.exists() {
108 if let Err(err) = std::fs::rename(&file_path, file_cache_path) {
109 hdc::error!("rename failed, {err}");
110 }
111 }
112 }
113
get_running_modenull114 fn get_running_mode() -> String {
115 let instance = Self::get_instance();
116 let Ok(meta) = instance.lock() else {
117 return "".to_string();
118 };
119 if meta.run_in_server {
120 "server".to_string()
121 } else {
122 "client".to_string()
123 }
124 }
125 }
126
127 struct SimpleHostLogger;
128 impl log::Log for SimpleHostLogger {
enablednull129 fn enabled(&self, metadata: &log::Metadata) -> bool {
130 metadata.level() <= log::max_level()
131 }
lognull132 fn log(&self, record: &log::Record) {
133 if self.enabled(record.metadata()) {
134 let ts = humantime::format_rfc3339_millis(SystemTime::now()).to_string();
135 let level = &record.level().to_string()[..1];
136 let Some(file) = record.file() else {
137 println!("Get record file failed");
138 return;
139 };
140 // cargo编译下的文件目录可能存在\\的目录,需要通过编译宏隔离
141 #[cfg(target_os = "windows")]
142 let file = file.replace('\\', "/");
143 let running_mode = HostLoggerMeta::get_running_mode();
144 let content = format!(
145 "{} {} {} [{}] {}:{} - {}",
146 &ts[..10],
147 &ts[11..23],
148 level,
149 running_mode,
150 file.split_once('/').unwrap_or(("", "")).1,
151 record.line().unwrap_or_default(),
152 record.args()
153 );
154 HostLoggerMeta::write_log(content);
155 }
156 }
flushnull157 fn flush(&self) {}
158 }
159
160 static LOGGER: SimpleHostLogger = SimpleHostLogger;
161
logger_initnull162 pub fn logger_init(log_level: log::LevelFilter, run_in_server: bool, spawned_server: bool) {
163 HostLoggerMeta::init(run_in_server, spawned_server, log_level);
164 if let Err(err) = log::set_logger(&LOGGER) {
165 println!("log::set_logger failed, {err}");
166 return;
167 }
168 log::set_max_level(log_level);
169 }
170