1 // Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #ifndef DB_LOG_H 8 #define DB_LOG_H 9 10 #include <log/macros.h> 11 12 #include <map> 13 #include <mutex> 14 #include <list> 15 16 /// @file db_log.h 17 /// 18 /// We want to reuse the database backend connection and exchange code 19 /// for other uses, in particular for hook libraries. But this code 20 /// includes some calls to the system logger for debug and uncommon 21 /// cases and of course we do not want to get log messages from 22 /// a hook library to seem to come from DHCP server core. 23 /// 24 /// The solution is to use a database logger which calls the right 25 /// logger with mapped messages. 26 27 namespace isc { 28 namespace db { 29 30 ///@{ 31 /// @brief Database logging levels 32 /// 33 /// Defines the levels used to output debug messages in the database 34 /// support. Note that higher numbers equate to more verbose (and detailed) 35 /// output. 36 37 /// @brief Additional information 38 /// 39 /// Record detailed tracing. This is generally reserved for tracing access to 40 /// the lease database. 41 extern const int DB_DBG_TRACE_DETAIL; 42 43 ///@} 44 45 /// @brief Common database library logger. 46 extern isc::log::Logger database_logger; 47 48 ///@{ 49 /// @brief Database messages 50 /// 51 enum DbMessageID { 52 DB_INVALID_ACCESS, 53 54 PGSQL_DEALLOC_ERROR, 55 PGSQL_FATAL_ERROR, 56 PGSQL_START_TRANSACTION, 57 PGSQL_COMMIT, 58 PGSQL_ROLLBACK, 59 60 MYSQL_FATAL_ERROR, 61 MYSQL_START_TRANSACTION, 62 MYSQL_COMMIT, 63 MYSQL_ROLLBACK, 64 65 CQL_DEALLOC_ERROR, 66 CQL_CONNECTION_BEGIN_TRANSACTION, 67 CQL_CONNECTION_COMMIT, 68 CQL_CONNECTION_ROLLBACK 69 }; 70 ///@} 71 72 /// @brief Database logger class 73 /// 74 class DbLogger { 75 public: 76 /// @brief Translation map type 77 typedef std::map<DbMessageID, isc::log::MessageID> MessageMap; 78 79 /// @brief Constructor 80 /// 81 /// @param logger logger which will be called 82 /// @param map message id translation map DbLogger(isc::log::Logger & logger,const MessageMap & map)83 DbLogger(isc::log::Logger& logger, const MessageMap& map) 84 : logger_(logger), map_(map) { 85 } 86 87 /// @brief Translate message 88 /// 89 /// @param id database message id 90 /// @return logger message 91 /// @throw Unexpected if the id is not in the message map 92 const isc::log::MessageID& translateMessage(const DbMessageID& id) const; 93 94 /// @brief The logger 95 isc::log::Logger& logger_; 96 97 /// @brief The translation map 98 const MessageMap& map_; 99 }; 100 101 /// @brief Database logger stack 102 typedef std::list<DbLogger> DbLoggerStack; 103 104 /// @brief Global database logger stack (initialized to database logger) 105 extern DbLoggerStack db_logger_stack; 106 107 /// @brief Global mutex to protect logger stack 108 extern std::mutex db_logger_mutex; 109 110 /// @brief Check database logger stack 111 /// 112 /// @throw Unexpected if the stack is empty 113 void checkDbLoggerStack(); 114 115 /// @brief log type enumerations for use in DB_LOG specializations 116 enum log_type_t { 117 fatal, 118 error, 119 warn, 120 info, 121 debug, 122 }; 123 124 /// @brief DB_LOG_* logic 125 template <log_type_t log_type> 126 struct DB_LOG { 127 /// @brief To preserve the old way of logging, this constructor facilitates 128 /// initiating the DB_LOG_* chain call. 129 DB_LOG(DbMessageID const message_id, int const debug_level = 0) { 130 std::lock_guard<std::mutex> lock(isc::db::db_logger_mutex); 131 isc::db::checkDbLoggerStack(); 132 if (isEnabled()) { 133 formatter_ = formatter(message_id, debug_level); 134 } 135 } 136 137 /// @brief Pass parameters to replace logger placeholders. 138 /// 139 /// @param first the parameter to be processed now 140 /// @param args the parameters to be processes in recursive calls 141 /// 142 /// @return reference to this object so that these calls may be chained. 143 template <typename T, typename... Args> argDB_LOG144 DB_LOG& arg(T first, Args... args) { 145 formatter_.arg(first); 146 return arg(args...); 147 } 148 149 /// @brief The last invocation of the arg() which is without parameters. 150 /// 151 /// Required when using variadic arguments. 152 /// 153 /// @return reference to this object so that these calls may be chained. argDB_LOG154 DB_LOG& arg() { 155 return *this; 156 } 157 158 private: 159 /// @brief Initializes the logging formatter. 160 /// 161 /// @param message_id one of the DbMessageID enums 162 /// @param debug_level one of debug levels specified in log_dbglevels.h 163 /// 164 /// @return the formatter responsible for logging 165 isc::log::Logger::Formatter 166 formatter(DbMessageID const message_id, int const debug_level = 0); 167 168 /// @brief Check if the logger is ready to log. 169 /// 170 /// @param debug_level required only for debug log type 171 /// 172 /// @return true if the logger is enabled, false otherwise 173 bool isEnabled(int const debug_level = 0) const; 174 175 /// @brief the formatter responsible for logging 176 isc::log::Logger::Formatter formatter_; 177 }; 178 179 /// @brief all DB_LOG specializations 180 /// @{ 181 struct DB_LOG_FATAL : DB_LOG<fatal> { DB_LOG_FATALDB_LOG_FATAL182 DB_LOG_FATAL(DbMessageID const message_id) : DB_LOG(message_id) { 183 } 184 }; 185 186 struct DB_LOG_ERROR : DB_LOG<error> { DB_LOG_ERRORDB_LOG_ERROR187 DB_LOG_ERROR(DbMessageID const message_id) : DB_LOG(message_id) { 188 } 189 }; 190 191 struct DB_LOG_WARN : DB_LOG<warn> { DB_LOG_WARNDB_LOG_WARN192 DB_LOG_WARN(DbMessageID const message_id) : DB_LOG(message_id) { 193 } 194 }; 195 196 struct DB_LOG_INFO : DB_LOG<info> { DB_LOG_INFODB_LOG_INFO197 DB_LOG_INFO(DbMessageID const message_id) : DB_LOG(message_id) { 198 } 199 }; 200 201 struct DB_LOG_DEBUG : DB_LOG<debug> { DB_LOG_DEBUGDB_LOG_DEBUG202 DB_LOG_DEBUG(int const debug_level, DbMessageID const message_id) 203 : DB_LOG(message_id, debug_level) { 204 } 205 }; 206 ///@} 207 208 /// @brief DHCP server database message map 209 extern const db::DbLogger::MessageMap db_message_map; 210 211 /// @brief Database logger translator. 212 extern db::DbLogger db_logger_translator; 213 214 } // namespace db 215 } // namespace isc 216 217 #endif // DB_LOG_H 218