diff --git a/framework/areg/base/GETypes.h b/framework/areg/base/GETypes.h index ed659ecca..87be9e259 100644 --- a/framework/areg/base/GETypes.h +++ b/framework/areg/base/GETypes.h @@ -58,12 +58,12 @@ #include -//! The type defining ID. It is 64-bit in 64-bit systems. -typedef unsigned long id_type; - //! The digital value type of the pointer. #ifdef BIT64 + //! The type defining ID. It is 64-bit in 64-bit systems. + typedef uint64_t id_type; + #ifdef _UINTPTR_T_DEFINED typedef uintptr_t ptr_type; #else // !_UINTPTR_T_DEFINED @@ -72,6 +72,9 @@ typedef unsigned long id_type; #else // defined(BIT32) + //! The type defining ID. It is 64-bit in 64-bit systems. + typedef uint32_t id_type; + #ifdef _UINTPTR_T_DEFINED typedef uintptr_t ptr_type; #else // !_UINTPTR_T_DEFINED diff --git a/framework/areg/logging/IELogDatabaseEngine.hpp b/framework/areg/logging/IELogDatabaseEngine.hpp index ae19b9174..f456ff758 100644 --- a/framework/areg/logging/IELogDatabaseEngine.hpp +++ b/framework/areg/logging/IELogDatabaseEngine.hpp @@ -57,7 +57,7 @@ class AREG_API IELogDatabaseEngine : public IEDatabaseEngine * \brief Returns true if the database and the log tables are initialized, * and ready to log messages. **/ - virtual bool tablesInitialized(void) const = 0; + virtual bool areTablesInitialized(void) const = 0; /** * \brief Called when logging message should be saved in the database. diff --git a/framework/areg/logging/NELogging.hpp b/framework/areg/logging/NELogging.hpp index 97000dd54..6e7480131 100644 --- a/framework/areg/logging/NELogging.hpp +++ b/framework/areg/logging/NELogging.hpp @@ -310,9 +310,9 @@ namespace NELogging **/ sLogMessage & operator = (const sLogMessage & src); - NELogging::eLogDataType logDataType; //!< The type of log message data. - NELogging::eLogMessageType logMsgType; //!< The type of the logging message. - NELogging::eLogPriority logMessagePrio; //!< The log message priority + NELogging::eLogDataType logDataType; //!< The type of log message data. + NELogging::eLogMessageType logMsgType; //!< The type of the logging message. + NELogging::eLogPriority logMessagePrio; //!< The log message priority ITEM_ID logSource; //!< The ID of the source that generated logging message. ITEM_ID logTarget; //!< The ID of the target to send logging message, valid only in case of TCP/IP logging. ITEM_ID logCookie; //!< The cookie set by the networking service, i.e. the log collector. Valid only in case of TCP/IP logging. diff --git a/framework/aregextend/db/LogSqliteDatabase.hpp b/framework/aregextend/db/LogSqliteDatabase.hpp index 48d325630..ad2efcf8f 100644 --- a/framework/aregextend/db/LogSqliteDatabase.hpp +++ b/framework/aregextend/db/LogSqliteDatabase.hpp @@ -18,33 +18,16 @@ * Include files. ************************************************************************/ #include "areg/base/GEGlobal.h" + +#include "aregextend/db/SqliteDatabase.hpp" +#include "aregextend/db/SqliteStatement.hpp" +#include "areg/component/NEService.hpp" +#include "areg/logging/NELogging.hpp" #include "areg/logging/IELogDatabaseEngine.hpp" #include "areg/base/String.hpp" -#if 0 #include -enum eLogItemType -{ - ItemUnknown = 0 //!< Unknown log item type - , ItemInstance //!< Log instance item - , ItemThread //!< Log thread item - , ItemScope //!< Log scope item - , ItemPriority //!< Log priority item -}; - -struct sLogItem -{ - ITEM_ID itemId { 0 }; // itemList{ }; //!< The list of log items -}; -#endif ////////////////////////////////////////////////////////////////////////// // LogSqliteDatabase class declaration ////////////////////////////////////////////////////////////////////////// @@ -150,7 +133,7 @@ class LogSqliteDatabase : public IELogDatabaseEngine * \brief Returns true if the database and the log tables are initialized, * and ready to log messages. **/ - virtual bool tablesInitialized(void) const override; + virtual bool areTablesInitialized(void) const override; /** * \brief Called when logging message should be saved in the database. @@ -231,30 +214,89 @@ class LogSqliteDatabase : public IELogDatabaseEngine ////////////////////////////////////////////////////////////////////////// // Attributes and operations ////////////////////////////////////////////////////////////////////////// -#if 0 - std::vector getLogInstanceNames(void) const; - std::vector getLogInstances(void) const; + /** + * \brief Call to query and get list of names of connected instances from log database. + **/ + std::vector getLogInstanceNames(void); + void getLogInstanceNames(std::vector& names); - std::vector getLogThreadNames(void) const; + /** + * \brief Call to query and get list of IDs of connected instances from log database. + **/ + std::vector getLogInstances(void); + void getLogInstances(std::vector& ids); - std::vector getLogThreads(void) const; + /** + * \brief Call to query and get list of names of threads of the connected instances from log database. + **/ + std::vector getLogThreadNames(void); + void getLogThreadNames(std::vector& names); - std::vector getLogScopeNames(void) const; + /** + * \brief Call to query and get list of IDs of threads of the connected instances from log database. + **/ + std::vector getLogThreads(void); + void getLogThreads(std::vector& ids); - std::vector getLogScopes(void) const; + /** + * \brief Call to get the list of log priorities. + **/ + std::vector getPriorityNames(void); + void getPriorityNames(std::vector& names); - std::vector getPriorityNames(void) const; + /** + * \brief Call to query and get information of connected instances from log database. + * This query will receive list of all registered instances. + **/ + std::vector< NEService::sServiceConnectedInstance> getLogInstanceInfos(void); + void getLogInstanceInfos(std::vector< NEService::sServiceConnectedInstance>& infos); - std::vector getLogInstScopes(ITEM_ID instId) const; + /** + * \brief Call to query and get information of log scopes of specified instance from log database. + * This query will receive list of all registered scopes. + * \param instID The ID of the instance. + **/ + std::vector getLogInstScopes(ITEM_ID instId); + void getLogInstScopes(std::vector& scopes, ITEM_ID instId); - std::vector getLodMessages(void) const; + /** + * \brief Call to get all log messages from log database. + **/ + std::vector getLogMessages(void); + void getLogMessages(std::vector& messages); - std::vector getLodInstMessages(ITEM_ID instId) const; + /** + * \brief Call to get log messages of the specified instance from log database. + * If `instId` is `NEService::COOKIE_ANY` it receives the list of all instances + * similar to the call to `getLogMessages()`. + * \param instId The ID of the instance to get log messages. + * If `NEService::COOKIE_ANY` it receives log messages of all instances. + **/ + std::vector getLogInstMessages(ITEM_ID instId = NEService::COOKIE_ANY); + void getLogInstMessages(std::vector& messages, ITEM_ID instId = NEService::COOKIE_ANY); - std::vector getLodScopeMessages(ITEM_ID instId, uint32_t scopeId) const; + /** + * \brief Call to get log messages of the specified scope from log database. + * If `scopeId` is `0` it receives the list of all scopes + * similar to the call to `getLogMessages()`. + * \param scopeId The ID of the scope to get log messages. + * If `0` it receives log messages of all scopes. + **/ + std::vector getLogScopeMessages(uint32_t scopeId = 0); + void getLogScopeMessages(std::vector& messages, uint32_t scopeId = 0); -#endif + /** + * \brief Call to get log messages of the specified instance and log scope ID from log database. + * If `instId` is `NEService::COOKIE_ANY` and `scopeId` is `0`, it receives the list of all logs + * similar to the call to `getLogMessages()`. + * \param instId The ID of the instance to get log messages. + * If `NEService::COOKIE_ANY` it receives log messages of all instances. + * \param scopeId The ID of the scope to get log messages. + * If `0` it receives log messages of all scopes. + **/ + std::vector getLogMessages(ITEM_ID instId, uint32_t scopeId); + void getLogMessages(std::vector& messages, ITEM_ID instId, uint32_t scopeId); ////////////////////////////////////////////////////////////////////////// // Hidden methods @@ -267,11 +309,6 @@ class LogSqliteDatabase : public IELogDatabaseEngine **/ inline bool _open(const String& dbPath); - /** - * \brief Closes previously opened database and releases resources. - **/ - inline void _close(void); - /** * \brief In the opened database file, creates the tables required to save logs. **/ @@ -287,29 +324,26 @@ class LogSqliteDatabase : public IELogDatabaseEngine **/ inline void _initialize(void); - /** - * \brief Executes the SQL script. The database should be already opened and initialized. - **/ - inline bool _execute(const char * sql); + inline void _copyLogMessage(SqliteStatement& stmt, SharedBuffer & buf); ////////////////////////////////////////////////////////////////////////// // Member variables. ////////////////////////////////////////////////////////////////////////// protected: //!< The path to the SQLite database file. - String mDbPath; + SqliteDatabase mDatabase; - //!< The initial path to the SQLIte database file. The path may contain mask like timestamp. - String mDbInitPath; + //!< The statement to log messages in the database. + SqliteStatement mStmtLogs; - //!< The SQLite database object. - void * mDbObject; + //!< The initial path to the SQLIte database file. The path may contain mask like timestamp. + String mDbInitPath; //!< Flag, indicating whether the database and data tables are initialized or not. - bool mIsInitialized; + bool mIsInitialized; //!< Flag, indicating whether the database logging is enabled or not. - bool mDbLogEnabled; + bool mDbLogEnabled; ////////////////////////////////////////////////////////////////////////// // Forbidden calls. @@ -334,7 +368,7 @@ inline void LogSqliteDatabase::setDatabaseLoggingEnabled(bool enable) inline const String& LogSqliteDatabase::getDatabasePath(void) const { - return mDbPath; + return mDatabase.getPath(); } inline const String& LogSqliteDatabase::getInitialDatabasePath(void) const diff --git a/framework/aregextend/db/SqliteStatement.hpp b/framework/aregextend/db/SqliteStatement.hpp index e7d1c612a..b8b9dad2f 100644 --- a/framework/aregextend/db/SqliteStatement.hpp +++ b/framework/aregextend/db/SqliteStatement.hpp @@ -122,31 +122,34 @@ class SqliteStatement /** * \brief Binds an integer value to the specified parameter index. - * \param index The 1-based parameter index. + * \param index The 0-based parameter index. * \param value The integer value to bind. * \return True if binding was successful, false otherwise. */ - bool bindInt(int index, int value); + bool bindInt32(int index, int32_t value); + bool bindUint32(int index, uint32_t value); /** * \brief Binds a 64-bit integer value to the specified parameter index. - * \param index The 1-based parameter index. + * \param index The 0-based parameter index. * \param value The 64-bit integer value to bind. * \return True if binding was successful, false otherwise. */ bool bindInt64(int index, int64_t value); + bool bindUint64(int index, uint64_t value); /** * \brief Binds a double value to the specified parameter index. - * \param index The 1-based parameter index. + * \param index The 0-based parameter index. * \param value The double value to bind. * \return True if binding was successful, false otherwise. */ bool bindDouble(int index, double value); + bool bindFloat(int index, float value); /** * \brief Binds a text value to the specified parameter index. - * \param index The 1-based parameter index. + * \param index The 0-based parameter index. * \param value The string value to bind. * \return True if binding was successful, false otherwise. */ @@ -154,7 +157,7 @@ class SqliteStatement /** * \brief Binds a NULL value to the specified parameter index. - * \param index The 1-based parameter index. + * \param index The 0-based parameter index. * \return True if binding was successful, false otherwise. */ bool bindNull(int index); @@ -166,73 +169,76 @@ class SqliteStatement /** * \brief Retrieves the integer value of the specified column in the current row. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return The integer value of the column. */ - int getInt(int column) const; + int32_t getInt32(int index) const; + uint32_t getUint32(int index) const; /** * \brief Retrieves the 64-bit integer value of the specified column in the current row. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return The 64-bit integer value of the column. */ - int64_t getInt64(int column) const; + int64_t getInt64(int index) const; + uint64_t getUint64(int index) const; /** * \brief Retrieves the double value of the specified column in the current row. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return The double value of the column. */ - double getDouble(int column) const; + double getDouble(int index) const; + float getFloat(int index) const; /** * \brief Retrieves the text value of the specified column in the current row. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return The string value of the column. */ - String getText(int column) const; + String getText(int index) const; /** * \brief Checks if the specified column in the current row is NULL. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return True if the column is NULL, false otherwise. */ bool isNull(int column) const; /** * \brief Checks if the specified column index is valid for the current result set. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return True if the column index is valid, false otherwise. */ - bool isColumnValid(int column) const; + bool isColumnValid(int index) const; /** * \brief Checks if the specified column contains a string value. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return True if the column is a string, false otherwise. */ - bool isString(int column) const; + bool isString(int index) const; /** * \brief Checks if the specified column contains a 32-bit integer value. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return True if the column is a 32-bit integer, false otherwise. */ - bool isInteger(int column) const; + bool isInteger(int index) const; /** * \brief Checks if the specified column contains a 64-bit integer value. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return True if the column is a 64-bit integer, false otherwise. */ - bool isInteger64(int column) const; + bool isInteger64(int index) const; /** * \brief Checks if the specified column contains a double value. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return True if the column is a double, false otherwise. */ - bool isDouble(int column) const; + bool isDouble(int index) const; /** * \brief Returns the number of columns in the result set. @@ -242,10 +248,10 @@ class SqliteStatement /** * \brief Returns the name of the specified column. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return The name of the column. */ - String getColumnName(int column) const; + String getColumnName(int index) const; /** * \brief Returns the index of the column with the specified name. @@ -256,10 +262,10 @@ class SqliteStatement /** * \brief Returns the type of the specified column. - * \param column The 0-based column index. + * \param index The 0-based column index. * \return The column type as eColumnType. */ - SqliteStatement::eColumnType getColumnType(int column) const; + SqliteStatement::eColumnType getColumnType(int index) const; /** * \brief Returns a SqliteRow object representing the current row. diff --git a/framework/aregextend/db/private/LogSqliteDatabase.cpp b/framework/aregextend/db/private/LogSqliteDatabase.cpp index 083480108..57e442166 100644 --- a/framework/aregextend/db/private/LogSqliteDatabase.cpp +++ b/framework/aregextend/db/private/LogSqliteDatabase.cpp @@ -17,6 +17,8 @@ ************************************************************************/ #include "aregextend/db/LogSqliteDatabase.hpp" +#include "aregextend/db/SqliteStatement.hpp" + #include "areg/base/DateTime.hpp" #include "areg/base/File.hpp" #include "areg/base/NEMath.hpp" @@ -138,6 +140,12 @@ namespace "INSERT INTO scopes (scope_id, cookie_id, scope_is_active, scope_prio, scope_name, time_received) VALUES (%u, %llu, 1, %u, \'%s\', %llu);" }; + //! A string to generate INSERT statement to insert a new scope in the scopes table. + constexpr std::string_view _sqlInsertScope + { + "INSERT INTO scopes (scope_id, cookie_id, scope_is_active, scope_prio, scope_name, time_received) VALUES (?, ?, 1, ?, ?, ?);" + }; + //! A string format to generate UPDATE statement to update the scope state of a connected instance. //! The script will mark all scopes of specified cookie ID as inactive. constexpr std::string_view _fmtUpdScopes @@ -188,6 +196,15 @@ namespace "(%llu, %u, %u, %u, %llu, %llu, \'%s\', \'%s\', \'%s\', %llu, %llu);" }; + //! A string format to create INSERT statement to insert new log message in the logs table. + constexpr std::string_view _sqlInsertLog + { + "INSERT INTO logs " + "(cookie_id, scope_id, msg_type, msg_prio, msg_module_id, msg_thread_id, msg_log, msg_thread, msg_module, time_created, time_received)" + "VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" + }; + //! A script to create index of the instances table. constexpr std::string_view _sqlCraeteIdxCookie { @@ -206,6 +223,66 @@ namespace "CREATE INDEX \"idx_logs\" ON \"logs\" (\"cookie_id\", \"scope_id\", \"msg_thread_id\"); " }; + //! A script to extract the names of connected log instances + constexpr std::string_view _sqlGetInstanceName + { + "SELECT inst_name FROM instances GROUP BY inst_name;" + }; + + //! A script to extract the IDs of connected log instances + constexpr std::string_view _sqlGetInstanceIds + { + "SELECT cookie_id FROM instances GROUP BY cookie_id;" + }; + + //! A script to extract the names of logging threads + constexpr std::string_view _sqlGetThreadNames + { + "SELECT msg_thread FROM logs GROUP BY msg_thread;" + }; + + //! A script to extract the IDs of logging threads + constexpr std::string_view _sqlGetThreadIds + { + "SELECT msg_thread_id FROM logs GROUP BY msg_thread_id;" + }; + + //! A script to extract the logging instances with their information. + constexpr std::string_view _sqlGetLogInstances + { + "SELECT inst_type, inst_bits, cookie_id, time_connected, inst_name, inst_location FROM instances ORDER BY time_connected;" + }; + + //! A script to extract the logging scopes of a certain instance with their information. + constexpr std::string_view _sqlGetLogScopes + { + "SELECT scope_name, scope_id, scope_prio FROM scopes WHERE cookie_id = ? ORDER BY time_received;" + }; + + //! A script to extract all logged messages + constexpr std::string_view _sqlGetAllLogMessages + { + "SELECT msg_type, msg_prio, cookie_id, msg_module_id, msg_thread_id, time_created, scope_id, msg_log, msg_thread, msg_module FROM logs ORDER BY time_created;" + }; + + //! A script to extract logged messages of the certain instance source + constexpr std::string_view _sqlGetInstLogMessages + { + "SELECT msg_type, msg_prio, cookie_id, msg_module_id, msg_thread_id, time_created, scope_id, msg_log, msg_thread, msg_module FROM logs WHERE cookie_id = ? ORDER BY time_created;" + }; + + //! A script to extract logged messages of the certain instance source + constexpr std::string_view _sqlGetScopeLogMessages + { + "SELECT msg_type, msg_prio, cookie_id, msg_module_id, msg_thread_id, time_created, scope_id, msg_log, msg_thread, msg_module FROM logs WHERE scope_id = ? ORDER BY time_created;" + }; + + //! A script to extract logged messages of the certain instance source + constexpr std::string_view _sqlGetInstScopeLogMessages + { + "SELECT msg_type, msg_prio, cookie_id, msg_module_id, msg_thread_id, time_created, scope_id, msg_log, msg_thread, msg_module FROM logs WHERE cookie_id = ? AND scope_id = ? ORDER BY time_created;" + }; + //! The size of the string buffer to generate a message. constexpr uint32_t MSG_LEN { 512 }; @@ -223,9 +300,9 @@ namespace LogSqliteDatabase::LogSqliteDatabase(void) : IELogDatabaseEngine ( ) - , mDbPath ( ) + , mDatabase ( ) + , mStmtLogs (mDatabase) , mDbInitPath ( ) - , mDbObject ( nullptr ) , mIsInitialized ( false ) , mDbLogEnabled ( true ) { @@ -233,7 +310,9 @@ LogSqliteDatabase::LogSqliteDatabase(void) LogSqliteDatabase::~LogSqliteDatabase(void) { - _close(); + mStmtLogs.finalize(); + mDatabase.disconnect(); + mIsInitialized = false; } inline bool LogSqliteDatabase::_open(const String& dbPath) @@ -242,53 +321,36 @@ inline bool LogSqliteDatabase::_open(const String& dbPath) return false; bool result{ true }; - _close(); + mDatabase.disconnect(); + mIsInitialized = false; if (dbPath.isEmpty() == false) { mDbInitPath = dbPath; } - mDbPath = File::normalizePath(mDbInitPath); - String folder = File::getFileDirectory(mDbPath); - if ((folder.isEmpty() == false) && (File::existDir(folder) == false)) + if (mDatabase.connect(mDbInitPath) == false) { - File::createDirCascaded(folder); - } - - if (SQLITE_OK != ::sqlite3_open(mDbPath.getString(), reinterpret_cast(&mDbObject))) - { - _close(); + mDatabase.disconnect(); + mIsInitialized = false; result = false; } return result; } -inline void LogSqliteDatabase::_close(void) -{ - if (mDbObject != nullptr) - { - ::sqlite3_close(reinterpret_cast(mDbObject)); - mDbObject = nullptr; - mIsInitialized = false; - } -} - inline void LogSqliteDatabase::_createTables(void) { - ASSERT(mDbObject != nullptr); - - VERIFY(_execute(_sqlCreateTbVersion.data())); - VERIFY(_execute(_sqlCreateTbInstances.data())); - VERIFY(_execute(_sqlCreateTbScopes.data())); - VERIFY(_execute(_sqlCreateTbLogs.data())); + VERIFY(mDatabase.execute(_sqlCreateTbVersion)); + VERIFY(mDatabase.execute(_sqlCreateTbInstances)); + VERIFY(mDatabase.execute(_sqlCreateTbScopes)); + VERIFY(mDatabase.execute(_sqlCreateTbLogs)); } inline void LogSqliteDatabase::_createIndexes(void) { - VERIFY(_execute(_sqlCraeteIdxCookie.data())); - VERIFY(_execute(_sqlCreateIdxScopes.data())); - VERIFY(_execute(_sqlCreateIdxLogs.data())); + VERIFY(mDatabase.execute(_sqlCraeteIdxCookie)); + VERIFY(mDatabase.execute(_sqlCreateIdxScopes)); + VERIFY(mDatabase.execute(_sqlCreateIdxLogs)); } inline void LogSqliteDatabase::_initialize(void) @@ -305,10 +367,10 @@ inline void LogSqliteDatabase::_initialize(void) , NELogging::LOG_VERSION.data() , "AREG SDK database logging module. Visit https://aregtech.com for more information." , "Created by AREG log observer API module." - , mDbPath.getString() + , mDatabase.getPath().getString() , static_cast(now.getTime()) ); - VERIFY(_execute(sql)); + VERIFY(mDatabase.execute(sql)); String::formatString(sql, SQL_LEN, _fmtLog.data() , static_cast(NEService::COOKIE_LOCAL) @@ -323,28 +385,50 @@ inline void LogSqliteDatabase::_initialize(void) , static_cast(now.getTime()) , static_cast(now.getTime()) ); - VERIFY(_execute(sql)); + VERIFY(mDatabase.execute(sql)); } -inline bool LogSqliteDatabase::_execute(const char* sql) +inline void LogSqliteDatabase::_copyLogMessage(SqliteStatement& stmt, SharedBuffer& buf) { - if (mDbLogEnabled) - { - ASSERT(NEString::isEmpty(sql) == false); - return (mDbObject != nullptr ? SQLITE_OK == ::sqlite3_exec(reinterpret_cast(mDbObject), sql, nullptr, nullptr, nullptr) : false); - } - - return false; + constexpr uint32_t _logSize{ static_cast(sizeof(NELogging::sLogMessage)) }; + + buf.setSizeUsed(_logSize); + buf.moveToBegin(); + NELogging::sLogMessage* log = reinterpret_cast(buf.getBuffer()); + + ASSERT(log != nullptr); + log->logDataType = NELogging::eLogDataType::LogDataRemote; + log->logSource = NEService::COOKIE_ANY; + log->logTarget = NEService::COOKIE_ANY; + + log->logMsgType = static_cast(stmt.getUint32(0)); + log->logMessagePrio = static_cast(stmt.getUint32(1)); + log->logCookie = static_cast( stmt.getInt64(2)); + log->logModuleId = static_cast( stmt.getInt64(3)); + log->logThreadId = static_cast( stmt.getInt64(4)); + log->logTimestamp = static_cast( stmt.getInt64(5)); + log->logScopeId = static_cast(stmt.getUint32(6)); + String msg = stmt.getText(7); + String thread = stmt.getText(8); + String module = stmt.getText(9); + + log->logMessageLen = msg.getLength(); + log->logThreadLen = thread.getLength(); + log->logModuleLen = module.getLength(); + + NEString::copyStringFast(log->logMessage, msg.getString(), msg.getLength()); + NEString::copyStringFast(log->logThread, thread.getString(), thread.getLength()); + NEString::copyStringFast(log->logModule, module.getString(), module.getLength()); } bool LogSqliteDatabase::isOperable(void) const { - return (mDbObject != nullptr); + return mDatabase.isOperable(); } bool LogSqliteDatabase::connect(const String& dbPath /*= String::EmptyString*/) { - if (mDbObject == nullptr) + if (mDbLogEnabled && mDatabase.isOperable() == false) { ASSERT(mIsInitialized == false); if (_open(dbPath)) @@ -354,6 +438,7 @@ bool LogSqliteDatabase::connect(const String& dbPath /*= String::EmptyString*/) _initialize(); commit(true); mIsInitialized = true; + mStmtLogs.prepare(_sqlInsertLog); } } @@ -362,6 +447,12 @@ bool LogSqliteDatabase::connect(const String& dbPath /*= String::EmptyString*/) void LogSqliteDatabase::disconnect(void) { + if (mDatabase.isOperable() == false) + return; + + if (mStmtLogs.isValid()) + mStmtLogs.finalize(); + Process& proc{ Process::getInstance() }; DateTime now{ DateTime::getNow() }; String module{ proc.getAppName() }; @@ -372,7 +463,7 @@ void LogSqliteDatabase::disconnect(void) String::formatString( sql, SQL_LEN, _fmtUpdVersion.data() , static_cast(now.getTime())); - _execute(sql); + mDatabase.execute(sql); String::formatString( sql, SQL_LEN, _fmtLog.data() , NEService::COOKIE_LOCAL @@ -387,59 +478,66 @@ void LogSqliteDatabase::disconnect(void) , static_cast(now.getTime()) , static_cast(now.getTime()) ); - _execute(sql); + mDatabase.execute(sql); String::formatString( sql, SQL_LEN, _fmtCloseScopes.data() , static_cast(now.getTime())); - _execute(sql); + mDatabase.execute(sql); String::formatString( sql, SQL_LEN, _fmCloseInstances.data() , static_cast(now.getTime()) , static_cast(now.getTime())); - _execute(sql); + mDatabase.execute(sql); - commit(true); - _close(); + mDatabase.commit(true); + mDatabase.disconnect(); + mIsInitialized = false; } bool LogSqliteDatabase::execute(const String& sql) { - return sql.isEmpty() ? false : _execute(sql.getString()); + return mDatabase.execute(sql); } bool LogSqliteDatabase::begin(void) { - return _execute("BEGIN TRANSACTION;"); + return mDatabase.begin(); } bool LogSqliteDatabase::commit(bool doCommit) { - return _execute(doCommit ? "COMMIT;" : "ROLLBACK;"); + return mDatabase.commit(doCommit); } -bool LogSqliteDatabase::tablesInitialized(void) const +bool LogSqliteDatabase::areTablesInitialized(void) const { return mIsInitialized; } bool LogSqliteDatabase::logMessage(const NELogging::sLogMessage& message, const DateTime& timestamp) { - char sql[SQL_LEN_MAX]; - String::formatString(sql, SQL_LEN_MAX, _fmtLog.data() - , static_cast(message.logCookie) - , static_cast(message.logScopeId) - , static_cast(message.logMsgType) - , static_cast(message.logMessagePrio) - , static_cast(message.logModuleId) - , static_cast(message.logThreadId) - , message.logMessage - , message.logThreadLen != 0 ? message.logThread : String::EmptyString - , message.logModuleId != 0 ? message.logModule : String::EmptyString - , static_cast(message.logTimestamp) - , static_cast(timestamp.getTime()) - ); + if (mStmtLogs.isValid() == false) + { + ASSERT(false && "LogSqliteDatabase::logMessage() - The statement to log messages is not prepared."); + return false; + } - return _execute(sql); + mStmtLogs.bindUint64( 0, static_cast(message.logCookie)); + mStmtLogs.bindUint32( 1, static_cast(message.logScopeId)); + mStmtLogs.bindUint32( 2, static_cast(message.logMsgType)); + mStmtLogs.bindUint32( 3, static_cast(message.logMessagePrio)); + mStmtLogs.bindUint64( 4, static_cast(message.logModuleId)); + mStmtLogs.bindUint64( 5, static_cast(message.logThreadId)); + mStmtLogs.bindText( 6, message.logMessage); + mStmtLogs.bindText( 7, message.logThreadLen != 0 ? message.logThread : String::EmptyString); + mStmtLogs.bindText( 8, message.logModuleLen != 0 ? message.logModule : String::EmptyString); + mStmtLogs.bindUint64( 9, static_cast(message.logTimestamp)); + mStmtLogs.bindUint64(10,static_cast(timestamp.getTime())); + + bool result{ mStmtLogs.next() }; + mStmtLogs.reset(); + mStmtLogs.clearBindings(); + return result; } bool LogSqliteDatabase::logInstanceConnected(const NEService::sServiceConnectedInstance& instance, const DateTime& timestamp) @@ -449,28 +547,6 @@ bool LogSqliteDatabase::logInstanceConnected(const NEService::sServiceConnectedI id_type threadId{ Thread::getCurrentThreadId() }; String thread{ Thread::getThreadName(threadId) }; - char msg[MSG_LEN]; - String::formatString( msg, MSG_LEN, "The %u-bit instance [ %s ] with cookie [ %llu ] is connected at time [ %s ]" - , static_cast(instance.ciBitness) - , instance.ciInstance.c_str() - , static_cast(instance.ciCookie) - , timestamp.formatTime().getString()); - - char sqlLog[SQL_LEN_MAX]; - String::formatString( sqlLog, SQL_LEN_MAX, _fmtLog.data() - , static_cast(NEService::COOKIE_LOCAL) - , static_cast(NEMath::CHECKSUM_IGNORE) - , static_cast(NELogging::eLogMessageType::LogMessageText) - , static_cast(NELogging::eLogPriority::PrioIgnore) - , static_cast(proc.getId()) - , static_cast(threadId) - , msg - , thread.getString() - , module.getString() - , static_cast(timestamp.getTime()) - , static_cast(timestamp.getTime()) - ); - char sqlInst[SQL_LEN]; String::formatString( sqlInst, SQL_LEN, _fmtInstance.data() , static_cast(instance.ciCookie) @@ -481,8 +557,53 @@ bool LogSqliteDatabase::logInstanceConnected(const NEService::sServiceConnectedI , static_cast(instance.ciTimestamp) , static_cast(timestamp.getTime()) ); + mDatabase.execute(sqlInst); - return (_execute(sqlLog) && _execute(sqlInst)); + char msg[MSG_LEN]; + String::formatString( msg, MSG_LEN, "The %u-bit instance [ %s ] with cookie [ %llu ] is connected at time [ %s ]" + , static_cast(instance.ciBitness) + , instance.ciInstance.c_str() + , static_cast(instance.ciCookie) + , timestamp.formatTime().getString()); + + if (mStmtLogs.isValid()) + { + mStmtLogs.bindUint64( 0, static_cast(NEService::COOKIE_LOCAL)); + mStmtLogs.bindUint32( 1, static_cast(NEMath::CHECKSUM_IGNORE)); + mStmtLogs.bindUint32( 2, static_cast(NELogging::eLogMessageType::LogMessageText)); + mStmtLogs.bindUint32( 3, static_cast(NELogging::eLogPriority::PrioIgnore)); + mStmtLogs.bindUint64( 4, static_cast(proc.getId())); + mStmtLogs.bindUint64( 5, static_cast(threadId)); + mStmtLogs.bindText( 6, msg); + mStmtLogs.bindText( 7, thread); + mStmtLogs.bindText( 8, module); + mStmtLogs.bindUint64( 9, static_cast(timestamp.getTime())); + mStmtLogs.bindUint64(10, static_cast(timestamp.getTime())); + + bool result{ mStmtLogs.next() }; + mStmtLogs.reset(); + mStmtLogs.clearBindings(); + return result; + } + else + { + char sqlLog[SQL_LEN_MAX]; + String::formatString( sqlLog, SQL_LEN_MAX, _fmtLog.data() + , static_cast(NEService::COOKIE_LOCAL) + , static_cast(NEMath::CHECKSUM_IGNORE) + , static_cast(NELogging::eLogMessageType::LogMessageText) + , static_cast(NELogging::eLogPriority::PrioIgnore) + , static_cast(proc.getId()) + , static_cast(threadId) + , msg + , thread.getString() + , module.getString() + , static_cast(timestamp.getTime()) + , static_cast(timestamp.getTime()) + ); + + return mDatabase.execute(sqlLog); + } } bool LogSqliteDatabase::logInstanceDisconnected(const ITEM_ID& cookie, const DateTime& timestamp) @@ -494,33 +615,56 @@ bool LogSqliteDatabase::logInstanceDisconnected(const ITEM_ID& cookie, const Dat id_type threadId{ Thread::getCurrentThreadId() }; String thread{ Thread::getThreadName(threadId) }; - char msg[MSG_LEN]; - String::formatString( msg, MSG_LEN, "The instance with cookie [ %llu ] is disconnected at time [ %s ]" - , static_cast(cookie) - , timestamp.formatTime().getString()); - - char sqlLog[SQL_LEN_MAX]; - String::formatString( sqlLog, SQL_LEN_MAX, _fmtLog.data() - , static_cast(NEService::COOKIE_LOCAL) - , static_cast(NEMath::CHECKSUM_IGNORE) - , static_cast(NELogging::eLogMessageType::LogMessageText) - , static_cast(NELogging::eLogPriority::PrioIgnore) - , static_cast(proc.getId()) - , static_cast(threadId) - , msg - , thread.getString() - , module.getString() - , static_cast(timestamp.getTime()) - , static_cast(timestamp.getTime()) - ); - char sqlInst[SQL_LEN]; String::formatString( sqlInst, SQL_LEN, _fmtUpdInstance.data() , static_cast(timestamp.getTime()) , static_cast(DateTime::getNow().getTime()) , static_cast(cookie)); + mDatabase.execute(sqlInst); + + char msg[MSG_LEN]; + String::formatString( msg, MSG_LEN, "The instance with cookie [ %llu ] is disconnected at time [ %s ]" + , static_cast(cookie) + , timestamp.formatTime().getString()); - return (_execute(sqlLog) && _execute(sqlInst)); + if (mStmtLogs.isValid()) + { + mStmtLogs.bindUint64( 0, static_cast(NEService::COOKIE_LOCAL)); + mStmtLogs.bindUint32( 1, static_cast(NEMath::CHECKSUM_IGNORE)); + mStmtLogs.bindUint32( 2, static_cast(NELogging::eLogMessageType::LogMessageText)); + mStmtLogs.bindUint32( 3, static_cast(NELogging::eLogPriority::PrioIgnore)); + mStmtLogs.bindUint64( 4, static_cast(proc.getId())); + mStmtLogs.bindUint64( 5, static_cast(threadId)); + mStmtLogs.bindText( 6, msg); + mStmtLogs.bindText( 7, thread); + mStmtLogs.bindText( 8, module); + mStmtLogs.bindUint64( 9, static_cast(timestamp.getTime())); + mStmtLogs.bindUint64(10, static_cast(timestamp.getTime())); + + bool result{ mStmtLogs.next() }; + mStmtLogs.reset(); + mStmtLogs.clearBindings(); + return result; + } + else + { + char sqlLog[SQL_LEN_MAX]; + String::formatString( sqlLog, SQL_LEN_MAX, _fmtLog.data() + , static_cast(NEService::COOKIE_LOCAL) + , static_cast(NEMath::CHECKSUM_IGNORE) + , static_cast(NELogging::eLogMessageType::LogMessageText) + , static_cast(NELogging::eLogPriority::PrioIgnore) + , static_cast(proc.getId()) + , static_cast(threadId) + , msg + , thread.getString() + , module.getString() + , static_cast(timestamp.getTime()) + , static_cast(timestamp.getTime()) + ); + + return mDatabase.execute(sqlLog); + } } bool LogSqliteDatabase::logScopeActivate(const NELogging::sScopeInfo & scope, const ITEM_ID& cookie, const DateTime& timestamp) @@ -532,22 +676,23 @@ bool LogSqliteDatabase::logScopeActivate(const NELogging::sScopeInfo & scope, co , static_cast(scope.scopePrio) , scope.scopeName.getString() , static_cast(timestamp.getTime())); - return _execute(sql); + return mDatabase.execute(sql); } uint32_t LogSqliteDatabase::logScopesActivate(const NELogging::ScopeNames& scopes, const ITEM_ID& cookie, const DateTime& timestamp) { uint32_t result{ 0 }; - char sql[SQL_LEN]; + SqliteStatement stmt(mDatabase, _sqlInsertScope); for (const auto& scope : scopes.getData()) { - String::formatString( sql, SQL_LEN, _fmtScopes.data() - , static_cast(scope.scopeId) - , static_cast(cookie) - , static_cast(scope.scopePrio) - , scope.scopeName.getString() - , static_cast(timestamp.getTime())); - result += _execute(sql) ? 1 : 0; + stmt.bindUint32(0, static_cast(scope.scopeId)); + stmt.bindUint64(1, static_cast(cookie)); + stmt.bindUint32(2, static_cast(scope.scopePrio)); + stmt.bindText( 3, scope.scopeName.getString()); + stmt.bindUint64(4, static_cast(timestamp.getTime())); + result += stmt.next() ? 1 : 0; + stmt.reset(); + stmt.clearBindings(); } return result; @@ -562,7 +707,7 @@ bool LogSqliteDatabase::logScopeActivate(const String& scopeName, uint32_t scope , static_cast(scopePrio) , scopeName.getString() , static_cast(timestamp.getTime())); - return _execute(sql); + return mDatabase.execute(sql); } bool LogSqliteDatabase::logScopesDeactivate(const ITEM_ID& cookie, const DateTime& timestamp) @@ -571,7 +716,7 @@ bool LogSqliteDatabase::logScopesDeactivate(const ITEM_ID& cookie, const DateTim String::formatString( sql, SQL_LEN, _fmtUpdScopes.data() , static_cast(timestamp.getTime()) , static_cast(cookie)); - return _execute(sql); + return mDatabase.execute(sql); } bool LogSqliteDatabase::logScopeDeactivate(const ITEM_ID& cookie, unsigned int scopeId, const DateTime& timestamp) @@ -582,67 +727,330 @@ bool LogSqliteDatabase::logScopeDeactivate(const ITEM_ID& cookie, unsigned int s , static_cast(cookie) , static_cast(scopeId) ); - return _execute(sql); + return mDatabase.execute(sql); } bool LogSqliteDatabase::rollback(void) { - return commit(false); + return mDatabase.rollback(); } -#if 0 -std::vector LogSqliteDatabase::getLogInstanceNames(void) const +std::vector LogSqliteDatabase::getLogInstanceNames(void) { - return std::vector(); + std::vector result; + getLogInstanceNames(result); + return result; } -std::vector LogSqliteDatabase::getLogInstances(void) const +void LogSqliteDatabase::getLogInstanceNames(std::vector& names) { - return std::vector(); + names.clear(); + SqliteStatement stmt(mDatabase, _sqlGetInstanceName); + if (stmt.isValid()) + { + while (stmt.next()) + { + String instName{ stmt.getText(0) }; + if (instName.isEmpty() == false) + { + names.push_back(instName); + } + } + } + + ASSERT(stmt.getRowPos() == static_cast(names.size())); } -std::vector LogSqliteDatabase::getLogThreadNames(void) const +std::vector LogSqliteDatabase::getLogInstances(void) { - return std::vector(); + std::vector result; + getLogInstances(result); + return result; } -std::vector LogSqliteDatabase::getLogThreads(void) const +void LogSqliteDatabase::getLogInstances(std::vector& ids) { - return std::vector(); + ids.clear(); + SqliteStatement stmt(mDatabase, _sqlGetInstanceIds); + if (stmt.isValid()) + { + while (stmt.next()) + { + ITEM_ID instId{ static_cast(stmt.getInt64(0)) }; + ids.push_back(instId); + } + } + + ASSERT(stmt.getRowPos() == static_cast(ids.size())); } -std::vector LogSqliteDatabase::getLogScopeNames(void) const +std::vector LogSqliteDatabase::getLogThreadNames(void) { - return std::vector(); + std::vector result; + getLogThreadNames(result); + return result; } -std::vector LogSqliteDatabase::getLogScopes(void) const +void LogSqliteDatabase::getLogThreadNames(std::vector& names) { - return std::vector(); + names.clear(); + SqliteStatement stmt(mDatabase, _sqlGetThreadNames); + if (stmt.isValid()) + { + while (stmt.next()) + { + String instName{ stmt.getText(0) }; + names.push_back(instName); + } + } + + ASSERT(stmt.getRowPos() == static_cast(names.size())); } -std::vector LogSqliteDatabase::getPriorityNames(void) const +std::vector LogSqliteDatabase::getLogThreads(void) { - return std::vector(); + std::vector result; + getLogThreads(result); + return result; } -std::vector LogSqliteDatabase::getLogInstScopes(ITEM_ID instId) const +void LogSqliteDatabase::getLogThreads(std::vector& ids) { - return std::vector(); + ids.clear(); + SqliteStatement stmt(mDatabase, _sqlGetThreadIds); + if (stmt.isValid()) + { + while (stmt.next()) + { + ITEM_ID instId{ static_cast(stmt.getInt64(0)) }; + ids.push_back(instId); + } + } + + ASSERT(stmt.getRowPos() == static_cast(ids.size())); } -std::vector LogSqliteDatabase::getLodMessages(void) const +std::vector LogSqliteDatabase::getPriorityNames(void) { - return std::vector(); + std::vector result{ + { + NELogging::logPrioToString(NELogging::eLogPriority::PrioAny) + , NELogging::logPrioToString(NELogging::eLogPriority::PrioScope) + , NELogging::logPrioToString(NELogging::eLogPriority::PrioDebug) + , NELogging::logPrioToString(NELogging::eLogPriority::PrioInfo) + , NELogging::logPrioToString(NELogging::eLogPriority::PrioWarning) + , NELogging::logPrioToString(NELogging::eLogPriority::PrioError) + , NELogging::logPrioToString(NELogging::eLogPriority::PrioFatal) + } + }; + return result; } -std::vector LogSqliteDatabase::getLodInstMessages(ITEM_ID instId) const +void LogSqliteDatabase::getPriorityNames(std::vector& names) { - return std::vector(); + names = getPriorityNames(); } -std::vector LogSqliteDatabase::getLodScopeMessages(ITEM_ID instId, uint32_t scopeId) const +std::vector LogSqliteDatabase::getLogInstanceInfos(void) { - return std::vector(); + std::vector result; + getLogInstanceInfos(result); + return result; +} + +void LogSqliteDatabase::getLogInstanceInfos(std::vector& infos) +{ + infos.clear(); + SqliteStatement stmt(mDatabase, _sqlGetLogInstances); + if (stmt.isValid()) + { + while (stmt.next()) + { + NEService::sServiceConnectedInstance inst; + inst.ciSource = static_cast( stmt.getUint32(0)); + inst.ciBitness = static_cast(stmt.getUint32(1)); + inst.ciCookie = static_cast(stmt.getInt64(2)); + inst.ciTimestamp= static_cast( stmt.getInt64(3)); + inst.ciInstance = stmt.getText(4); + inst.ciLocation = stmt.getText(5); + infos.push_back(inst); + } + } + + ASSERT(stmt.getRowPos() == static_cast(infos.size())); +} + +std::vector LogSqliteDatabase::getLogInstScopes(ITEM_ID instId) +{ + std::vector result; + getLogInstScopes(result, instId); + return result; +} + +void LogSqliteDatabase::getLogInstScopes(std::vector& scopes, ITEM_ID instId) +{ + scopes.clear(); + SqliteStatement stmt(mDatabase, _sqlGetLogScopes); + if (stmt.isValid()) + { + stmt.bindUint64(0, static_cast(instId)); + while (stmt.next()) + { + NELogging::sScopeInfo log; + log.scopeName = stmt.getText(0); + log.scopeId = static_cast(stmt.getUint32(1)); + log.scopePrio = static_cast(stmt.getUint32(2)); + scopes.push_back(log); + } + } + + ASSERT(stmt.getRowPos() == static_cast(scopes.size())); +} + +std::vector LogSqliteDatabase::getLogMessages(void) +{ + std::vector result; + getLogMessages(result); + return result; +} + +void LogSqliteDatabase::getLogMessages(std::vector& messages) +{ + messages.clear(); + SqliteStatement stmt(mDatabase, _sqlGetAllLogMessages); + if (stmt.isValid()) + { + while (stmt.next()) + { + SharedBuffer buf; + _copyLogMessage(stmt, buf); + messages.push_back(buf); + } + } + + ASSERT(stmt.getRowPos() == static_cast(messages.size())); +} + +std::vector LogSqliteDatabase::getLogInstMessages(ITEM_ID instId) +{ + std::vector result; + getLogInstMessages(result, instId); + return result; +} + +void LogSqliteDatabase::getLogInstMessages(std::vector& messages, ITEM_ID instId) +{ + if (instId == NEService::COOKIE_ANY) + { + getLogMessages(messages); + return; + } + + messages.clear(); + SqliteStatement stmt(mDatabase, _sqlGetInstLogMessages); + if (stmt.isValid()) + { + stmt.bindUint64(0, static_cast(instId)); + while (stmt.next()) + { + SharedBuffer buf; + _copyLogMessage(stmt, buf); + messages.push_back(buf); + } + } + + ASSERT(stmt.getRowPos() == static_cast(messages.size())); +} + +std::vector LogSqliteDatabase::getLogScopeMessages(uint32_t scopeId) +{ + std::vector result; + getLogScopeMessages(result, scopeId); + return result; +} + +void LogSqliteDatabase::getLogScopeMessages(std::vector& messages, uint32_t scopeId) +{ + if (scopeId == 0) + { + getLogMessages(messages); + return; + } + + messages.clear(); + SqliteStatement stmt(mDatabase, _sqlGetScopeLogMessages); + if (stmt.isValid()) + { + stmt.bindUint32(0, static_cast(scopeId)); + while (stmt.next()) + { + SharedBuffer buf; + _copyLogMessage(stmt, buf); + messages.push_back(buf); + } + } + + ASSERT(stmt.getRowPos() == static_cast(messages.size())); +} + +std::vector LogSqliteDatabase::getLogMessages(ITEM_ID instId, uint32_t scopeId) +{ + if (instId == NEService::COOKIE_ANY) + { + return (scopeId == 0 ? getLogMessages() : getLogScopeMessages(scopeId)); + } + else if (scopeId == 0) + { + return getLogInstMessages(instId); + } + + std::vector result; + SqliteStatement stmt(mDatabase, _sqlGetInstScopeLogMessages); + if (stmt.isValid()) + { + stmt.bindUint64(0, static_cast(instId)); + stmt.bindUint32(1, static_cast(scopeId)); + while (stmt.next()) + { + SharedBuffer buf; + _copyLogMessage(stmt, buf); + result.push_back(buf); + } + } + + ASSERT(stmt.getRowPos() == static_cast(result.size())); + return result; +} + +void LogSqliteDatabase::getLogMessages(std::vector& messages, ITEM_ID instId, uint32_t scopeId) +{ + if (instId == NEService::COOKIE_ANY) + { + if (scopeId == 0) + getLogMessages(messages); + else + getLogScopeMessages(messages, scopeId); + return; + } + else if (scopeId == 0) + { + getLogInstMessages(messages, instId); + return; + } + + messages.clear(); + SqliteStatement stmt(mDatabase, _sqlGetInstScopeLogMessages); + if (stmt.isValid()) + { + stmt.bindUint64(0, static_cast(instId)); + stmt.bindUint32(1, static_cast(scopeId)); + while (stmt.next()) + { + SharedBuffer buf; + _copyLogMessage(stmt, buf); + messages.push_back(buf); + } + } + + ASSERT(stmt.getRowPos() == static_cast(messages.size())); } -#endif diff --git a/framework/aregextend/db/private/SqliteDatabase.cpp b/framework/aregextend/db/private/SqliteDatabase.cpp index 55661a08a..0ee2822cc 100644 --- a/framework/aregextend/db/private/SqliteDatabase.cpp +++ b/framework/aregextend/db/private/SqliteDatabase.cpp @@ -49,15 +49,16 @@ SqliteDatabase::SqliteDatabase(void) SqliteDatabase::SqliteDatabase(const String& dbPath, bool open) : IEDatabaseEngine ( ) - , mDbPath (dbPath.isEmpty() ? String::getEmptyString() : File::normalizePath(dbPath)) + , mDbPath ( ) , mDbObject ( nullptr ) { - if (open && (mDbPath.isEmpty() == false)) + if (open) + { + _open(dbPath); + } + else { - if (::sqlite3_open(mDbPath.getString(), _sqlite(&mDbObject)) != SQLITE_OK) - { - _close(); - } + mDbPath = dbPath.isEmpty() ? String::getEmptyString() : File::normalizePath(dbPath); } } @@ -71,6 +72,18 @@ inline bool SqliteDatabase::_open(const String& dbPath) bool result{ true }; _close(); mDbPath = dbPath.isEmpty() == false ? File::normalizePath(dbPath) : mDbPath; + if (mDbPath.isEmpty()) + { + ASSERT(false && "SqliteDatabase::_open: Database path is empty."); + return false; + } + + String folder = File::getFileDirectory(mDbPath); + if ((folder.isEmpty() == false) && (File::existDir(folder) == false)) + { + File::createDirCascaded(folder); + } + if (SQLITE_OK != ::sqlite3_open(mDbPath.getString(), _sqlite(&mDbObject))) { _close(); @@ -125,9 +138,9 @@ bool SqliteDatabase::begin(void) bool SqliteDatabase::commit(bool doCommit) { constexpr std::string_view sqlCommit{ "COMMIT;" }; - constexpr std::string_view sqlRoolback{ "ROLLBACK;" }; + constexpr std::string_view sqlRollback{ "ROLLBACK;" }; - return (mDbObject != nullptr ? SQLITE_OK == ::sqlite3_exec(_sqlite(mDbObject), doCommit ? sqlCommit.data() : sqlRoolback.data(), nullptr, nullptr, nullptr) : false); + return (mDbObject != nullptr ? SQLITE_OK == ::sqlite3_exec(_sqlite(mDbObject), doCommit ? sqlCommit.data() : sqlRollback.data(), nullptr, nullptr, nullptr) : false); } bool SqliteDatabase::rollback(void) diff --git a/framework/aregextend/db/private/SqliteStatement.cpp b/framework/aregextend/db/private/SqliteStatement.cpp index 980bf2c7b..2fa13cbca 100644 --- a/framework/aregextend/db/private/SqliteStatement.cpp +++ b/framework/aregextend/db/private/SqliteStatement.cpp @@ -69,7 +69,7 @@ SqliteStatement::~SqliteStatement(void) bool SqliteStatement::prepare(const String& sql) { bool result{ (mDatabase.isOperable() && !sql.isEmpty() && (SQLITE_OK == ::sqlite3_prepare_v2(_sqlite(mDatabase.mDbObject), sql.getString(), -1, _sqlite_stmt(&mStatement), nullptr))) }; - mRowPos = result ? 1 : 0; // Reset row position + mRowPos = 0; // Reset row position return result; } @@ -101,29 +101,44 @@ void SqliteStatement::finalize() } } -bool SqliteStatement::bindInt(int index, int value) +bool SqliteStatement::bindInt32(int index, int32_t value) +{ + return ((index >= 0) && isValid() && (sqlite3_bind_int(_sqlite_stmt(mStatement), index + 1, value) == SQLITE_OK)); +} + +bool SqliteStatement::bindUint32(int index, uint32_t value) { - return isValid() && (sqlite3_bind_int(_sqlite_stmt(mStatement), index, value) == SQLITE_OK); + return ((index >= 0) && isValid() && (sqlite3_bind_int64(_sqlite_stmt(mStatement), index + 1, static_cast(value)) == SQLITE_OK)); } bool SqliteStatement::bindInt64(int index, int64_t value) { - return isValid() && (sqlite3_bind_int64(_sqlite_stmt(mStatement), index, value) == SQLITE_OK); + return ((index >= 0) && isValid() && (sqlite3_bind_int64(_sqlite_stmt(mStatement), index + 1, static_cast(value)) == SQLITE_OK)); +} + +bool SqliteStatement::bindUint64(int index, uint64_t value) +{ + return ((index >= 0) && isValid() && (sqlite3_bind_int64(_sqlite_stmt(mStatement), index + 1, static_cast(value)) == SQLITE_OK)); } bool SqliteStatement::bindDouble(int index, double value) { - return isValid() && (sqlite3_bind_double(_sqlite_stmt(mStatement), index, value) == SQLITE_OK); + return ((index >= 0) && isValid() && (sqlite3_bind_double(_sqlite_stmt(mStatement), index + 1, value) == SQLITE_OK)); +} + +bool SqliteStatement::bindFloat(int index, float value) +{ + return ((index >= 0) && isValid() && (sqlite3_bind_double(_sqlite_stmt(mStatement), index + 1, value) == SQLITE_OK)); } bool SqliteStatement::bindText(int index, const String& value) { - return isValid() && (sqlite3_bind_text(_sqlite_stmt(mStatement), index, value.getString(), -1, SQLITE_TRANSIENT) == SQLITE_OK); + return ((index >= 0) && isValid() && (sqlite3_bind_text(_sqlite_stmt(mStatement), index + 1, value.getString(), -1, SQLITE_TRANSIENT) == SQLITE_OK)); } bool SqliteStatement::bindNull(int index) { - return isValid() && (sqlite3_bind_null(_sqlite_stmt(mStatement), index) == SQLITE_OK); + return ((index >= 0) && isValid() && (sqlite3_bind_null(_sqlite_stmt(mStatement), index + 1) == SQLITE_OK)); } void SqliteStatement::clearBindings(void) @@ -132,72 +147,95 @@ void SqliteStatement::clearBindings(void) sqlite3_clear_bindings(_sqlite_stmt(mStatement)); } -int SqliteStatement::getInt(int column) const +int SqliteStatement::getInt32(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return sqlite3_column_int(_sqlite_stmt(mStatement), column); + ASSERT(index >= 0); + return static_cast(sqlite3_column_int(_sqlite_stmt(mStatement), index)); } -int64_t SqliteStatement::getInt64(int column) const +uint32_t SqliteStatement::getUint32(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return sqlite3_column_int64(_sqlite_stmt(mStatement), column); + ASSERT(index >= 0); + return static_cast(sqlite3_column_int64(_sqlite_stmt(mStatement), index)); } -double SqliteStatement::getDouble(int column) const +int64_t SqliteStatement::getInt64(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return sqlite3_column_double(_sqlite_stmt(mStatement), column); + ASSERT(index >= 0); + return static_cast(sqlite3_column_int64(_sqlite_stmt(mStatement), index)); } -String SqliteStatement::getText(int column) const +uint64_t SqliteStatement::getUint64(int index) const { - return String(reinterpret_cast(sqlite3_column_text(_sqlite_stmt(mStatement), column))); + ASSERT(isValid()); + ASSERT(index >= 0); + return static_cast(sqlite3_column_int64(_sqlite_stmt(mStatement), index)); +} + +double SqliteStatement::getDouble(int index) const +{ + ASSERT(isValid()); + ASSERT(index >= 0); + return static_cast(sqlite3_column_double(_sqlite_stmt(mStatement), index)); +} + +float SqliteStatement::getFloat(int index) const +{ + ASSERT(isValid()); + ASSERT(index >= 0); + return static_cast(sqlite3_column_double(_sqlite_stmt(mStatement), index)); +} + +String SqliteStatement::getText(int index) const +{ + ASSERT(isValid()); + ASSERT(index >= 0); + return String(reinterpret_cast(sqlite3_column_text(_sqlite_stmt(mStatement), index))); } -bool SqliteStatement::isNull(int column) const +bool SqliteStatement::isNull(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_NULL); + ASSERT(index >= 0); + return (sqlite3_column_type(_sqlite_stmt(mStatement), index) == SQLITE_NULL); } -bool SqliteStatement::isColumnValid(int column) const +bool SqliteStatement::isColumnValid(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return (sqlite3_column_type(_sqlite_stmt(mStatement), column) != SQLITE_NULL); + ASSERT(index >= 0); + return (sqlite3_column_type(_sqlite_stmt(mStatement), index) != SQLITE_NULL); } -bool SqliteStatement::isString(int column) const +bool SqliteStatement::isString(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_TEXT); + ASSERT(index >= 0); + return (sqlite3_column_type(_sqlite_stmt(mStatement), index) == SQLITE_TEXT); } -bool SqliteStatement::isInteger(int column) const +bool SqliteStatement::isInteger(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_INTEGER); + ASSERT(index >= 0); + return (sqlite3_column_type(_sqlite_stmt(mStatement), index) == SQLITE_INTEGER); } -bool SqliteStatement::isInteger64(int column) const +bool SqliteStatement::isInteger64(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_INTEGER); + ASSERT(index >= 0); + return (sqlite3_column_type(_sqlite_stmt(mStatement), index) == SQLITE_INTEGER); } -bool SqliteStatement::isDouble(int column) const +bool SqliteStatement::isDouble(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_FLOAT); + ASSERT(index >= 0); + return (sqlite3_column_type(_sqlite_stmt(mStatement), index) == SQLITE_FLOAT); } int SqliteStatement::getColumnCount(void) const @@ -206,11 +244,11 @@ int SqliteStatement::getColumnCount(void) const return sqlite3_column_count(_sqlite_stmt(mStatement)); } -String SqliteStatement::getColumnName(int column) const +String SqliteStatement::getColumnName(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - const char* columnName = sqlite3_column_name(_sqlite_stmt(mStatement), column); + ASSERT(index >= 0); + const char* columnName = sqlite3_column_name(_sqlite_stmt(mStatement), index); return String((columnName != nullptr) ? columnName : String::EmptyString); } @@ -230,11 +268,11 @@ int SqliteStatement::getColumnIndex(const String& columnName) const return NECommon::INVALID_INDEX; // Column not found } -SqliteStatement::eColumnType SqliteStatement::getColumnType(int column) const +SqliteStatement::eColumnType SqliteStatement::getColumnType(int index) const { ASSERT(isValid()); - ASSERT(column >= 0); - int type = sqlite3_column_type(_sqlite_stmt(mStatement), column); + ASSERT(index >= 0); + int type = sqlite3_column_type(_sqlite_stmt(mStatement), index); switch (type) { case SQLITE_INTEGER: diff --git a/framework/areglogger/client/LogObserverBase.hpp b/framework/areglogger/client/LogObserverBase.hpp index 478b9419e..73e55dc74 100644 --- a/framework/areglogger/client/LogObserverBase.hpp +++ b/framework/areglogger/client/LogObserverBase.hpp @@ -24,6 +24,7 @@ #include "areg/base/NESocket.hpp" #include "areg/component/NEService.hpp" +#include "areg/logging/NELogging.hpp" #include #include @@ -250,6 +251,89 @@ class LOGGER_API LogObserverBase **/ std::string getInitDatabasePath(void) const; + /** + * \brief Call to query and get list of names of connected instances from log database. + * \param names On output, contains the list of names of connected instances. + **/ + void getLogInstanceNames(std::vector& names); + + /** + * \brief Call to query and get list of IDs of connected instances from log database + * \param ids On output, contains the list of IDs of connected instances. + **/ + void getLogInstances(std::vector& ids); + + /** + * \brief Call to query and get list of names of threads of the connected instances from log database. + * \param names On output, contains the list of all thread names that sent messages. + **/ + void getLogThreadNames(std::vector& names); + + /** + * \brief Call to query and get list of IDs of threads of the connected instances from log database. + * \param ids On output, contains the list of all thread IDs that sent messages. + **/ + void getLogThreads(std::vector& ids); + + /** + * \brief Call to get the list of log priorities. + * \param names On output, contains the names of all priorities. + **/ + void getPriorityNames(std::vector& names); + + /** + * \brief Call to query and get information of connected instances from log database. + * This query will receive list of all registered instances. + * \param infos On output, contains the list of information of all registered instances in database. + **/ + void getLogInstanceInfos(std::vector< NEService::sServiceConnectedInstance>& infos); + + /** + * \brief Call to query and get information of log scopes of specified instance from log database. + * This query will receive list of all registered scopes. + * \param scopes On output, contains the list of all registered scopes in database related with the specified instance ID. + * \param instID The ID of the instance. + **/ + void getLogInstScopes(std::vector& scopes, ITEM_ID instId); + + /** + * \brief Call to get all log messages from log database. + * \param messages On output, contains the list of all log messages. + **/ + void getLogMessages(std::vector& messages); + + /** + * \brief Call to get log messages of the specified instance from log database. + * If `instId` is `NEService::COOKIE_ANY` it receives the list of all instances + * similar to the call to `getLogMessages()`. + * \param messages On output, contains the list of log messages of the specified instance. + * \param instId The ID of the instance to get log messages. + * If `NEService::COOKIE_ANY` it receives log messages of all instances. + **/ + void getLogInstMessages(std::vector& messages, ITEM_ID instId = NEService::COOKIE_ANY); + + /** + * \brief Call to get log messages of the specified scope from log database. + * If `scopeId` is `0` it receives the list of all scopes + * similar to the call to `getLogMessages()`. + * \param messages On output, contains the list of log messages of the specified scope. + * \param scopeId The ID of the scope to get log messages. + * If `0` it receives log messages of all scopes. + **/ + void getLogScopeMessages(std::vector& messages, uint32_t scopeId = 0); + + /** + * \brief Call to get log messages of the specified instance and log scope ID from log database. + * If `instId` is `NEService::COOKIE_ANY` and `scopeId` is `0`, it receives the list of all logs + * similar to the call to `getLogMessages()`. + * \param messages On output, contains the list of log messages of the specified instance and scope. + * \param instId The ID of the instance to get log messages. + * If `NEService::COOKIE_ANY` it receives log messages of all instances. + * \param scopeId The ID of the scope to get log messages. + * If `0` it receives log messages of all scopes. + **/ + void getLogMessages(std::vector& messages, ITEM_ID instId, uint32_t scopeId); + ////////////////////////////////////////////////////////////////////////// // Actions ////////////////////////////////////////////////////////////////////////// diff --git a/framework/areglogger/client/private/LogObserverBase.cpp b/framework/areglogger/client/private/LogObserverBase.cpp index cb035ebb1..ea36508d2 100644 --- a/framework/areglogger/client/private/LogObserverBase.cpp +++ b/framework/areglogger/client/private/LogObserverBase.cpp @@ -208,3 +208,58 @@ void LogObserverBase::saveLoggerConfig(void) { LoggerClient::getInstance().saveConfiguration(); } + +void LogObserverBase::getLogInstanceNames(std::vector& names) +{ + LoggerClient::getInstance().getLogInstanceNames(names); +} + +void LogObserverBase::getLogInstances(std::vector& ids) +{ + LoggerClient::getInstance().getLogInstances(ids); +} + +void LogObserverBase::getLogThreadNames(std::vector& names) +{ + LoggerClient::getInstance().getLogThreadNames(names); +} + +void LogObserverBase::getLogThreads(std::vector& ids) +{ + LoggerClient::getInstance().getLogThreads(ids); +} + +void LogObserverBase::getPriorityNames(std::vector& names) +{ + LoggerClient::getInstance().getPriorityNames(names); +} + +void LogObserverBase::getLogInstanceInfos(std::vector< NEService::sServiceConnectedInstance>& infos) +{ + LoggerClient::getInstance().getLogInstanceInfos(infos); +} + +void LogObserverBase::getLogInstScopes(std::vector& scopes, ITEM_ID instId) +{ + LoggerClient::getInstance().getLogInstScopes(scopes, instId); +} + +void LogObserverBase::getLogMessages(std::vector& messages) +{ + LoggerClient::getInstance().getLogMessages(messages); +} + +void LogObserverBase::getLogInstMessages(std::vector& messages, ITEM_ID instId /*= NEService::COOKIE_ANY*/) +{ + LoggerClient::getInstance().getLogInstMessages(messages, instId); +} + +void LogObserverBase::getLogScopeMessages(std::vector& messages, uint32_t scopeId /*= 0*/) +{ + LoggerClient::getInstance().getLogScopeMessages(messages, scopeId); +} + +void LogObserverBase::getLogMessages(std::vector& messages, ITEM_ID instId, uint32_t scopeId) +{ + LoggerClient::getInstance().getLogMessages(messages, instId, scopeId); +} diff --git a/framework/areglogger/client/private/LoggerClient.hpp b/framework/areglogger/client/private/LoggerClient.hpp index dd67d8f25..027231f1a 100644 --- a/framework/areglogger/client/private/LoggerClient.hpp +++ b/framework/areglogger/client/private/LoggerClient.hpp @@ -285,6 +285,89 @@ class LoggerClient : public ServiceClientConnectionBase **/ void saveConfiguration(void); + /** + * \brief Call to query and get list of names of connected instances from log database. + * \param names On output, contains the list of names of connected instances. + **/ + inline void getLogInstanceNames(std::vector& names); + + /** + * \brief Call to query and get list of IDs of connected instances from log database + * \param ids On output, contains the list of IDs of connected instances. + **/ + inline void getLogInstances(std::vector& ids); + + /** + * \brief Call to query and get list of names of threads of the connected instances from log database. + * \param names On output, contains the list of all thread names that sent messages. + **/ + inline void getLogThreadNames(std::vector& names); + + /** + * \brief Call to query and get list of IDs of threads of the connected instances from log database. + * \param ids On output, contains the list of all thread IDs that sent messages. + **/ + inline void getLogThreads(std::vector& ids); + + /** + * \brief Call to get the list of log priorities. + * \param names On output, contains the names of all priorities. + **/ + inline void getPriorityNames(std::vector& names); + + /** + * \brief Call to query and get information of connected instances from log database. + * This query will receive list of all registered instances. + * \param infos On output, contains the list of information of all registered instances in database. + **/ + inline void getLogInstanceInfos(std::vector< NEService::sServiceConnectedInstance>& infos); + + /** + * \brief Call to query and get information of log scopes of specified instance from log database. + * This query will receive list of all registered scopes. + * \param scopes On output, contains the list of all registered scopes in database related with the specified instance ID. + * \param instID The ID of the instance. + **/ + inline void getLogInstScopes(std::vector& scopes, ITEM_ID instId); + + /** + * \brief Call to get all log messages from log database. + * \param messages On output, contains the list of all log messages. + **/ + inline void getLogMessages(std::vector& messages); + + /** + * \brief Call to get log messages of the specified instance from log database. + * If `instId` is `NEService::COOKIE_ANY` it receives the list of all instances + * similar to the call to `getLogMessages()`. + * \param messages On output, contains the list of log messages of the specified instance. + * \param instId The ID of the instance to get log messages. + * If `NEService::COOKIE_ANY` it receives log messages of all instances. + **/ + inline void getLogInstMessages(std::vector& messages, ITEM_ID instId = NEService::COOKIE_ANY); + + /** + * \brief Call to get log messages of the specified scope from log database. + * If `scopeId` is `0` it receives the list of all scopes + * similar to the call to `getLogMessages()`. + * \param messages On output, contains the list of log messages of the specified scope. + * \param scopeId The ID of the scope to get log messages. + * If `0` it receives log messages of all scopes. + **/ + inline void getLogScopeMessages(std::vector& messages, uint32_t scopeId = 0); + + /** + * \brief Call to get log messages of the specified instance and log scope ID from log database. + * If `instId` is `NEService::COOKIE_ANY` and `scopeId` is `0`, it receives the list of all logs + * similar to the call to `getLogMessages()`. + * \param messages On output, contains the list of log messages of the specified instance and scope. + * \param instId The ID of the instance to get log messages. + * If `NEService::COOKIE_ANY` it receives log messages of all instances. + * \param scopeId The ID of the scope to get log messages. + * If `0` it receives log messages of all scopes. + **/ + inline void getLogMessages(std::vector& messages, ITEM_ID instId, uint32_t scopeId); + ////////////////////////////////////////////////////////////////////////// // Overrides ////////////////////////////////////////////////////////////////////////// @@ -471,6 +554,61 @@ class LoggerClient : public ServiceClientConnectionBase // LoggerClient inline methods. ////////////////////////////////////////////////////////////////////////// +inline void LoggerClient::getLogInstanceNames(std::vector& names) +{ + mLogDatabase.getLogInstanceNames(names); +} + +inline void LoggerClient::getLogInstances(std::vector& ids) +{ + mLogDatabase.getLogInstances(ids); +} + +inline void LoggerClient::getLogThreadNames(std::vector& names) +{ + mLogDatabase.getLogThreadNames(names); +} + +inline void LoggerClient::getLogThreads(std::vector& ids) +{ + mLogDatabase.getLogThreads(ids); +} + +inline void LoggerClient::getPriorityNames(std::vector& names) +{ + mLogDatabase.getPriorityNames(names); +} + +inline void LoggerClient::getLogInstanceInfos(std::vector< NEService::sServiceConnectedInstance>& infos) +{ + mLogDatabase.getLogInstanceInfos(infos); +} + +inline void LoggerClient::getLogInstScopes(std::vector& scopes, ITEM_ID instId) +{ + mLogDatabase.getLogInstScopes(scopes, instId); +} + +inline void LoggerClient::getLogMessages(std::vector& messages) +{ + mLogDatabase.getLogMessages(messages); +} + +inline void LoggerClient::getLogInstMessages(std::vector& messages, ITEM_ID instId /*= NEService::COOKIE_ANY*/) +{ + mLogDatabase.getLogInstMessages(messages, instId); +} + +inline void LoggerClient::getLogScopeMessages(std::vector& messages, uint32_t scopeId /*= 0*/) +{ + mLogDatabase.getLogScopeMessages(messages, scopeId); +} + +inline void LoggerClient::getLogMessages(std::vector& messages, ITEM_ID instId, uint32_t scopeId) +{ + mLogDatabase.getLogMessages(messages, instId, scopeId); +} + inline LoggerClient& LoggerClient::self(void) { return (*this);