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...