15#include <boost/date_time/posix_time/posix_time.hpp>
45 string base(
"kea-legal");
53 if (parameters.find(
"path") != parameters.end()) {
54 path = parameters.at(
"path");
56 if (parameters.find(
"base-name") != parameters.end()) {
57 base = parameters.at(
"base-name");
59 if (parameters.find(
"time-unit") != parameters.end()) {
60 string time_unit(parameters.at(
"time-unit"));
62 if (time_unit ==
"second") {
64 }
else if (time_unit ==
"day") {
66 }
else if (time_unit ==
"month") {
68 }
else if (time_unit ==
"year") {
72 <<
", expected one of: second, day, month, year");
75 if (parameters.find(
"count") != parameters.end()) {
77 count = boost::lexical_cast<int64_t>(parameters.at(
"count"));
79 isc_throw(
BadValue,
"bad value: " << parameters.at(
"count") <<
" for count parameter");
82 (count > numeric_limits<uint32_t>::max())) {
84 <<
" is out of range, expected value: 0.."
85 << numeric_limits<uint32_t>::max());
88 if (parameters.find(
"prerotate") != parameters.end()) {
89 prerotate = parameters.at(
"prerotate");
91 if (parameters.find(
"postrotate") != parameters.end()) {
92 postrotate = parameters.at(
"postrotate");
94 if (parameters.find(
"mark-continuation-lines") != parameters.end()) {
95 string mcl(parameters.at(
"mark-continuation-lines"));
102 count_ =
static_cast<uint32_t
>(count);
103 prerotate_ = prerotate;
104 postrotate_ = postrotate;
110 if (base_name_.empty()) {
114 if (!prerotate_.empty()) {
123 if (!postrotate_.empty()) {
140 strftime(buffer,
sizeof(buffer),
"%Y%m%d", &time_info);
141 return (
string(buffer));
146 ostringstream stream;
147 string name = base_name_ +
".";
149 stream << path_ <<
"/";
152 time_t timestamp = mktime(&time_info);
153 ostringstream name_stream;
154 name_stream << right << setfill(
'0') << setw(20)
155 <<
static_cast<uint64_t
>(timestamp);
157 name += name_stream.str();
162 stream << name <<
".txt";
164 file_name_ = stream.str();
173 DIR* dir = opendir(path_.c_str());
178 unique_ptr<DIR, void(*)(DIR*)> defer(dir, [](DIR* d) { closedir(d); });
184 for (
struct dirent* dent = readdir(dir); dent; dent = readdir(dir)) {
185 string name(dent->d_name);
188 if ((name.size() != (base_name_.size() +
sizeof(
".YYYYMMDD.txt") - 1)) &&
189 (name.size() != (base_name_.size() +
sizeof(
".TXXXXXXXXXXXXXXXXXXXX.txt") - 1))) {
194 if (name.substr(name.size() - 4) !=
".txt") {
198 string file = name.substr(0, name.size() - 4);
201 if (base_name_ !=
file.substr(0, base_name_.size())) {
205 file =
file.substr(base_name_.size() + 1);
206 uint32_t tag_size =
sizeof(
"YYYYMMDD") - 1;
209 if (
file.at(0) !=
'T') {
212 tag_size =
sizeof(
"TXXXXXXXXXXXXXXXXXXXX") - 1;
215 if (
file.size() != tag_size) {
218 for (; index < tag_size; ++index) {
219 if (!isdigit(
file.at(index))) {
223 if (index != tag_size) {
233 string file = *files.rbegin();
236 time_t file_timestamp;
238 file_timestamp =
static_cast<time_t
>(boost::lexical_cast<uint64_t>(
file.substr(1)));
242 time_t current_timestamp = mktime(&time_info);
243 if (current_timestamp < (file_timestamp +
static_cast<time_t
>(count_))) {
244 localtime_r(&file_timestamp, &time_info);
249 boost::gregorian::date file_date;
251 file_date = boost::gregorian::from_undelimited_string(
file);
255 boost::gregorian::date current_date = boost::gregorian::date_from_tm(time_info);
257 boost::gregorian::date_duration dd(count_);
258 if (current_date < (file_date + dd)) {
259 time_info = boost::gregorian::to_tm(file_date);
264 boost::gregorian::months mm(count_);
265 if (current_date < (file_date + mm)) {
266 time_info = boost::gregorian::to_tm(file_date);
271 boost::gregorian::years yy(count_);
272 if (current_date < (file_date + yy)) {
273 time_info = boost::gregorian::to_tm(file_date);
280 file_name_ = path_ +
"/" + base_name_ +
"." +
file +
".txt";
298 file_.open(file_name_.c_str(), ofstream::app);
299 int sav_error = errno;
300 if (!file_.is_open()) {
302 <<
" reason: " << strerror(sav_error));
306 timestamp_ = mktime(&time_info);
314 if (
isOpen() && !count_) {
318 bool rotate_file =
false;
322 localtime_r(×tamp_, &time_info);
328 time_t timestamp = mktime(¤t_time_info);
331 boost::gregorian::date old_date = boost::gregorian::date_from_tm(time_info);
334 boost::gregorian::date new_date = boost::gregorian::date_from_tm(current_time_info);
339 if (
static_cast<time_t
>(count_) <= (timestamp - timestamp_)) {
343 boost::gregorian::date_duration dd(count_);
344 if ((old_date + dd) <= new_date) {
348 boost::gregorian::months mm(count_);
349 if ((old_date + mm) <= new_date) {
353 boost::gregorian::years yy(count_);
354 if ((old_date + yy) <= new_date) {
362 if (!prerotate_.empty()) {
371 if (!postrotate_.empty()) {
383 lock_guard<mutex> lock(mutex_);
384 writelnInternal(text);
386 writelnInternal(text);
391RotatingFile::writelnInternal(
const string& text) {
400 stringstream ss(text);
403 for (
string line; getline(ss, line,
'\n');) {
404 lines.push_back(line);
406 while (!lines.empty()) {
407 string line = lines.front();
415 file_ << line << endl;
417 int sav_error = errno;
419 isc_throw(LegalLogMgrError,
"error writing to file:" << file_name_
420 <<
" reason: " << strerror(sav_error));
426 return (file_.is_open());
432 if (file_.is_open()) {
438 }
catch (
const exception& ex) {
442 .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...