/* * Copyright (c) 2006,2007 INRIA * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Mathieu Lacage */ #include "log.h" #include "assert.h" #include "fatal-error.h" #include "ns3/core-config.h" #include // getenv #include // strlen #include #include #include #include /** * \file * \ingroup logging * ns3::LogComponent and related implementations. */ namespace ns3 { /** * \ingroup logging * The Log TimePrinter. * This is private to the logging implementation. */ static TimePrinter g_logTimePrinter = nullptr; /** * \ingroup logging * The Log NodePrinter. */ static NodePrinter g_logNodePrinter = nullptr; /** * \ingroup logging * Handler for \c print-list token in NS_LOG * to print the list of log components. * This is private to the logging implementation. */ class PrintList { public: PrintList(); //begin(); i != components->end(); i++) { if (i->first == name) { NS_FATAL_ERROR("Log component \"" << name << "\" has already been registered once."); } } components->insert(std::make_pair(name, this)); } LogComponent& GetLogComponent(const std::string name) { LogComponent::ComponentList* components = LogComponent::GetComponentList(); LogComponent* ret; try { ret = components->at(name); } catch (std::out_of_range&) { NS_FATAL_ERROR("Log component \"" << name << "\" does not exist."); } return *ret; } void LogComponent::EnvVarCheck() { const char* envVar = std::getenv("NS_LOG"); if (envVar == nullptr || std::strlen(envVar) == 0) { return; } std::string env = envVar; std::string::size_type cur = 0; std::string::size_type next = 0; while (next != std::string::npos) { next = env.find_first_of(':', cur); std::string tmp = std::string(env, cur, next - cur); std::string::size_type equal = tmp.find('='); std::string component; if (equal == std::string::npos) { component = tmp; if (component == m_name || component == "*" || component == "***") { int level = LOG_LEVEL_ALL | LOG_PREFIX_ALL; Enable((enum LogLevel)level); return; } } else { component = tmp.substr(0, equal); if (component == m_name || component == "*") { int level = 0; std::string::size_type cur_lev; std::string::size_type next_lev = equal; bool pre_pipe = true; // before the first '|', enables positional 'all', '*' do { cur_lev = next_lev + 1; next_lev = tmp.find('|', cur_lev); std::string lev = tmp.substr(cur_lev, next_lev - cur_lev); if (lev == "error") { level |= LOG_ERROR; } else if (lev == "warn") { level |= LOG_WARN; } else if (lev == "debug") { level |= LOG_DEBUG; } else if (lev == "info") { level |= LOG_INFO; } else if (lev == "function") { level |= LOG_FUNCTION; } else if (lev == "logic") { level |= LOG_LOGIC; } else if (pre_pipe && (lev == "all" || lev == "*")) { level |= LOG_LEVEL_ALL; } else if (lev == "prefix_func" || lev == "func") { level |= LOG_PREFIX_FUNC; } else if (lev == "prefix_time" || lev == "time") { level |= LOG_PREFIX_TIME; } else if (lev == "prefix_node" || lev == "node") { level |= LOG_PREFIX_NODE; } else if (lev == "prefix_level" || lev == "level") { level |= LOG_PREFIX_LEVEL; } else if (lev == "prefix_all" || (!pre_pipe && (lev == "all" || lev == "*"))) { level |= LOG_PREFIX_ALL; } else if (lev == "level_error") { level |= LOG_LEVEL_ERROR; } else if (lev == "level_warn") { level |= LOG_LEVEL_WARN; } else if (lev == "level_debug") { level |= LOG_LEVEL_DEBUG; } else if (lev == "level_info") { level |= LOG_LEVEL_INFO; } else if (lev == "level_function") { level |= LOG_LEVEL_FUNCTION; } else if (lev == "level_logic") { level |= LOG_LEVEL_LOGIC; } else if (lev == "level_all") { level |= LOG_LEVEL_ALL; } else if (lev == "**") { level |= LOG_LEVEL_ALL | LOG_PREFIX_ALL; } pre_pipe = false; } while (next_lev != std::string::npos); Enable((enum LogLevel)level); } } cur = next + 1; } } bool LogComponent::IsEnabled(const LogLevel level) const { // LogComponentEnableEnvVar (); return (level & m_levels) ? 1 : 0; } bool LogComponent::IsNoneEnabled() const { return m_levels == 0; } void LogComponent::SetMask(const LogLevel level) { m_mask |= level; } void LogComponent::Enable(const LogLevel level) { m_levels |= (level & ~m_mask); } void LogComponent::Disable(const LogLevel level) { m_levels &= ~level; } const char* LogComponent::Name() const { return m_name.c_str(); } std::string LogComponent::File() const { return m_file; } /* static */ std::string LogComponent::GetLevelLabel(const LogLevel level) { if (level == LOG_ERROR) { return "ERROR"; } else if (level == LOG_WARN) { // whitespace left at the end for alignment return "WARN "; } else if (level == LOG_DEBUG) { return "DEBUG"; } else if (level == LOG_INFO) { // whitespace left at the end for alignment return "INFO "; } else if (level == LOG_FUNCTION) { return "FUNCT"; } else if (level == LOG_LOGIC) { return "LOGIC"; } else { return "unknown"; } } void LogComponentEnable(const char* name, LogLevel level) { LogComponent::ComponentList* components = LogComponent::GetComponentList(); LogComponent::ComponentList::const_iterator i; for (i = components->begin(); i != components->end(); i++) { if (i->first == name) { i->second->Enable(level); return; } } if (i == components->end()) { // nothing matched LogComponentPrintList(); NS_FATAL_ERROR("Logging component \"" << name << "\" not found. See above for a list of available log components"); } } void LogComponentEnableAll(LogLevel level) { LogComponent::ComponentList* components = LogComponent::GetComponentList(); for (LogComponent::ComponentList::const_iterator i = components->begin(); i != components->end(); i++) { i->second->Enable(level); } } void LogComponentDisable(const char* name, LogLevel level) { LogComponent::ComponentList* components = LogComponent::GetComponentList(); for (LogComponent::ComponentList::const_iterator i = components->begin(); i != components->end(); i++) { if (i->first == name) { i->second->Disable(level); break; } } } void LogComponentDisableAll(LogLevel level) { LogComponent::ComponentList* components = LogComponent::GetComponentList(); for (LogComponent::ComponentList::const_iterator i = components->begin(); i != components->end(); i++) { i->second->Disable(level); } } void LogComponentPrintList() { LogComponent::ComponentList* components = LogComponent::GetComponentList(); for (LogComponent::ComponentList::const_iterator i = components->begin(); i != components->end(); i++) { std::cout << i->first << "="; if (i->second->IsNoneEnabled()) { std::cout << "0" << std::endl; continue; } if (i->second->IsEnabled(LOG_LEVEL_ALL)) { std::cout << "all"; } else { if (i->second->IsEnabled(LOG_ERROR)) { std::cout << "error"; } if (i->second->IsEnabled(LOG_WARN)) { std::cout << "|warn"; } if (i->second->IsEnabled(LOG_DEBUG)) { std::cout << "|debug"; } if (i->second->IsEnabled(LOG_INFO)) { std::cout << "|info"; } if (i->second->IsEnabled(LOG_FUNCTION)) { std::cout << "|function"; } if (i->second->IsEnabled(LOG_LOGIC)) { std::cout << "|logic"; } } if (i->second->IsEnabled(LOG_PREFIX_ALL)) { std::cout << "|prefix_all"; } else { if (i->second->IsEnabled(LOG_PREFIX_FUNC)) { std::cout << "|func"; } if (i->second->IsEnabled(LOG_PREFIX_TIME)) { std::cout << "|time"; } if (i->second->IsEnabled(LOG_PREFIX_NODE)) { std::cout << "|node"; } if (i->second->IsEnabled(LOG_PREFIX_LEVEL)) { std::cout << "|level"; } } std::cout << std::endl; } } /** * \ingroup logging * Check if a log component exists. * This is private to the logging implementation. * * \param [in] componentName The putative log component name. * \returns \c true if \c componentName exists. */ static bool ComponentExists(std::string componentName) { const char* name = componentName.c_str(); LogComponent::ComponentList* components = LogComponent::GetComponentList(); LogComponent::ComponentList::const_iterator i; for (i = components->begin(); i != components->end(); i++) { if (i->first == name) { return true; } } NS_ASSERT(i == components->end()); // nothing matched return false; } /** * \ingroup logging * Parse the \c NS_LOG environment variable. * This is private to the logging implementation. */ static void CheckEnvironmentVariables() { const char* envVar = std::getenv("NS_LOG"); if (envVar == nullptr || std::strlen(envVar) == 0) { return; } std::string env = envVar; std::string::size_type cur = 0; std::string::size_type next = 0; while (next != std::string::npos) { next = env.find_first_of(':', cur); std::string tmp = std::string(env, cur, next - cur); std::string::size_type equal = tmp.find('='); std::string component; if (equal == std::string::npos) { // ie no '=' characters found component = tmp; if (ComponentExists(component) || component == "*" || component == "***") { return; } else { LogComponentPrintList(); NS_FATAL_ERROR( "Invalid or unregistered component name \"" << component << "\" in env variable NS_LOG, see above for a list of valid components"); } } else { component = tmp.substr(0, equal); if (ComponentExists(component) || component == "*") { std::string::size_type cur_lev; std::string::size_type next_lev = equal; do { cur_lev = next_lev + 1; next_lev = tmp.find('|', cur_lev); std::string lev = tmp.substr(cur_lev, next_lev - cur_lev); if (lev == "error" || lev == "warn" || lev == "debug" || lev == "info" || lev == "function" || lev == "logic" || lev == "all" || lev == "prefix_func" || lev == "func" || lev == "prefix_time" || lev == "time" || lev == "prefix_node" || lev == "node" || lev == "prefix_level" || lev == "level" || lev == "prefix_all" || lev == "level_error" || lev == "level_warn" || lev == "level_debug" || lev == "level_info" || lev == "level_function" || lev == "level_logic" || lev == "level_all" || lev == "*" || lev == "**") { continue; } else { NS_FATAL_ERROR("Invalid log level \"" << lev << "\" in env variable NS_LOG for component name " << component); } } while (next_lev != std::string::npos); } else { LogComponentPrintList(); NS_FATAL_ERROR( "Invalid or unregistered component name \"" << component << "\" in env variable NS_LOG, see above for a list of valid components"); } } cur = next + 1; // parse next component } } void LogSetTimePrinter(TimePrinter printer) { g_logTimePrinter = printer; /** \internal * This is the only place where we are more or less sure that all log variables * are registered. See \bugid{1082} for details. */ CheckEnvironmentVariables(); } TimePrinter LogGetTimePrinter() { return g_logTimePrinter; } void LogSetNodePrinter(NodePrinter printer) { g_logNodePrinter = printer; } NodePrinter LogGetNodePrinter() { return g_logNodePrinter; } ParameterLogger::ParameterLogger(std::ostream& os) : m_os(os) { } void ParameterLogger::CommaRest() { if (m_first) { m_first = false; } else { m_os << ", "; } } template <> ParameterLogger& ParameterLogger::operator<< (const std::string& param) { CommaRest(); m_os << "\"" << param << "\""; return *this; } ParameterLogger& ParameterLogger::operator<<(const char* param) { (*this) << std::string(param); return *this; } template <> ParameterLogger& ParameterLogger::operator<< (const int8_t param) { (*this) << static_cast(param); return *this; } template <> ParameterLogger& ParameterLogger::operator<< (const uint8_t param) { (*this) << static_cast(param); return *this; } } // namespace ns3