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]

Reply via email to