Skip to content

Commit

Permalink
Register a custom audit log item builder (#12268)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewstalin authored Dec 12, 2024
1 parent 0c63856 commit 95f1072
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 33 deletions.
4 changes: 3 additions & 1 deletion ydb/core/audit/audit_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ namespace NActors {

namespace NKikimr::NAudit {

using TAuditLogParts = TVector<std::pair<TString, TString>>;

extern std::atomic<bool> AUDIT_LOG_ENABLED;

void SendAuditLog(const NActors::TActorSystem* sys, TVector<std::pair<TString, TString>>&& parts);
void SendAuditLog(const NActors::TActorSystem* sys, TAuditLogParts&& parts);

} // namespace NKikimr::NAudit
70 changes: 38 additions & 32 deletions ydb/core/audit/audit_log_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
#include <library/cpp/logger/record.h>
#include <library/cpp/logger/backend.h>

#include <ydb/core/base/events.h>
#include <ydb/library/actors/core/log.h>
#include <ydb/library/actors/core/actor.h>
#include <ydb/library/actors/core/events.h>
#include <ydb/library/actors/core/hfunc.h>
#include <ydb/library/services/services.pb.h>

#include <ydb/core/base/events.h>

#include "audit_log_item_builder.h"
#include "audit_log_service.h"
#include "audit_log.h"

Expand Down Expand Up @@ -55,9 +55,9 @@ struct TEvAuditLog {

struct TEvWriteAuditLog : public NActors::TEventLocal<TEvWriteAuditLog, EvWriteAuditLog> {
TInstant Time;
TVector<std::pair<TString, TString>> Parts;
TAuditLogParts Parts;

TEvWriteAuditLog(TInstant time, TVector<std::pair<TString, TString>>&& parts)
TEvWriteAuditLog(TInstant time, TAuditLogParts&& parts)
: Time(time)
, Parts(std::move(parts))
{}
Expand All @@ -78,32 +78,30 @@ void WriteLog(const TString& log, const TVector<THolder<TLogBackend>>& 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);
ss << Endl;
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();
Expand All @@ -112,19 +110,35 @@ 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;
}
ss << Endl;
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<TAuditLogItemBuilder> AuditLogItemBuilders = { nullptr, GetJsonLog, GetTxtLog, GetJsonLogCompatibleLog, nullptr };

// numbering enumeration starts from one
static constexpr size_t DefaultAuditLogItemBuilder = static_cast<size_t>(NKikimrConfig::TAuditConfig::JSON);

void RegisterAuditLogItemBuilder(NKikimrConfig::TAuditConfig::EFormat format, TAuditLogItemBuilder builder) {
size_t index = static_cast<size_t>(format);
if (index < AuditLogItemBuilders.size()) {
AuditLogItemBuilders[index] = builder;
}
}

class TAuditLogActor final : public TActor<TAuditLogActor> {
private:
const TAuditLogBackends LogBackends;
Expand Down Expand Up @@ -160,20 +174,12 @@ class TAuditLogActor final : public TActor<TAuditLogActor> {
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<size_t>(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);
}
}

Expand All @@ -190,7 +196,7 @@ class TAuditLogActor final : public TActor<TAuditLogActor> {

std::atomic<bool> AUDIT_LOG_ENABLED = false;

void SendAuditLog(const NActors::TActorSystem* sys, TVector<std::pair<TString, TString>>&& parts)
void SendAuditLog(const NActors::TActorSystem* sys, TAuditLogParts&& parts)
{
auto request = MakeHolder<TEvAuditLog::TEvWriteAuditLog>(Now(), std::move(parts));
sys->Send(MakeAuditServiceID(), request.Release());
Expand Down
14 changes: 14 additions & 0 deletions ydb/core/audit/audit_log_item_builder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <ydb/core/audit/audit_log.h>
#include <ydb/core/protos/config.pb.h>


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);

}
1 change: 1 addition & 0 deletions ydb/core/audit/ya.make
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
LIBRARY()

SRCS(
audit_log_item_builder.h
audit_log.h
audit_log_service.h
audit_log_impl.cpp
Expand Down
3 changes: 3 additions & 0 deletions ydb/core/protos/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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: "<time>: {"k1": "v1", "k2": "v2", ...}" where <time> is ISO 8601 format time string, k1, k2, ..., kn - fields of audit log message and v1, v2, ..., vn are their values
TXT = 2; // Outputs audit log in format: "<time>: k1=v1, k2=v2, ..." where <time> is ISO 8601 format time string, k1, k2, ..., kn - fields of audit log message and v1, v2, ..., vn are their values
JSON_LOG_COMPATIBLE = 3; // Outputs audit log in format: "{"@timestamp": "<ISO 8601 time>", "@log_type": "audit", "k1": "v1", "k2": "v2", ...}" where @timestamp is ISO 8601 format time string, k1, k2, ..., kn - fields of audit log message and v1, v2, ..., vn are their values // Suitable for output both debug log and audit log to the same destination (stderr)
FORMAT_4 = 4; // Reserved
}

message TStderrBackend {
Expand Down

0 comments on commit 95f1072

Please sign in to comment.