root/src/Logger.h @ 856fcf9a
| 2c54c4c3 | david.sorber | /********************************************************************
|
||
* CONFIDENTIAL - All source code is the propriety and confidential *
|
||||
* information of David Sorber. *
|
||||
* *
|
||||
* Copyright 2024 David Sorber *
|
||||
* Unpublished -- all rights reserved under the copyright laws *
|
||||
* of the United States. *
|
||||
********************************************************************/
|
||||
#ifndef __LOGGER__
|
||||
#define __LOGGER__
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <mutex>
|
||||
#include <sys/time.h>
|
||||
#include "CopyManagerOptions.h"
|
||||
// Defined outside of namespace just for convenience.
|
||||
// NOTE: when using >= C++14 and >= -O1 the following function will be executed
|
||||
// at compile time. This avoids the need for the previous CMake path length trick.
|
||||
inline constexpr size_t PATH_OFFSET(const char* input)
|
||||
{
|
||||
| eee13fa3 | david.sorber | // OTHER NOTE: this assumes truncating the file path after the "src/"
|
||
// portion which is currently valid for copytool source tree organization.
|
||||
| 2c54c4c3 | david.sorber | const char* output = std::strstr(input, "src/");
|
||
if (output == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (output - input) + 4;
|
||||
}
|
||||
namespace DBS
|
||||
{
|
||||
// Enumeration representing the log severity levels
|
||||
enum LOG_LEVEL {off=-1, error=0, warn=1, info=2, debug=3, trace=4};
|
||||
| eee13fa3 | david.sorber | // Convenience LOG macro definition
|
||
#define LOG(sev) DBS::Logger::getInstance(sev).internalLog() \
|
||||
| 2c54c4c3 | david.sorber | << &(__FILE__[PATH_OFFSET(__FILE__)]) << ":" << __LINE__ << "|"
|
||
class Logger
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Logger Destructor
|
||||
*/
|
||||
~Logger();
|
||||
/**
|
||||
* Get the singleton instance
|
||||
*/
|
||||
static Logger& getInstance(
|
||||
enum LOG_LEVEL sev,
|
||||
| eee13fa3 | david.sorber | CopyManagerOptions* optionsObj=nullptr)
|
||
| 2c54c4c3 | david.sorber | {
|
||
| eee13fa3 | david.sorber | static Logger instance(optionsObj);
|
||
| 2c54c4c3 | david.sorber | if (sev >= 0)
|
||
{
|
||||
// Lock our mutex and set the severity level
|
||||
instance.lockMutex();
|
||||
instance.setSeverity(sev);
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
/**
|
||||
* Nested class used to get around the "endl" tag, it automatically
|
||||
* handles the "cleanup" at the end of the log message stream in the
|
||||
* destructor
|
||||
*/
|
||||
class InternalLogger
|
||||
{
|
||||
public:
|
||||
InternalLogger(enum LOG_LEVEL severity, Logger &outer)
|
||||
: m_internalSev(severity),
|
||||
r_outerLogger(outer)
|
||||
{
|
||||
}
|
||||
InternalLogger(const InternalLogger &other)
|
||||
: m_internalSev(other.m_internalSev),
|
||||
r_outerLogger(other.r_outerLogger)
|
||||
{
|
||||
}
|
||||
~InternalLogger()
|
||||
{
|
||||
std::string str = m_internalMsgStream.str();
|
||||
if (! str.empty())
|
||||
{
|
||||
r_outerLogger.log_msg(m_internalSev, str);
|
||||
// Clean the output stream for future logging
|
||||
m_internalMsgStream.str("");
|
||||
}
|
||||
// Make sure we unlock!
|
||||
r_outerLogger.unlockMutex();
|
||||
}
|
||||
/**
|
||||
* Overriding the insertion operator to build log message
|
||||
*/
|
||||
template<typename T>
|
||||
InternalLogger& operator<< (const T& msg)
|
||||
{
|
||||
m_internalMsgStream << msg;
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
enum LOG_LEVEL m_internalSev;
|
||||
Logger& r_outerLogger;
|
||||
std::stringstream m_internalMsgStream;
|
||||
};
|
||||
InternalLogger internalLog()
|
||||
{
|
||||
return InternalLogger(m_severity, *this);
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Private constructor (singleton)
|
||||
*/
|
||||
Logger(CopyManagerOptions* configObj);
|
||||
/**
|
||||
* Set the log severity level
|
||||
*/
|
||||
void setSeverity(enum LOG_LEVEL sev)
|
||||
{
|
||||
m_severity = sev;
|
||||
}
|
||||
/**
|
||||
* Lock the internal mutex
|
||||
*/
|
||||
void lockMutex()
|
||||
{
|
||||
m_rloggerMutex.lock();
|
||||
}
|
||||
/**
|
||||
* Unlock the internal mutex
|
||||
*/
|
||||
void unlockMutex()
|
||||
{
|
||||
m_rloggerMutex.unlock();
|
||||
}
|
||||
| eee13fa3 | david.sorber | /**
|
||
* Select the output stream based on the specified options
|
||||
* @return
|
||||
*/
|
||||
inline std::ostream& getStream()
|
||||
{
|
||||
return (r_options.getLogToStderr() ? std::cerr : m_logFile);
|
||||
}
|
||||
| 2c54c4c3 | david.sorber | /**
|
||
* Write a log message to the log file.
|
||||
*
|
||||
* @param level - the severity of the message being logged
|
||||
* @param message - the message to send
|
||||
*/
|
||||
void log_msg(enum LOG_LEVEL level, const std::string& msg);
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* The log message to write
|
||||
*/
|
||||
std::ostringstream m_outputStream;
|
||||
/**
|
||||
* Severity level of the log message
|
||||
*/
|
||||
enum LOG_LEVEL m_severity;
|
||||
/**
|
||||
* Mutex for making this singleton thread-safe
|
||||
*/
|
||||
std::mutex m_rloggerMutex;
|
||||
std::ofstream m_logFile;
|
||||
CopyManagerOptions& r_options;
|
||||
};
|
||||
} // DBS
|
||||
#endif // __LOGGER__
|