-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
logrotate: Support incremental file rotation strategy
Advantages of the incremental rotation strategy: 1. Each file is created only once. If the file is traversed and packaged by an external process, there will be no duplication or loss problems in the rename rotation method. 2. You can estimate how much data has been rolled back by looking at the file name.
- Loading branch information
1 parent
2d56017
commit e8d0588
Showing
14 changed files
with
428 additions
and
154 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#pragma once | ||
|
||
#include <fstream> | ||
#include <iostream> | ||
#include <string> | ||
#include <utility> | ||
|
||
#include "rotation_strategy_interface.h" | ||
#include "ulog/status.h" | ||
|
||
namespace ulog::file { | ||
|
||
class RotationStrategyIncremental final : public RotationStrategyInterface { | ||
public: | ||
RotationStrategyIncremental(std::string basename, std::string ext, const size_t max_files) | ||
: basename_(std::move(basename)), ext_(std::move(ext)), max_files_(max_files == 0 ? 1 : max_files) { | ||
if (const auto status = ReadNumberFile(get_number_filename(), &final_number_); !status.ok()) { | ||
// Maybe first write | ||
final_number_ = 0; | ||
} | ||
} | ||
|
||
// Example: | ||
// max_files == 10; | ||
// final_num == 29 + 1; | ||
// remove file: log-20.txt | ||
// remain files: log-21.txt log-22.txt ... log-29.txt | ||
// Next, call LatestFilename() to get log-30.txt for writing | ||
Status Rotate() override { | ||
++final_number_; | ||
|
||
if (final_number_ >= max_files_) { | ||
std::remove(get_filename(final_number_ - max_files_).c_str()); | ||
|
||
// Try to clear the files that were previously configured too much | ||
size_t not_exists = 0; | ||
for (size_t i = final_number_ - max_files_; i != 0; --i) { | ||
std::string filename = get_filename(i); | ||
if (!path_exists(filename)) { | ||
if (++not_exists == 2) break; | ||
continue; | ||
} | ||
std::remove(filename.c_str()); | ||
} | ||
std::remove(get_filename(0).c_str()); | ||
} | ||
return WriteNumberFile(get_number_filename(), final_number_); | ||
} | ||
|
||
std::string LatestFilename() override { return basename_ + "-" + std::to_string(final_number_) + ext_; } | ||
|
||
private: | ||
[[nodiscard]] std::string get_number_filename() const { return basename_ + ext_ + ".latest"; } | ||
[[nodiscard]] std::string get_filename(const size_t index) const { | ||
return basename_ + "-" + std::to_string(index) + ext_; | ||
} | ||
|
||
static Status ReadNumberFile(const std::string& filename, size_t* const final_number) { | ||
std::ifstream input_file(filename); | ||
if (!input_file.is_open()) { | ||
*final_number = 0; | ||
return Status::IOError("Failed to open file: " + filename); | ||
} | ||
|
||
input_file >> *final_number; | ||
input_file.close(); | ||
return Status::OK(); | ||
} | ||
|
||
// Directly writes the latest number to the file | ||
static Status WriteNumberFile(const std::string& filename, const size_t number) { | ||
std::ofstream output_file(filename); | ||
|
||
if (!output_file.is_open()) { | ||
return Status::IOError("Failed to write number to: " + filename); | ||
} | ||
|
||
output_file << number; | ||
output_file.close(); | ||
return Status::OK(); | ||
} | ||
|
||
// config | ||
const std::string basename_; | ||
const std::string ext_; | ||
const size_t max_files_; | ||
|
||
size_t final_number_ = 0; | ||
}; | ||
|
||
} // namespace ulog::file |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#pragma once | ||
|
||
#include "ulog/status.h" | ||
|
||
namespace ulog::file { | ||
|
||
class RotationStrategyInterface { | ||
public: | ||
RotationStrategyInterface() = default; | ||
virtual ~RotationStrategyInterface() = default; | ||
|
||
virtual Status Rotate() = 0; | ||
virtual std::string LatestFilename() = 0; | ||
}; | ||
|
||
} // namespace ulog::file |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <utility> | ||
|
||
#include "ulog/file/file.h" | ||
#include "ulog/file/rotation_strategy_interface.h" | ||
|
||
namespace ulog::file { | ||
|
||
class RotationStrategyRename final : public RotationStrategyInterface { | ||
public: | ||
RotationStrategyRename(std::string basename, std::string ext, const size_t max_files) | ||
: basename_(std::move(basename)), ext_(std::move(ext)), max_files_(max_files == 0 ? 1 : max_files) {} | ||
|
||
// Rotate files: | ||
// log.txt -> log.1.txt | ||
// log.1.txt -> log.2.txt | ||
// log.2.txt -> log.3.txt | ||
// log.3.txt -> delete | ||
// "tail -f" may be interrupted when rename is executed, and "tail -F" can | ||
// be used instead, but some "-F" implementations (busybox tail) cannot | ||
// obtain all logs in real time. | ||
Status Rotate() override { | ||
for (size_t i = max_files_ - 1; i > 0; --i) { | ||
std::string src = get_filename(i - 1); | ||
if (!path_exists(src)) { | ||
continue; | ||
} | ||
RenameFile(src, get_filename(i)); | ||
} | ||
|
||
// Try to clear the files that were previously configured too much | ||
size_t not_exists = 0; | ||
for (size_t i = max_files_;; ++i) { | ||
std::string filename = get_filename(i); | ||
if (!path_exists(filename)) { | ||
if (++not_exists == 2) break; | ||
continue; | ||
} | ||
std::remove(filename.c_str()); | ||
} | ||
return Status::OK(); | ||
} | ||
|
||
std::string LatestFilename() override { return basename_ + ext_; } | ||
|
||
private: | ||
[[nodiscard]] std::string get_filename(const size_t index) const { | ||
if (index == 0u) { | ||
return basename_ + ext_; | ||
} | ||
|
||
return basename_ + "." + std::to_string(index) + ext_; | ||
} | ||
std::string basename_; | ||
std::string ext_; | ||
size_t max_files_; | ||
}; | ||
|
||
} // namespace ulog::file |
Oops, something went wrong.