// Copyright (C) 2018-2023 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef DB_LOG_H #define DB_LOG_H #include #include #include #include /// @file db_log.h /// /// We want to reuse the database backend connection and exchange code /// for other uses, in particular for hook libraries. But this code /// includes some calls to the system logger for debug and uncommon /// cases and of course we do not want to get log messages from /// a hook library to seem to come from DHCP server core. /// /// The solution is to use a database logger which calls the right /// logger with mapped messages. namespace isc { namespace db { ///@{ /// @brief Database logging levels /// /// Defines the levels used to output debug messages in the database /// support. Note that higher numbers equate to more verbose (and detailed) /// output. /// @brief Additional information /// /// Record detailed tracing. This is generally reserved for tracing access to /// the lease database. extern const int DB_DBG_TRACE_DETAIL; ///@} /// @brief Common database library logger. extern isc::log::Logger database_logger; ///@{ /// @brief Database messages /// enum DbMessageID { DB_INVALID_ACCESS, PGSQL_DEALLOC_ERROR, PGSQL_FATAL_ERROR, PGSQL_START_TRANSACTION, PGSQL_COMMIT, PGSQL_ROLLBACK, PGSQL_CREATE_SAVEPOINT, PGSQL_ROLLBACK_SAVEPOINT, PGSQL_TCP_USER_TIMEOUT_UNSUPPORTED, MYSQL_FATAL_ERROR, MYSQL_START_TRANSACTION, MYSQL_COMMIT, MYSQL_ROLLBACK, }; ///@} /// @brief Database logger class /// class DbLogger { public: /// @brief Translation map type typedef std::map MessageMap; /// @brief Constructor /// /// @param logger logger which will be called /// @param map message id translation map DbLogger(isc::log::Logger& logger, const MessageMap& map) : logger_(logger), map_(map) { } /// @brief Translate message /// /// @param id database message id /// @return logger message /// @throw Unexpected if the id is not in the message map const isc::log::MessageID& translateMessage(const DbMessageID& id) const; /// @brief The logger isc::log::Logger& logger_; /// @brief The translation map const MessageMap& map_; }; /// @brief Database logger stack typedef std::list DbLoggerStack; /// @brief Global database logger stack (initialized to database logger) extern DbLoggerStack db_logger_stack; /// @brief Global mutex to protect logger stack extern std::mutex db_logger_mutex; /// @brief Check database logger stack /// /// @throw Unexpected if the stack is empty void checkDbLoggerStack(); /// @brief log type enumerations for use in DB_LOG specializations enum log_type_t { fatal, error, warn, info, debug, }; /// @brief DB_LOG_* logic template struct DB_LOG { /// @brief To preserve the old way of logging, this constructor facilitates /// initiating the DB_LOG_* chain call. DB_LOG(DbMessageID const message_id, int const debug_level = 0) { std::lock_guard lock(isc::db::db_logger_mutex); isc::db::checkDbLoggerStack(); if (isEnabled()) { formatter_ = formatter(message_id, debug_level); } } /// @brief Pass parameters to replace logger placeholders. /// /// @param first the parameter to be processed now /// @param args the parameters to be processes in recursive calls /// /// @return reference to this object so that these calls may be chained. template DB_LOG& arg(T first, Args... args) { formatter_.arg(first); return arg(args...); } /// @brief The last invocation of the arg() which is without parameters. /// /// Required when using variadic arguments. /// /// @return reference to this object so that these calls may be chained. DB_LOG& arg() { return *this; } private: /// @brief Initializes the logging formatter. /// /// @param message_id one of the DbMessageID enums /// @param debug_level one of debug levels specified in log_dbglevels.h /// /// @return the formatter responsible for logging isc::log::Logger::Formatter formatter(DbMessageID const message_id, int const debug_level = 0); /// @brief Check if the logger is ready to log. /// /// @param debug_level required only for debug log type /// /// @return true if the logger is enabled, false otherwise bool isEnabled(int const debug_level = 0) const; /// @brief the formatter responsible for logging isc::log::Logger::Formatter formatter_; }; /// @brief all DB_LOG specializations /// @{ struct DB_LOG_FATAL : DB_LOG { DB_LOG_FATAL(DbMessageID const message_id) : DB_LOG(message_id) { } }; struct DB_LOG_ERROR : DB_LOG { DB_LOG_ERROR(DbMessageID const message_id) : DB_LOG(message_id) { } }; struct DB_LOG_WARN : DB_LOG { DB_LOG_WARN(DbMessageID const message_id) : DB_LOG(message_id) { } }; struct DB_LOG_INFO : DB_LOG { DB_LOG_INFO(DbMessageID const message_id) : DB_LOG(message_id) { } }; struct DB_LOG_DEBUG : DB_LOG { DB_LOG_DEBUG(int const debug_level, DbMessageID const message_id) : DB_LOG(message_id, debug_level) { } }; ///@} /// @brief DHCP server database message map extern const db::DbLogger::MessageMap db_message_map; /// @brief Database logger translator. extern db::DbLogger db_logger_translator; } // namespace db } // namespace isc #endif // DB_LOG_H