diff --git a/framework/areg/logging/private/DatabaseLogger.cpp b/framework/areg/logging/private/DatabaseLogger.cpp index 6b06492c0..1a7dfe4ef 100644 --- a/framework/areg/logging/private/DatabaseLogger.cpp +++ b/framework/areg/logging/private/DatabaseLogger.cpp @@ -57,7 +57,7 @@ bool DatabaseLogger::openLogger(void) String fileName(mLogConfiguration.getDatabaseFullPath()); dbFile = File::normalizePath(fileName.getString()); - if (mDatabase->connect(dbFile)) + if (mDatabase->connect(dbFile, false)) { result = true; } diff --git a/framework/areg/persist/IEDatabaseEngine.hpp b/framework/areg/persist/IEDatabaseEngine.hpp index 51e2189e1..496ffd637 100644 --- a/framework/areg/persist/IEDatabaseEngine.hpp +++ b/framework/areg/persist/IEDatabaseEngine.hpp @@ -52,14 +52,15 @@ class AREG_API IEDatabaseEngine /** * \brief Connects to the specified database. - * \param dbPath The path to the database. If needed, the path may contain - * file path or URL, user name and password. It is up to - * Database engine to parse the path and initialize the connection. - * If the parameter is empty, it should take the data from the - * 'areg.init' configuration file. + * \param dbPath The path to the database. If needed, the path may contain + * file path or URL, user name and password. It is up to + * Database engine to parse the path and initialize the connection. + * If the parameter is empty, it should take the data from the + * 'areg.init' configuration file. + * \param readOnly If true, the database engine should connect in read-only mode. * \return Returns true if succeeded to connect. Otherwise, returns false. **/ - virtual bool connect(const String & dbPath) = 0; + virtual bool connect(const String & dbPath, bool readOnly) = 0; /** * \brief Disconnects connected database. diff --git a/framework/aregextend/db/LogSqliteDatabase.hpp b/framework/aregextend/db/LogSqliteDatabase.hpp index ad2efcf8f..f35b3df98 100644 --- a/framework/aregextend/db/LogSqliteDatabase.hpp +++ b/framework/aregextend/db/LogSqliteDatabase.hpp @@ -89,15 +89,16 @@ class LogSqliteDatabase : public IELogDatabaseEngine virtual bool isOperable(void) const override; /** - * \brief Connects to the specified SqliteDatabase. - * \param dbPath The path to the SqliteDatabase. If needed, the path may contain - * file path or URL, user name and password. It is up to - * SqliteDatabase engine to parse the path and initialize the connection. - * If the parameter is empty, it should take the data from the - * 'areg.init' configuration file. + * \brief Connects to the specified database. + * \param dbPath The path to the database. If needed, the path may contain + * file path or URL, user name and password. It is up to + * Database engine to parse the path and initialize the connection. + * If the parameter is empty, it should take the data from the + * 'areg.init' configuration file. + * \param readOnly If true, the database engine should connect in read-only mode. * \return Returns true if succeeded to connect. Otherwise, returns false. **/ - virtual bool connect(const String & dbPath) override; + virtual bool connect(const String& dbPath, bool readOnly) override; /** * \brief Disconnects connected SqliteDatabase. @@ -217,86 +218,97 @@ class LogSqliteDatabase : public IELogDatabaseEngine /** * \brief Call to query and get list of names of connected instances from log database. + * \param names On output, the vector contains names of connected instances. **/ + void getLogInstanceNames(std::vector& OUT names); std::vector getLogInstanceNames(void); - void getLogInstanceNames(std::vector& names); /** * \brief Call to query and get list of IDs of connected instances from log database. + * \param ids On output, the vector contains IDs of connected instances. **/ + void getLogInstances(std::vector& OUT ids); std::vector getLogInstances(void); - 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, the vector contains names of threads of connected instances. **/ + void getLogThreadNames(std::vector& OUT names); std::vector getLogThreadNames(void); - 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, the vector contains IDs of threads of connected instances. **/ + void getLogThreads(std::vector& OUT ids); std::vector getLogThreads(void); - void getLogThreads(std::vector& ids); /** * \brief Call to get the list of log priorities. + * \param names On output, the vector contains names of log priorities. **/ + void getPriorityNames(std::vector& OUT names); std::vector getPriorityNames(void); - 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, the vector contains information of connected instances. **/ + void getLogInstanceInfos(std::vector< NEService::sServiceConnectedInstance>& OUT infos); std::vector< NEService::sServiceConnectedInstance> getLogInstanceInfos(void); - 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, the vector contains information of log scopes. * \param instID The ID of the instance. **/ - std::vector getLogInstScopes(ITEM_ID instId); - void getLogInstScopes(std::vector& scopes, ITEM_ID instId); + void getLogInstScopes(std::vector& OUT scopes, ITEM_ID IN instId); + std::vector getLogInstScopes(ITEM_ID IN instId); /** * \brief Call to get all log messages from log database. + * \param messages On output, the vector contains all log messages. **/ + void getLogMessages(std::vector& OUT messages); std::vector getLogMessages(void); - 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 instId The ID of the instance to get log messages. - * If `NEService::COOKIE_ANY` it receives log messages of all instances. + * \param messages On output, the vector contains 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. **/ - std::vector getLogInstMessages(ITEM_ID instId = NEService::COOKIE_ANY); - void getLogInstMessages(std::vector& messages, ITEM_ID instId = NEService::COOKIE_ANY); + void getLogInstMessages(std::vector& OUT messages, ITEM_ID IN instId = NEService::COOKIE_ANY); + std::vector getLogInstMessages(ITEM_ID IN 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, the vector contains 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. **/ - std::vector getLogScopeMessages(uint32_t scopeId = 0); - void getLogScopeMessages(std::vector& messages, uint32_t scopeId = 0); + void getLogScopeMessages(std::vector& OUT messages, uint32_t IN scopeId = 0); + std::vector getLogScopeMessages(uint32_t IN 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, the vector contains 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. **/ - std::vector getLogMessages(ITEM_ID instId, uint32_t scopeId); - void getLogMessages(std::vector& messages, ITEM_ID instId, uint32_t scopeId); + void getLogMessages(std::vector& OUT messages, ITEM_ID IN instId, uint32_t IN scopeId); + std::vector getLogMessages(ITEM_ID IN instId, uint32_t IN scopeId); ////////////////////////////////////////////////////////////////////////// // Hidden methods @@ -306,8 +318,11 @@ class LogSqliteDatabase : public IELogDatabaseEngine /** * \brief Opens or creates the specified database file. * The path can be relative or absolute, it may as contain the mask. + * \param dbPath The relative or absolute path the database file. + * \param readOnly If true, the database engine should connect in read-only mode. + * \return Returns true if succeeded to open or create the database file. **/ - inline bool _open(const String& dbPath); + inline bool _open(const String& dbPath, bool readOnly); /** * \brief In the opened database file, creates the tables required to save logs. @@ -324,6 +339,11 @@ class LogSqliteDatabase : public IELogDatabaseEngine **/ inline void _initialize(void); + /** + * \brief Extracts the log message from the SqliteStatement and copies it to the SharedBuffer. + * \param stmt The SqliteStatement to extract the log message. + * \param buf The SharedBuffer to copy the log message. + **/ inline void _copyLogMessage(SqliteStatement& stmt, SharedBuffer & buf); ////////////////////////////////////////////////////////////////////////// diff --git a/framework/aregextend/db/SqliteDatabase.hpp b/framework/aregextend/db/SqliteDatabase.hpp index 44ac01520..874461c46 100644 --- a/framework/aregextend/db/SqliteDatabase.hpp +++ b/framework/aregextend/db/SqliteDatabase.hpp @@ -76,15 +76,16 @@ class SqliteDatabase : public IEDatabaseEngine virtual bool isOperable(void) const override; /** - * \brief Connects to the specified SqliteDatabase. - * \param dbPath The path to the SqliteDatabase. If needed, the path may contain - * file path or URL, user name and password. It is up to - * SqliteDatabase engine to parse the path and initialize the connection. - * If the parameter is empty, it should take the data from the - * 'areg.init' configuration file. + * \brief Connects to the specified database. + * \param dbPath The path to the database. If needed, the path may contain + * file path or URL, user name and password. It is up to + * Database engine to parse the path and initialize the connection. + * If the parameter is empty, it should take the data from the + * 'areg.init' configuration file. + * \param readOnly If true, the database engine should connect in read-only mode. * \return Returns true if succeeded to connect. Otherwise, returns false. **/ - virtual bool connect(const String & dbPath) override; + virtual bool connect(const String& dbPath, bool readOnly) override; /** * \brief Disconnects connected SqliteDatabase. diff --git a/framework/aregextend/db/private/LogSqliteDatabase.cpp b/framework/aregextend/db/private/LogSqliteDatabase.cpp index 57e442166..6ae2a687a 100644 --- a/framework/aregextend/db/private/LogSqliteDatabase.cpp +++ b/framework/aregextend/db/private/LogSqliteDatabase.cpp @@ -315,7 +315,7 @@ LogSqliteDatabase::~LogSqliteDatabase(void) mIsInitialized = false; } -inline bool LogSqliteDatabase::_open(const String& dbPath) +inline bool LogSqliteDatabase::_open(const String& dbPath, bool readOnly) { if (mDbLogEnabled == false) return false; @@ -328,7 +328,7 @@ inline bool LogSqliteDatabase::_open(const String& dbPath) mDbInitPath = dbPath; } - if (mDatabase.connect(mDbInitPath) == false) + if (mDatabase.connect(mDbInitPath, readOnly) == false) { mDatabase.disconnect(); mIsInitialized = false; @@ -391,7 +391,7 @@ inline void LogSqliteDatabase::_initialize(void) inline void LogSqliteDatabase::_copyLogMessage(SqliteStatement& stmt, SharedBuffer& buf) { constexpr uint32_t _logSize{ static_cast(sizeof(NELogging::sLogMessage)) }; - + buf.reserve(_logSize, false); buf.setSizeUsed(_logSize); buf.moveToBegin(); NELogging::sLogMessage* log = reinterpret_cast(buf.getBuffer()); @@ -426,19 +426,27 @@ bool LogSqliteDatabase::isOperable(void) const return mDatabase.isOperable(); } -bool LogSqliteDatabase::connect(const String& dbPath /*= String::EmptyString*/) +bool LogSqliteDatabase::connect(const String& dbPath, bool readOnly) { if (mDbLogEnabled && mDatabase.isOperable() == false) { + bool exists = File::existFile(dbPath); ASSERT(mIsInitialized == false); - if (_open(dbPath)) + if (_open(dbPath, readOnly)) { - _createTables(); - _createIndexes(); - _initialize(); - commit(true); + if (exists == false) + { + _createTables(); + _createIndexes(); + _initialize(); + commit(true); + } + mIsInitialized = true; - mStmtLogs.prepare(_sqlInsertLog); + if (readOnly == false) + { + mStmtLogs.prepare(_sqlInsertLog); + } } } @@ -742,7 +750,7 @@ std::vector LogSqliteDatabase::getLogInstanceNames(void) return result; } -void LogSqliteDatabase::getLogInstanceNames(std::vector& names) +void LogSqliteDatabase::getLogInstanceNames(std::vector& OUT names) { names.clear(); SqliteStatement stmt(mDatabase, _sqlGetInstanceName); @@ -768,7 +776,7 @@ std::vector LogSqliteDatabase::getLogInstances(void) return result; } -void LogSqliteDatabase::getLogInstances(std::vector& ids) +void LogSqliteDatabase::getLogInstances(std::vector& OUT ids) { ids.clear(); SqliteStatement stmt(mDatabase, _sqlGetInstanceIds); @@ -791,7 +799,7 @@ std::vector LogSqliteDatabase::getLogThreadNames(void) return result; } -void LogSqliteDatabase::getLogThreadNames(std::vector& names) +void LogSqliteDatabase::getLogThreadNames(std::vector& OUT names) { names.clear(); SqliteStatement stmt(mDatabase, _sqlGetThreadNames); @@ -814,7 +822,7 @@ std::vector LogSqliteDatabase::getLogThreads(void) return result; } -void LogSqliteDatabase::getLogThreads(std::vector& ids) +void LogSqliteDatabase::getLogThreads(std::vector& OUT ids) { ids.clear(); SqliteStatement stmt(mDatabase, _sqlGetThreadIds); @@ -846,7 +854,7 @@ std::vector LogSqliteDatabase::getPriorityNames(void) return result; } -void LogSqliteDatabase::getPriorityNames(std::vector& names) +void LogSqliteDatabase::getPriorityNames(std::vector& OUT names) { names = getPriorityNames(); } @@ -858,7 +866,7 @@ std::vector LogSqliteDatabase::getLogInsta return result; } -void LogSqliteDatabase::getLogInstanceInfos(std::vector& infos) +void LogSqliteDatabase::getLogInstanceInfos(std::vector& OUT infos) { infos.clear(); SqliteStatement stmt(mDatabase, _sqlGetLogInstances); @@ -880,14 +888,14 @@ void LogSqliteDatabase::getLogInstanceInfos(std::vector(infos.size())); } -std::vector LogSqliteDatabase::getLogInstScopes(ITEM_ID instId) +std::vector LogSqliteDatabase::getLogInstScopes(ITEM_ID IN instId) { std::vector result; getLogInstScopes(result, instId); return result; } -void LogSqliteDatabase::getLogInstScopes(std::vector& scopes, ITEM_ID instId) +void LogSqliteDatabase::getLogInstScopes(std::vector& OUT scopes, ITEM_ID IN instId) { scopes.clear(); SqliteStatement stmt(mDatabase, _sqlGetLogScopes); @@ -914,7 +922,7 @@ std::vector LogSqliteDatabase::getLogMessages(void) return result; } -void LogSqliteDatabase::getLogMessages(std::vector& messages) +void LogSqliteDatabase::getLogMessages(std::vector& OUT messages) { messages.clear(); SqliteStatement stmt(mDatabase, _sqlGetAllLogMessages); @@ -931,14 +939,14 @@ void LogSqliteDatabase::getLogMessages(std::vector& messages) ASSERT(stmt.getRowPos() == static_cast(messages.size())); } -std::vector LogSqliteDatabase::getLogInstMessages(ITEM_ID instId) +std::vector LogSqliteDatabase::getLogInstMessages(ITEM_ID IN instId) { std::vector result; getLogInstMessages(result, instId); return result; } -void LogSqliteDatabase::getLogInstMessages(std::vector& messages, ITEM_ID instId) +void LogSqliteDatabase::getLogInstMessages(std::vector& OUT messages, ITEM_ID IN instId) { if (instId == NEService::COOKIE_ANY) { @@ -962,14 +970,14 @@ void LogSqliteDatabase::getLogInstMessages(std::vector& messages, ASSERT(stmt.getRowPos() == static_cast(messages.size())); } -std::vector LogSqliteDatabase::getLogScopeMessages(uint32_t scopeId) +std::vector LogSqliteDatabase::getLogScopeMessages(uint32_t IN scopeId) { std::vector result; getLogScopeMessages(result, scopeId); return result; } -void LogSqliteDatabase::getLogScopeMessages(std::vector& messages, uint32_t scopeId) +void LogSqliteDatabase::getLogScopeMessages(std::vector& OUT messages, uint32_t IN scopeId) { if (scopeId == 0) { @@ -993,7 +1001,7 @@ void LogSqliteDatabase::getLogScopeMessages(std::vector& messages, ASSERT(stmt.getRowPos() == static_cast(messages.size())); } -std::vector LogSqliteDatabase::getLogMessages(ITEM_ID instId, uint32_t scopeId) +std::vector LogSqliteDatabase::getLogMessages(ITEM_ID IN instId, uint32_t IN scopeId) { if (instId == NEService::COOKIE_ANY) { @@ -1022,7 +1030,7 @@ std::vector LogSqliteDatabase::getLogMessages(ITEM_ID instId, uint return result; } -void LogSqliteDatabase::getLogMessages(std::vector& messages, ITEM_ID instId, uint32_t scopeId) +void LogSqliteDatabase::getLogMessages(std::vector& OUT messages, ITEM_ID IN instId, uint32_t IN scopeId) { if (instId == NEService::COOKIE_ANY) { diff --git a/framework/aregextend/db/private/SqliteDatabase.cpp b/framework/aregextend/db/private/SqliteDatabase.cpp index 0ee2822cc..dddaface6 100644 --- a/framework/aregextend/db/private/SqliteDatabase.cpp +++ b/framework/aregextend/db/private/SqliteDatabase.cpp @@ -107,7 +107,7 @@ bool SqliteDatabase::isOperable(void) const return (mDbObject != nullptr); } -bool SqliteDatabase::connect(const String& dbPath) +bool SqliteDatabase::connect(const String& dbPath, bool /*readOnly*/) { return _open(dbPath); } diff --git a/framework/areglogger/client/private/LoggerClient.cpp b/framework/areglogger/client/private/LoggerClient.cpp index df1ab3225..b191efc9f 100644 --- a/framework/areglogger/client/private/LoggerClient.cpp +++ b/framework/areglogger/client/private/LoggerClient.cpp @@ -240,7 +240,7 @@ bool LoggerClient::openLoggingDatabase(const char* dbPath /*= nullptr*/) } } - bool result{ mLogDatabase.connect(filePath) }; + bool result{ mLogDatabase.connect(filePath, false) }; FuncLogDbCreated callback{ mLogDatabase.isOperable() && (mCallbacks != nullptr) ? mCallbacks->evtLogDbCreated : nullptr}; if (LogObserverBase::_theLogObserver != nullptr) {