From 65788a80ecaa0157f852fac860d88cd0524b45be Mon Sep 17 00:00:00 2001
From: Dmitry Ivanov <ivadmi5@gmail.com>
Date: Fri, 24 Nov 2023 14:11:35 +0300
Subject: [PATCH] feat(audit): add more fields to audit events

---
 src/audit.rs      | 37 +++++++++++++++++++++++++++++--------
 src/storage.rs    | 21 +++++++++++++++++++++
 src/traft/node.rs | 12 ++++++++++--
 3 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/src/audit.rs b/src/audit.rs
index 5d9019fb9f..92b6277d41 100644
--- a/src/audit.rs
+++ b/src/audit.rs
@@ -280,9 +280,29 @@ pub fn root() -> Option<&'static slog::Logger> {
     }
 }
 
+// A helper macro which rewrites audit field syntax to the one used by slog.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! audit_kv(
+    // Format using Display. Example: `key: %value`.
+    ($key:ident : %$value:expr, $($rest:tt)*) => {
+        (slog::slog_kv!(stringify!($key) => %$value), $crate::audit_kv!($($rest)*))
+    };
+    // Format using Debug. Example: `key: ?value`.
+    ($key:ident : ?$value:expr, $($rest:tt)*) => {
+        (slog::slog_kv!(stringify!($key) => ?$value), $crate::audit_kv!($($rest)*))
+    };
+    // Substitute as is. Example: `key: value`.
+    ($key:ident : $value:expr, $($rest:tt)*) => {
+        (slog::slog_kv!(stringify!($key) => $value), $crate::audit_kv!($($rest)*))
+    };
+    () => { () };
+);
+
 /// This is the main API for adding new entries to the audit log.
 /// The required fields are `message`, `title` and `severity`,
-/// the rest is up to the caller.
+/// the rest is up to the caller. Auxiliary values may be prefixed
+/// with `%` or `?` to format them using `Display` or `Debug`.
 ///
 /// Example:
 /// ```
@@ -293,13 +313,13 @@ pub fn root() -> Option<&'static slog::Logger> {
 ///     severity: Low,
 /// );
 /// ```
-#[macro_export]
+#[macro_export(local_inner_macros)]
 macro_rules! audit(
     (
         message: $message:expr,
         title: $title:expr,
         severity: $severity:ident,
-        $($key:ident: $value:expr),* $(,)?
+        $($aux_fields:tt)*
     ) => {
         if let Some(root) = $crate::audit::root() {
             slog::slog_log!(
@@ -307,11 +327,12 @@ macro_rules! audit(
                 root, slog::Level::Info, "",
                 // The message itself.
                 $message;
-                // Mandatory fields.
-                "title" => $title,
-                "severity" => $crate::audit::Severity::$severity.as_str(),
-                // Arbitrary fields.
-                $(stringify!($key) => $value,)*
+                // Additional fields.
+                audit_kv!(
+                    title: $title,
+                    severity: $crate::audit::Severity::$severity.as_str(),
+                    $($aux_fields)*
+                )
             );
         }
     };
diff --git a/src/storage.rs b/src/storage.rs
index 1e9c57e248..26c738937a 100644
--- a/src/storage.rs
+++ b/src/storage.rs
@@ -2669,6 +2669,7 @@ pub mod acl {
             title: "create_user",
             severity: High,
             auth_type: user_def.auth.method.as_str(),
+            user: user,
         );
 
         Ok(())
@@ -2689,6 +2690,7 @@ pub mod acl {
             title: "change_password",
             severity: High,
             auth_type: auth.method.as_str(),
+            user: user,
         );
 
         Ok(())
@@ -2706,6 +2708,7 @@ pub mod acl {
             message: "dropped user `{user}`",
             title: "drop_user",
             severity: Medium,
+            user: user,
         );
 
         Ok(())
@@ -2720,6 +2723,7 @@ pub mod acl {
             message: "created role `{role}`",
             title: "create_role",
             severity: High,
+            role: role,
         );
 
         Ok(())
@@ -2742,6 +2746,7 @@ pub mod acl {
                 message: "dropped role `{role}`",
                 title: "drop_role",
                 severity: Medium,
+                role: role,
             );
         }
 
@@ -2765,6 +2770,9 @@ pub mod acl {
                     message: "granted role `{object}` to {grantee_type} `{grantee}`",
                     title: "grant_role",
                     severity: High,
+                    role: object,
+                    grantee: &grantee,
+                    grantee_type: grantee_type,
                 );
             }
             _ => {
@@ -2773,6 +2781,11 @@ pub mod acl {
                               to {grantee_type} `{grantee}`",
                     title: "grant_privilege",
                     severity: High,
+                    privilege: privilege,
+                    object: object,
+                    object_type: object_type,
+                    grantee: &grantee,
+                    grantee_type: grantee_type,
                 );
             }
         }
@@ -2803,6 +2816,9 @@ pub mod acl {
                     message: "revoke role `{object}` from {grantee_type} `{grantee}`",
                     title: "revoke_role",
                     severity: High,
+                    role: object,
+                    grantee: &grantee,
+                    grantee_type: grantee_type,
                 );
             }
             _ => {
@@ -2811,6 +2827,11 @@ pub mod acl {
                               from {grantee_type} `{grantee}`",
                     title: "revoke_privilege",
                     severity: High,
+                    privilege: privilege,
+                    object: object,
+                    object_type: object_type,
+                    grantee: &grantee,
+                    grantee_type: grantee_type,
                 );
             }
         }
diff --git a/src/traft/node.rs b/src/traft/node.rs
index dff31a071b..502a4b48ed 100644
--- a/src/traft/node.rs
+++ b/src/traft/node.rs
@@ -680,9 +680,11 @@ impl NodeImpl {
                         if prev.as_ref().map(|x| x.raft_id) != Some(new.raft_id) {
                             let instance_id = &new.instance_id;
                             crate::audit!(
-                                message: "added a new instance `{instance_id}` to the cluster",
-                                title: "create_database",
+                                message: "a new instance `{instance_id}` joined the cluster",
+                                title: "join_instance",
                                 severity: Low,
+                                instance_id: %instance_id,
+                                raft_id: %new.raft_id,
                             );
                         }
 
@@ -693,6 +695,8 @@ impl NodeImpl {
                                 message: "current grade of instance `{instance_id}` changed to {grade}",
                                 title: "change_current_grade",
                                 severity: Medium,
+                                instance_id: %instance_id,
+                                new_grade: %grade,
                             );
                         }
 
@@ -703,6 +707,8 @@ impl NodeImpl {
                                 message: "target grade of instance `{instance_id}` changed to {grade}",
                                 title: "change_target_grade",
                                 severity: Low,
+                                instance_id: %instance_id,
+                                raft_id: %new.raft_id,
                             );
                         }
 
@@ -790,6 +796,7 @@ impl NodeImpl {
                             message: "created table `{name}`",
                             title: "create_table",
                             severity: Medium,
+                            name: &name,
                         );
                     }
 
@@ -803,6 +810,7 @@ impl NodeImpl {
                             message: "dropped table `{name}`",
                             title: "drop_table",
                             severity: Medium,
+                            name: &name,
                         );
                     }
 
-- 
GitLab