vapcore_logger/
rotating.rs

1// Copyright 2015-2020 Parity Technologies (UK) Ltd.
2// This file is part of Tetsy Vapory.
3
4// Tetsy Vapory is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Tetsy Vapory is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Tetsy Vapory.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Common log helper functions
18
19use std::env;
20use rlog::LevelFilter;
21use env_logger::Builder as LogBuilder;
22use arrayvec::ArrayVec;
23
24use parking_lot::{RwLock, RwLockReadGuard};
25
26lazy_static! {
27	static ref LOG_DUMMY: () = {
28		let mut builder = LogBuilder::new();
29		builder.filter(None, LevelFilter::Info);
30
31		if let Ok(log) = env::var("RUST_LOG") {
32			builder.parse(&log);
33		}
34
35		if !builder.try_init().is_ok() {
36			println!("logger initialization failed!");
37		}
38	};
39}
40
41/// Intialize log with default settings
42pub fn init_log() {
43	*LOG_DUMMY
44}
45
46const LOG_SIZE : usize = 128;
47
48/// Logger implementation that keeps up to `LOG_SIZE` log elements.
49pub struct RotatingLogger {
50	/// Defined logger levels
51	levels: String,
52	/// Logs array. Latest log is always at index 0
53	logs: RwLock<ArrayVec<[String; LOG_SIZE]>>,
54}
55
56impl RotatingLogger {
57
58	/// Creates new `RotatingLogger` with given levels.
59	/// It does not enforce levels - it's just read only.
60	pub fn new(levels: String) -> Self {
61		RotatingLogger {
62			levels: levels,
63			logs: RwLock::new(ArrayVec::<[_; LOG_SIZE]>::new()),
64		}
65	}
66
67	/// Append new log entry
68	pub fn append(&self, log: String) {
69		let mut logs = self.logs.write();
70		if logs.is_full() {
71			logs.pop();
72		}
73		logs.insert(0, log);
74	}
75
76	/// Return levels
77	pub fn levels(&self) -> &str {
78		&self.levels
79	}
80
81	/// Return logs
82	pub fn logs(&self) -> RwLockReadGuard<ArrayVec<[String; LOG_SIZE]>> {
83		self.logs.read()
84	}
85
86}
87
88#[cfg(test)]
89mod test {
90	use super::RotatingLogger;
91
92	fn logger() -> RotatingLogger {
93		RotatingLogger::new("test".to_owned())
94	}
95
96	#[test]
97	fn should_return_log_levels() {
98		// given
99		let logger = logger();
100
101		// when
102		let levels = logger.levels();
103
104		// then
105		assert_eq!(levels, "test");
106	}
107
108	#[test]
109	fn should_return_latest_logs() {
110		// given
111		let logger = logger();
112
113		// when
114		logger.append("a".to_owned());
115		logger.append("b".to_owned());
116
117		// then
118		let logs = logger.logs();
119		assert_eq!(logs[0], "b".to_owned());
120		assert_eq!(logs[1], "a".to_owned());
121		assert_eq!(logs.len(), 2);
122	}
123}