diff --git a/ydb/core/audit/audit_log.h b/ydb/core/audit/audit_log.h index 97ecc6e78acf..1696e0f7b924 100644 --- a/ydb/core/audit/audit_log.h +++ b/ydb/core/audit/audit_log.h @@ -37,8 +37,10 @@ namespace NActors { namespace NKikimr::NAudit { +using TAuditLogParts = TVector>; + extern std::atomic AUDIT_LOG_ENABLED; -void SendAuditLog(const NActors::TActorSystem* sys, TVector>&& parts); +void SendAuditLog(const NActors::TActorSystem* sys, TAuditLogParts&& parts); } // namespace NKikimr::NAudit diff --git a/ydb/core/audit/audit_log_impl.cpp b/ydb/core/audit/audit_log_impl.cpp index 538e267d5e61..bfab6d72bef4 100644 --- a/ydb/core/audit/audit_log_impl.cpp +++ b/ydb/core/audit/audit_log_impl.cpp @@ -3,14 +3,14 @@ #include #include +#include #include #include #include #include #include -#include - +#include "audit_log_item_builder.h" #include "audit_log_service.h" #include "audit_log.h" @@ -55,9 +55,9 @@ struct TEvAuditLog { struct TEvWriteAuditLog : public NActors::TEventLocal { TInstant Time; - TVector> Parts; + TAuditLogParts Parts; - TEvWriteAuditLog(TInstant time, TVector>&& parts) + TEvWriteAuditLog(TInstant time, TAuditLogParts&& parts) : Time(time) , Parts(std::move(parts)) {} @@ -78,12 +78,11 @@ void WriteLog(const TString& log, const TVector>& logBacken } } -TString GetJsonLog(const TEvAuditLog::TEvWriteAuditLog::TPtr& ev) { - const auto* msg = ev->Get(); +TString GetJsonLog(TInstant time, const TAuditLogParts& parts) { TStringStream ss; - ss << msg->Time << ": "; + ss << time << ": "; NJson::TJsonMap m; - for (auto& [k, v] : msg->Parts) { + for (auto& [k, v] : parts) { m[k] = v; } NJson::WriteJson(&ss, &m, false, false); @@ -91,19 +90,18 @@ TString GetJsonLog(const TEvAuditLog::TEvWriteAuditLog::TPtr& ev) { return ss.Str(); } -TString GetJsonLogCompatibleLog(const TEvAuditLog::TEvWriteAuditLog::TPtr& ev) { - const auto* msg = ev->Get(); +TString GetJsonLogCompatibleLog(TInstant time, const TAuditLogParts& parts) { TStringStream ss; NJsonWriter::TBuf json(NJsonWriter::HEM_DONT_ESCAPE_HTML, &ss); { auto obj = json.BeginObject(); obj .WriteKey("@timestamp") - .WriteString(msg->Time.ToString().data()) + .WriteString(time.ToString().data()) .WriteKey("@log_type") .WriteString("audit"); - for (auto& [k, v] : msg->Parts) { + for (auto& [k, v] : parts) { obj.WriteKey(k).WriteString(v); } json.EndObject(); @@ -112,12 +110,11 @@ TString GetJsonLogCompatibleLog(const TEvAuditLog::TEvWriteAuditLog::TPtr& ev) { return ss.Str(); } -TString GetTxtLog(const TEvAuditLog::TEvWriteAuditLog::TPtr& ev) { - const auto* msg = ev->Get(); +TString GetTxtLog(TInstant time, const TAuditLogParts& parts) { TStringStream ss; - ss << msg->Time << ": "; - for (auto it = msg->Parts.begin(); it != msg->Parts.end(); it++) { - if (it != msg->Parts.begin()) + ss << time << ": "; + for (auto it = parts.begin(); it != parts.end(); it++) { + if (it != parts.begin()) ss << ", "; ss << it->first << "=" << it->second; } @@ -125,6 +122,23 @@ TString GetTxtLog(const TEvAuditLog::TEvWriteAuditLog::TPtr& ev) { return ss.Str(); } +// Array of functions for converting a audit event parameters to a string. +// Indexing in the array occurs by the value of the NKikimrConfig::TAuditConfig::EFormat enumeration. +// For each new format, we need to register the audit event conversion function. +// The size of AuditLogItemBuilders must be larger by one of the maximum value of the NKikimrConfig::TAuditConfig::EFormat enumeration. +// The first value of AuditLogItemBuilders is a stub for the convenience of indexing by enumeration value. +static std::vector AuditLogItemBuilders = { nullptr, GetJsonLog, GetTxtLog, GetJsonLogCompatibleLog, nullptr }; + +// numbering enumeration starts from one +static constexpr size_t DefaultAuditLogItemBuilder = static_cast(NKikimrConfig::TAuditConfig::JSON); + +void RegisterAuditLogItemBuilder(NKikimrConfig::TAuditConfig::EFormat format, TAuditLogItemBuilder builder) { + size_t index = static_cast(format); + if (index < AuditLogItemBuilders.size()) { + AuditLogItemBuilders[index] = builder; + } +} + class TAuditLogActor final : public TActor { private: const TAuditLogBackends LogBackends; @@ -160,20 +174,12 @@ class TAuditLogActor final : public TActor { Y_UNUSED(ctx); for (auto& logBackends : LogBackends) { - switch (logBackends.first) { - case NKikimrConfig::TAuditConfig::JSON: - WriteLog(GetJsonLog(ev), logBackends.second); - break; - case NKikimrConfig::TAuditConfig::TXT: - WriteLog(GetTxtLog(ev), logBackends.second); - break; - case NKikimrConfig::TAuditConfig::JSON_LOG_COMPATIBLE: - WriteLog(GetJsonLogCompatibleLog(ev), logBackends.second); - break; - default: - WriteLog(GetJsonLog(ev), logBackends.second); - break; - } + const auto builderIndex = static_cast(logBackends.first); + const auto builder = builderIndex < AuditLogItemBuilders.size() && AuditLogItemBuilders[builderIndex] != nullptr + ? AuditLogItemBuilders[builderIndex] : AuditLogItemBuilders[DefaultAuditLogItemBuilder]; + const auto msg = ev->Get(); + const auto auditLogItem = builder(msg->Time, msg->Parts); + WriteLog(auditLogItem, logBackends.second); } } @@ -190,7 +196,7 @@ class TAuditLogActor final : public TActor { std::atomic AUDIT_LOG_ENABLED = false; -void SendAuditLog(const NActors::TActorSystem* sys, TVector>&& parts) +void SendAuditLog(const NActors::TActorSystem* sys, TAuditLogParts&& parts) { auto request = MakeHolder(Now(), std::move(parts)); sys->Send(MakeAuditServiceID(), request.Release()); diff --git a/ydb/core/audit/audit_log_item_builder.h b/ydb/core/audit/audit_log_item_builder.h new file mode 100644 index 000000000000..609d80afb946 --- /dev/null +++ b/ydb/core/audit/audit_log_item_builder.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + + +namespace NKikimr::NAudit { + +using TAuditLogItemBuilder = TString(*)(TInstant, const TAuditLogParts&); + +// Registration of a function for converting audit events to a string in a specified format +void RegisterAuditLogItemBuilder(NKikimrConfig::TAuditConfig::EFormat format, TAuditLogItemBuilder builder); + +} diff --git a/ydb/core/audit/ya.make b/ydb/core/audit/ya.make index 3c2272d2d866..127eacc2a6d9 100644 --- a/ydb/core/audit/ya.make +++ b/ydb/core/audit/ya.make @@ -1,6 +1,7 @@ LIBRARY() SRCS( + audit_log_item_builder.h audit_log.h audit_log_service.h audit_log_impl.cpp diff --git a/ydb/core/protos/config.proto b/ydb/core/protos/config.proto index 968db47fb066..315749c25984 100644 --- a/ydb/core/protos/config.proto +++ b/ydb/core/protos/config.proto @@ -1493,10 +1493,13 @@ message TMeteringConfig { }; message TAuditConfig { + // For each new format, we need to register the audit event conversion function + // See ydb/core/audit/audit_log_impl.cpp for details enum EFormat { JSON = 1; // Outputs audit log in format: "