blob: 742423b5319199b5f4e8a5056282389ebe40df27 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define __STDC_CONSTANT_MACROS
#include <log4cxx/logstring.h>
#include <log4cxx/helpers/filewatchdog.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/helpers/exception.h>
#include <log4cxx/helpers/threadutility.h>
#include <log4cxx/helpers/stringhelper.h>
#include <functional>
#include <chrono>
using namespace LOG4CXX_NS;
using namespace LOG4CXX_NS::helpers;
long FileWatchdog::DEFAULT_DELAY = 60000;
struct FileWatchdog::FileWatchdogPrivate{
FileWatchdogPrivate(const File& file1) :
file(file1), delay(DEFAULT_DELAY), lastModif(0),
warnedAlready(false), interrupted(0), thread(){}
/**
The name of the file to observe for changes.
*/
File file;
/**
The delay to observe between every check.
By default set DEFAULT_DELAY.*/
long delay;
log4cxx_time_t lastModif;
bool warnedAlready;
volatile int interrupted;
Pool pool;
std::thread thread;
std::condition_variable interrupt;
std::mutex interrupt_mutex;
};
FileWatchdog::FileWatchdog(const File& file1)
: m_priv(std::make_unique<FileWatchdogPrivate>(file1))
{
}
FileWatchdog::~FileWatchdog()
{
if (m_priv->thread.joinable())
stop();
}
bool FileWatchdog::is_active()
{
return m_priv->thread.joinable();
}
void FileWatchdog::stop()
{
LogLog::debug(LOG4CXX_STR("Stopping file watchdog"));
{
std::lock_guard<std::mutex> lock(m_priv->interrupt_mutex);
m_priv->interrupted = 0xFFFF;
}
m_priv->interrupt.notify_all();
m_priv->thread.join();
}
const File& FileWatchdog::file()
{
return m_priv->file;
}
void FileWatchdog::checkAndConfigure()
{
LogString msg(LOG4CXX_STR("Checking ["));
msg += m_priv->file.getPath();
msg += LOG4CXX_STR("]");
LogLog::debug(msg);
Pool pool1;
if (!m_priv->file.exists(pool1))
{
if (!m_priv->warnedAlready)
{
LogLog::debug(((LogString) LOG4CXX_STR("["))
+ m_priv->file.getPath()
+ LOG4CXX_STR("] does not exist."));
m_priv->warnedAlready = true;
}
}
else
{
auto thisMod = m_priv->file.lastModified(pool1);
if (thisMod > m_priv->lastModif)
{
m_priv->lastModif = thisMod;
doOnChange();
m_priv->warnedAlready = false;
}
}
}
void FileWatchdog::run()
{
LogString msg(LOG4CXX_STR("Checking ["));
msg += m_priv->file.getPath();
msg += LOG4CXX_STR("] at ");
StringHelper::toString((int)m_priv->delay, m_priv->pool, msg);
msg += LOG4CXX_STR(" ms interval");
LogLog::debug(msg);
while (!is_interrupted())
{
std::unique_lock<std::mutex> lock( m_priv->interrupt_mutex );
if (!m_priv->interrupt.wait_for( lock, std::chrono::milliseconds( m_priv->delay ),
std::bind(&FileWatchdog::is_interrupted, this) ))
checkAndConfigure();
}
LogString msg2(LOG4CXX_STR("Stop checking ["));
msg2 += m_priv->file.getPath();
msg2 += LOG4CXX_STR("]");
LogLog::debug(msg2);
}
void FileWatchdog::start()
{
checkAndConfigure();
if (!m_priv->thread.joinable())
{
m_priv->interrupted = 0;
m_priv->thread = ThreadUtility::instance()->createThread(LOG4CXX_STR("FileWatchdog"), &FileWatchdog::run, this);
}
}
bool FileWatchdog::is_interrupted()
{
return m_priv->interrupted == 0xFFFF;
}
void FileWatchdog::setDelay(long delay1){
m_priv->delay = delay1;
}