Mercurial > hg > orthanc-databases
changeset 715:7c0157bf749c sql-opti
added the name of the source plugin in audit logs
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sun, 10 Aug 2025 15:27:45 +0200 |
parents | c1b73bf5c122 |
children | 951d2ef62f58 |
files | Framework/Plugins/DatabaseBackendAdapterV4.cpp Framework/Plugins/IDatabaseBackend.h Framework/Plugins/IndexBackend.cpp Framework/Plugins/IndexBackend.h MySQL/Plugins/IndexPlugin.cpp Odbc/Plugins/IndexPlugin.cpp PostgreSQL/Plugins/SQL/PrepareIndex.sql SQLite/Plugins/IndexPlugin.cpp |
diffstat | 8 files changed, 125 insertions(+), 41 deletions(-) [+] |
line wrap: on
line diff
--- a/Framework/Plugins/DatabaseBackendAdapterV4.cpp Fri Aug 08 18:01:19 2025 +0200 +++ b/Framework/Plugins/DatabaseBackendAdapterV4.cpp Sun Aug 10 15:27:45 2025 +0200 @@ -1525,7 +1525,8 @@ } - OrthancPluginErrorCode AuditLogHandler(const char* userId, + OrthancPluginErrorCode AuditLogHandler(const char* sourcePlugin, + const char* userId, OrthancPluginResourceType resourceType, const char* resourceId, const char* action, @@ -1542,6 +1543,7 @@ { BaseIndexConnectionsPool::Accessor accessor(*connectionPool_); accessor.GetBackend().RecordAuditLog(accessor.GetManager(), + sourcePlugin, userId, resourceType, resourceId, @@ -1612,7 +1614,6 @@ toTs = boost::lexical_cast<uint64_t>(getArguments["to-timestamp"]); } - // note: right now, we assume the logData is always JSON Json::Value jsonLogs; #if ORTHANC_PLUGINS_HAS_AUDIT_LOGS == 1 @@ -1631,20 +1632,51 @@ for (std::list<IDatabaseBackend::AuditLog>::const_iterator it = logs.begin(); it != logs.end(); ++it) { Json::Value serializedAuditLog; - serializedAuditLog["Timestamp"] = it->timeStamp; - serializedAuditLog["UserId"] = it->userId; - serializedAuditLog["ResourceId"] = it->resourceId; - serializedAuditLog["ResourceType"] = it->resourceType; - serializedAuditLog["Action"] = it->action; + serializedAuditLog["SourcePlugin"] = it->GetSourcePlugin(); + serializedAuditLog["Timestamp"] = it->GetTimestamp(); + serializedAuditLog["UserId"] = it->GetUserId(); + serializedAuditLog["ResourceId"] = it->GetResourceId(); + serializedAuditLog["Action"] = it->GetAction(); + + std::string level; + switch (it->GetResourceType()) + { + case OrthancPluginResourceType_Patient: + level = "Patient"; + break; + + case OrthancPluginResourceType_Study: + level = "Study"; + break; - if (it->logData.empty()) + case OrthancPluginResourceType_Series: + level = "Series"; + break; + + case OrthancPluginResourceType_Instance: + level = "Instance"; + break; + + case OrthancPluginResourceType_None: + level = "None"; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + serializedAuditLog["ResourceType"] = level; + + // TODO - Shouldn't the "LogData" information be Base64-encoded? + // Plugins are not required to write JSON (e.g., could be Protocol Buffers) + if (it->GetLogData().empty()) { serializedAuditLog["LogData"] = Json::nullValue; } else { Json::Value logData; - Orthanc::Toolbox::ReadJson(logData, it->logData); + Orthanc::Toolbox::ReadJson(logData, it->GetLogData()); serializedAuditLog["LogData"] = logData; }
--- a/Framework/Plugins/IDatabaseBackend.h Fri Aug 08 18:01:19 2025 +0200 +++ b/Framework/Plugins/IDatabaseBackend.h Sun Aug 10 15:27:45 2025 +0200 @@ -37,28 +37,68 @@ class IDatabaseBackend : public boost::noncopyable { public: - struct AuditLog + class AuditLog { - std::string timeStamp; - std::string userId; - OrthancPluginResourceType resourceType; - std::string resourceId; - std::string action; - std::string logData; + private: + std::string timestamp_; + std::string sourcePlugin_; + std::string userId_; + OrthancPluginResourceType resourceType_; + std::string resourceId_; + std::string action_; + std::string logData_; - AuditLog(const std::string& timeStamp, + public: + AuditLog(const std::string& timestamp, + const std::string& sourcePlugin, const std::string& userId, OrthancPluginResourceType resourceType, const std::string& resourceId, const std::string& action, const std::string& logData) : - timeStamp(timeStamp), - userId(userId), - resourceType(resourceType), - resourceId(resourceId), - action(action), - logData(logData) + timestamp_(timestamp), + sourcePlugin_(sourcePlugin), + userId_(userId), + resourceType_(resourceType), + resourceId_(resourceId), + action_(action), + logData_(logData) + { + } + + const std::string& GetTimestamp() const + { + return timestamp_; + } + + const std::string& GetSourcePlugin() const + { + return sourcePlugin_; + } + + const std::string& GetUserId() const { + return userId_; + } + + OrthancPluginResourceType GetResourceType() const + { + return resourceType_; + } + + const std::string& GetResourceId() const + { + return resourceId_; + } + + const std::string& GetAction() const + { + return action_; + } + + const std::string& GetLogData() const + { + return logData_; } }; @@ -489,6 +529,7 @@ #if ORTHANC_PLUGINS_HAS_AUDIT_LOGS == 1 virtual void RecordAuditLog(DatabaseManager& manager, + const std::string& sourcePlugin, const std::string& userId, OrthancPluginResourceType type, const std::string& resourceId,
--- a/Framework/Plugins/IndexBackend.cpp Fri Aug 08 18:01:19 2025 +0200 +++ b/Framework/Plugins/IndexBackend.cpp Sun Aug 10 15:27:45 2025 +0200 @@ -4685,6 +4685,7 @@ #if ORTHANC_PLUGINS_HAS_AUDIT_LOGS == 1 void IndexBackend::RecordAuditLog(DatabaseManager& manager, + const std::string& sourcePlugin, const std::string& userId, OrthancPluginResourceType resourceType, const std::string& resourceId, @@ -4694,22 +4695,22 @@ { DatabaseManager::CachedStatement statement( STATEMENT_FROM_HERE, manager, - "INSERT INTO AuditLogs (userId, resourceType, resourceId, action, logData) " - "VALUES(${userId}, ${resourceType}, ${resourceId}, ${action}, ${logData})"); - + "INSERT INTO AuditLogs (sourcePlugin, userId, resourceType, resourceId, action, logData) " + "VALUES(${sourcePlugin}, ${userId}, ${resourceType}, ${resourceId}, ${action}, ${logData})"); + + statement.SetParameterType("sourcePlugin", ValueType_Utf8String); statement.SetParameterType("userId", ValueType_Utf8String); + statement.SetParameterType("resourceType", ValueType_Integer64); statement.SetParameterType("resourceId", ValueType_Utf8String); - statement.SetParameterType("resourceType", ValueType_Integer64); statement.SetParameterType("action", ValueType_Utf8String); - statement.SetParameterType("userId", ValueType_Utf8String); statement.SetParameterType("logData", ValueType_BinaryString); Dictionary args; + args.SetUtf8Value("sourcePlugin", sourcePlugin); args.SetUtf8Value("userId", userId); args.SetIntegerValue("resourceType", static_cast<int>(resourceType)); args.SetUtf8Value("resourceId", resourceId); args.SetUtf8Value("action", action); - args.SetUtf8Value("userId", userId); if (logData != NULL && logDataSize > 0) { @@ -4736,7 +4737,7 @@ LookupFormatter formatter(manager.GetDialect()); std::vector<std::string> filters; - std::string sql = "SELECT to_char(ts, 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"'), userId, resourceType, resourceId, action, logData FROM AuditLogs "; + std::string sql = "SELECT to_char(ts, 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"'), sourcePlugin, userId, resourceType, resourceId, action, logData FROM AuditLogs "; if (!userIdFilter.empty()) { @@ -4791,19 +4792,21 @@ statement.SetResultFieldType(0, ValueType_Utf8String); statement.SetResultFieldType(1, ValueType_Utf8String); - statement.SetResultFieldType(2, ValueType_Integer64); - statement.SetResultFieldType(3, ValueType_Utf8String); + statement.SetResultFieldType(2, ValueType_Utf8String); + statement.SetResultFieldType(3, ValueType_Integer64); statement.SetResultFieldType(4, ValueType_Utf8String); - statement.SetResultFieldType(5, ValueType_BinaryString); + statement.SetResultFieldType(5, ValueType_Utf8String); + statement.SetResultFieldType(6, ValueType_BinaryString); while (!statement.IsDone()) { logs.push_back(AuditLog(statement.ReadString(0), statement.ReadString(1), - static_cast<OrthancPluginResourceType>(statement.ReadInteger64(2)), - statement.ReadString(3), + statement.ReadString(2), + static_cast<OrthancPluginResourceType>(statement.ReadInteger64(3)), statement.ReadString(4), - statement.ReadStringOrNull(5))); + statement.ReadString(5), + statement.ReadStringOrNull(6))); statement.Next(); }
--- a/Framework/Plugins/IndexBackend.h Fri Aug 08 18:01:19 2025 +0200 +++ b/Framework/Plugins/IndexBackend.h Sun Aug 10 15:27:45 2025 +0200 @@ -523,6 +523,7 @@ #if ORTHANC_PLUGINS_HAS_AUDIT_LOGS == 1 virtual void RecordAuditLog(DatabaseManager& manager, + const std::string& sourcePlugin, const std::string& userId, OrthancPluginResourceType type, const std::string& resourceId, @@ -539,10 +540,8 @@ uint64_t toTs, uint64_t since, uint64_t limit) ORTHANC_OVERRIDE; - #endif - virtual bool HasPerformDbHousekeeping() ORTHANC_OVERRIDE { return false;
--- a/MySQL/Plugins/IndexPlugin.cpp Fri Aug 08 18:01:19 2025 +0200 +++ b/MySQL/Plugins/IndexPlugin.cpp Sun Aug 10 15:27:45 2025 +0200 @@ -86,8 +86,11 @@ OrthancDatabases::MySQLParameters parameters(mysql, configuration); OrthancDatabases::IndexBackend::Register( - new OrthancDatabases::MySQLIndex(context, parameters, readOnly), countConnections, - parameters.GetMaxConnectionRetries(), housekeepingDelaySeconds); + new OrthancDatabases::MySQLIndex(context, parameters, readOnly), + countConnections, + false /* useDynamicConnectionPool */, + parameters.GetMaxConnectionRetries(), + housekeepingDelaySeconds); } catch (Orthanc::OrthancException& e) {
--- a/Odbc/Plugins/IndexPlugin.cpp Fri Aug 08 18:01:19 2025 +0200 +++ b/Odbc/Plugins/IndexPlugin.cpp Sun Aug 10 15:27:45 2025 +0200 @@ -130,7 +130,11 @@ index->SetMaxConnectionRetries(maxConnectionRetries); index->SetConnectionRetryInterval(connectionRetryInterval); - OrthancDatabases::IndexBackend::Register(index.release(), countConnections, maxConnectionRetries, housekeepingDelaySeconds); + OrthancDatabases::IndexBackend::Register(index.release(), + countConnections, + false /* useDynamicConnectionPool */, + maxConnectionRetries, + housekeepingDelaySeconds); } catch (Orthanc::OrthancException& e) {
--- a/PostgreSQL/Plugins/SQL/PrepareIndex.sql Fri Aug 08 18:01:19 2025 +0200 +++ b/PostgreSQL/Plugins/SQL/PrepareIndex.sql Sun Aug 10 15:27:45 2025 +0200 @@ -826,6 +826,7 @@ CREATE TABLE IF NOT EXISTS AuditLogs ( ts TIMESTAMP DEFAULT NOW(), + sourcePlugin TEXT NOT NULL, userId TEXT NOT NULL, resourceType INTEGER NOT NULL, resourceId VARCHAR(64) NOT NULL,
--- a/SQLite/Plugins/IndexPlugin.cpp Fri Aug 08 18:01:19 2025 +0200 +++ b/SQLite/Plugins/IndexPlugin.cpp Sun Aug 10 15:27:45 2025 +0200 @@ -75,6 +75,7 @@ OrthancDatabases::IndexBackend::Register( new OrthancDatabases::SQLiteIndex(context, "index.db"), // TODO parameter 1 /* only 1 connection is possible with SQLite */, + false /* useDynamicConnectionPool */, 0 /* no collision is possible, as SQLite has a global lock */, 0 /* housekeeping delay, unused for SQLite */); }