iccicci / rotating-file-stream

Opens a stream.Writable to a file rotated by interval and/or size. A logrotate alternative.
MIT License
291 stars 39 forks source link

[bug] Files may get reordered by the rotation job #107

Open gmasclet opened 2 months ago

gmasclet commented 2 months ago

We're using rotating-file-stream to handle the rotation of our log files.

We've recently noticed that the filenames are sometimes out of order in the history file, meaning that the rotation may delete another file than the oldest one.

Unless I'm wrong, in the history() method, the files are sorted by their ctime. See the last line of the following extract:

https://github.com/iccicci/rotating-file-stream/blob/73165e22f9400c8c102ddeaa0287f30d5a57b79d/index.ts#L500-L518

And from what I see in the Node documentation on https://nodejs.org/api/fs.html#class-fsstats:

ctime "Change Time": Time when file status was last changed (inode data modification). Changed by the chmod(2), chown(2), link(2), mknod(2), rename(2), unlink(2), utimes(2), read(2), and write(2) system calls.

So, it seems that in some cases, the ctime of the file may be externally modified, which causes the history file to be reordered during the next rotation job.

May I suggest we instead keep the history file order, disregarding the file ctime?

iccicci commented 2 months ago

Hi @gmasclet ,

Thank you for reporting.

In the page you are referring, the previous line to the one you highlighted:

mtime "Modified Time": Time when file data last modified. Changed by the mknod(2), utimes(2), and write(2) system calls.

It seems checking mtime rather than ctime would be the right way to achieve the target desired by the design. I'm goign to apply this fix (which also is much more cheap than your proposal).

Do you think it could be enough to solve your problem?

Thank you

gmasclet commented 2 months ago

Hi @iccicci,

Thanks for your responsiveness :slightly_smiling_face:

I think that checking mtime rather than ctime is a clear improvement: looks like there are too many things that can affect ctime. Yet, I fear that there can still be some edge cases not covered, for instance an admin opening an archived log file and saving it inadvertently. I know it seems a bit unlikely, but it's not impossible.

My proposal would simply be to remove the res.sort((a, b) => a.time - b.time); statement. This way, the history file is never reordered and behaves as a FIFO queue:

Let me know what you think about that.

iccicci commented 2 months ago

That would break this.

When options.maxFiles or options.maxSize are enabled for first time, an history file can be created with one rotated filename (as returned by filename generator function) at each line.

That would make required also the history file to be created with correct sort, in case somebody wants to enable the feature after some log files are already created.

Since every system has its own requirements, probably your request could be accomplished with a new configuration option.

My plan:

Does it work for you? Thank you

iccicci commented 2 months ago

Released v3.2.5 with mtime fix.

gmasclet commented 2 months ago

Thanks a lot @iccicci!

The mtime fix clearly mitigates the issue, so we're going to bump to v3.2.5 to benefit from it.


When options.maxFiles or options.maxSize are enabled for first time, an history file can be created with one rotated filename (as returned by filename generator function) at each line.

I wasn't aware about that rule, this explains why the "sort by time" statement can not be simply removed.

I'm definitely interested if you can implement a new option so that the history file is never reordered once created.