20#include <boost/date_time/posix_time/posix_time.hpp>
46 string base(
"kea-legal");
54 if (parameters.find(
"path") != parameters.end()) {
55 path = parameters.at(
"path");
57 if (parameters.find(
"base-name") != parameters.end()) {
58 base = parameters.at(
"base-name");
60 if (parameters.find(
"time-unit") != parameters.end()) {
61 string time_unit(parameters.at(
"time-unit"));
63 if (time_unit ==
"second") {
65 }
else if (time_unit ==
"day") {
67 }
else if (time_unit ==
"month") {
69 }
else if (time_unit ==
"year") {
73 <<
", expected one of: second, day, month, year");
76 if (parameters.find(
"count") != parameters.end()) {
78 count = boost::lexical_cast<int64_t>(parameters.at(
"count"));
80 isc_throw(
BadValue,
"bad value: " << parameters.at(
"count") <<
" for count parameter");
83 (count > numeric_limits<uint32_t>::max())) {
85 <<
" is out of range, expected value: 0.."
86 << numeric_limits<uint32_t>::max());
89 if (parameters.find(
"prerotate") != parameters.end()) {
90 prerotate = parameters.at(
"prerotate");
92 if (parameters.find(
"postrotate") != parameters.end()) {
93 postrotate = parameters.at(
"postrotate");
95 if (parameters.find(
"mark-continuation-lines") != parameters.end()) {
96 string mcl(parameters.at(
"mark-continuation-lines"));
103 count_ =
static_cast<uint32_t
>(count);
104 prerotate_ = prerotate;
105 postrotate_ = postrotate;
111 if (base_name_.empty()) {
115 if (!prerotate_.empty()) {
124 if (!postrotate_.empty()) {
141 strftime(buffer,
sizeof(buffer),
"%Y%m%d", &time_info);
142 return (
string(buffer));
147 ostringstream stream;
148 string name = base_name_ +
".";
150 stream << path_ <<
"/";
153 time_t timestamp = mktime(&time_info);
154 ostringstream name_stream;
155 name_stream << right << setfill(
'0') << setw(20)
156 <<
static_cast<uint64_t
>(timestamp);
158 name += name_stream.str();
163 stream << name <<
".txt";
165 file_name_ = stream.str();
174 DIR* dir = opendir(path_.c_str());
179 unique_ptr<DIR, void(*)(DIR*)> defer(dir, [](DIR* d) { closedir(d); });
185 for (
struct dirent* dent = readdir(dir); dent; dent = readdir(dir)) {
186 string name(dent->d_name);
189 if ((name.size() != (base_name_.size() +
sizeof(
".YYYYMMDD.txt") - 1)) &&
190 (name.size() != (base_name_.size() +
sizeof(
".TXXXXXXXXXXXXXXXXXXXX.txt") - 1))) {
195 if (name.substr(name.size() - 4) !=
".txt") {
199 string file = name.substr(0, name.size() - 4);
202 if (base_name_ !=
file.substr(0, base_name_.size())) {
206 file =
file.substr(base_name_.size() + 1);
207 uint32_t tag_size =
sizeof(
"YYYYMMDD") - 1;
210 if (
file.at(0) !=
'T') {
213 tag_size =
sizeof(
"TXXXXXXXXXXXXXXXXXXXX") - 1;
216 if (
file.size() != tag_size) {
219 for (; index < tag_size; ++index) {
220 if (!isdigit(
file.at(index))) {
224 if (index != tag_size) {
234 string file = *files.rbegin();
237 time_t file_timestamp;
239 file_timestamp =
static_cast<time_t
>(boost::lexical_cast<uint64_t>(
file.substr(1)));
243 time_t current_timestamp = mktime(&time_info);
244 if (current_timestamp < (file_timestamp +
static_cast<time_t
>(count_))) {
245 localtime_r(&file_timestamp, &time_info);
250 boost::gregorian::date file_date;
252 file_date = boost::gregorian::from_undelimited_string(
file);
256 boost::gregorian::date current_date = boost::gregorian::date_from_tm(time_info);
258 boost::gregorian::date_duration dd(count_);
259 if (current_date < (file_date + dd)) {
260 time_info = boost::gregorian::to_tm(file_date);
265 boost::gregorian::months mm(count_);
266 if (current_date < (file_date + mm)) {
267 time_info = boost::gregorian::to_tm(file_date);
272 boost::gregorian::years yy(count_);
273 if (current_date < (file_date + yy)) {
274 time_info = boost::gregorian::to_tm(file_date);
281 file_name_ = path_ +
"/" + base_name_ +
"." +
file +
".txt";
299 file_.open(file_name_.c_str(), ofstream::app);
300 int sav_error = errno;
301 if (!file_.is_open()) {
303 <<
" reason: " << strerror(sav_error));
307 timestamp_ = mktime(&time_info);
315 if (
isOpen() && !count_) {
319 bool rotate_file =
false;
323 localtime_r(×tamp_, &time_info);
329 time_t timestamp = mktime(¤t_time_info);
332 boost::gregorian::date old_date = boost::gregorian::date_from_tm(time_info);
335 boost::gregorian::date new_date = boost::gregorian::date_from_tm(current_time_info);
340 if (
static_cast<time_t
>(count_) <= (timestamp - timestamp_)) {
344 boost::gregorian::date_duration dd(count_);
345 if ((old_date + dd) <= new_date) {
349 boost::gregorian::months mm(count_);
350 if ((old_date + mm) <= new_date) {
354 boost::gregorian::years yy(count_);
355 if ((old_date + yy) <= new_date) {
363 if (!prerotate_.empty()) {
372 if (!postrotate_.empty()) {
384 lock_guard<mutex> lock(mutex_);
385 writelnInternal(text);
387 writelnInternal(text);
392RotatingFile::writelnInternal(
const string& text) {
401 stringstream ss(text);
404 for (
string line; getline(ss, line,
'\n');) {
405 lines.push_back(line);
407 while (!lines.empty()) {
408 string line = lines.front();
416 file_ << line << endl;
418 int sav_error = errno;
420 isc_throw(LegalLogMgrError,
"error writing to file:" << file_name_
421 <<
" reason: " << strerror(sav_error));
427 return (file_.is_open());
433 if (file_.is_open()) {
439 }
catch (
const exception& ex) {
443 .arg(file_name_).arg(ex.what());
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Utility class for spawning new processes.
static std::string redactedAccessString(const ParameterMap ¶meters)
Redact database access string.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Thrown if a LegalLogMgr encounters an error.
virtual struct tm currentTimeInfo() const
Returns the current local date and time.
static std::string getLogPath(bool reset=false, const std::string explicit_path="")
Fetches the supported legal log file path.
LegalLogMgr(const isc::db::DatabaseConnection::ParameterMap parameters)
Constructor.
virtual std::string getNowString() const
Returns the current date and time as string.
static std::string validatePath(const std::string libpath)
Validates a script path (script loaded by a hook) against the supported path.
virtual void writeln(const std::string &text, const std::string &addr)
Appends a string to the current file.
bool mark_continuation_lines_
The mark continuation lines flag.
virtual void close()
Closes the underlying file.
std::string getFileName() const
Returns the current file name.
static std::string getYearMonthDay(const struct tm &time_info)
Build the year-month-day string from a date.
virtual ~RotatingFile()
Destructor.
static isc::dhcp::LegalLogMgrPtr factory(const isc::db::DatabaseConnection::ParameterMap ¶meters)
Factory class method.
void useExistingFiles(struct tm &time_info)
Update file name with previously created file.
virtual void open()
Opens the current file for writing.
RotatingFile(const isc::db::DatabaseConnection::ParameterMap ¶meters)
Constructor.
virtual void rotate()
Rotates the file if necessary.
void apply(const isc::db::DatabaseConnection::ParameterMap ¶meters)
Parse file specification and create forensic log backend.
virtual bool isOpen() const
Returns true if the file is open.
TimeUnit
Time unit type used to rotate file.
void updateFileNameAndTimestamp(struct tm &time_info, bool use_existing)
Function which updates the file name and internal timestamp from previously created file name (if it ...
virtual void openInternal(struct tm &time_info, bool use_existing)
Open file using specified timestamp.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
const isc::log::MessageID LEGAL_LOG_STORE_OPEN
const isc::log::MessageID LEGAL_LOG_STORE_CLOSE_ERROR
const isc::log::MessageID LEGAL_LOG_STORE_OPENED
const isc::log::MessageID LEGAL_LOG_STORE_CLOSED
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
std::vector< std::string > ProcessArgs
Type of the container holding arguments of the executable being run as a background process.
boost::shared_ptr< LegalLogMgr > LegalLogMgrPtr
Defines a smart pointer to a LegalLogMgr.
isc::log::Logger legal_log_logger("legal-log-hooks")
Legal Log Logger.
Defines the logger used by the top-level component of kea-lfc.
Defines the class, RotatingFile, which implements an appending text file that rotates to a new file o...