15#include <boost/date_time/posix_time/posix_time.hpp>
43 string base(
"kea-legal");
51 if (parameters.find(
"path") != parameters.end()) {
52 path = parameters.at(
"path");
54 if (parameters.find(
"base-name") != parameters.end()) {
55 base = parameters.at(
"base-name");
57 if (parameters.find(
"time-unit") != parameters.end()) {
58 string time_unit(parameters.at(
"time-unit"));
60 if (time_unit ==
"second") {
62 }
else if (time_unit ==
"day") {
64 }
else if (time_unit ==
"month") {
66 }
else if (time_unit ==
"year") {
70 <<
", expected one of: second, day, month, year");
73 if (parameters.find(
"count") != parameters.end()) {
75 count = boost::lexical_cast<int64_t>(parameters.at(
"count"));
77 isc_throw(
BadValue,
"bad value: " << parameters.at(
"count") <<
" for count parameter");
80 (count > numeric_limits<uint32_t>::max())) {
82 <<
" is out of range, expected value: 0.."
83 << numeric_limits<uint32_t>::max());
86 if (parameters.find(
"prerotate") != parameters.end()) {
87 prerotate = parameters.at(
"prerotate");
89 if (parameters.find(
"postrotate") != parameters.end()) {
90 postrotate = parameters.at(
"postrotate");
95 count_ =
static_cast<uint32_t
>(count);
96 prerotate_ = prerotate;
97 postrotate_ = postrotate;
103 if (base_name_.empty()) {
107 if (!prerotate_.empty()) {
116 if (!postrotate_.empty()) {
133 strftime(buffer,
sizeof(buffer),
"%Y%m%d", &time_info);
134 return (
string(buffer));
139 ostringstream stream;
140 string name = base_name_ +
".";
142 stream << path_ <<
"/";
145 time_t timestamp = mktime(&time_info);
146 ostringstream name_stream;
147 name_stream << right << setfill(
'0') << setw(20)
148 <<
static_cast<uint64_t
>(timestamp);
150 name += name_stream.str();
155 stream << name <<
".txt";
157 file_name_ = stream.str();
166 DIR* dir = opendir(path_.c_str());
171 unique_ptr<DIR, void(*)(DIR*)> defer(dir, [](DIR* d) { closedir(d); });
177 for (
struct dirent* dent = readdir(dir); dent; dent = readdir(dir)) {
178 string name(dent->d_name);
181 if ((name.size() != (base_name_.size() +
sizeof(
".YYYYMMDD.txt") - 1)) &&
182 (name.size() != (base_name_.size() +
sizeof(
".TXXXXXXXXXXXXXXXXXXXX.txt") - 1))) {
187 if (name.substr(name.size() - 4) !=
".txt") {
191 string file = name.substr(0, name.size() - 4);
194 if (base_name_ !=
file.substr(0, base_name_.size())) {
198 file =
file.substr(base_name_.size() + 1);
199 uint32_t tag_size =
sizeof(
"YYYYMMDD") - 1;
202 if (
file.at(0) !=
'T') {
205 tag_size =
sizeof(
"TXXXXXXXXXXXXXXXXXXXX") - 1;
208 if (
file.size() != tag_size) {
211 for (; index < tag_size; ++index) {
212 if (!isdigit(
file.at(index))) {
216 if (index != tag_size) {
226 string file = *files.rbegin();
229 time_t file_timestamp;
231 file_timestamp =
static_cast<time_t
>(boost::lexical_cast<uint64_t>(
file.substr(1)));
235 time_t current_timestamp = mktime(&time_info);
236 if (current_timestamp < (file_timestamp + count_)) {
237 localtime_r(&file_timestamp, &time_info);
242 boost::gregorian::date file_date;
244 file_date = boost::gregorian::from_undelimited_string(
file);
248 boost::gregorian::date current_date = boost::gregorian::date_from_tm(time_info);
250 boost::gregorian::date_duration dd(count_);
251 if (current_date < (file_date + dd)) {
252 time_info = boost::gregorian::to_tm(file_date);
257 boost::gregorian::months mm(count_);
258 if (current_date < (file_date + mm)) {
259 time_info = boost::gregorian::to_tm(file_date);
264 boost::gregorian::years yy(count_);
265 if (current_date < (file_date + yy)) {
266 time_info = boost::gregorian::to_tm(file_date);
273 file_name_ = path_ +
"/" + base_name_ +
"." +
file +
".txt";
291 file_.open(file_name_.c_str(), ofstream::app);
292 int sav_error = errno;
293 if (!file_.is_open()) {
295 <<
" reason: " << strerror(sav_error));
299 timestamp_ = mktime(&time_info);
307 if (
isOpen() && !count_) {
311 bool rotate_file =
false;
315 localtime_r(×tamp_, &time_info);
321 time_t timestamp = mktime(¤t_time_info);
324 boost::gregorian::date old_date = boost::gregorian::date_from_tm(time_info);
327 boost::gregorian::date new_date = boost::gregorian::date_from_tm(current_time_info);
332 if (count_ <= (timestamp - timestamp_)) {
336 boost::gregorian::date_duration dd(count_);
337 if ((old_date + dd) <= new_date) {
341 boost::gregorian::months mm(count_);
342 if ((old_date + mm) <= new_date) {
346 boost::gregorian::years yy(count_);
347 if ((old_date + yy) <= new_date) {
355 if (!prerotate_.empty()) {
364 if (!postrotate_.empty()) {
376 lock_guard<mutex> lock(mutex_);
377 writelnInternal(text);
379 writelnInternal(text);
384RotatingFile::writelnInternal(
const string& text) {
393 stringstream ss(text);
394 for (
string line; getline(ss, line,
'\n');) {
395 file_ << timestamp <<
" " << line << endl;
397 int sav_error = errno;
400 <<
" reason: " << strerror(sav_error));
406 return (file_.is_open());
412 if (file_.is_open()) {
418 }
catch (
const exception& ex) {
422 .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.
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...