/* * @project The CERN Tape Archive (CTA) * @copyright Copyright © 2021-2022 CERN * @license This program is free software, distributed under the terms of the GNU General Public * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * In applying this licence, CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization or * submit itself to any jurisdiction. */ #include "common/log/Logger.hpp" #include "common/log/LogLevel.hpp" #include "common/utils/utils.hpp" #include "common/exception/Exception.hpp" #include "PriorityMaps.hpp" #include #include namespace cta::log { //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ Logger::Logger(std::string_view hostName, std::string_view programName, const int logMask): m_hostName(hostName), m_programName(programName), m_logMask(logMask), m_priorityToText(generatePriorityToTextMap()) {} //------------------------------------------------------------------------------ // getProgramName //------------------------------------------------------------------------------ const std::string &Logger::getProgramName() const { return m_programName; } //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ Logger::~Logger() = default; //----------------------------------------------------------------------------- // operator() //----------------------------------------------------------------------------- void Logger::operator() (int priority, std::string_view msg, const std::list& params) { const std::string rawParams; struct timeval timeStamp; gettimeofday(&timeStamp, nullptr); const int pid = getpid(); // Ignore messages whose priority is not of interest if(priority > m_logMask) { return; } // Try to find the textual representation of the syslog priority std::map::const_iterator priorityTextPair = m_priorityToText.find(priority); // Do nothing if the log priority is not valid if(m_priorityToText.end() == priorityTextPair) { return; } // Safe to get a reference to the textual representation of the priority const std::string &priorityText = priorityTextPair->second; const std::string header = createMsgHeader(timeStamp, m_hostName, m_programName, pid); const std::string body = createMsgBody(priorityText, msg, params, rawParams, pid); writeMsgToUnderlyingLoggingSystem(header, body); } //----------------------------------------------------------------------------- // cleanString //----------------------------------------------------------------------------- std::string Logger::cleanString(const std::string &s, const bool replaceUnderscores) { // Trim both left and right white-space std::string result = utils::trimString(s); for (std::string::iterator it = result.begin(); it != result.end(); ++it) { // Replace double quote with single quote if ('"' == *it) { *it = '\''; } // Replace newline and tab with a space if ('\t' == *it || '\n' == *it) { *it = ' '; } // If requested, replace spaces with underscores if(replaceUnderscores && ' ' == *it) { *it = '_'; } } return result; } //------------------------------------------------------------------------------ // generatePriorityToTextMap //------------------------------------------------------------------------------ std::map Logger::generatePriorityToTextMap() { return PriorityMaps::c_priorityToTextMap; } //------------------------------------------------------------------------------ // generateConfigTextToPriorityMap //------------------------------------------------------------------------------ std::map Logger::generateConfigTextToPriorityMap() { return PriorityMaps::c_configTextToPriorityMap; } //------------------------------------------------------------------------------ // setLogMask //------------------------------------------------------------------------------ void Logger::setLogMask(std::string_view logMask) { try { setLogMask(toLogLevel(logMask)); } catch(exception::Exception &ex) { throw exception::Exception(std::string("Failed to set log mask: ") + ex.getMessage().str()); } } //------------------------------------------------------------------------------ // setLogMask //------------------------------------------------------------------------------ void Logger::setLogMask(const int logMask) { m_logMask = logMask; } //----------------------------------------------------------------------------- // createMsgHeader //----------------------------------------------------------------------------- std::string Logger::createMsgHeader( const struct timeval &timeStamp, std::string_view hostName, std::string_view programName, const int pid) { std::ostringstream os; char buf[80]; int bufLen = sizeof(buf); int len = 0; struct tm localTime; localtime_r(&(timeStamp.tv_sec), &localTime); len += strftime(buf, bufLen, "%b %e %T", &localTime); len += snprintf(buf + len, bufLen - len, ".%06lu ", static_cast(timeStamp.tv_usec)); buf[sizeof(buf) - 1] = '\0'; os << buf << hostName << " " << programName << ": "; return os.str(); } //----------------------------------------------------------------------------- // createMsgBody //----------------------------------------------------------------------------- std::string Logger::createMsgBody(std::string_view priorityText, std::string_view msg, const std::list ¶ms, std::string_view rawParams, int pid) { std::ostringstream os; const int tid = syscall(__NR_gettid); // Append the log level, the thread id and the message text os << "LVL=\"" << priorityText << "\" PID=\"" << pid << "\" TID=\"" << tid << "\" MSG=\"" << msg << "\" "; // Process parameters for(auto itor = params.cbegin(); itor != params.cend(); itor++) { const Param ¶m = *itor; // Check the parameter name, if it's an empty string set the value to // "Undefined". const std::string name = param.getName() == "" ? "Undefined" : cleanString(param.getName(), true); // Process the parameter value const std::string value = cleanString(param.getValue(), false); // Write the name and value to the buffer os << name << "=\"" << value << "\" "; } // Append raw parameters os << rawParams; return os.str(); } } // namespace cta::log