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

Implement rotating file logger #881

Merged
merged 7 commits into from
Sep 22, 2020

Conversation

zariiii9003
Copy link
Collaborator

See #874

Any API or testing suggestions are very welcome.

@zariiii9003 zariiii9003 added enhancement work-in-progress file-io about reading & writing to files labels Aug 1, 2020
@codecov
Copy link

codecov bot commented Aug 1, 2020

Codecov Report

Merging #881 into develop will increase coverage by 0.37%.
The diff coverage is 90.58%.

@@             Coverage Diff             @@
##           develop     #881      +/-   ##
===========================================
+ Coverage    70.71%   71.08%   +0.37%     
===========================================
  Files           71       71              
  Lines         6915     6976      +61     
===========================================
+ Hits          4890     4959      +69     
+ Misses        2025     2017       -8     

@christiansandberg
Copy link
Collaborator

I remember we discussed this topic once and the challenge is that there are an infinite number of log rotation strategies so if we want to add support for one, we have to be prepared to include support for a large number of strategies, like size based, date and time based, or some external trigger like current test case or something. There will also be a need to add support to the logger CLI.

I'm not totally against it, it just needs to be carefully designed so it won't come back and bite us in the ass later on. :)

@zariiii9003
Copy link
Collaborator Author

zariiii9003 commented Aug 4, 2020

Here is an alternative. This one is similar to the python builtins logger. I copied some code from here. I thought a familiar API might be beneficial.

What do you think?

class BaseRotatingCanLogger(Listener, ABC):
    supported_writers = {
        ".asc": ASCWriter,
        ".blf": BLFWriter,
        ".csv": CSVWriter,
        ".log": CanutilsLogWriter,
        ".txt": Printer,
    }
    namer = None
    rotator = None
    writer: FileIOMessageWriter

    def __init__(self, *args, **kwargs):
        self.writer_args = args
        self.writer_kwargs = kwargs

        self.rollover_count = 0

    def rotation_filename(self, default_name):
        if not callable(self.namer):
            result = default_name
        else:
            result = self.namer(default_name)
        return result

    def rotate(self, source: StringPathLike, dest: StringPathLike):
        if not callable(self.rotator):
            if os.path.exists(source):
                os.rename(source, dest)
        else:
            self.rotator(source, dest)

    def on_message_received(self, msg: Message):
        if self.should_rollover(msg):
            self.do_rollover()
            self.rollover_count += 1

        self.writer.on_message_received(msg)

    def get_new_writer(self, filename: StringPathLike) -> FileIOMessageWriter:
        suffix = pathlib.Path(filename).suffix.lower()
        try:
            writer_class = self.supported_writers[suffix]
        except KeyError:
            raise ValueError(
                f'Log format with suffix"{suffix}" is '
                f"not supported by {self.__class__.__name__}."
            )
        return writer_class(filename, *self.writer_args, **self.writer_kwargs)

    def on_error(self, exc: Exception):
        ...

    @abstractmethod
    def should_rollover(self, msg: Message) -> bool:
        ...

    @abstractmethod
    def do_rollover(self):
        ...


class SizedRotatingCanLogger(BaseRotatingCanLogger):
    def __init__(self, filename: StringPathLike, max_bytes: int = 0, *args, **kwargs):
        super(SizedRotatingCanLogger, self).__init__(*args, **kwargs)

        self.base_filename = os.path.abspath(filename)
        self.max_bytes = max_bytes

        self.writer = self.get_new_writer(self.base_filename)

    def should_rollover(self, msg: Message) -> bool:
        if self.writer.file.tell() >= self.max_bytes:
            return True

        return False

    def do_rollover(self):
        if self.writer:
            self.writer.stop()

        sfn = self.base_filename
        dfn = self.rotation_filename(self._default_name())
        self.rotate(sfn, dfn)

        self.writer = self.get_new_writer(self.base_filename)

    def _default_name(self) -> StringPathLike:
        path = pathlib.Path(self.base_filename)
        new_name = (
            path.stem
            + datetime.now().strftime("_%Y-%m-%d_%H-%M-%S")
            + f"_#{self.rollover_count:03}"
            + path.suffix
        )
        return str(path.parent / new_name)

@christiansandberg
Copy link
Collaborator

I like that!

1 similar comment
@christiansandberg
Copy link
Collaborator

I like that!

Copy link
Collaborator

@felixdivo felixdivo left a comment

Choose a reason for hiding this comment

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

Hey @zariiii9003, that's a great implementation! Nice code, documentation and tests.

The only thing that I might discuss is the naming of the *RotatingCanLogger. Do we need the "Can" in there, as the plain Logger also does not contain it? I'd leave it out.

Oh, and thanks for showing me the ellipsis object of Python ^^. It's quite rare (and I think usually pass is used instead) but we can keep it.

@zariiii9003
Copy link
Collaborator Author

Thank you for your review and your kind words @felixdivo
I updated the class names. Having CAN in the class names indeed seems a bit redundant in a can library.

Copy link
Collaborator

@felixdivo felixdivo left a comment

Choose a reason for hiding this comment

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

Looks good 👍

@felixdivo
Copy link
Collaborator

@christiansandberg Do you also approve these changes? If yes, we can merge.

@felixdivo felixdivo added this to the 4.0 Release milestone Sep 21, 2020
@mergify mergify bot merged commit 7f1549f into hardbyte:develop Sep 22, 2020
@zariiii9003 zariiii9003 deleted the rotating_file_logger branch October 14, 2022 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement file-io about reading & writing to files
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants