SockIt
Static Public Member Functions | Static Public Attributes | Private Member Functions | Static Private Member Functions | Static Private Attributes

Logger Class Reference

#include <Logger.h>

List of all members.

Static Public Member Functions

static void error (string msg, int port=NO_PORT, string host="local")
static void info (string msg, int port=NO_PORT, string host="local")
static void warn (string msg, int port=NO_PORT, string host="local")
static const bool is_enabled ()
static void shutdown ()

Static Public Attributes

static const int NO_PORT = 0

Private Member Functions

 Logger ()

Static Private Member Functions

static void queue (string host, int port, string msg, string cat)
static string get_date ()
static string get_timestamp ()
static string get_log_base_path ()
static void initialize ()
static void log_writer_run ()
static void handle_write_request (string dir, string line)
static void formatter_run ()
static void handle_format_request (string host, int port, string msg, string cat)

Static Private Attributes

static const int SLEEP_TIME_MS = 50
static bool initialized = false
static bool enabled = true
static boost::mutex log_writer_mtx
static boost::mutex formatter_mtx
static boost::mutex shutdown_mtx
static boost::condition_variable shutdown_cvar
static boost::condition_variable formatter_cvar
static boost::condition_variable log_writer_cvar
static std::queue< pair< pair
< string, int >, pair< string,
string > > > 
raw_requests
static std::queue< pair
< string, string > > 
write_requests
static string pid
static boost::thread frm_t
static boost::thread lw_t

Detailed Description

Logger.h

Do not instantiate or inherit from this class.

An asynchronous logger. Call by using Logger::info("msg"); or equivalent method. Designed to have the main thread do as little work as possible.

Internally, there are two background threads. One formats a log request into a file directory and a log entry. The other actually writes this into the log. Hopefully, one thread can be in a system call (to get the current date or time) and the other can be doing I/O.

Sadly, a bug in firebreath+boost prevents both background threads from sleeping and just periodically checking that there's work. The bug makes the sleeping thread hang indefinitely (until interrupted). Since the bug affects waiting/timed waiting on a condition variable, (which is how boost implements sleep), the main thread has to signal the formatter thread just in case the bug happened. The formatter thread then signals the log writing thread when there's work.

Logs are placed in /sockit/YYYY-MM-DD/REMOTEHOST/PROCESSID/sockit-traffic.log.

Note: Logger::shutdown() should only be called once, when the plugin is shutting down. After this is called, no more logging will take place.

Definition at line 60 of file Logger.h.


Constructor & Destructor Documentation

Logger::Logger ( ) [inline, private]

Definition at line 122 of file Logger.h.

        {
        }

Member Function Documentation

static void Logger::error ( string  msg,
int  port = NO_PORT,
string  host = "local" 
) [inline, static]
void Logger::formatter_run ( ) [static, private]

Only the formatter thread should be here. Run until logging is disabled and handle formatting requests.

Definition at line 130 of file Logger.cpp.

References enabled, formatter_cvar, formatter_mtx, handle_format_request(), raw_requests, and SLEEP_TIME_MS.

Referenced by initialize().

{
    // needed for sleeping on a boost cvar
    boost::unique_lock<boost::mutex> fmt_lock(formatter_mtx);

    // continue as long as logging is enabled and there are still raw requests to process
    while(true)
    {
        while (!raw_requests.empty())
        {
            // handle one request
            pair<pair<string, int> , pair<string, string> > p = raw_requests.front();
            raw_requests.pop();
            fmt_lock.unlock();
            handle_format_request(p.first.first, p.first.second, p.second.first, p.second.second);
            fmt_lock.lock();
        }
       
        if(enabled || !raw_requests.empty()) 
        {
            // Sigh. There's a bug with firebreath + boost::this_thread::sleep/boost::condition_variable.timed_wait
            // where the sleeping thread hangs forever. So this is a compromise/work around.

            // don't hold the lock across the gettime system call
            fmt_lock.unlock();
            boost::system_time sleep_time = boost::get_system_time() + boost::posix_time::milliseconds(SLEEP_TIME_MS);
            fmt_lock.lock();

            // wake up periodically to check for work.
            formatter_cvar.timed_wait(fmt_lock, sleep_time);
        }
        else
        {
            fmt_lock.unlock();
            break;
        }
    }
}
string Logger::get_date ( ) [static, private]

Helper for building the directory path. Gets the current date (local time) in YYYY-MM-DD format.

Definition at line 65 of file Logger.cpp.

Referenced by handle_format_request().

{
    boost::gregorian::date d(boost::gregorian::day_clock::local_day());
    return boost::gregorian::to_iso_extended_string(d);
}
string Logger::get_log_base_path ( ) [static, private]

Helper for building the directory path. Gets the base log path.

Definition at line 79 of file Logger.cpp.

References PROFILE_BUF_LEN.

Referenced by handle_format_request().

{
#if defined (__UNIX__) || defined (__OSX__)

    string path(getenv("HOME"));

#else

#define PROFILE_BUF_LEN 250
    char profilepath[PROFILE_BUF_LEN];
    ExpandEnvironmentStringsA("%USERPROFILE%", profilepath, PROFILE_BUF_LEN);
    string path(profilepath);

#endif
    path.append("/sockit");
    return path;
}
string Logger::get_timestamp ( ) [static, private]

Helper for building the directory path. Gets the current timestamp (local time) in HH:MM:SS format

Definition at line 72 of file Logger.cpp.

Referenced by handle_format_request().

{
    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
    return boost::posix_time::to_simple_string(now);
}
void Logger::handle_format_request ( string  host,
int  port,
string  msg,
string  cat 
) [static, private]

Only the formatter thread should be here. Handles a format request.

Definition at line 170 of file Logger.cpp.

References get_date(), get_log_base_path(), get_timestamp(), log_writer_cvar, log_writer_mtx, NO_PORT, pid, and write_requests.

Referenced by formatter_run().

{
    // used to build the log path
    string host_str = (host == "local" ? "localhost" : host);
    string port_str = (port == NO_PORT ? "" : boost::lexical_cast<string>(port));

    string day = get_date();
    string time = get_timestamp();

    // figure out the path for this message
    string log_path(get_log_base_path() + "/" + day + "/" + host_str + "/" + pid);
    string entry(cat + "[" + time + "] " + "[" + host_str + (port == NO_PORT ? "] " : "] [" + port_str + "] ") + msg);

    // log request item
    pair<string, string> item(log_path, entry);

    // add item to log write queue
    log_writer_mtx.lock();
    write_requests.push(item);

    // awaken log writing thread - it has work
    log_writer_mtx.unlock();
    log_writer_cvar.notify_one();
}
void Logger::handle_write_request ( string  dir,
string  line 
) [static, private]

Only the log writing thread should be in this function. Handles a log write request.

Definition at line 238 of file Logger.cpp.

Referenced by log_writer_run().

{
    namespace fs = boost::filesystem;

    if (!fs::exists(dir))
    {
        try
        {
            fs::create_directories(dir);
        } catch (fs::filesystem_error &err)
        {
            // hope someone is listening..
            std::cout << "Error: could not create directory " << dir << std::endl;
            return;
        }
    }

    string fileName(dir + "/sockit-traffic.log");
    line.append("\n");

    FILE *fp = fopen(fileName.c_str(), "a");

    if(fp)
    {
        fwrite(line.c_str(), line.size(), 1,  fp);
        fclose(fp);
    }
    else
    {
        std::cout << "Error: could not open file " << fileName << std::endl;
    }
}
static void Logger::info ( string  msg,
int  port = NO_PORT,
string  host = "local" 
) [inline, static]
void Logger::initialize ( ) [static, private]

Initialize the background logging thread. Should only be called once.

Definition at line 56 of file Logger.cpp.

References formatter_run(), frm_t, initialized, log_writer_run(), and lw_t.

Referenced by queue().

{
    initialized = true;

    frm_t = boost::thread(&Logger::formatter_run);
    lw_t = boost::thread(&Logger::log_writer_run);
}
static const bool Logger::is_enabled ( ) [inline, static]

Returns true if logging is enabled (default). Returns false if the shutdown method has been called (and logging has been disabled).

Definition at line 107 of file Logger.h.

References enabled.

Referenced by error(), info(), and warn().

        {
            return Logger::enabled;
        }
void Logger::log_writer_run ( ) [static, private]

Only the log writing thread should be in this function. Run until logging is disabled and handle log writing requests.

Definition at line 197 of file Logger.cpp.

References enabled, handle_write_request(), log_writer_cvar, log_writer_mtx, raw_requests, shutdown_cvar, SLEEP_TIME_MS, and write_requests.

Referenced by initialize().

{
    // Needed to sleep on a boost cvar
    boost::unique_lock<boost::mutex> lw_lock(log_writer_mtx);

    // continue as long as logging is enabled and there are either
    // raw requests to process or log writing requests to process
    while(true)
    {
        while (!write_requests.empty())
        {
            // handle one request
            pair<string, string> p = write_requests.front();
            write_requests.pop();
            log_writer_mtx.unlock();
            handle_write_request(p.first, p.second);
            log_writer_mtx.lock();
        }

        if(enabled || !raw_requests.empty() || !write_requests.empty())
        {
            // don't hold the lock across a system call
            lw_lock.unlock();
            boost::system_time sleep_time = boost::get_system_time() + boost::posix_time::milliseconds(SLEEP_TIME_MS);
            lw_lock.lock();

            // wait until there's work
            log_writer_cvar.timed_wait(lw_lock, sleep_time);
        }
        else
        {
            lw_lock.unlock();
            break;
        }
    }

    // notify the main thread to wake up
    shutdown_cvar.notify_all();
}
void Logger::queue ( string  host,
int  port,
string  msg,
string  cat 
) [static, private]

Definition at line 112 of file Logger.cpp.

References formatter_cvar, formatter_mtx, initialize(), initialized, and raw_requests.

Referenced by error(), info(), and warn().

{
    pair<string, int> item1(host, port);
    pair<string, string> item2(msg, cat);
    pair<pair<string, int> , pair<string, string> > item(item1, item2);

    formatter_mtx.lock();

    if (!Logger::initialized)
        Logger::initialize();

    raw_requests.push(item);
    formatter_cvar.notify_one();

    formatter_mtx.unlock();
}
void Logger::shutdown ( ) [static]

Dangerous. Disables logging and forces the remaining logging requests to finish. Should only be called when the plugin is shutting down.

Definition at line 98 of file Logger.cpp.

References enabled, initialized, shutdown_cvar, and shutdown_mtx.

{
    // disable any more log requests and disable the background threads from sleeping
    enabled = false;

    if(initialized)
    {
        // wait until the log writing queue is done
        boost::unique_lock<boost::mutex> lock(shutdown_mtx);
        shutdown_cvar.wait(lock);
    }
}
static void Logger::warn ( string  msg,
int  port = NO_PORT,
string  host = "local" 
) [inline, static]

Log that there is an warning, along with a message.

Parameters:
hostEither a client's remote host or the localhost for servers
portEither the remote host's port (for a client) or the server's local port
msgThe message to log

Definition at line 97 of file Logger.h.

References is_enabled(), and queue().

Referenced by TcpServer::accept_handler(), TcpServer::close(), TcpClient::close(), TcpClient::connect_handler(), UdpServer::listen(), UdpClient::listen(), Tcp::receive_handler(), TcpClient::resolve_handler(), Tcp::send_handler(), and NetworkThread::~NetworkThread().

        {
            if (Logger::is_enabled())
                Logger::queue(host, port, msg, "WARN  :  ");
        }

Member Data Documentation

bool Logger::enabled = true [static, private]

Enabled?

Definition at line 160 of file Logger.h.

Referenced by formatter_run(), is_enabled(), log_writer_run(), and shutdown().

boost::condition_variable Logger::formatter_cvar [static, private]

The formatter thread sleeps on this.

Definition at line 175 of file Logger.h.

Referenced by formatter_run(), and queue().

boost::mutex Logger::formatter_mtx [static, private]

Mutex for the formatter queue

Definition at line 166 of file Logger.h.

Referenced by formatter_run(), and queue().

boost::thread Logger::frm_t [static, private]

The formatter thread

Definition at line 190 of file Logger.h.

Referenced by initialize().

bool Logger::initialized = false [static, private]

Initialized?

Definition at line 157 of file Logger.h.

Referenced by initialize(), queue(), and shutdown().

boost::condition_variable Logger::log_writer_cvar [static, private]

The log writer thread sleeps on this.

Definition at line 178 of file Logger.h.

Referenced by handle_format_request(), and log_writer_run().

boost::mutex Logger::log_writer_mtx [static, private]

Mutex for the log writer queue

Definition at line 163 of file Logger.h.

Referenced by handle_format_request(), and log_writer_run().

boost::thread Logger::lw_t [static, private]

The log-writer thread

Definition at line 193 of file Logger.h.

Referenced by initialize().

const int Logger::NO_PORT = 0 [static]
string Logger::pid [static, private]

The logger's pid

Definition at line 187 of file Logger.h.

Referenced by handle_format_request().

std::queue< pair< pair< string, int >, pair< string, string > > > Logger::raw_requests [static, private]

Queue for the raw requests

Definition at line 181 of file Logger.h.

Referenced by formatter_run(), log_writer_run(), and queue().

boost::condition_variable Logger::shutdown_cvar [static, private]

Cvar for shutting down (main thread uses this)

Definition at line 172 of file Logger.h.

Referenced by log_writer_run(), and shutdown().

boost::mutex Logger::shutdown_mtx [static, private]

Mutex for the shutdown cvar

Definition at line 169 of file Logger.h.

Referenced by shutdown().

const int Logger::SLEEP_TIME_MS = 50 [static, private]

The formatter thread polls for work; this sets its sleep time.

Definition at line 127 of file Logger.h.

Referenced by formatter_run(), and log_writer_run().

std::queue< pair< string, string > > Logger::write_requests [static, private]

Queue for the write requests

Definition at line 184 of file Logger.h.

Referenced by handle_format_request(), and log_writer_run().


The documentation for this class was generated from the following files:
 All Classes Files Functions Variables Typedefs Friends Defines