#include #include "Log.h" Log * g_Log = nullptr; static const char * g_LogLevelStr[eNumLogLevels] = { "error", // eLogError "warn", // eLogWarning "info", // eLogInfo "debug" // eLogDebug }; #ifndef _WIN32 /** convert LogLevel enum to syslog priority level */ static int ToSyslogLevel(LogLevel lvl) { switch (lvl) { case eLogError: return LOG_ERR; case eLogWarning: return LOG_WARNING; case eLogInfo: return LOG_INFO; case eLogDebug: return LOG_DEBUG; default: // WTF? invalid log level? return LOG_CRIT; } } #endif void LogMsg::Process() { #ifndef _WIN32 if (log && log->SyslogEnabled()) { // only log to syslog syslog(ToSyslogLevel(level), "%s", s.str().c_str()); return; } #endif auto stream = log ? log->GetLogStream () : nullptr; auto& output = stream ? *stream : std::cout; if (log) output << log->GetTimestamp (); else output << boost::posix_time::second_clock::local_time().time_of_day (); output << "/" << g_LogLevelStr[level] << " - "; output << s.str(); } const std::string& Log::GetTimestamp () { #if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__) auto ts = std::chrono::monotonic_clock::now (); #else auto ts = std::chrono::steady_clock::now (); #endif if (ts > m_LastTimestampUpdate + std::chrono::milliseconds (500)) // 0.5 second { m_LastTimestampUpdate = ts; m_Timestamp = boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time().time_of_day ()); } return m_Timestamp; } void Log::Flush () { if (m_LogStream) m_LogStream->flush(); } void Log::SetLogFile (const std::string& fullFilePath, bool truncate) { m_FullFilePath = fullFilePath; auto mode = std::ofstream::out | std::ofstream::binary; mode |= truncate ? std::ofstream::trunc : std::ofstream::app; auto logFile = std::make_shared (fullFilePath, mode); if (logFile->is_open ()) { SetLogStream (logFile); LogPrint(eLogInfo, "Log: will send messages to ", fullFilePath); } } void Log::ReopenLogFile () { if (m_FullFilePath.length () > 0) { SetLogFile (m_FullFilePath, false); // don't truncate LogPrint(eLogInfo, "Log: file ", m_FullFilePath, " reopen"); } } void Log::SetLogLevel (const std::string& level) { if (level == "error") { m_MinLevel = eLogError; } else if (level == "warn") { m_MinLevel = eLogWarning; } else if (level == "info") { m_MinLevel = eLogInfo; } else if (level == "debug") { m_MinLevel = eLogDebug; } else { LogPrint(eLogError, "Log: Unknown loglevel: ", level); return; } LogPrint(eLogInfo, "Log: min msg level set to ", level); } void Log::SetLogStream (std::shared_ptr logStream) { m_LogStream = logStream; } void Log::StartSyslog(const std::string & ident, const int facility) { #ifndef _WIN32 m_Ident = ident; openlog(m_Ident.c_str(), LOG_PID, facility); #endif } void Log::StopSyslog() { #ifndef _WIN32 closelog(); m_Ident.clear(); #endif } bool Log::SyslogEnabled() { return m_Ident.size() > 0; }