#ifndef STATEMENT_H #define STATEMENT_H /* * * Copyright (c) 2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "qpid/Msg.h" #include "qpid/CommonImportExport.h" #include #include namespace qpid { namespace log { /** Debugging severity levels * - trace: High-volume debugging messages. * - debug: Debugging messages. * - info: Informational messages. * - notice: Normal but significant condition. * - warning: Warn of a possible problem. * - error: A definite error has occured. * - critical: System in danger of severe failure. */ enum Level { trace, debug, info, notice, warning, error, critical }; struct LevelTraits { static const int COUNT=critical+1; /** Get level from string name. *@exception if name invalid. */ static Level level(const char* name); /** Get level from string name. *@exception if name invalid. */ static Level level(const std::string& name) { return level(name.c_str()); } /** String name of level */ static const char* name(Level); }; /** Formal message categories * https://issues.apache.org/jira/browse/QPID-3902 * * Category Source code directory * -------- --------------------- * Security acl ssl gssapi sasl cyrus * Broker broker * Management agent console qmf * Amqp amqp_0_10 framing * System log sys types xml thread mutex fork pipe time ... * HA cluster ha replication * Messaging messaging client * Store store * IO tcp rdma AsynchIO socket epoll * Test * Unspecified */ enum Category { security, broker, management, amqp, system, ha, messaging, store, io, test, unspecified }; struct CategoryTraits { static const int COUNT=unspecified+1; /** Test if given name is a Category name */ static bool isCategory(const std::string& name); /** Get category from string name * @exception if name invalid. */ static Category category(const char* name); /** Get category from string name. * @exception if name invalid. */ static Category category(const std::string& name) { return category(name.c_str()); } /** String name of category */ static const char* name(Category); }; class CategoryFileNameHints { public: CategoryFileNameHints(){ hintList.push_back(std::make_pair("AsynchIo", io)); hintList.push_back(std::make_pair("TCP", io)); hintList.push_back(std::make_pair("epoll", io)); hintList.push_back(std::make_pair("Pollable", io)); hintList.push_back(std::make_pair("Socket", io)); hintList.push_back(std::make_pair("Sasl", security)); hintList.push_back(std::make_pair("Ssl", security)); hintList.push_back(std::make_pair("Acl", security)); hintList.push_back(std::make_pair("acl", security)); hintList.push_back(std::make_pair("cyrus", security)); hintList.push_back(std::make_pair("amqp_", amqp)); hintList.push_back(std::make_pair("framing", amqp)); hintList.push_back(std::make_pair("management", management)); hintList.push_back(std::make_pair("qmf", management)); hintList.push_back(std::make_pair("console", management)); hintList.push_back(std::make_pair("cluster", ha)); hintList.push_back(std::make_pair("qpid/ha", ha)); hintList.push_back(std::make_pair("qpid\\ha", ha)); hintList.push_back(std::make_pair("replication", ha)); hintList.push_back(std::make_pair("ClusterSafe", ha)); hintList.push_back(std::make_pair("broker", broker)); hintList.push_back(std::make_pair("SessionState",broker)); hintList.push_back(std::make_pair("DataDir", broker)); hintList.push_back(std::make_pair("qpidd", broker)); hintList.push_back(std::make_pair("store", store)); hintList.push_back(std::make_pair("assert", system)); hintList.push_back(std::make_pair("Exception", system)); hintList.push_back(std::make_pair("sys", system)); hintList.push_back(std::make_pair("SCM", system)); hintList.push_back(std::make_pair("tests", test)); hintList.push_back(std::make_pair("messaging", messaging)); hintList.push_back(std::make_pair("types", messaging)); } static Category categoryOf(const char*const fName); private: std::list > hintList; }; /** POD struct representing a logging statement in source code. */ struct Statement { bool enabled; const char* file; int line; const char* function; Level level; Category category; QPID_COMMON_EXTERN void log(const std::string& message); QPID_COMMON_EXTERN static void categorize(Statement& s); struct Initializer { QPID_COMMON_EXTERN Initializer(Statement& s); Statement& statement; }; }; ///@internal static initializer for a Statement. #define QPID_LOG_STATEMENT_INIT_CAT(LEVEL, CATEGORY) \ { 0, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, (::qpid::log::LEVEL), \ (::qpid::log::CATEGORY) } ///@internal static initializer for a Statement with unspecified category #define QPID_LOG_STATEMENT_INIT(LEVEL) \ QPID_LOG_STATEMENT_INIT_CAT ( LEVEL , unspecified ) /** * Like QPID_LOG but computes an additional boolean test expression * to determine if the message should be logged. Evaluation of both * the test and message expressions occurs only if the requested log level * is enabled. *@param LEVEL severity Level for message, should be one of: * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix. *@param TEST message is logged only if expression TEST evaluates to true. *@param MESSAGE any object with an @eostream operator<<, or a sequence * like of ostreamable objects separated by @e<<. */ #define QPID_LOG_IF(LEVEL, TEST, MESSAGE) \ do { \ using ::qpid::log::Statement; \ static Statement stmt_= QPID_LOG_STATEMENT_INIT(LEVEL); \ static Statement::Initializer init_(stmt_); \ if (stmt_.enabled && (TEST)) \ stmt_.log(::qpid::Msg() << MESSAGE); \ } while(0) /** * Line QPID_LOG_IF but with the additional specification of a category. * @param CATEGORY message category. */ #define QPID_LOG_IF_CAT(LEVEL, CATEGORY, TEST, MESSAGE) \ do { \ using ::qpid::log::Statement; \ static Statement stmt_= QPID_LOG_STATEMENT_INIT_CAT(LEVEL, CATEGORY); \ static Statement::Initializer init_(stmt_); \ if (stmt_.enabled && (TEST)) \ stmt_.log(::qpid::Msg() << MESSAGE); \ } while(0) /** * FLAG must be a boolean variable. Assigns FLAG to true iff logging * is enabled for LEVEL in the calling context. Use when extra * support code is needed to generate log messages, to ensure that it * is only run if the logging level is enabled. * e.g. * bool logWarning; * QPID_LOG_TEST(warning, logWarning); * if (logWarning) { do stuff needed for warning log messages } */ #define QPID_LOG_TEST(LEVEL, FLAG) \ do { \ using ::qpid::log::Statement; \ static Statement stmt_= QPID_LOG_STATEMENT_INIT(LEVEL); \ static Statement::Initializer init_(stmt_); \ FLAG = stmt_.enabled; \ } while(0) /** * FLAG must be a boolean variable. Assigns FLAG to true iff logging * is enabled for LEVEL in the calling context. Use when extra * support code is needed to generate log messages, to ensure that it * is only run if the logging level is enabled. * e.g. * bool logWarning; * QPID_LOG_TEST_CAT(warning, System, logWarning); * if (logWarning) { do stuff needed for warning log messages } */ #define QPID_LOG_TEST_CAT(LEVEL, CATEGORY, FLAG) \ do { \ using ::qpid::log::Statement; \ static Statement stmt_= QPID_LOG_STATEMENT_INIT_CAT(LEVEL, CATEGORY); \ static Statement::Initializer init_(stmt_); \ FLAG = stmt_.enabled; \ } while(0) /** * Macro for log statements. Example of use: * @code * QPID_LOG(debug, "There are " << foocount << " foos in the bar."); * QPID_LOG(error, boost::format("Dohickey %s exploded") % dohicky.name()); * @endcode * Using QPID_LOG implies a category of Unspecified. * * You can subscribe to log messages by level, by component, by filename * or a combination @see Configuration. *@param LEVEL severity Level for message, should be one of: * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix. *@param MESSAGE any object with an @eostream operator<<, or a sequence * like of ostreamable objects separated by @e<<. */ #define QPID_LOG(LEVEL, MESSAGE) QPID_LOG_IF(LEVEL, true, MESSAGE); /** * Macro for log statements. Example of use: * @code * QPID_LOG_CAT(debug, System, "There are " << foocount << " foos in the bar."); * QPID_LOG_CAT(error, System, boost::format("Dohickey %s exploded") % dohicky.name()); * @endcode * Using QPID_LOG_CAT requires the specification of a category. * * You can subscribe to log messages by level, by component, by filename * or a combination @see Configuration. * *@param LEVEL severity Level for message, should be one of: * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix. *@param CATEGORY basic Category for the message. *@param MESSAGE any object with an @eostream operator<<, or a sequence * like of ostreamable objects separated by @e<<. */ #define QPID_LOG_CAT(LEVEL, CATEGORY, MESSAGE) QPID_LOG_IF_CAT(LEVEL, CATEGORY, true, MESSAGE); }} // namespace qpid::log #endif /*!STATEMENT_H*/