logger.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use log::{LevelFilter, Log, Metadata, Record};
  19. use simplelog::{CombinedLogger, Config, ConfigBuilder, SharedLogger};
  20. #[cfg(feature = "enable-filelog")]
  21. use {
  22. file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate},
  23. simplelog::WriteLogger,
  24. std::{path::PathBuf, thread::sleep, time::Duration},
  25. };
  26. // Measured in bytes
  27. #[cfg(feature = "enable-filelog")]
  28. const LOGFILE_MAXSIZE: usize = 5_000_000;
  29. static MUTED_TARGETS: &[&'static str] = &[
  30. "sled",
  31. "rustls",
  32. "net::channel",
  33. "net::message_publisher",
  34. "net::hosts",
  35. "net::protocol",
  36. "net::session",
  37. "net::outbound_session",
  38. "net::tcp",
  39. "net::p2p::seed",
  40. "net::refinery::handshake_node()",
  41. "system::publisher",
  42. "event_graph::dag_sync()",
  43. "event_graph::dag_insert()",
  44. "event_graph::protocol",
  45. ];
  46. static ALLOW_TRACE: &[&'static str] = &["ui", "app", "gfx"];
  47. #[cfg(all(target_os = "android", feature = "enable-filelog"))]
  48. fn logfile_path() -> PathBuf {
  49. use crate::android::get_external_storage_path;
  50. get_external_storage_path().join("darkfi-app.log")
  51. }
  52. #[cfg(all(not(target_os = "android"), feature = "enable-filelog"))]
  53. fn logfile_path() -> PathBuf {
  54. dirs::cache_dir().unwrap().join("darkfi/darkfi-app.log")
  55. }
  56. #[cfg(target_os = "android")]
  57. mod android {
  58. use super::*;
  59. use android_logger::{AndroidLogger, Config as AndroidConfig};
  60. /// Implements a wrapper around the android logger so it's compatible with simplelog.
  61. pub struct AndroidLoggerWrapper {
  62. logger: AndroidLogger,
  63. level: LevelFilter,
  64. config: Config,
  65. }
  66. impl AndroidLoggerWrapper {
  67. pub fn new(level: LevelFilter, config: Config) -> Box<Self> {
  68. let cfg = AndroidConfig::default().with_max_level(level).with_tag("darkfi");
  69. Box::new(Self { logger: AndroidLogger::new(cfg), level, config })
  70. }
  71. }
  72. impl Log for AndroidLoggerWrapper {
  73. fn enabled(&self, metadata: &Metadata<'_>) -> bool {
  74. let target = metadata.target();
  75. for allow in ALLOW_TRACE {
  76. if target.starts_with(allow) {
  77. return true
  78. }
  79. }
  80. for muted in MUTED_TARGETS {
  81. if target.starts_with(muted) {
  82. return false
  83. }
  84. }
  85. if metadata.level() > self.level {
  86. return false
  87. }
  88. self.logger.enabled(metadata)
  89. }
  90. fn log(&self, record: &Record<'_>) {
  91. if self.enabled(record.metadata()) {
  92. self.logger.log(record)
  93. }
  94. }
  95. fn flush(&self) {}
  96. }
  97. impl SharedLogger for AndroidLoggerWrapper {
  98. fn level(&self) -> LevelFilter {
  99. self.level
  100. }
  101. fn config(&self) -> Option<&Config> {
  102. Some(&self.config)
  103. }
  104. fn as_log(self: Box<Self>) -> Box<dyn Log> {
  105. Box::new(*self)
  106. }
  107. }
  108. }
  109. #[cfg(not(target_os = "android"))]
  110. mod desktop {
  111. use super::*;
  112. use simplelog::{ColorChoice, TermLogger, TerminalMode};
  113. /// Implements a wrapper around the android logger so it's compatible with simplelog.
  114. pub struct CustomTermLogger {
  115. logger: TermLogger,
  116. }
  117. impl CustomTermLogger {
  118. pub fn new(_level: LevelFilter, cfg: Config) -> Box<Self> {
  119. let logger =
  120. TermLogger::new(LevelFilter::Trace, cfg, TerminalMode::Mixed, ColorChoice::Auto);
  121. Box::new(Self { logger: *logger })
  122. }
  123. }
  124. impl Log for CustomTermLogger {
  125. fn enabled(&self, metadata: &Metadata<'_>) -> bool {
  126. let target = metadata.target();
  127. for allow in ALLOW_TRACE {
  128. if target.starts_with(allow) {
  129. return true
  130. }
  131. }
  132. for muted in MUTED_TARGETS {
  133. if target.starts_with(muted) && metadata.level() > LevelFilter::Info {
  134. return false
  135. }
  136. }
  137. if metadata.level() > self.level() {
  138. return false
  139. }
  140. self.logger.enabled(metadata)
  141. }
  142. fn log(&self, record: &Record<'_>) {
  143. if self.enabled(record.metadata()) {
  144. self.logger.log(record)
  145. }
  146. }
  147. fn flush(&self) {
  148. self.logger.flush()
  149. }
  150. }
  151. impl SharedLogger for CustomTermLogger {
  152. fn level(&self) -> LevelFilter {
  153. self.logger.level()
  154. }
  155. fn config(&self) -> Option<&Config> {
  156. self.logger.config()
  157. }
  158. fn as_log(self: Box<Self>) -> Box<dyn Log> {
  159. Box::new(self.logger).as_log()
  160. }
  161. }
  162. }
  163. pub fn setup_logging() {
  164. // https://gist.github.com/jb-alvarado/6e223936446bb88cd9a93e7028fc2c4f
  165. let mut loggers: Vec<Box<dyn SharedLogger>> = vec![];
  166. let mut cfg = ConfigBuilder::new();
  167. #[cfg(feature = "enable-filelog")]
  168. {
  169. let mut cfg = cfg.clone();
  170. cfg.add_filter_ignore_str("sled");
  171. cfg.add_filter_ignore_str("rustls");
  172. let cfg = cfg.build();
  173. let log_file = FileRotate::new(
  174. logfile_path(),
  175. AppendCount::new(0),
  176. ContentLimit::BytesSurpassed(LOGFILE_MAXSIZE),
  177. Compression::None,
  178. #[cfg(unix)]
  179. None,
  180. );
  181. let file_logger = WriteLogger::new(LevelFilter::Trace, cfg, log_file);
  182. loggers.push(file_logger);
  183. }
  184. let cfg = cfg.build();
  185. #[cfg(target_os = "android")]
  186. {
  187. use android::AndroidLoggerWrapper;
  188. let android_logger = AndroidLoggerWrapper::new(LevelFilter::Trace, cfg);
  189. loggers.push(android_logger);
  190. }
  191. #[cfg(not(target_os = "android"))]
  192. {
  193. use desktop::CustomTermLogger;
  194. // For ANSI colors in the terminal
  195. colored::control::set_override(true);
  196. let term_logger = CustomTermLogger::new(LevelFilter::Debug, cfg);
  197. loggers.push(term_logger);
  198. }
  199. CombinedLogger::init(loggers).expect("logger");
  200. }