This is an automated email from the ASF dual-hosted git repository.

yongzao pushed a commit to branch fix-audit-logger
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/fix-audit-logger by this push:
     new ca82a9af9d9 stash 4 collaborate
ca82a9af9d9 is described below

commit ca82a9af9d9f910c776b0bbcdbde624a4197e230
Author: Yongzao <[email protected]>
AuthorDate: Wed Sep 24 16:40:08 2025 +0800

    stash 4 collaborate
---
 .../iotdb/confignode/audit/CNAuditLogger.java      |  18 +-
 .../org/apache/iotdb/db/audit/DNAuditLogger.java   |  34 +-
 .../db/queryengine/common/MPPQueryContext.java     |  21 +-
 .../relational/security/ITableAuthCheckerImpl.java |  54 +-
 .../security/TreeAccessCheckContext.java           |  22 +-
 .../security/TreeAccessCheckVisitor.java           | 723 +++++++++++++++------
 .../iotdb/db/service/DataNodeShutdownHook.java     |   2 +-
 .../iotdb/commons/audit/AbstractAuditLogger.java   |  53 +-
 .../apache/iotdb/commons/audit/AuditEventType.java |   1 +
 .../apache/iotdb/commons/audit/AuditLogFields.java |  76 ++-
 .../apache/iotdb/commons/audit/IAuditEntity.java   |   8 +-
 .../org/apache/iotdb/commons/audit/UserEntity.java |  21 +-
 12 files changed, 741 insertions(+), 292 deletions(-)

diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/audit/CNAuditLogger.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/audit/CNAuditLogger.java
index 7c65372bb1b..9b14d7b8423 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/audit/CNAuditLogger.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/audit/CNAuditLogger.java
@@ -24,7 +24,7 @@ import org.apache.iotdb.common.rpc.thrift.TConsensusGroupType;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
 import org.apache.iotdb.commons.audit.AbstractAuditLogger;
-import org.apache.iotdb.commons.audit.AuditLogFields;
+import org.apache.iotdb.commons.audit.IAuditEntity;
 import 
org.apache.iotdb.confignode.client.async.AsyncDataNodeHeartbeatClientPool;
 import 
org.apache.iotdb.confignode.client.async.handlers.audit.DataNodeWriteAuditLogHandler;
 import org.apache.iotdb.confignode.conf.ConfigNodeConfig;
@@ -37,6 +37,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.List;
+import java.util.function.Supplier;
 
 public class CNAuditLogger extends AbstractAuditLogger {
   private static final Logger logger = 
LoggerFactory.getLogger(CNAuditLogger.class);
@@ -48,11 +49,12 @@ public class CNAuditLogger extends AbstractAuditLogger {
     this.configManager = configManager;
   }
 
-  public void log(AuditLogFields auditLogFields, String log) {
+  @Override
+  public void log(IAuditEntity auditLogFields, Supplier<String> log) {
     if (!IS_AUDIT_LOG_ENABLED) {
       return;
     }
-    if (!checkBeforeLog(auditLogFields)) {
+    if (noNeedInsertAuditLog(auditLogFields)) {
       return;
     }
     // find database "__audit"'s data_region
@@ -72,13 +74,13 @@ public class CNAuditLogger extends AbstractAuditLogger {
             auditLogFields.getUsername(),
             auditLogFields.getUserId(),
             auditLogFields.getCliHostname(),
-            auditLogFields.getAuditType().toString(),
-            auditLogFields.getOperationType().toString(),
-            auditLogFields.getPrivilegeType().toString(),
-            auditLogFields.isResult(),
+            auditLogFields.getAuditEventType().toString(),
+            auditLogFields.getAuditLogOperation().toString(),
+            auditLogFields.getPrivilegeTypeString(),
+            auditLogFields.getResult(),
             auditLogFields.getDatabase(),
             auditLogFields.getSqlString(),
-            log,
+            log.get(),
             CONF.getConfigNodeId());
     // refer the implementation of HeartbeatService.pingRegisteredDataNode(). 
By appending a new
     // writeAudtiLog() interface in AsyncDataNodeHeartbeatClientPool, the main 
thread is not
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java
index 51d1a7dbc51..ef69a5c8403 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java
@@ -24,6 +24,7 @@ import org.apache.iotdb.commons.audit.AbstractAuditLogger;
 import org.apache.iotdb.commons.audit.AuditEventType;
 import org.apache.iotdb.commons.audit.AuditLogFields;
 import org.apache.iotdb.commons.audit.AuditLogOperation;
+import org.apache.iotdb.commons.audit.IAuditEntity;
 import org.apache.iotdb.commons.audit.PrivilegeLevel;
 import org.apache.iotdb.commons.audit.UserEntity;
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
@@ -75,6 +76,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
 
 import static 
org.apache.iotdb.db.pipe.receiver.protocol.legacy.loader.ILoader.SCHEMA_FETCHER;
 
@@ -135,13 +137,18 @@ public class DNAuditLogger extends AbstractAuditLogger {
 
   @NotNull
   private static InsertRowStatement generateInsertStatement(
-      AuditLogFields auditLogFields, String log, PartialPath log_device) {
+      IAuditEntity auditLogFields, String log, PartialPath log_device) {
     String username = auditLogFields.getUsername();
     String address = auditLogFields.getCliHostname();
-    AuditEventType type = auditLogFields.getAuditType();
-    AuditLogOperation operation = auditLogFields.getOperationType();
-    PrivilegeType privilegeType = auditLogFields.getPrivilegeType();
-    PrivilegeLevel privilegeLevel = judgePrivilegeLevel(privilegeType);
+    AuditEventType type = auditLogFields.getAuditEventType();
+    AuditLogOperation operation = auditLogFields.getAuditLogOperation();
+    PrivilegeLevel privilegeLevel = null;
+    for (PrivilegeType privilegeType : auditLogFields.getPrivilegeTypes()) {
+      privilegeLevel = judgePrivilegeLevel(privilegeType);
+      if (privilegeLevel.equals(PrivilegeLevel.GLOBAL)) {
+        break;
+      }
+    }
     String dataNodeId = String.valueOf(config.getDataNodeId());
     InsertRowStatement insertStatement = new InsertRowStatement();
     insertStatement.setDevicePath(log_device);
@@ -167,13 +174,11 @@ public class DNAuditLogger extends AbstractAuditLogger {
           new Binary(type == null ? "null" : type.toString(), 
TSFileConfig.STRING_CHARSET),
           new Binary(
               operation == null ? "null" : operation.toString(), 
TSFileConfig.STRING_CHARSET),
-          new Binary(
-              privilegeType == null ? "null" : privilegeType.toString(),
-              TSFileConfig.STRING_CHARSET),
+          new Binary(auditLogFields.getPrivilegeTypeString(), 
TSFileConfig.STRING_CHARSET),
           new Binary(
               privilegeLevel == null ? "null" : privilegeLevel.toString(),
               TSFileConfig.STRING_CHARSET),
-          auditLogFields.isResult(),
+          auditLogFields.getResult(),
           new Binary(
               auditLogFields.getDatabase() == null ? "null" : 
auditLogFields.getDatabase(),
               TSFileConfig.STRING_CHARSET),
@@ -323,12 +328,13 @@ public class DNAuditLogger extends AbstractAuditLogger {
     }
   }
 
-  public void log(AuditLogFields auditLogFields, String log) {
+  @Override
+  public void log(IAuditEntity auditLogFields, Supplier<String> log) {
     if (!IS_AUDIT_LOG_ENABLED) {
       return;
     }
     createViewIfNecessary();
-    if (!checkBeforeLog(auditLogFields)) {
+    if (noNeedInsertAuditLog(auditLogFields)) {
       return;
     }
     long userId = auditLogFields.getUserId();
@@ -342,7 +348,7 @@ public class DNAuditLogger extends AbstractAuditLogger {
       statement =
           generateInsertStatement(
               auditLogFields,
-              log,
+              log.get(),
               DEVICE_PATH_CACHE.getPartialPath(String.format(AUDIT_LOG_DEVICE, 
dataNodeId, user)));
     } catch (IllegalPathException e) {
       logger.error("Failed to log audit events because ", e);
@@ -366,7 +372,7 @@ public class DNAuditLogger extends AbstractAuditLogger {
         logger.error("Audit log insertion retry sleep was interrupted", e);
       }
     }
-    AuditEventType type = auditLogFields.getAuditType();
+    AuditEventType type = auditLogFields.getAuditEventType();
     if (isLoginEvent(type)) {
       // TODO: @wenyanshi-123 Reactivate the following codes in the future
       //      try {
@@ -390,7 +396,7 @@ public class DNAuditLogger extends AbstractAuditLogger {
   public void logFromCN(AuditLogFields auditLogFields, String log, int nodeId)
       throws IllegalPathException {
     createViewIfNecessary();
-    if (!checkBeforeLog(auditLogFields)) {
+    if (noNeedInsertAuditLog(auditLogFields)) {
       return;
     }
     InsertRowStatement statement =
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java
index 0c0311bc105..8ab0347b626 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java
@@ -38,7 +38,9 @@ import 
org.apache.iotdb.db.queryengine.statistics.QueryPlanStatistics;
 import org.apache.tsfile.read.filter.basic.Filter;
 
 import java.time.ZoneId;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -439,7 +441,7 @@ public class MPPQueryContext implements IAuditEntity {
 
   private AuditLogOperation auditLogOperation;
 
-  private PrivilegeType privilegeType;
+  private List<PrivilegeType> privilegeTypeList;
 
   private boolean result;
 
@@ -481,13 +483,24 @@ public class MPPQueryContext implements IAuditEntity {
   }
 
   @Override
-  public PrivilegeType getPrivilegeType() {
-    return privilegeType;
+  public List<PrivilegeType> getPrivilegeTypes() {
+    return privilegeTypeList;
+  }
+
+  @Override
+  public String getPrivilegeTypeString() {
+    return privilegeTypeList.toString();
   }
 
   @Override
   public IAuditEntity setPrivilegeType(PrivilegeType privilegeType) {
-    this.privilegeType = privilegeType;
+    this.privilegeTypeList = Collections.singletonList(privilegeType);
+    return this;
+  }
+
+  @Override
+  public IAuditEntity setPrivilegeTypes(List<PrivilegeType> privilegeTypes) {
+    this.privilegeTypeList = privilegeTypes;
     return this;
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
index b2c86f601a1..56ccdcb1744 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
@@ -20,7 +20,6 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.security;
 
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.audit.AuditEventType;
-import org.apache.iotdb.commons.audit.AuditLogFields;
 import org.apache.iotdb.commons.audit.AuditLogOperation;
 import org.apache.iotdb.commons.audit.IAuditEntity;
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
@@ -188,22 +187,19 @@ public class ITableAuthCheckerImpl implements 
ITableAuthChecker {
               .setResult(false),
           TABLE_MODEL_AUDIT_DATABASE);
       AUDIT_LOGGER.log(
-          new AuditLogFields(
-              userName,
-              auditEntity.getUserId(),
-              auditEntity.getCliHostname(),
-              AuditEventType.OBJECT_AUTHENTICATION,
-              AuditLogOperation.QUERY,
-              PrivilegeType.SELECT,
-              false,
-              TABLE_MODEL_AUDIT_DATABASE,
-              auditEntity.getSqlString()),
-          String.format(
-              OBJECT_AUTHENTICATION_AUDIT_STR,
-              userName,
-              auditEntity.getUserId(),
-              TABLE_MODEL_AUDIT_DATABASE,
-              false));
+          auditEntity
+              .setAuditEventType(AuditEventType.OBJECT_AUTHENTICATION)
+              .setAuditLogOperation(AuditLogOperation.QUERY)
+              .setPrivilegeType(PrivilegeType.SELECT)
+              .setResult(false)
+              .setDatabase(TABLE_MODEL_AUDIT_DATABASE),
+          () ->
+              String.format(
+                  OBJECT_AUTHENTICATION_AUDIT_STR,
+                  userName,
+                  auditEntity.getUserId(),
+                  TABLE_MODEL_AUDIT_DATABASE,
+                  false));
       throw new AccessDeniedException(
           String.format(
               "The database '%s' can only be queried by AUDIT admin.", 
TABLE_MODEL_AUDIT_DATABASE));
@@ -483,21 +479,13 @@ public class ITableAuthCheckerImpl implements 
ITableAuthChecker {
 
   private static void recordAuditLog(IAuditEntity auditEntity, String 
auditObject) {
     AUDIT_LOGGER.log(
-        new AuditLogFields(
-            auditEntity.getUsername(),
-            auditEntity.getUserId(),
-            auditEntity.getCliHostname(),
-            AuditEventType.OBJECT_AUTHENTICATION,
-            auditEntity.getAuditLogOperation(),
-            auditEntity.getPrivilegeType(),
-            auditEntity.getResult(),
-            auditEntity.getDatabase(),
-            auditEntity.getSqlString()),
-        String.format(
-            OBJECT_AUTHENTICATION_AUDIT_STR,
-            auditEntity.getUsername(),
-            auditEntity.getUserId(),
-            auditObject,
-            true));
+        auditEntity.setAuditEventType(AuditEventType.OBJECT_AUTHENTICATION),
+        () ->
+            String.format(
+                OBJECT_AUTHENTICATION_AUDIT_STR,
+                auditEntity.getUsername(),
+                auditEntity.getUserId(),
+                auditObject,
+                true));
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckContext.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckContext.java
index 30ff465d0a2..446bb73c70d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckContext.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckContext.java
@@ -25,6 +25,9 @@ import org.apache.iotdb.commons.audit.IAuditEntity;
 import org.apache.iotdb.commons.audit.UserEntity;
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 
+import java.util.Collections;
+import java.util.List;
+
 public class TreeAccessCheckContext implements IAuditEntity {
 
   private final UserEntity userEntity;
@@ -50,7 +53,7 @@ public class TreeAccessCheckContext implements IAuditEntity {
 
   private AuditEventType auditEventType;
   private AuditLogOperation auditLogOperation;
-  private PrivilegeType privilegeType;
+  private List<PrivilegeType> privilegeTypeList;
   private boolean result;
   private String database;
   private String sqlString;
@@ -78,13 +81,24 @@ public class TreeAccessCheckContext implements IAuditEntity 
{
   }
 
   @Override
-  public PrivilegeType getPrivilegeType() {
-    return privilegeType;
+  public List<PrivilegeType> getPrivilegeTypes() {
+    return privilegeTypeList;
+  }
+
+  @Override
+  public String getPrivilegeTypeString() {
+    return privilegeTypeList.toString();
   }
 
   @Override
   public IAuditEntity setPrivilegeType(PrivilegeType privilegeType) {
-    this.privilegeType = privilegeType;
+    this.privilegeTypeList = Collections.singletonList(privilegeType);
+    return this;
+  }
+
+  @Override
+  public IAuditEntity setPrivilegeTypes(List<PrivilegeType> privilegeTypes) {
+    this.privilegeTypeList = privilegeTypes;
     return this;
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
index 4dbd54b457a..4d7b430bf64 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
@@ -20,11 +20,15 @@
 package org.apache.iotdb.db.queryengine.plan.relational.security;
 
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.audit.AuditEventType;
+import org.apache.iotdb.commons.audit.AuditLogOperation;
+import org.apache.iotdb.commons.audit.IAuditEntity;
 import org.apache.iotdb.commons.auth.AuthException;
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTreeUtils;
+import org.apache.iotdb.db.audit.DNAuditLogger;
 import org.apache.iotdb.db.auth.AuthorityChecker;
 import org.apache.iotdb.db.queryengine.plan.statement.AuthorType;
 import 
org.apache.iotdb.db.queryengine.plan.statement.AuthorityInformationStatement;
@@ -153,9 +157,11 @@ import com.google.common.collect.ImmutableList;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import static 
org.apache.iotdb.commons.schema.table.Audit.TREE_MODEL_AUDIT_DATABASE;
@@ -166,6 +172,11 @@ import static 
org.apache.iotdb.db.queryengine.plan.relational.security.AccessCon
 
 public class TreeAccessCheckVisitor extends StatementVisitor<TSStatus, 
TreeAccessCheckContext> {
 
+  private static final DNAuditLogger AUDIT_LOGGER = 
DNAuditLogger.getInstance();
+
+  private static final String OBJECT_AUTHENTICATION_AUDIT_STR =
+      "User %s (ID=%d) requests authority on object %s with result %s";
+
   @Override
   public TSStatus visitNode(StatementNode node, TreeAccessCheckContext 
context) {
     throw new IllegalStateException("Each operation should have permission 
check.");
@@ -174,15 +185,27 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitAuthorityInformation(
       AuthorityInformationStatement statement, TreeAccessCheckContext context) 
{
+    context
+        .setAuditLogOperation(AuditLogOperation.QUERY)
+        .setPrivilegeType(PrivilegeType.READ_SCHEMA);
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return SUCCEED;
     }
     try {
       statement.setAuthorityScope(
           AuthorityChecker.getAuthorizedPathTree(context.getUsername(), 
PrivilegeType.READ_SCHEMA));
     } catch (AuthException e) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(false),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(e.getCode().getStatusCode());
     }
+    recordObjectAuthenticationAuditLog(
+        context.setResult(true),
+        () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
     return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
   }
 
@@ -191,49 +214,70 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitCreateSchemaTemplate(
       CreateSchemaTemplateStatement createTemplateStatement, 
TreeAccessCheckContext context) {
-    return checkSystemAuth(context.getUsername());
+    return checkSystemAuth(
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        () -> createTemplateStatement.getMeasurements().toString());
   }
 
   @Override
   public TSStatus visitSetSchemaTemplate(
       SetSchemaTemplateStatement setSchemaTemplateStatement, 
TreeAccessCheckContext context) {
+    context.setAuditLogOperation(AuditLogOperation.DDL);
     // root.__audit can never be set template
-    TSStatus status = 
checkWriteOnReadOnlyPath(setSchemaTemplateStatement.getPath());
+    TSStatus status =
+        checkWriteOnReadOnlyPath(
+            context.setPrivilegeType(PrivilegeType.WRITE_DATA),
+            setSchemaTemplateStatement.getPath());
     if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
       return status;
     }
-    return checkSystemAuth(context.getUsername());
+    return checkSystemAuth(context, () -> 
setSchemaTemplateStatement.getPath().toString());
   }
 
   @Override
   public TSStatus visitActivateTemplate(
       ActivateTemplateStatement statement, TreeAccessCheckContext context) {
     return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        statement.getPaths(),
+        PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
   public TSStatus visitBatchActivateTemplate(
       BatchActivateTemplateStatement statement, TreeAccessCheckContext 
context) {
     return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        statement.getPaths(),
+        PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
   public TSStatus visitInternalBatchActivateTemplate(
       InternalBatchActivateTemplateStatement statement, TreeAccessCheckContext 
context) {
     return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        statement.getPaths(),
+        PrivilegeType.WRITE_SCHEMA);
   }
 
   private TSStatus checkTemplateShowRelated(
       ShowSchemaTemplateStatement statement, TreeAccessCheckContext context) {
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       statement.setCanSeeAll(true);
+      recordObjectAuthenticationAuditLog(
+          context
+              .setAuditLogOperation(AuditLogOperation.QUERY)
+              .setPrivilegeType(PrivilegeType.SYSTEM)
+              .setResult(true),
+          () -> statement.getPaths().toString());
       return SUCCEED;
     }
     // own SYSTEM can see all, otherwise can only see PATHS that user has 
READ_SCHEMA auth
-    if (!checkHasGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM)) {
+    if (!checkHasGlobalAuth(
+        context.setAuditLogOperation(AuditLogOperation.QUERY),
+        PrivilegeType.SYSTEM,
+        () -> statement.getPaths().toString())) {
       statement.setCanSeeAll(false);
       return visitAuthorityInformation(statement, context);
     } else {
@@ -272,34 +316,50 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   public TSStatus visitDeactivateTemplate(
       DeactivateTemplateStatement statement, TreeAccessCheckContext context) {
     return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        statement.getPaths(),
+        PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
   public TSStatus visitUnsetSchemaTemplate(
       UnsetSchemaTemplateStatement unsetSchemaTemplateStatement, 
TreeAccessCheckContext context) {
-    return checkSystemAuth(context.getUsername());
+    return checkSystemAuth(
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        () -> unsetSchemaTemplateStatement.getPaths().toString());
   }
 
   @Override
   public TSStatus visitDropSchemaTemplate(
       DropSchemaTemplateStatement dropSchemaTemplateStatement, 
TreeAccessCheckContext context) {
-    return checkSystemAuth(context.getUsername());
+    return checkSystemAuth(
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        () -> dropSchemaTemplateStatement.getPaths().toString());
   }
 
   @Override
   public TSStatus visitAlterSchemaTemplate(
       AlterSchemaTemplateStatement alterSchemaTemplateStatement, 
TreeAccessCheckContext context) {
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          context
+              .setAuditLogOperation(AuditLogOperation.DDL)
+              .setPrivilegeType(PrivilegeType.EXTEND_TEMPLATE)
+              .setResult(true),
+          () -> alterSchemaTemplateStatement.getPaths().toString());
       return SUCCEED;
     }
-    return checkGlobalAuth(context.getUsername(), 
PrivilegeType.EXTEND_TEMPLATE);
+    return checkGlobalAuth(
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        PrivilegeType.EXTEND_TEMPLATE,
+        () -> alterSchemaTemplateStatement.getPaths().toString());
   }
 
   // ============================= timeseries view related ===============
   @Override
   public TSStatus visitCreateLogicalView(
       CreateLogicalViewStatement statement, TreeAccessCheckContext context) {
+    context.setAuditLogOperation(AuditLogOperation.DDL);
     final List<PartialPath> paths =
         Objects.nonNull(statement.getTargetPathList())
             ? statement.getTargetPathList()
@@ -312,6 +372,8 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       // audit db is read-only
       if (includeByAuditTreeDB(path)
           && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+        recordObjectAuthenticationAuditLog(
+            context.setPrivilegeType(PrivilegeType.AUDIT).setResult(false), 
path::toString);
         return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
             .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
       }
@@ -322,9 +384,15 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       if (statement.getQueryStatement() != null) {
         statement.getQueryStatement().setCanSeeAuditDB(true);
       }
+      recordObjectAuthenticationAuditLog(
+          context
+              .setPrivilegeTypes(
+                  Arrays.asList(PrivilegeType.WRITE_SCHEMA, 
PrivilegeType.READ_SCHEMA))
+              .setResult(true),
+          paths::toString);
       return SUCCEED;
     }
-    if (!checkHasGlobalAuth(context.getUsername(), PrivilegeType.AUDIT)) {
+    if (!checkHasGlobalAuth(context, PrivilegeType.AUDIT, paths::toString)) {
       statement.setCanSeeAuditDB(false);
       if (statement.getQueryStatement() != null) {
         statement.getQueryStatement().setCanSeeAuditDB(false);
@@ -334,20 +402,16 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     TSStatus status = new 
TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
     List<PartialPath> sourcePathList = statement.getSourcePaths().fullPathList;
     if (sourcePathList != null) {
-      status =
-          checkTimeSeriesPermission(
-              context.getUsername(), sourcePathList, 
PrivilegeType.READ_SCHEMA);
+      status = checkTimeSeriesPermission(context, sourcePathList, 
PrivilegeType.READ_SCHEMA);
     }
     QueryStatement queryStatement = statement.getQueryStatement();
     if (queryStatement != null && status.getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
       sourcePathList = queryStatement.getPaths();
-      status =
-          checkTimeSeriesPermission(
-              context.getUsername(), sourcePathList, 
PrivilegeType.READ_SCHEMA);
+      status = checkTimeSeriesPermission(context, sourcePathList, 
PrivilegeType.READ_SCHEMA);
     }
 
     if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-      return checkTimeSeriesPermission(context.getUsername(), paths, 
PrivilegeType.WRITE_SCHEMA);
+      return checkTimeSeriesPermission(context, paths, 
PrivilegeType.WRITE_SCHEMA);
     }
     return status;
   }
@@ -356,7 +420,9 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   public TSStatus visitDeleteLogicalView(
       DeleteLogicalViewStatement statement, TreeAccessCheckContext context) {
     return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        statement.getPaths(),
+        PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
@@ -368,14 +434,22 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitAlterLogicalView(
       AlterLogicalViewStatement statement, TreeAccessCheckContext context) {
+    context.setAuditLogOperation(AuditLogOperation.DDL);
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       statement.setCanSeeAuditDB(true);
       if (statement.getQueryStatement() != null) {
         statement.getQueryStatement().setCanSeeAuditDB(true);
       }
+      recordObjectAuthenticationAuditLog(
+          context
+              .setPrivilegeTypes(
+                  Arrays.asList(PrivilegeType.READ_SCHEMA, 
PrivilegeType.WRITE_SCHEMA))
+              .setResult(true),
+          () -> statement.getSourcePaths().fullPathList.toString());
       return SUCCEED;
     }
-    if (!checkHasGlobalAuth(context.getUsername(), PrivilegeType.AUDIT)) {
+    if (!checkHasGlobalAuth(
+        context, PrivilegeType.AUDIT, (() -> 
statement.getSourcePaths().fullPathList.toString()))) {
       statement.setCanSeeAuditDB(false);
       if (statement.getQueryStatement() != null) {
         statement.getQueryStatement().setCanSeeAuditDB(false);
@@ -385,21 +459,17 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     TSStatus status = new 
TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
     List<PartialPath> sourcePathList = statement.getSourcePaths().fullPathList;
     if (sourcePathList != null) {
-      status =
-          checkTimeSeriesPermission(
-              context.getUsername(), sourcePathList, 
PrivilegeType.READ_SCHEMA);
+      status = checkTimeSeriesPermission(context, sourcePathList, 
PrivilegeType.READ_SCHEMA);
     }
     QueryStatement queryStatement = statement.getQueryStatement();
     if (queryStatement != null && status.getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
       sourcePathList = queryStatement.getPaths();
-      status =
-          checkTimeSeriesPermission(
-              context.getUsername(), sourcePathList, 
PrivilegeType.READ_SCHEMA);
+      status = checkTimeSeriesPermission(context, sourcePathList, 
PrivilegeType.READ_SCHEMA);
     }
 
     if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
       return checkTimeSeriesPermission(
-          context.getUsername(), statement.getTargetPathList(), 
PrivilegeType.WRITE_SCHEMA);
+          context, statement.getTargetPathList(), PrivilegeType.WRITE_SCHEMA);
     }
     return status;
   }
@@ -407,14 +477,18 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitRenameLogicalView(
       RenameLogicalViewStatement statement, TreeAccessCheckContext context) {
+    context.setAuditLogOperation(AuditLogOperation.DDL);
     // audit db is read-only
     if (includeByAuditTreeDB(statement.getNewName())
         && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+      recordObjectAuthenticationAuditLog(
+          
context.setPrivilegeType(PrivilegeType.WRITE_SCHEMA).setResult(false),
+          () -> statement.getOldName().toString());
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
     return checkTimeSeriesPermission(
-        context.getUsername(),
+        context,
         ImmutableList.of(statement.getOldName(), statement.getNewName()),
         PrivilegeType.WRITE_SCHEMA);
   }
@@ -426,16 +500,25 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     switch (authorType) {
       case CREATE_USER:
       case DROP_USER:
-        return checkGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_USER);
+        return checkGlobalAuth(
+            context.setAuditLogOperation(AuditLogOperation.DDL),
+            PrivilegeType.MANAGE_USER,
+            statement::getUserName);
       case UPDATE_USER:
         // users can change passwords of themselves
         if (statement.getUserName().equals(context.getUsername())) {
           return RpcUtils.SUCCESS_STATUS;
         }
-        return checkGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_USER);
+        return checkGlobalAuth(
+            context.setAuditLogOperation(AuditLogOperation.DDL),
+            PrivilegeType.MANAGE_USER,
+            statement::getUserName);
 
       case LIST_USER:
-        if (checkHasGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_USER)) {
+        if (checkHasGlobalAuth(
+            context.setAuditLogOperation(AuditLogOperation.QUERY),
+            PrivilegeType.MANAGE_USER,
+            null)) {
           return RpcUtils.SUCCESS_STATUS;
         }
         statement.setUserName(context.getUsername());
@@ -445,17 +528,26 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
         if (context.getUsername().equals(statement.getUserName())) {
           return RpcUtils.SUCCESS_STATUS;
         }
-        return checkGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_USER);
+        return checkGlobalAuth(
+            context.setAuditLogOperation(AuditLogOperation.QUERY),
+            PrivilegeType.MANAGE_USER,
+            statement::getUserName);
 
       case LIST_ROLE_PRIVILEGE:
         if (!AuthorityChecker.checkRole(context.getUsername(), 
statement.getRoleName())) {
-          return checkGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_ROLE);
+          return checkGlobalAuth(
+              context.setAuditLogOperation(AuditLogOperation.QUERY),
+              PrivilegeType.MANAGE_ROLE,
+              statement::getRoleName);
         } else {
           return SUCCEED;
         }
 
       case LIST_ROLE:
-        if (checkHasGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_ROLE)) {
+        if (checkHasGlobalAuth(
+            context.setAuditLogOperation(AuditLogOperation.QUERY),
+            PrivilegeType.MANAGE_ROLE,
+            null)) {
           return SUCCEED;
         }
         // list roles of other user is not allowed
@@ -470,20 +562,31 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       case DROP_ROLE:
       case GRANT_USER_ROLE:
       case REVOKE_USER_ROLE:
-        return checkGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_ROLE);
+        return checkGlobalAuth(
+            context.setAuditLogOperation(AuditLogOperation.DDL),
+            PrivilegeType.MANAGE_ROLE,
+            statement::getRoleName);
 
       case REVOKE_USER:
       case GRANT_USER:
       case GRANT_ROLE:
       case REVOKE_ROLE:
-        if (checkHasGlobalAuth(context.getUsername(), PrivilegeType.SECURITY)) 
{
+        context.setAuditLogOperation(AuditLogOperation.DDL);
+        Supplier<String> auditObject =
+            () ->
+                authorType == AuthorType.REVOKE_USER || authorType == 
AuthorType.GRANT_USER
+                    ? statement.getUserName()
+                    : statement.getRoleName();
+        if (checkHasGlobalAuth(
+            context.setAuditLogOperation(AuditLogOperation.DDL),
+            PrivilegeType.SECURITY,
+            auditObject)) {
           return RpcUtils.SUCCESS_STATUS;
         }
-
         for (String s : statement.getPrivilegeList()) {
           PrivilegeType privilegeType = PrivilegeType.valueOf(s.toUpperCase());
           if (privilegeType.isSystemPrivilege()) {
-            if (!checkHasGlobalAuth(context.getUsername(), privilegeType)) {
+            if (!checkHasGlobalAuth(context, privilegeType, auditObject)) {
               return AuthorityChecker.getTSStatus(
                   false,
                   "Has no permission to execute "
@@ -514,184 +617,214 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitCreateContinuousQuery(
       CreateContinuousQueryStatement statement, TreeAccessCheckContext 
context) {
-    return checkCQManagement(context.getUsername());
+    return checkCQManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), () -> 
statement.getPaths().toString());
   }
 
   @Override
   public TSStatus visitDropContinuousQuery(
       DropContinuousQueryStatement statement, TreeAccessCheckContext context) {
-    return checkCQManagement(context.getUsername());
+    return checkCQManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), () -> 
statement.getPaths().toString());
   }
 
   @Override
   public TSStatus visitShowContinuousQueries(
       ShowContinuousQueriesStatement statement, TreeAccessCheckContext 
context) {
-    return checkCQManagement(context.getUsername());
+    return checkCQManagement(
+        context.setAuditLogOperation(AuditLogOperation.QUERY),
+        () -> statement.getPaths().toString());
   }
 
-  private TSStatus checkCQManagement(String userName) {
-    if (AuthorityChecker.SUPER_USER.equals(userName)) {
+  private TSStatus checkCQManagement(IAuditEntity auditEntity, 
Supplier<String> auditObject) {
+    if (AuthorityChecker.SUPER_USER.equals(auditEntity.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          auditEntity.setPrivilegeType(PrivilegeType.USE_CQ).setResult(true), 
auditObject);
       return SUCCEED;
     }
-    return checkGlobalAuth(userName, PrivilegeType.USE_CQ);
+    return checkGlobalAuth(auditEntity, PrivilegeType.USE_CQ, auditObject);
   }
 
   // =================================== UDF related 
====================================
   @Override
   public TSStatus visitCreateFunction(
       CreateFunctionStatement statement, TreeAccessCheckContext context) {
-    return checkUDFManagement(context.getUsername());
+    return checkUDFManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getUdfName);
   }
 
   @Override
   public TSStatus visitDropFunction(
       DropFunctionStatement statement, TreeAccessCheckContext context) {
-    return checkUDFManagement(context.getUsername());
+    return checkUDFManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getUdfName);
   }
 
   @Override
   public TSStatus visitShowFunctions(
       ShowFunctionsStatement statement, TreeAccessCheckContext context) {
     // anyone can show functions
+    recordObjectAuthenticationAuditLog(
+        context.setAuditLogOperation(AuditLogOperation.QUERY).setResult(true), 
null);
     return SUCCEED;
   }
 
-  private TSStatus checkUDFManagement(String userName) {
-    return checkGlobalAuth(userName, PrivilegeType.USE_UDF);
+  private TSStatus checkUDFManagement(IAuditEntity auditEntity, 
Supplier<String> auditObject) {
+    return checkGlobalAuth(auditEntity, PrivilegeType.USE_UDF, auditObject);
   }
 
   // =================================== model related 
====================================
   @Override
   public TSStatus visitCreateModel(CreateModelStatement statement, 
TreeAccessCheckContext context) {
-    return checkModelManagement(context.getUsername());
+    return checkModelManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getModelId);
   }
 
   @Override
   public TSStatus visitDropModel(DropModelStatement statement, 
TreeAccessCheckContext context) {
-    return checkModelManagement(context.getUsername());
+    return checkModelManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getModelId);
   }
 
   @Override
   public TSStatus visitCreateTraining(
       CreateTrainingStatement createTrainingStatement, TreeAccessCheckContext 
context) {
-    return checkModelManagement(context.getUsername());
+    return checkModelManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        createTrainingStatement::getExistingModelId);
   }
 
   @Override
   public TSStatus visitUnloadModel(
       UnloadModelStatement unloadModelStatement, TreeAccessCheckContext 
context) {
-    return checkModelManagement(context.getUsername());
+    return checkModelManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
unloadModelStatement::getModelId);
   }
 
   @Override
   public TSStatus visitLoadModel(
       LoadModelStatement loadModelStatement, TreeAccessCheckContext context) {
-    return checkModelManagement(context.getUsername());
+    return checkModelManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
loadModelStatement::getModelId);
   }
 
   @Override
   public TSStatus visitShowAIDevices(
       ShowAIDevicesStatement showAIDevicesStatement, TreeAccessCheckContext 
context) {
-    return checkModelManagement(context.getUsername());
+    return 
checkModelManagement(context.setAuditLogOperation(AuditLogOperation.DDL), () -> 
"");
   }
 
   @Override
   public TSStatus visitShowLoadedModels(
       ShowLoadedModelsStatement showLoadedModelsStatement, 
TreeAccessCheckContext context) {
-    return SUCCEED;
+    return 
checkModelManagement(context.setAuditLogOperation(AuditLogOperation.DDL), () -> 
"");
   }
 
   @Override
   public TSStatus visitShowModels(ShowModelsStatement statement, 
TreeAccessCheckContext context) {
-    return SUCCEED;
+    return 
checkModelManagement(context.setAuditLogOperation(AuditLogOperation.DDL), () -> 
"");
   }
 
-  private TSStatus checkModelManagement(String userName) {
-    return checkGlobalAuth(userName, PrivilegeType.USE_MODEL);
+  private TSStatus checkModelManagement(IAuditEntity auditEntity, 
Supplier<String> auditObject) {
+    return checkGlobalAuth(auditEntity, PrivilegeType.USE_MODEL, auditObject);
   }
 
   // ================================ pipe plugin related 
==================================
   @Override
   public TSStatus visitCreatePipePlugin(
       CreatePipePluginStatement statement, TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), () -> 
statement.getPaths().toString());
   }
 
   @Override
   public TSStatus visitDropPipePlugin(
       DropPipePluginStatement statement, TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), () -> 
statement.getPaths().toString());
   }
 
   @Override
   public TSStatus visitShowPipePlugins(
       ShowPipePluginsStatement statement, TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), () -> 
statement.getPaths().toString());
   }
 
   // =============================== pipe related 
========================================
 
   @Override
   public TSStatus visitCreatePipe(CreatePipeStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getPipeName);
   }
 
   @Override
   public TSStatus visitShowPipes(ShowPipesStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getPipeName);
   }
 
   @Override
   public TSStatus visitDropPipe(DropPipeStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getPipeName);
   }
 
   @Override
   public TSStatus visitAlterPipe(AlterPipeStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getPipeName);
   }
 
   @Override
   public TSStatus visitStartPipe(StartPipeStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getPipeName);
   }
 
   @Override
   public TSStatus visitStopPipe(StopPipeStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getPipeName);
   }
 
-  private TSStatus checkPipeManagement(String userName) {
-    return checkGlobalAuth(userName, PrivilegeType.USE_PIPE);
+  private TSStatus checkPipeManagement(IAuditEntity auditEntity, 
Supplier<String> auditObject) {
+    return checkGlobalAuth(auditEntity, PrivilegeType.USE_PIPE, auditObject);
   }
 
   // =============================== subscription related 
========================================
 
   @Override
   public TSStatus visitCreateTopic(CreateTopicStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getTopicName);
   }
 
   @Override
   public TSStatus visitShowTopics(ShowTopicsStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getTopicName);
   }
 
   @Override
   public TSStatus visitDropTopic(DropTopicStatement statement, 
TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getTopicName);
   }
 
   @Override
   public TSStatus visitShowSubscriptions(
       ShowSubscriptionsStatement statement, TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getTopicName);
   }
 
   @Override
   public TSStatus visitDropSubscription(
       DropSubscriptionStatement statement, TreeAccessCheckContext context) {
-    return checkPipeManagement(context.getUsername());
+    return checkPipeManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getSubscriptionId);
   }
 
   // ======================= trigger related ================================
@@ -699,51 +832,67 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   public TSStatus visitCreateTrigger(
       CreateTriggerStatement statement, TreeAccessCheckContext context) {
     if (TREE_MODEL_AUDIT_DATABASE_PATH.include(statement.getPathPattern())) {
+      recordObjectAuthenticationAuditLog(
+          context
+              .setAuditLogOperation(AuditLogOperation.DDL)
+              .setPrivilegeType(PrivilegeType.USE_TRIGGER)
+              .setResult(false),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
-    return checkTriggerManagement(context.getUsername());
+    return checkTriggerManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
   }
 
   @Override
   public TSStatus visitDropTrigger(DropTriggerStatement statement, 
TreeAccessCheckContext context) {
-    return checkTriggerManagement(context.getUsername());
+    return checkTriggerManagement(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement::getTriggerName);
   }
 
   @Override
   public TSStatus visitShowTriggers(
       ShowTriggersStatement statement, TreeAccessCheckContext context) {
-    return checkTriggerManagement(context.getUsername());
+    return 
checkTriggerManagement(context.setAuditLogOperation(AuditLogOperation.QUERY), 
() -> "");
   }
 
-  private TSStatus checkTriggerManagement(String userName) {
-    if (AuthorityChecker.SUPER_USER.equals(userName)) {
+  private TSStatus checkTriggerManagement(IAuditEntity auditEntity, 
Supplier<String> auditObject) {
+    if (AuthorityChecker.SUPER_USER.equals(auditEntity.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          
auditEntity.setPrivilegeType(PrivilegeType.USE_TRIGGER).setResult(true), 
auditObject);
       return SUCCEED;
     }
-    return checkGlobalAuth(userName, PrivilegeType.USE_TRIGGER);
+    return checkGlobalAuth(auditEntity, PrivilegeType.USE_TRIGGER, 
auditObject);
   }
 
   // ============================== database related 
===========================
   @Override
   public TSStatus visitSetDatabase(
       DatabaseSchemaStatement statement, TreeAccessCheckContext context) {
-    return checkCreateOrAlterDatabasePermission(context.getUsername(), 
statement.getDatabasePath());
+    return checkCreateOrAlterDatabasePermission(
+        context.setAuditLogOperation(AuditLogOperation.DDL), 
statement.getDatabasePath());
   }
 
   @Override
   public TSStatus visitAlterDatabase(
       DatabaseSchemaStatement databaseSchemaStatement, TreeAccessCheckContext 
context) {
     return checkCreateOrAlterDatabasePermission(
-        context.getUsername(), databaseSchemaStatement.getDatabasePath());
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        databaseSchemaStatement.getDatabasePath());
   }
 
   @Override
   public TSStatus visitShowStorageGroup(
       ShowDatabaseStatement showDatabaseStatement, TreeAccessCheckContext 
context) {
+    context.setAuditLogOperation(AuditLogOperation.QUERY);
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true), () -> 
showDatabaseStatement.getPathPattern().toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(showDatabaseStatement, context.getUsername());
+    setCanSeeAuditDB(showDatabaseStatement, context);
     return checkShowOrCountDatabasePermission(showDatabaseStatement, context);
   }
 
@@ -753,47 +902,68 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       return SUCCEED;
     }
-    setCanSeeAuditDB(countDatabaseStatement, context.getUsername());
+    setCanSeeAuditDB(countDatabaseStatement, context);
     return checkShowOrCountDatabasePermission(countDatabaseStatement, context);
   }
 
   @Override
   public TSStatus visitDeleteStorageGroup(
       DeleteDatabaseStatement statement, TreeAccessCheckContext context) {
+    context.setAuditLogOperation(AuditLogOperation.DDL);
     for (String prefixPath : statement.getPrefixPath()) {
       // root.__audit can never be deleted
       if (TREE_MODEL_AUDIT_DATABASE.equals(prefixPath)) {
+        recordObjectAuthenticationAuditLog(
+            
context.setPrivilegeType(PrivilegeType.MANAGE_DATABASE).setResult(false),
+            () -> prefixPath);
         return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
             .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
       }
     }
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          
context.setPrivilegeType(PrivilegeType.MANAGE_DATABASE).setResult(true),
+          () -> statement.getPrefixPath().toString());
       return SUCCEED;
     }
-    return checkGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_DATABASE);
+    return checkGlobalAuth(
+        context, PrivilegeType.MANAGE_DATABASE, () -> 
statement.getPrefixPath().toString());
   }
 
-  private TSStatus checkCreateOrAlterDatabasePermission(String userName, 
PartialPath databaseName) {
+  private TSStatus checkCreateOrAlterDatabasePermission(
+      IAuditEntity auditEntity, PartialPath databaseName) {
+    
auditEntity.setDatabase(databaseName.getFullPath()).setAuditLogOperation(AuditLogOperation.DDL);
     // root.__audit can never be created or alter
     if (TREE_MODEL_AUDIT_DATABASE_PATH.equals(databaseName)) {
+      recordObjectAuthenticationAuditLog(auditEntity.setResult(false), 
databaseName::getFullPath);
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
 
-    if (AuthorityChecker.SUPER_USER.equals(userName)) {
+    if (AuthorityChecker.SUPER_USER.equals(auditEntity.getUsername())) {
+      recordObjectAuthenticationAuditLog(auditEntity.setResult(true), 
databaseName::getFullPath);
       return SUCCEED;
     }
 
-    return checkGlobalAuth(userName, PrivilegeType.MANAGE_DATABASE);
+    return checkGlobalAuth(auditEntity, PrivilegeType.MANAGE_DATABASE, 
databaseName::getFullPath);
   }
 
   private TSStatus checkShowOrCountDatabasePermission(
       AuthorityInformationStatement statement, TreeAccessCheckContext context) 
{
     // own SYSTEM/MAINTAIN can see all except for root.__audit, otherwise can 
only see PATHS that
     // user has READ_SCHEMA auth
-    if (!checkHasGlobalAuth(context.getUsername(), 
PrivilegeType.MANAGE_DATABASE)) {
+    if (!checkHasGlobalAuth(
+        context.setAuditLogOperation(AuditLogOperation.QUERY),
+        PrivilegeType.MANAGE_DATABASE,
+        () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString()))
 {
       return visitAuthorityInformation(statement, context);
     } else {
+      recordObjectAuthenticationAuditLog(
+          context
+              .setAuditLogOperation(AuditLogOperation.QUERY)
+              .setPrivilegeType(PrivilegeType.MANAGE_DATABASE)
+              .setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return SUCCEED;
     }
   }
@@ -801,35 +971,41 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   // ==================================== data related 
========================================
   @Override
   public TSStatus visitInsertBase(InsertBaseStatement statement, 
TreeAccessCheckContext context) {
-
+    
context.setAuditLogOperation(AuditLogOperation.DML).setPrivilegeType(PrivilegeType.WRITE_DATA);
     for (PartialPath path : statement.getDevicePaths()) {
       // audit db is read-only
       if (includeByAuditTreeDB(path)
           && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+        recordObjectAuthenticationAuditLog(context.setResult(false), 
path::toString);
         return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
             .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
       }
     }
 
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return SUCCEED;
     }
     return checkTimeSeriesPermission(
-        context.getUsername(),
+        context,
         statement.getPaths().stream().distinct().collect(Collectors.toList()),
         PrivilegeType.WRITE_DATA);
   }
 
   @Override
   public TSStatus visitInsert(InsertStatement statement, 
TreeAccessCheckContext context) {
+    
context.setAuditLogOperation(AuditLogOperation.DML).setPrivilegeType(PrivilegeType.WRITE_DATA);
     // audit db is read-only
     if (includeByAuditTreeDB(statement.getDevice())
         && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(false), () -> statement.getDevice().toString());
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), PrivilegeType.WRITE_DATA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_DATA);
   }
 
   @Override
@@ -840,31 +1016,42 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
 
   @Override
   public TSStatus visitDeleteData(DeleteDataStatement statement, 
TreeAccessCheckContext context) {
+    
context.setAuditLogOperation(AuditLogOperation.DML).setPrivilegeType(PrivilegeType.WRITE_DATA);
     for (PartialPath path : statement.getPaths()) {
       // audit db is read-only
       if (includeByAuditTreeDB(path)
           && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+        recordObjectAuthenticationAuditLog(context.setResult(false), 
path::toString);
         return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
             .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
       }
     }
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), PrivilegeType.WRITE_DATA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_DATA);
   }
 
   @Override
   public TSStatus visitQuery(QueryStatement statement, TreeAccessCheckContext 
context) {
+    
context.setAuditLogOperation(AuditLogOperation.QUERY).setPrivilegeType(PrivilegeType.READ_DATA);
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       statement.setCanSeeAuditDB(true);
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(statement, context.getUsername());
+    setCanSeeAuditDB(statement, context);
     try {
       statement.setAuthorityScope(
           AuthorityChecker.getAuthorizedPathTree(context.getUsername(), 
PrivilegeType.READ_DATA));
     } catch (AuthException e) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(false),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(e.getCode().getStatusCode());
     }
+    recordObjectAuthenticationAuditLog(
+        context.setResult(true),
+        () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
     return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
   }
 
@@ -881,27 +1068,38 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
 
   // ============================= timeseries related 
=================================
   public static TSStatus checkTimeSeriesPermission(
-      String userName, List<? extends PartialPath> checkedPaths, PrivilegeType 
permission) {
-    if (AuthorityChecker.SUPER_USER.equals(userName)) {
+      IAuditEntity context, List<? extends PartialPath> checkedPaths, 
PrivilegeType permission) {
+    context.setPrivilegeType(permission);
+    if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+      recordObjectAuthenticationAuditLog(context.setResult(true), 
checkedPaths::toString);
       return SUCCEED;
     }
-    return AuthorityChecker.getTSStatus(
-        AuthorityChecker.checkFullPathOrPatternListPermission(userName, 
checkedPaths, permission),
-        checkedPaths,
-        permission);
+    TSStatus result =
+        AuthorityChecker.getTSStatus(
+            AuthorityChecker.checkFullPathOrPatternListPermission(
+                context.getUsername(), checkedPaths, permission),
+            checkedPaths,
+            permission);
+    recordObjectAuthenticationAuditLog(context.setResult(true), 
checkedPaths::toString);
+    return result;
   }
 
   @Override
   public TSStatus visitCreateTimeseries(
       CreateTimeSeriesStatement statement, TreeAccessCheckContext context) {
+    context
+        .setPrivilegeType(PrivilegeType.WRITE_SCHEMA)
+        .setAuditLogOperation(AuditLogOperation.DDL);
     // audit db is read-only
     if (includeByAuditTreeDB(statement.getPath())
         && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(false),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
@@ -910,16 +1108,21 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     // audit db is read-only
     if (includeByAuditTreeDB(statement.getDevicePath())
         && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(false),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
   public TSStatus visitCreateMultiTimeSeries(
       CreateMultiTimeSeriesStatement statement, TreeAccessCheckContext 
context) {
+    context
+        .setPrivilegeType(PrivilegeType.WRITE_SCHEMA)
+        .setAuditLogOperation(AuditLogOperation.DDL);
     // audit db is read-only
     for (PartialPath path : statement.getPaths()) {
       if (includeByAuditTreeDB(path)
@@ -929,23 +1132,25 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       }
     }
 
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
   public TSStatus visitInternalCreateMultiTimeSeries(
       InternalCreateMultiTimeSeriesStatement statement, TreeAccessCheckContext 
context) {
+    context
+        .setPrivilegeType(PrivilegeType.WRITE_SCHEMA)
+        .setAuditLogOperation(AuditLogOperation.DDL);
     // audit db is read-only
     for (PartialPath path : statement.getDeviceMap().keySet()) {
       if (includeByAuditTreeDB(path)
           && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+        recordObjectAuthenticationAuditLog(context.setResult(false), 
path::toString);
         return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
             .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
       }
     }
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
@@ -954,21 +1159,29 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     // audit db is read-only
     if (includeByAuditTreeDB(statement.getDevicePath())
         && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(false),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
   public TSStatus visitShowTimeSeries(
       ShowTimeSeriesStatement statement, TreeAccessCheckContext context) {
+    context
+        .setAuditLogOperation(AuditLogOperation.QUERY)
+        .setPrivilegeTypes(Arrays.asList(PrivilegeType.READ_DATA, 
PrivilegeType.READ_SCHEMA));
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       statement.setCanSeeAuditDB(true);
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(statement, context.getUsername());
+    setCanSeeAuditDB(statement, context);
     if (statement.hasTimeCondition()) {
       try {
         statement.setAuthorityScope(
@@ -980,6 +1193,9 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       } catch (AuthException e) {
         return new TSStatus(e.getCode().getStatusCode());
       }
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
     } else {
       return visitAuthorityInformation(statement, context);
@@ -991,9 +1207,12 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       CountTimeSeriesStatement statement, TreeAccessCheckContext context) {
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       statement.setCanSeeAuditDB(true);
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(statement, context.getUsername());
+    setCanSeeAuditDB(statement, context);
     if (statement.hasTimeCondition()) {
       try {
         statement.setAuthorityScope(
@@ -1003,8 +1222,14 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
                 AuthorityChecker.getAuthorizedPathTree(
                     context.getUsername(), PrivilegeType.READ_DATA)));
       } catch (AuthException e) {
+        recordObjectAuthenticationAuditLog(
+            context.setResult(false),
+            () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
         return new TSStatus(e.getCode().getStatusCode());
       }
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
     } else {
       return visitAuthorityInformation(statement, context);
@@ -1016,9 +1241,16 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       CountLevelTimeSeriesStatement countStatement, TreeAccessCheckContext 
context) {
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       countStatement.setCanSeeAuditDB(true);
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () ->
+              countStatement.getPaths().stream()
+                  .distinct()
+                  .collect(Collectors.toList())
+                  .toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(countStatement, context.getUsername());
+    setCanSeeAuditDB(countStatement, context);
     return visitAuthorityInformation(countStatement, context);
   }
 
@@ -1027,9 +1259,16 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       CountNodesStatement countStatement, TreeAccessCheckContext context) {
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       countStatement.setCanSeeAuditDB(true);
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () ->
+              countStatement.getPaths().stream()
+                  .distinct()
+                  .collect(Collectors.toList())
+                  .toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(countStatement, context.getUsername());
+    setCanSeeAuditDB(countStatement, context);
     return visitAuthorityInformation(countStatement, context);
   }
 
@@ -1038,9 +1277,16 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       ShowChildNodesStatement showChildNodesStatement, TreeAccessCheckContext 
context) {
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       showChildNodesStatement.setCanSeeAuditDB(true);
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () ->
+              showChildNodesStatement.getPaths().stream()
+                  .distinct()
+                  .collect(Collectors.toList())
+                  .toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(showChildNodesStatement, context.getUsername());
+    setCanSeeAuditDB(showChildNodesStatement, context);
     return visitAuthorityInformation(showChildNodesStatement, context);
   }
 
@@ -1049,9 +1295,16 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       ShowChildPathsStatement showChildPathsStatement, TreeAccessCheckContext 
context) {
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       showChildPathsStatement.setCanSeeAuditDB(true);
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () ->
+              showChildPathsStatement.getPaths().stream()
+                  .distinct()
+                  .collect(Collectors.toList())
+                  .toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(showChildPathsStatement, context.getUsername());
+    setCanSeeAuditDB(showChildPathsStatement, context);
     return visitAuthorityInformation(showChildPathsStatement, context);
   }
 
@@ -1061,11 +1314,13 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     // audit db is read-only
     if (includeByAuditTreeDB(statement.getPath())
         && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(false),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
   }
 
   @Override
@@ -1075,47 +1330,67 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     for (PartialPath path : statement.getPathPatternList()) {
       if (includeByAuditTreeDB(path)
           && 
!context.getUsername().equals(AuthorityChecker.INTERNAL_AUDIT_USER)) {
+        recordObjectAuthenticationAuditLog(
+            context.setResult(false),
+            () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
         return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
             .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
       }
     }
-    return checkTimeSeriesPermission(
-        context.getUsername(), statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
+    return checkTimeSeriesPermission(context, statement.getPaths(), 
PrivilegeType.WRITE_SCHEMA);
   }
 
   // ================================== maintain related 
=============================
   @Override
   public TSStatus visitExtendRegion(
       ExtendRegionStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(
+        context.setAuditLogOperation(AuditLogOperation.DDL),
+        PrivilegeType.MAINTAIN,
+        () -> statement.getRegionIds().toString());
   }
 
   @Override
   public TSStatus visitGetRegionId(GetRegionIdStatement statement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(
+        
context.setAuditLogOperation(AuditLogOperation.QUERY).setDatabase(statement.getDatabase()),
+        PrivilegeType.MAINTAIN,
+        statement::getDatabase);
   }
 
   @Override
   public TSStatus visitGetSeriesSlotList(
       GetSeriesSlotListStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(
+        
context.setAuditLogOperation(AuditLogOperation.QUERY).setDatabase(statement.getDatabase()),
+        PrivilegeType.MAINTAIN,
+        statement::getDatabase);
   }
 
   @Override
   public TSStatus visitGetTimeSlotList(
       GetTimeSlotListStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(
+        
context.setAuditLogOperation(AuditLogOperation.QUERY).setDatabase(statement.getDatabase()),
+        PrivilegeType.MAINTAIN,
+        statement::getDatabase);
   }
 
   @Override
   public TSStatus visitCountTimeSlotList(
       CountTimeSlotListStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(
+        
context.setAuditLogOperation(AuditLogOperation.QUERY).setDatabase(statement.getDatabase()),
+        PrivilegeType.MAINTAIN,
+        statement::getDatabase);
   }
 
   @Override
   public TSStatus visitKillQuery(KillQueryStatement statement, 
TreeAccessCheckContext context) {
-    if (checkHasGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN)) {
+    if (checkHasGlobalAuth(
+        context.setAuditLogOperation(AuditLogOperation.CONTROL),
+        PrivilegeType.MAINTAIN,
+        () -> "")) {
       statement.setAllowedUsername(context.getUsername());
     }
     return SUCCEED;
@@ -1123,17 +1398,33 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
 
   @Override
   public TSStatus visitFlush(FlushStatement flushStatement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(
+        context.setAuditLogOperation(AuditLogOperation.CONTROL),
+        PrivilegeType.SYSTEM,
+        () ->
+            
flushStatement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
   }
 
   @Override
   public TSStatus visitSetConfiguration(
       SetConfigurationStatement setConfigurationStatement, 
TreeAccessCheckContext context) {
+    List<PrivilegeType> relatedPrivileges;
     try {
-      return AuthorityChecker.getTSStatus(
-          AuthorityChecker.checkUserMissingSystemPermissions(
-              context.getUsername(), 
setConfigurationStatement.getNeededPrivileges()));
+      relatedPrivileges = new 
ArrayList<>(setConfigurationStatement.getNeededPrivileges());
+      TSStatus result =
+          AuthorityChecker.getTSStatus(
+              AuthorityChecker.checkUserMissingSystemPermissions(
+                  context.getUsername(), relatedPrivileges));
+      recordObjectAuthenticationAuditLog(
+          context
+              .setResult(result.getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode())
+              .setAuditLogOperation(AuditLogOperation.CONTROL)
+              .setPrivilegeTypes(relatedPrivileges),
+          () -> "");
+      return result;
     } catch (IOException e) {
+      recordObjectAuthenticationAuditLog(
+          
context.setResult(false).setAuditLogOperation(AuditLogOperation.CONTROL), () -> 
"");
       return AuthorityChecker.getTSStatus(false, "Failed to check config item 
permission");
     }
   }
@@ -1141,61 +1432,63 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitSetSystemStatus(
       SetSystemStatusStatement setSystemStatusStatement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(
+        context.setAuditLogOperation(AuditLogOperation.CONTROL), 
PrivilegeType.SYSTEM, () -> "");
   }
 
   @Override
   public TSStatus visitStartRepairData(
       StartRepairDataStatement startRepairDataStatement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(
+        context.setAuditLogOperation(AuditLogOperation.CONTROL), 
PrivilegeType.SYSTEM, () -> "");
   }
 
   @Override
   public TSStatus visitStopRepairData(
       StopRepairDataStatement stopRepairDataStatement, TreeAccessCheckContext 
context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitClearCache(
       ClearCacheStatement clearCacheStatement, TreeAccessCheckContext context) 
{
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitMigrateRegion(
       MigrateRegionStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitReconstructRegion(
       ReconstructRegionStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitRemoveAINode(
       RemoveAINodeStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitRemoveConfigNode(
       RemoveConfigNodeStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitRemoveDataNode(
       RemoveDataNodeStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitRemoveRegion(
       RemoveRegionStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
@@ -1206,24 +1499,24 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
 
   @Override
   public TSStatus visitShowAINodes(ShowAINodesStatement statement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitShowClusterId(
       ShowClusterIdStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitShowCluster(ShowClusterStatement statement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitShowConfigNodes(
       ShowConfigNodesStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
@@ -1241,12 +1534,12 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitShowDataNodes(
       ShowDataNodesStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitShowQueries(ShowQueriesStatement statement, 
TreeAccessCheckContext context) {
-    if (checkHasGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN)) {
+    if (checkHasGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "")) {
       statement.setAllowedUsername(context.getUsername());
     }
     return SUCCEED;
@@ -1254,48 +1547,48 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
 
   @Override
   public TSStatus visitShowRegion(ShowRegionStatement statement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitSetSpaceQuota(
       SetSpaceQuotaStatement setSpaceQuotaStatement, TreeAccessCheckContext 
context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitSetThrottleQuota(
       SetThrottleQuotaStatement setThrottleQuotaStatement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitShowThrottleQuota(
       ShowThrottleQuotaStatement showThrottleQuotaStatement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitShowSpaceQuota(
       ShowSpaceQuotaStatement showSpaceQuotaStatement, TreeAccessCheckContext 
context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitShowVariables(
       ShowVariablesStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitShowVersion(ShowVersionStatement statement, 
TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
   public TSStatus visitTestConnection(
       TestConnectionStatement statement, TreeAccessCheckContext context) {
-    return checkGlobalAuth(context.getUsername(), PrivilegeType.MAINTAIN);
+    return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
   @Override
@@ -1307,17 +1600,18 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitLoadConfiguration(
       LoadConfigurationStatement loadConfigurationStatement, 
TreeAccessCheckContext context) {
-    return checkOnlySuperUser(context.getUsername());
+    return checkOnlySuperUser(context, null, () -> "");
   }
 
   // ======================== TTL related ===========================
   @Override
   public TSStatus visitSetTTL(SetTTLStatement statement, 
TreeAccessCheckContext context) {
+    
context.setPrivilegeType(PrivilegeType.SYSTEM).setAuditLogOperation(AuditLogOperation.DDL);
     List<PartialPath> checkedPaths = statement.getPaths();
     boolean[] pathsNotEndWithMultiLevelWildcard = null;
     for (int i = 0; i < checkedPaths.size(); i++) {
       PartialPath checkedPath = checkedPaths.get(i);
-      TSStatus status = checkWriteOnReadOnlyPath(checkedPath);
+      TSStatus status = checkWriteOnReadOnlyPath(context, checkedPath);
       if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
         return status;
       }
@@ -1329,7 +1623,7 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
         pathsNotEndWithMultiLevelWildcard[i] = true;
       }
     }
-    if (checkHasGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM)) {
+    if (checkHasGlobalAuth(context, PrivilegeType.SYSTEM, 
checkedPaths::toString)) {
       return SUCCEED;
     }
 
@@ -1346,16 +1640,33 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
         pathsForCheckingPermissions.add(checkedPaths.get(i));
       }
     }
-    return AuthorityChecker.getTSStatus(
-        AuthorityChecker.checkFullPathOrPatternListPermission(
-            context.getUsername(), pathsForCheckingPermissions, 
PrivilegeType.WRITE_SCHEMA),
-        pathsForCheckingPermissions,
-        PrivilegeType.WRITE_SCHEMA);
+    TSStatus result =
+        AuthorityChecker.getTSStatus(
+            AuthorityChecker.checkFullPathOrPatternListPermission(
+                context.getUsername(), pathsForCheckingPermissions, 
PrivilegeType.WRITE_SCHEMA),
+            pathsForCheckingPermissions,
+            PrivilegeType.WRITE_SCHEMA);
+    recordObjectAuthenticationAuditLog(
+        context
+            .setPrivilegeType(PrivilegeType.WRITE_SCHEMA)
+            .setResult(result.getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()),
+        pathsForCheckingPermissions::toString);
+    return result;
   }
 
   @Override
   public TSStatus visitShowTTL(ShowTTLStatement showTTLStatement, 
TreeAccessCheckContext context) {
-    if (checkHasGlobalAuth(context.getUsername(), PrivilegeType.SYSTEM)) {
+    context
+        .setAuditLogOperation(AuditLogOperation.QUERY)
+        .setPrivilegeType(PrivilegeType.READ_SCHEMA);
+    if (checkHasGlobalAuth(
+        context,
+        PrivilegeType.SYSTEM,
+        () ->
+            showTTLStatement.getPaths().stream()
+                .distinct()
+                .collect(Collectors.toList())
+                .toString())) {
       return SUCCEED;
     }
     for (PartialPath path : showTTLStatement.getPaths()) {
@@ -1366,6 +1677,7 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
           context.getUsername(),
           path.concatNode(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD),
           PrivilegeType.READ_SCHEMA)) {
+        recordObjectAuthenticationAuditLog(context.setResult(false), 
path::getFullPath);
         return AuthorityChecker.getTSStatus(false, path, 
PrivilegeType.READ_SCHEMA);
       }
     }
@@ -1381,11 +1693,17 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   // ================================= device related 
=============================
   @Override
   public TSStatus visitShowDevices(ShowDevicesStatement statement, 
TreeAccessCheckContext context) {
+    context
+        .setAuditLogOperation(AuditLogOperation.QUERY)
+        .setPrivilegeTypes(Arrays.asList(PrivilegeType.READ_DATA, 
PrivilegeType.READ_SCHEMA));
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
       statement.setCanSeeAuditDB(true);
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(statement, context.getUsername());
+    setCanSeeAuditDB(statement, context);
     if (statement.hasTimeCondition()) {
       try {
         statement.setAuthorityScope(
@@ -1395,8 +1713,14 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
                 AuthorityChecker.getAuthorizedPathTree(
                     context.getUsername(), PrivilegeType.READ_DATA)));
       } catch (AuthException e) {
+        recordObjectAuthenticationAuditLog(
+            context.setResult(false),
+            () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
         return new TSStatus(e.getCode().getStatusCode());
       }
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
     } else {
       return visitAuthorityInformation(statement, context);
@@ -1406,10 +1730,16 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
   @Override
   public TSStatus visitCountDevices(
       CountDevicesStatement statement, TreeAccessCheckContext context) {
+    context
+        .setPrivilegeTypes(Arrays.asList(PrivilegeType.READ_DATA, 
PrivilegeType.READ_SCHEMA))
+        .setAuditLogOperation(AuditLogOperation.QUERY);
     if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          context.setResult(true),
+          () -> 
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
       return SUCCEED;
     }
-    setCanSeeAuditDB(statement, context.getUsername());
+    setCanSeeAuditDB(statement, context);
     if (statement.hasTimeCondition()) {
       try {
         statement.setAuthorityScope(
@@ -1427,43 +1757,74 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     }
   }
 
-  protected TSStatus checkSystemAuth(String userName) {
-    return checkGlobalAuth(userName, PrivilegeType.SYSTEM);
+  protected TSStatus checkSystemAuth(IAuditEntity context, Supplier<String> 
auditObject) {
+    return checkGlobalAuth(context, PrivilegeType.SYSTEM, auditObject);
   }
 
-  protected TSStatus checkGlobalAuth(String userName, PrivilegeType 
requiredPrivilege) {
-    if (checkHasGlobalAuth(userName, requiredPrivilege)) {
+  protected TSStatus checkGlobalAuth(
+      IAuditEntity context, PrivilegeType requiredPrivilege, Supplier<String> 
auditObject) {
+    if (checkHasGlobalAuth(context, requiredPrivilege, auditObject)) {
       return SUCCEED;
     }
-    return AuthorityChecker.getTSStatus(false, requiredPrivilege);
+    TSStatus result = AuthorityChecker.getTSStatus(false, requiredPrivilege);
+    recordObjectAuthenticationAuditLog(
+        context.setResult(result.getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()),
+        auditObject);
+    return result;
   }
 
-  protected boolean checkHasGlobalAuth(String userName, PrivilegeType 
requiredPrivilege) {
-    if (AuthorityChecker.SUPER_USER.equals(userName)) {
+  protected boolean checkHasGlobalAuth(
+      IAuditEntity context, PrivilegeType requiredPrivilege, Supplier<String> 
auditObject) {
+    if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+      recordObjectAuthenticationAuditLog(
+          context.setPrivilegeType(requiredPrivilege).setResult(true), 
auditObject);
       return true;
     }
-    return AuthorityChecker.checkSystemPermission(userName, requiredPrivilege);
+    boolean result =
+        AuthorityChecker.checkSystemPermission(context.getUsername(), 
requiredPrivilege);
+    recordObjectAuthenticationAuditLog(
+        context.setPrivilegeType(requiredPrivilege).setResult(result), 
auditObject);
+    return result;
   }
 
-  protected TSStatus checkWriteOnReadOnlyPath(PartialPath path) {
+  protected TSStatus checkWriteOnReadOnlyPath(IAuditEntity auditEntity, 
PartialPath path) {
     if (includeByAuditTreeDB(path)
         && !AuthorityChecker.INTERNAL_AUDIT_USER.equals(path.getFullPath())) {
+      recordObjectAuthenticationAuditLog(auditEntity, path::getFullPath);
       return new TSStatus(TSStatusCode.NO_PERMISSION.getStatusCode())
           .setMessage(String.format(READ_ONLY_DB_ERROR_MSG, 
TREE_MODEL_AUDIT_DATABASE));
     }
     return SUCCEED;
   }
 
-  protected void setCanSeeAuditDB(AuthorityInformationStatement statement, 
String userName) {
-    if (!checkHasGlobalAuth(userName, PrivilegeType.AUDIT)) {
+  protected void setCanSeeAuditDB(
+      AuthorityInformationStatement statement, IAuditEntity auditEntity) {
+    if (!checkHasGlobalAuth(auditEntity, PrivilegeType.AUDIT, () -> 
TREE_MODEL_AUDIT_DATABASE)) {
       statement.setCanSeeAuditDB(false);
     }
   }
 
-  private TSStatus checkOnlySuperUser(String userName) {
-    if (AuthorityChecker.SUPER_USER.equals(userName)) {
+  private TSStatus checkOnlySuperUser(
+      IAuditEntity auditEntity, PrivilegeType privilegeType, Supplier<String> 
auditObject) {
+    auditEntity.setPrivilegeType(privilegeType);
+    if (AuthorityChecker.SUPER_USER.equals(auditEntity.getUsername())) {
+      recordObjectAuthenticationAuditLog(auditEntity.setResult(true), 
auditObject);
       return SUCCEED;
     }
+    recordObjectAuthenticationAuditLog(auditEntity.setResult(false), 
auditObject);
     return AuthorityChecker.getTSStatus(false, "Only the admin user can 
perform this operation");
   }
+
+  private static void recordObjectAuthenticationAuditLog(
+      IAuditEntity auditEntity, Supplier<String> auditObject) {
+    AUDIT_LOGGER.log(
+        auditEntity.setAuditEventType(AuditEventType.OBJECT_AUTHENTICATION),
+        () ->
+            String.format(
+                OBJECT_AUTHENTICATION_AUDIT_STR,
+                auditEntity.getUsername(),
+                auditEntity.getUserId(),
+                auditObject.get(),
+                true));
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNodeShutdownHook.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNodeShutdownHook.java
index a21cc3dccd7..a2d91eb1f32 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNodeShutdownHook.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNodeShutdownHook.java
@@ -107,7 +107,7 @@ public class DataNodeShutdownHook extends Thread {
             null,
             null);
     String logMessage = String.format("DataNode %s exiting...", nodeLocation);
-    DNAuditLogger.getInstance().log(fields, logMessage);
+    DNAuditLogger.getInstance().log(fields, () -> logMessage);
 
     startWatcher();
     // Stop external rpc service firstly.
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AbstractAuditLogger.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AbstractAuditLogger.java
index 4522ddeba30..ce361ba225f 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AbstractAuditLogger.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AbstractAuditLogger.java
@@ -24,48 +24,49 @@ import org.apache.iotdb.commons.conf.CommonConfig;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 
 import java.util.List;
+import java.util.function.Supplier;
 
-public class AbstractAuditLogger {
-  private static final CommonConfig config = 
CommonDescriptor.getInstance().getConfig();
-  protected static final boolean IS_AUDIT_LOG_ENABLED = 
config.isEnableAuditLog();
+public abstract class AbstractAuditLogger {
+  private static final CommonConfig CONFIG = 
CommonDescriptor.getInstance().getConfig();
+  protected static final boolean IS_AUDIT_LOG_ENABLED = 
CONFIG.isEnableAuditLog();
 
-  private static final List<AuditLogOperation> auditLogOperationList =
-      config.getAuditableOperationType();
+  private static final List<AuditLogOperation> AUDITABLE_OPERATION_TYPE =
+      CONFIG.getAuditableOperationType();
 
-  private static final PrivilegeLevel auditablePrivilegeLevel = 
config.getAuditableOperationLevel();
+  private static final PrivilegeLevel AUDITABLE_OPERATION_LEVEL =
+      CONFIG.getAuditableOperationLevel();
 
-  private static final String auditableOperationResult = 
config.getAuditableOperationResult();
+  private static final String AUDITABLE_OPERATION_RESULT = 
CONFIG.getAuditableOperationResult();
 
-  void log(AuditLogFields auditLogFields, String log) {
-    // do nothing
-  }
+  public abstract void log(IAuditEntity auditLogFields, Supplier<String> log);
 
-  public boolean checkBeforeLog(AuditLogFields auditLogFields) {
+  public boolean noNeedInsertAuditLog(IAuditEntity auditLogFields) {
     String username = auditLogFields.getUsername();
     String address = auditLogFields.getCliHostname();
-    AuditEventType type = auditLogFields.getAuditType();
-    AuditLogOperation operation = auditLogFields.getOperationType();
-    PrivilegeType privilegeType = auditLogFields.getPrivilegeType();
-    PrivilegeLevel privilegeLevel = judgePrivilegeLevel(privilegeType);
-    boolean result = auditLogFields.isResult();
+    AuditEventType type = auditLogFields.getAuditEventType();
+    AuditLogOperation operation = auditLogFields.getAuditLogOperation();
+    boolean result = auditLogFields.getResult();
 
     // to do: check whether this event should be logged.
     // if whitelist or blacklist is used, only ip on the whitelist or 
blacklist can be logged
 
-    if (auditLogOperationList == null || 
!auditLogOperationList.contains(operation)) {
-      return false;
+    if (AUDITABLE_OPERATION_TYPE == null || 
!AUDITABLE_OPERATION_TYPE.contains(operation)) {
+      return true;
     }
-    if (auditablePrivilegeLevel == PrivilegeLevel.OBJECT
-        && privilegeLevel == PrivilegeLevel.GLOBAL) {
-      return false;
+    for (PrivilegeType privilegeType : auditLogFields.getPrivilegeTypes()) {
+      PrivilegeLevel privilegeLevel = judgePrivilegeLevel(privilegeType);
+      if (AUDITABLE_OPERATION_LEVEL == PrivilegeLevel.GLOBAL
+          && privilegeLevel == PrivilegeLevel.OBJECT) {
+        return true;
+      }
     }
-    if (result && !auditableOperationResult.contains("SUCCESS")) {
-      return false;
+    if (result && !AUDITABLE_OPERATION_RESULT.contains("SUCCESS")) {
+      return true;
     }
-    if (!result && !auditableOperationResult.contains("FAIL")) {
-      return false;
+    if (!result && !AUDITABLE_OPERATION_RESULT.contains("FAIL")) {
+      return true;
     }
-    return true;
+    return false;
   }
 
   public static PrivilegeLevel judgePrivilegeLevel(PrivilegeType type) {
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditEventType.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditEventType.java
index 81ac94ad4dd..39b13835481 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditEventType.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditEventType.java
@@ -44,6 +44,7 @@ public enum AuditEventType {
   SESSION_TIME_EXCEEDED,
   LOGIN_REJECT_IP,
   SESSION_ENCRYPT_FAILED,
+  SYSTEM_OPERATION,
 
   DN_SHUTDOWN;
 
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditLogFields.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditLogFields.java
index 22f3ad408f9..06a0545a310 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditLogFields.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditLogFields.java
@@ -21,15 +21,18 @@ package org.apache.iotdb.commons.audit;
 
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 
-public class AuditLogFields {
-  private final String username;
+import java.util.Collections;
+import java.util.List;
+
+public class AuditLogFields implements IAuditEntity {
 
   private final long userId;
+  private final String username;
   private final String cliHostname;
   private final AuditEventType auditType;
   private final AuditLogOperation operationType;
-  private final PrivilegeType privilegeType;
-  private boolean result;
+  private final List<PrivilegeType> privilegeTypes;
+  private final boolean result;
   private final String database;
   private final String sqlString;
 
@@ -48,7 +51,7 @@ public class AuditLogFields {
     this.cliHostname = cliHostname;
     this.auditType = auditType;
     this.operationType = operationType;
-    this.privilegeType = privilegeType;
+    this.privilegeTypes = Collections.singletonList(privilegeType);
     this.result = result;
     this.database = database;
     this.sqlString = sqlString;
@@ -66,32 +69,73 @@ public class AuditLogFields {
     return cliHostname;
   }
 
-  public AuditEventType getAuditType() {
+  @Override
+  public AuditEventType getAuditEventType() {
     return auditType;
   }
 
-  public AuditLogOperation getOperationType() {
+  @Override
+  public AuditLogOperation getAuditLogOperation() {
     return operationType;
   }
 
-  public PrivilegeType getPrivilegeType() {
-    return privilegeType;
-  }
-
-  public boolean isResult() {
-    return result;
+  @Override
+  public List<PrivilegeType> getPrivilegeTypes() {
+    return privilegeTypes;
   }
 
-  public AuditLogFields setResult(boolean result) {
-    this.result = result;
-    return this;
+  @Override
+  public String getPrivilegeTypeString() {
+    return privilegeTypes.toString();
   }
 
+  @Override
   public String getDatabase() {
     return database;
   }
 
+  @Override
   public String getSqlString() {
     return sqlString;
   }
+
+  @Override
+  public boolean getResult() {
+    return result;
+  }
+
+  @Override
+  public IAuditEntity setAuditEventType(AuditEventType auditEventType) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public IAuditEntity setAuditLogOperation(AuditLogOperation 
auditLogOperation) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public IAuditEntity setPrivilegeType(PrivilegeType privilegeType) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public IAuditEntity setPrivilegeTypes(List<PrivilegeType> privilegeTypes) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public IAuditEntity setResult(boolean result) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public IAuditEntity setDatabase(String database) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public IAuditEntity setSqlString(String sqlString) {
+    throw new UnsupportedOperationException();
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/IAuditEntity.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/IAuditEntity.java
index 2731f3c375d..0b46b0fd286 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/IAuditEntity.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/IAuditEntity.java
@@ -21,6 +21,8 @@ package org.apache.iotdb.commons.audit;
 
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 
+import java.util.List;
+
 public interface IAuditEntity {
 
   long getUserId();
@@ -37,10 +39,14 @@ public interface IAuditEntity {
 
   IAuditEntity setAuditLogOperation(AuditLogOperation auditLogOperation);
 
-  PrivilegeType getPrivilegeType();
+  List<PrivilegeType> getPrivilegeTypes();
+
+  String getPrivilegeTypeString();
 
   IAuditEntity setPrivilegeType(PrivilegeType privilegeType);
 
+  IAuditEntity setPrivilegeTypes(List<PrivilegeType> privilegeTypes);
+
   boolean getResult();
 
   IAuditEntity setResult(boolean result);
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/UserEntity.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/UserEntity.java
index c80548039af..94f16c3ade2 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/UserEntity.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/UserEntity.java
@@ -21,6 +21,8 @@ package org.apache.iotdb.commons.audit;
 
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 
 /** This class defines the fields of a user entity to be audited. */
@@ -68,7 +70,7 @@ public class UserEntity implements IAuditEntity {
 
   private AuditEventType auditEventType;
   private AuditLogOperation auditLogOperation;
-  private PrivilegeType privilegeType;
+  private List<PrivilegeType> privilegeTypeList;
   private boolean result;
   private String database;
   private String sqlString;
@@ -96,13 +98,24 @@ public class UserEntity implements IAuditEntity {
   }
 
   @Override
-  public PrivilegeType getPrivilegeType() {
-    return privilegeType;
+  public List<PrivilegeType> getPrivilegeTypes() {
+    return privilegeTypeList;
+  }
+
+  @Override
+  public String getPrivilegeTypeString() {
+    return privilegeTypeList.toString();
   }
 
   @Override
   public IAuditEntity setPrivilegeType(PrivilegeType privilegeType) {
-    this.privilegeType = privilegeType;
+    this.privilegeTypeList = Collections.singletonList(privilegeType);
+    return this;
+  }
+
+  @Override
+  public IAuditEntity setPrivilegeTypes(List<PrivilegeType> privilegeTypes) {
+    this.privilegeTypeList = privilegeTypes;
     return this;
   }
 

Reply via email to