Skip to content

Add log Rotation #62

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7a331c4
test_generate_filename supports windows
AliceLanniste Jun 10, 2019
b4e360f
te2 tests's functions supports windows
AliceLanniste Jun 10, 2019
343eb96
cargo fmt
Fullstop000 Jun 10, 2019
f15cc46
add some set_*** testcase in version_edit
AliceLanniste Oct 27, 2019
e9e41f8
cargo fmt
AliceLanniste Oct 30, 2019
d0b24ea
cargo fmt --check
AliceLanniste Oct 31, 2019
3489f0a
cargo fmt --check before rustc updated
AliceLanniste Nov 1, 2019
5634f41
parenthesis added
AliceLanniste Nov 5, 2019
d3fdc3b
cargo fmt
AliceLanniste Nov 6, 2019
946dcfe
add testcases for Version::find_file
AliceLanniste Nov 16, 2019
fb70318
My own comments deleted
AliceLanniste Nov 16, 2019
38564a1
Fix FileMetaDatas.geneerator() error
AliceLanniste Nov 17, 2019
0a262c2
re-arrange tests
Fullstop000 Nov 21, 2019
6696691
assoicated type in iterator.rs
AliceLanniste Feb 6, 2020
07a7a2c
completed assoicated type implementation
AliceLanniste Feb 7, 2020
d68806e
completed assoicated type implemenation
AliceLanniste Feb 9, 2020
5c14c16
fix conflict files
AliceLanniste Feb 9, 2020
e35c113
fix conflict changes
AliceLanniste Feb 10, 2020
2298102
remove unnecessary information
AliceLanniste Feb 10, 2020
3f036a7
added associated type for db
AliceLanniste Feb 10, 2020
731255f
make sure InternalKey live longer than Slice
AliceLanniste Feb 13, 2020
1f8cdd8
cargo fmt
AliceLanniste Feb 13, 2020
85fb6be
cargo fmt again
AliceLanniste Feb 13, 2020
f3420a7
add Rotator trait
AliceLanniste Apr 23, 2020
5a2ae75
add add_rotator to FileBaseDrain
AliceLanniste Apr 24, 2020
f631794
initially complete `RotatedFileBySize`
AliceLanniste May 6, 2020
42c0a2d
update upstream
AliceLanniste May 7, 2020
36c3fb7
add simple log rotation
AliceLanniste May 7, 2020
c2aa6d0
merge
AliceLanniste May 7, 2020
746d23b
cargo fmt
AliceLanniste May 7, 2020
1d82110
update
AliceLanniste May 7, 2020
daf1437
add test for rotate
AliceLanniste May 21, 2020
7110a01
complete rotate test
AliceLanniste May 26, 2020
f37634e
using memStorage instead of FileStorage
AliceLanniste Jun 11, 2020
5d27d2c
delete unncessary import
AliceLanniste Jun 23, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ num-derive = "0.3"
slog = "2.5.2"
slog-term = "2.5.0"
slog-async = "2.4.0"

chrono = "0.4"
[dev-dependencies]
criterion = "0.3.0"

Expand Down
150 changes: 127 additions & 23 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,26 @@
// limitations under the License.

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};

use chrono::prelude::*;
use std::sync::Mutex;

/// A `slog` based logger which can be used with `log` crate
///
/// See `slog` at https://github.com/slog-rs/slog
/// See `log` at https://github.com/rust-lang/log
///

fn create_file<S: Storage>(storage: &S, dp_path: &str, timestamp: i64) -> Result<S::F> {
let new_path = generate_filename(dp_path, FileType::OldInfoLog, timestamp as u64);
storage.rename(dp_path, new_path.as_str())?;
storage.create(dp_path)
}

pub struct Logger {
inner: slog::Logger,
level: LevelFilter,
Expand All @@ -35,11 +44,11 @@ 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>(
pub fn new<S: Storage + Clone + 'static>(
inner: Option<slog::Logger>,
level: LevelFilter,
storage: &S,
db_path: &str,
storage: S,
db_path: String,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

db_path could be a &'static str I think

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try

) -> Self {
let inner = match inner {
Some(l) => l,
Expand All @@ -52,12 +61,14 @@ impl Logger {
} else {
// Use a file `Log` to record all logs
// TODO: add file rotation
let file = storage
.create(generate_filename(db_path, FileType::InfoLog, 0).as_str())
.unwrap();
let drain = slog_async::Async::new(FileBasedDrain::new(file))
.build()
.fuse();
let file =
create_file(&storage, db_path.as_str(), 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.clone(), file_fn)
.add_rotator(RotatedFileBySize::new(0));
let drain = slog_async::Async::new(drain).build().fuse();
slog::Logger::root(drain, o!())
}
}
Expand Down Expand Up @@ -104,7 +115,6 @@ impl Log for Logger {
}
}
}

fn flush(&self) {}
}

Expand All @@ -120,13 +130,44 @@ fn log_to_slog_level(level: log::Level) -> Level {

struct FileBasedDrain<F: File> {
inner: Mutex<F>,
rotators: Vec<Box<dyn Rotator>>,
dp_path: String,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this db_path ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YES,you ar right

new_file: Box<dyn Send + Fn(String) -> Result<F>>,
}

impl<F: File> FileBasedDrain<F> {
fn new(f: F) -> Self {
fn new<H>(f: F, path: String, new_file: H) -> Self
where
H: 'static + Send + Fn(String) -> Result<F>,
{
FileBasedDrain {
dp_path: path.clone(),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

inner: Mutex::new(f),
rotators: vec![],
new_file: Box::new(new_file),
}
}

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() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use self.rotators.as_ref().iter() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NO, THIS CANNOT COMPILER

rotator.prepare(&*self.inner.lock().unwrap()).unwrap();
}
self
}

fn flush(&self) -> Result<()> {
self.inner.lock().unwrap().flush()?;
let new_file = (self.new_file)(self.dp_path.clone()).unwrap();

let mut old_file = self.inner.lock().unwrap();
std::mem::replace(&mut *old_file, new_file);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be

*old_file = new_file

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

Expand All @@ -138,17 +179,79 @@ impl<F: File> Drain for FileBasedDrain<F> {
&self,
record: &slog::Record,
values: &slog::OwnedKVList,
) -> Result<Self::Ok, Self::Err> {
// Ignore errors here
let _ = self.inner.lock().unwrap().write(
format!(
"[{}] : {:?} \n {:?} \n",
record.level(),
record.msg(),
values
)
.as_bytes(),
) -> std::result::Result<Self::Ok, Self::Err> {
let by = format!(
"[{}] : {:?} \n {:?} \n",
record.level(),
record.msg(),
values
);
for rotator in self.rotators.iter() {
if rotator.should_rotate() {
self.flush().unwrap();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unwrap() seems not suitable here. At least we can throw the error I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what kind of error should throw,Error:: CorruptionError::IO or Error::Customized

return Ok(());
}
}

for rotator in self.rotators.iter() {
rotator.on_write(by.as_bytes()).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.
fn is_enabled(&self) -> bool;

/// Call by operator, initializes the states of rotators.
fn prepare(&self, file: &dyn File) -> Result<()>;

/// Return if the file need to be rotated.
fn should_rotate(&self) -> bool;

fn on_write(&self, buf: &[u8]) -> Result<()>;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls add rustdoc

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

struct RotatedFileBySize {
rotation_size: u64,
file_size: Mutex<u64>,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use AtomicU64 instead ?

}

impl RotatedFileBySize {
fn new(rotation_size: u64) -> Self {
RotatedFileBySize {
rotation_size,
file_size: Mutex::new(0),
}
}
}

impl Rotator for RotatedFileBySize {
fn is_enabled(&self) -> bool {
self.rotation_size != 0
}
fn prepare(&self, file: &dyn File) -> Result<()> {
*self.file_size.lock().unwrap() = file.len().unwrap();
Ok(())
}

fn should_rotate(&self) -> bool {
*self.file_size.lock().unwrap() > self.rotation_size
}
fn on_write(&self, buf: &[u8]) -> Result<()> {
*self.file_size.lock().unwrap() += buf.len() as u64;
Ok(())
}

fn on_rotate(&self) -> Result<()> {
*self.file_size.lock().unwrap() = 0;
Ok(())
}
}
Expand All @@ -165,8 +268,9 @@ mod tests {
#[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);
let logger = Logger::new(None, LevelFilter::Debug, s, db_path.to_string());
// Ignore the error if the logger have been set
let _ = log::set_logger(Box::leak(Box::new(logger)));
log::set_max_level(LevelFilter::Debug);
Expand Down
11 changes: 8 additions & 3 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ 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>>(
pub(crate) fn initialize<O: File + 'static, S: Storage<F = O> + Clone + 'static>(
&mut self,
db_name: String,
storage: &S,
Expand All @@ -225,9 +225,14 @@ impl Options {
}

#[allow(unused_must_use)]
fn apply_logger<S: Storage>(&mut self, storage: &S, db_path: &str) {
fn apply_logger<S: 'static + Storage + Clone>(&mut self, storage: &S, db_path: &str) {
let user_logger = std::mem::replace(&mut self.logger, None);
let logger = Logger::new(user_logger, self.logger_level, storage, db_path);
let logger = Logger::new(
user_logger,
self.logger_level,
storage.clone(),
db_path.to_string(),
);
let static_logger: &'static dyn Log = Box::leak(Box::new(logger));
log::set_logger(static_logger);
log::set_max_level(self.logger_level);
Expand Down
2 changes: 2 additions & 0 deletions src/version/version_edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ mod tests {
let mut edit = VersionEdit::new(7);
let filename = String::from("Hello");
edit.set_comparator_name(filename);

assert_eq!("Hello", edit.comparator_name.unwrap().as_str());
}

Expand All @@ -488,6 +489,7 @@ mod tests {
let mut edit = VersionEdit::new(7);
let log_num = u64::max_value();
edit.set_log_number(log_num);

assert_eq!(edit.log_number.unwrap(), log_num);
}

Expand Down