Project

General

Profile

Download (4.86 KB) Statistics
| Branch: | Revision:
/********************************************************************
* 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)
{
// OTHER NOTE: this assumes truncating the file path after the "src/"
// portion which is currently valid for copytool source tree organization.
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};

// Convenience LOG macro definition
#define LOG(sev) DBS::Logger::getInstance(sev).internalLog() \
<< &(__FILE__[PATH_OFFSET(__FILE__)]) << ":" << __LINE__ << "|"

class Logger
{
public:

/**
* Logger Destructor
*/
~Logger();

/**
* Get the singleton instance
*/
static Logger& getInstance(
enum LOG_LEVEL sev,
CopyManagerOptions* optionsObj=nullptr)
{
static Logger instance(optionsObj);
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();
}

/**
* Select the output stream based on the specified options
* @return
*/
inline std::ostream& getStream()
{
return (r_options.getLogToStderr() ? std::cerr : m_logFile);
}

/**
* 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__
(6-6/9)