Skip to content
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

Size Based Rotating File Appender #865

Conversation

CfirTsabari
Copy link

@CfirTsabari CfirTsabari commented Jul 30, 2020

Motivation

Adding an appender with max size per log file and max number of log files.
Addressing #858

Solution

Adding an appender very similar to the RollingFileAppender,
that will base the rotation on the size of the log file and the number of log files.

@CfirTsabari CfirTsabari force-pushed the cfirtsabari/rotatingfileappender-858 branch 2 times, most recently from 7d23a15 to 36de84e Compare July 31, 2020 21:55
Motivation
Adding an appender with max size per log file and max number of log files.
Addressing  tokio-rs#858

Solution
Adding an appender very similar to the `RollingFileAppender`,
that will base the rotation on size of log file and number of log files.
@CfirTsabari CfirTsabari force-pushed the cfirtsabari/rotatingfileappender-858 branch from 36de84e to c775505 Compare August 1, 2020 11:05
@CfirTsabari CfirTsabari changed the title WIP Size Based Rotating File Appender Size Based Rotating File Appender Aug 1, 2020
@CfirTsabari
Copy link
Author

All of the CI failures are due to tracing-macros/examples/factorial.rs which is not part of the PR.

@CfirTsabari CfirTsabari marked this pull request as ready for review August 1, 2020 11:14
@CfirTsabari CfirTsabari requested a review from a team as a code owner August 1, 2020 11:14
@zekisherif
Copy link
Contributor

Thanks @CfirTsabari, I'll take a look at it later today

/// ```
///
/// This will result in a log file located at `/some/path/rotating.log`.
pub fn mb_100(
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there some significance to 100 MB log files and max of 9 back ups?? I ask because I think creating helpers for different values will be too cumbersome. I think in this case it makes more sense to just take in the size of log files and max backups desired.

Copy link
Author

Choose a reason for hiding this comment

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

I just wanted to create at least one helper that will show an example on how to create a new appender\rotation.
If you think it's better to remove it I will remove it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think making the helper more generic taht takes in a size parameter would be good enough to show how it works and is probably the only helper we would need.

Copy link
Author

Choose a reason for hiding this comment

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

will change

Comment on lines 92 to 94
let buf_len = buf.len();
self.refresh_writer(&buf_len);
self.writer.write_all(buf).map(|_| buf_len)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is fairly similar to what InnerRollingAppender does except it encapsulates it with a method call.

It might make more sense to have a parent struct called InnerAppender which wraps a trait called InnerAppenderTrait (not sure of a good name, just a placeholder). I feel it'll also help in the future when/if new types of appenders may be needed.

Both InnerRotatingAppender and InnerRollingAppender can implement this trait.

pub(crate) trait InnerAppenderTrait {
       record(&mut self, buf: &[u8]) -> Result<usize>;
       refresh_writer(&mut self);
       .... 
}

pub(crate) struct InnerAppender<T: InnerAppenderTrait> {
     appender: T,
}

impl io::Write for InnerAppender<T: InnerAppenderTrait> {
      fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.appender.record(buf);
      }
     ....
}

Maybe this is not ideomatic in rust and @hawkw feels differently.

Copy link
Author

Choose a reason for hiding this comment

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

I will try to create something like that, but I a little unsure of how to work correctly with traits.

Copy link
Author

Choose a reason for hiding this comment

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

done

rotation,
})
}
fn refresh_writer(&mut self, size: &usize) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: A new line between methods could be added in a few places.

Copy link
Author

Choose a reason for hiding this comment

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

will fix this.

Copy link
Author

Choose a reason for hiding this comment

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

done

Introduced InnerAppenderTrait.
InnerAppenderWrapper will wrap structs that implement InnerAppenderTrait
RotatingFileAppender and RollingFileAppender use this new wrapper.
Added lines between functions.
@CfirTsabari CfirTsabari removed the request for review from a team August 6, 2020 15:35
Copy link
Contributor

@zekisherif zekisherif left a comment

Choose a reason for hiding this comment

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

This is some good progress. Still a few things to address concerning the major structures and then I'll look at the rest of the review.

use std::path::Path;

pub(crate) trait InnerAppenderTrait<R>: io::Write
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Something better named would be nice as pub(crate) trait already signifies this is a trait. Something like AppendInnder?

Copy link
Author

Choose a reason for hiding this comment

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

will rename

Comment on lines +26 to +27
}
impl<R, T: InnerAppenderTrait<R>> InnerAppenderWrapper<R, T> {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit let's add a line break here.

Copy link
Author

Choose a reason for hiding this comment

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

will fix

use std::path::Path;

pub(crate) trait InnerAppenderTrait<R>: io::Write
where
Self: Sized,
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe specifying this will prevent making the trait into an object

https://doc.rust-lang.org/std/marker/trait.Sized.html

I may be wrong though. I've never used Sized before.

Copy link
Author

Choose a reason for hiding this comment

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

i need it for Result

where
Self: Sized,
{
fn new(rotation: R, log_directory: &Path, log_filename_prefix: &Path) -> io::Result<Self>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Tying the constructor to a trait method will make the code brittle.

The constructor should only be implemented by InnerAppenderWrapper. InnerAppenderTrait I think would be more appropriate for only specifying the contract for how logs are appended.

Copy link
Author

Choose a reason for hiding this comment

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

i have to have this function since InnerAppenderWrapper need it in order to create the appenders.

/// ```
///
/// This will result in a log file located at `/some/path/rotating.log`.
pub fn mb_100(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think making the helper more generic taht takes in a size parameter would be good enough to show how it works and is probably the only helper we would need.

Comment on lines +122 to +130
impl io::Write for InnerRotatingAppender {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let buf_len = buf.len();
self.writer.write_all(buf).map(|_| buf_len)
}

fn flush(&mut self) -> io::Result<()> {
self.writer.flush()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need to implement io::Write again for each appender impl. If you add a default method record/write then you can just call that from the impl of io::Write for InnerAppenderWrapper and not have to duplicate code for every appender.

Copy link
Author

Choose a reason for hiding this comment

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

i will still have to create these methods for each appender, I can't create a default method that will access the appenders buffers.

@CfirTsabari
Copy link
Author

Ok so after reading your comments, and reviewing the code again I did notice the flaws of using a Trait here.
I have started this trait in order to solve 3 duplicates lines, and ended up with ~50 more lines of code.
I failed to see the merits of using any trait here( other than io::Write).

so I thought to remove the entire trait, what do you think?
@zekisherif

@zekisherif
Copy link
Contributor

Ok so after reading your comments, and reviewing the code again I did notice the flaws of using a Trait here.
I have started this trait in order to solve 3 duplicates lines, and ended up with ~50 more lines of code.
I failed to see the merits of using any trait here( other than io::Write).

so I thought to remove the entire trait, what do you think?
@zekisherif

I'll take a crack at it (can't until thursday). I feel like there's a cleaner approach here.

@JRAndreassen
Copy link

I'd like to see this change as well... :)

@CfirTsabari
Copy link
Author

@zekisherif did you had the chance to look at it?

@zekisherif
Copy link
Contributor

Hi @CfirTsabari

Thanks for the contribution and the time you spent working on it. However, I think that there might be a simpler solution and us asking you to write it through this PR would be draining and tiring for all parties. for that reason, we’ll close this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants