Skip to content

Commit

Permalink
complete rotate test
Browse files Browse the repository at this point in the history
  • Loading branch information
AliceLanniste committed May 26, 2020
1 parent 97c77e3 commit e76a743
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 90 deletions.
189 changes: 102 additions & 87 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use crate::db::filename::{generate_filename, FileType};
use crate::error::Result;
use crate::storage::{File, Storage};


use log::{LevelFilter, Log, Metadata, Record};
use slog::{o, Drain, Level};

Expand All @@ -26,12 +25,11 @@ use std::sync::Mutex;
///
/// See `slog` at https://github.com/slog-rs/slog
/// See `log` at https://github.com/rust-lang/log
///
///

pub fn create_file<S:Storage>(storage:&S,db_path:&str,timestamp:i64) -> Result<S::F> {
let new_path = generate_filename(db_path, FileType::Log, timestamp as u64);
storage.create(new_path)

pub fn create_file<S: Storage>(storage: &S, db_path: &str, timestamp: i64) -> Result<S::F> {
let log_path = generate_filename(db_path, FileType::Log, timestamp as u64);
storage.create(log_path)
}

pub struct Logger {
Expand All @@ -46,10 +44,10 @@ impl Logger {
/// If `inner` is `None`
/// - In dev mode, use a std output
/// - In release mode, use a storage specific file with name `LOG`
pub fn new<S:Storage+Clone+'static>(
pub fn new<S: Storage + Clone + 'static>(
inner: Option<slog::Logger>,
level: LevelFilter,
storage:S,
storage: S,
db_path: &'static str,
) -> Self {
let inner = match inner {
Expand All @@ -62,14 +60,12 @@ impl Logger {
slog::Logger::root(drain, o!())
} else {
// Use a file `Log` to record all logs
// TODO: add file rotation
//db_path 是generate_filename
let file = create_file(&storage, db_path,Local::now().timestamp()).unwrap();
let file_fn = move |path: String| {create_file(&storage,
path.as_str(),Local::now().timestamp())};
let drain =FileBasedDrain::new(file,db_path,
file_fn)
.add_rotator(RotatedFileBySize::new(1));
let file = create_file(&storage, db_path, Local::now().timestamp()).unwrap();
let file_fn = move |path: String| {
create_file(&storage, path.as_str(), Local::now().timestamp())
};
let drain = FileBasedDrain::new(file, db_path, file_fn)
.add_rotator(RotatedFileBySize::new(1));
let drain = slog_async::Async::new(drain).build().fuse();
slog::Logger::root(drain, o!())
}
Expand Down Expand Up @@ -130,56 +126,56 @@ fn log_to_slog_level(level: log::Level) -> Level {
}
}

struct FileBasedDrain<F: File> {
struct FileBasedDrain<F: File> {
inner: Mutex<F>,
rotators: Vec<Box<dyn Rotator>>,
db_path:String,
new_file:Box<dyn Send+Fn(String)->Result<F>>
db_path: String,
new_file: Box<dyn Send + Fn(String) -> Result<F>>,
}

impl<F: File> FileBasedDrain<F> {
fn new<H>(f:F,path:&str,new_file: H) -> Self
where H:'static+Send+Fn(String)->Result<F>
{
impl<F: File> FileBasedDrain<F> {
fn new<H>(f: F, path: &str, new_file: H) -> Self
where
H: 'static + Send + Fn(String) -> Result<F>,
{
FileBasedDrain {
db_path: path.to_string(),
inner: Mutex::new(f),
rotators: vec![],
new_file:Box::new(new_file)
new_file: Box::new(new_file),
}
}


fn add_rotator<R: 'static+Rotator>(mut self, rotator: R) -> Self {
fn add_rotator<R: 'static + Rotator>(mut self, rotator: R) -> Self {
if rotator.is_enabled() {
self.rotators.push(Box::new(rotator));
}
for rotator in (&self).rotators.iter() {
for rotator in self.rotators.iter() {
rotator.prepare(&*self.inner.lock().unwrap()).unwrap();
}
self
}

fn flush(&self) -> Result<()>{
// use crate::storage::file::FileStorage;
// let storage = FileStorage::default();
fn flush(&self) -> Result<()> {
for rotator in self.rotators.iter() {
if rotator.should_rotate() {
// let _ = storage.rename("log/000000.log","log/000000.log");
if rotator.should_rotate() {
let new_file = (self.new_file)(self.db_path.clone()).unwrap();

let mut old_file = self.inner.lock().unwrap();
*old_file =new_file;
*old_file = new_file;

for rotator in self.rotators.iter() {
rotator.on_rotate();
}

return Ok(());
}
}
}

self.inner.lock().unwrap().flush()
}
}
impl<F:File> Drain for FileBasedDrain<F> {
impl<F: File> Drain for FileBasedDrain<F> {
type Ok = ();
type Err = slog::Never;

Expand All @@ -194,23 +190,20 @@ impl<F:File> Drain for FileBasedDrain<F> {
record.msg(),
values
);


for rotator in self.rotators.iter() {
rotator.on_write(by.as_bytes()).unwrap();
for rotator in self.rotators.iter() {
rotator.on_write(by.as_bytes()).unwrap();
}
let _f = self.flush().unwrap();

self.flush().unwrap();

//Ignore errors here
let _ = self.inner.lock().unwrap().write(by.as_bytes());

Ok(())
}
}



trait Rotator: Send {
/// Check if the option is enabled in configuration.
/// Return true if the `rotator` is valid.
Expand All @@ -224,7 +217,7 @@ trait Rotator: Send {

fn on_write(&self, buf: &[u8]) -> Result<()>;
// Call by operator, update rotators' state while the operator execute a rotation.
fn on_rotate(&self) ;
fn on_rotate(&self);
}

struct RotatedFileBySize {
Expand All @@ -245,10 +238,9 @@ impl Rotator for RotatedFileBySize {
fn is_enabled(&self) -> bool {
self.rotation_size != 0
}
fn prepare(&self, file: &dyn File) -> Result<()> {
fn prepare(&self, file: &dyn File) -> Result<()> {
*self.file_size.lock().unwrap() = file.len().unwrap();
Ok(())

}

fn should_rotate(&self) -> bool {
Expand All @@ -259,7 +251,7 @@ impl Rotator for RotatedFileBySize {
Ok(())
}

fn on_rotate(&self) {
fn on_rotate(&self) {
*self.file_size.lock().unwrap() = 0;
}
}
Expand All @@ -268,52 +260,75 @@ impl Rotator for RotatedFileBySize {
mod tests {

use super::*;
use crate::storage::mem::MemStorage;
use crate::storage::file::FileStorage;
use slog::info;
use std::fs;
use std::thread;
use std::time::Duration;
use crate::storage::mem::MemStorage;
use std::path::Path;
use std::thread;
use std::time::Duration;

fn file_exists(file: impl AsRef<Path>,storage:FileStorage) -> bool {
fn file_exists(file: impl AsRef<Path>, storage: impl Storage) -> bool {
storage.exists(file)
}
// #[test]
// fn test_default_logger() {
// let s =MemStorage::default();
// // let s = &'static s;
// let db_path = "test";
// let logger = Logger::new(None, LevelFilter::Debug, s, db_path);
// // Ignore the error if the logger have been set
// let _ = log::set_logger(Box::leak(Box::new(logger)));
// log::set_max_level(LevelFilter::Debug);
// self::info!(,"Hello World");
// // Wait for the async logger print the result
// thread::sleep(Duration::from_millis(100));
// }


#[test]
fn test_rotate_by_size() {
fn test_default_logger() {
let s = MemStorage::default();
// let s = &'static s;
let db_path = "test";
let logger = Logger::new(None, LevelFilter::Debug, s, db_path);
// Ignore the error if the logger have been set
let _ = log::set_logger(Box::leak(Box::new(logger)));
log::set_max_level(LevelFilter::Debug);
log::info!("Hello World");
// Wait for the async logger print the result
thread::sleep(Duration::from_millis(100));
}

#[test]
fn test_rotate_by_size() {
let db_path = "log";

let storage = FileStorage::default();
let _= storage.mkdir_all(db_path);
let storage2 = storage.clone();
let file= create_file(&storage,db_path, 0).unwrap();
let new_path = generate_filename(db_path, FileType::Log, 1 );



let file_fn = move |path: String| {create_file(&storage,
path.as_str(), 1)};

let drain =FileBasedDrain::new(file,db_path, file_fn)
.add_rotator(RotatedFileBySize::new(1));
let drain = slog_async::Async::new(drain).build().fuse();
let _log = slog::Logger::root(drain, o!());
self::info!(_log,"Test log file rotated by size");

assert!(file_exists(new_path,FileStorage::default()));

let _ = storage.mkdir_all(db_path);
let file = create_file(&storage, db_path, 0).unwrap();
let new_path = generate_filename(db_path, FileType::Log, 1);

{
let file_fn = move |path: String| create_file(&storage, path.as_str(), 1);

let drain =
FileBasedDrain::new(file, db_path, file_fn).add_rotator(RotatedFileBySize::new(1));
let drain = slog_async::Async::new(drain).build().fuse();
let _log = slog::Logger::root(drain, o!());
slog::info!(_log, "Test log file rotated by size");
}
assert_eq!(true, file_exists(new_path, FileStorage::default()));
}

#[test]
fn test_not_rotate_by_size() {
let db_path = "norotate";

let storage = FileStorage::default();

let _ = storage.mkdir_all(db_path);
let file = create_file(&storage, db_path, 0).unwrap();
let new_path = generate_filename(db_path, FileType::Log, 1);

{
let file_fn = move |path: String| create_file(&storage, path.as_str(), 1);

let drain = FileBasedDrain::new(file, db_path, file_fn)
.add_rotator(RotatedFileBySize::new(100));
let drain = slog_async::Async::new(drain).build().fuse();
let _log = slog::Logger::root(drain, o!());
slog::info!(_log, "Test log file rotated by size");
}
assert_eq!(
true,
file_exists("norotate/000000.log", FileStorage::default())
);
assert_eq!(false, file_exists(new_path, FileStorage::default()));
}
}
6 changes: 3 additions & 3 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ impl Options {
}

/// Initialize Options by limiting ranges of some flags, applying customized Logger and etc.
pub(crate) fn initialize<O: File + 'static, S:Storage<F = O>+Clone+'static>(
pub(crate) fn initialize<O: File + 'static, S: Storage<F = O> + Clone + 'static>(
&mut self,
db_name: &'static str,
storage: &S,
storage: &S,
) {
self.max_open_files =
Self::clip_range(self.max_open_files, 64 + self.non_table_cache_files, 50000);
Expand All @@ -225,7 +225,7 @@ impl Options {
}

#[allow(unused_must_use)]
fn apply_logger<S: 'static+Storage+Clone>(&mut self, storage: &S, db_path: &'static str) {
fn apply_logger<S: 'static + Storage + Clone>(&mut self, storage: &S, db_path: &'static str) {
let user_logger = std::mem::replace(&mut self.logger, None);
let logger = Logger::new(user_logger, self.logger_level, storage.clone(), db_path);
let static_logger: &'static dyn Log = Box::leak(Box::new(logger));
Expand Down

0 comments on commit e76a743

Please sign in to comment.