Sherlock0203 opened a new pull request, #3687:
URL: https://github.com/apache/brpc/pull/3687
### What problem does this PR solve?
Issue Number: resolve #2696
Problem Summary:
butil ships a logging implementation that services can already run in
production, but it had no rotation: a long-running process kept appending
to a single file until the disk filled, so users had to move to glog or
run an external logrotate beside it. Issue #2696 asks whether butil
logging is meant to be production ready; this adds the missing rotation
so that it can be used standalone.
### What is changed and the side effects?
Changed:
Two new gflags, both changeable at run time via `/flags`:
- `--log_rotate_size_mb` (default 0, rotation off): rotate the log file
once it is about to grow beyond this size in megabytes. Only takes
effect when logging to a file.
- `--log_rotate_max_backups` (default 10): number of rotated files kept
besides the current one.
When the limit is reached, the current file is renamed to
`<log_file>.1`, the older backups shift down (`.1` -> `.2` -> ...) and
the ones beyond the limit are removed, so `.1` is always the most recent
backup. Lowering `--log_rotate_max_backups` at run time also removes the
files left over from the previous, larger value.
Design notes:
- The check lives in `Log2File()`, the single funnel of both
`DefaultLogSink` and `AsyncLogger::DoLog`, so rotation covers
synchronous and asynchronous logging alike.
- The file is opened in append mode, so the size a restarted process
starts from is read with `fstat()`/`GetFileSizeEx()` instead of being
counted from zero.
- Rotation happens before the write, so a single log is never split into
two files; an empty file is never rotated, so a log larger than the
limit is written as a whole instead of producing empty backups.
- A rotation failure does not disable rotation and does not drop logs:
the size at which it failed is remembered and rotation is retried once
the file has grown by another `--log_rotate_size_mb`, with the error
printed once, naming the rename that failed and why. Logs keep being
appended to the current file in the meantime.
- A backup that cannot be renamed out of the way (another process holds
it open, a directory sits on the slot) stops the rotation instead of
being overwritten with the current file, so no generation is silently
dropped.
- A file that turns out to be smaller than it was when rotation failed
has been replaced or truncated from the outside, and rotation resumes
immediately.
- A log file that disappeared from under the process is not a failure:
the handle is closed so that the next write starts a fresh file, and
the backups are left untouched.
- Backups are shifted from the highest existing index, so a huge
`--log_rotate_max_backups` (only validated to be a positive int) still
costs a handful of rename() calls per rotation rather than one per
index, all under the logging lock.
Docs: `docs/en/streaming_log.md` and `docs/cn/streaming_log.md` describe
the two flags and the failure handling. Sharing one log file between
several processes, and running an external rotator such as logrotate on
the same file, are documented as unsupported together with rotation.
Side effects:
- Performance effects: rotation is off by default; with
`--log_rotate_size_mb=0` the only addition on the write path is a flag
check. When enabled, each log additionally updates a size counter, and
each rotation performs a bounded number of rename()/unlink() calls
(only the existing backups) while holding the logging lock.
- Breaking backward compatibility: none. Rotation is disabled by
default, so existing deployments see no change in file names or file
contents. The two flags are new, all new code lives in the anonymous
namespace of `logging.cc`, and there is no header or API change.
### Tests
13 new cases in `test/logging_unittest.cc` (`LogRotationTest`):
rotation and pruning, keeping one backup, a single log larger than the
limit, taking the size of an existing file into account after a restart,
async logging, lowering `--log_rotate_max_backups` at run time, external
rename of the current file, backing off while rotation keeps failing,
recovery after the file is replaced from the outside, a failed shift
keeping the newest backup, a huge `--log_rotate_max_backups` staying fast
(1e8, a handful of backups, ~11ms for several rotations), and 8 threads
logging synchronously through rotations without losing, duplicating or
tearing a single log.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]