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

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 9823d77a58 [#5902] feat: Add tag failure event to Gravitino server 
(#5944)
9823d77a58 is described below

commit 9823d77a582a170eed40742b172847381d141e3d
Author: Cheng-Yi Shih <48374270+cool9850...@users.noreply.github.com>
AuthorDate: Tue Jan 7 19:29:43 2025 +0800

    [#5902] feat: Add tag failure event to Gravitino server (#5944)
    
    ### What changes were proposed in this pull request?
    
    Add tag failure event to Gravitino server
    
    ### Why are the changes needed?
    
    Subtask: apache#5902
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Unit tests.
---
 .../gravitino/listener/TagEventDispatcher.java     |  63 ++++--
 .../listener/api/event/AlterTagFailureEvent.java   |  67 ++++++
 ...AssociateTagsForMetadataObjectFailureEvent.java |  84 +++++++
 .../listener/api/event/CreateTagFailureEvent.java  |  65 ++++++
 .../listener/api/event/DeleteTagFailureEvent.java  |  53 +++++
 .../listener/api/event/GetTagFailureEvent.java     |  53 +++++
 .../event/GetTagForMetadataObjectFailureEvent.java |  61 ++++++
 .../ListMetadataObjectsForTagFailureEvent.java     |  53 +++++
 .../listener/api/event/ListTagsFailureEvent.java   |  50 +++++
 .../ListTagsForMetadataObjectFailureEvent.java     |  55 +++++
 .../api/event/ListTagsInfoFailureEvent.java        |  52 +++++
 .../ListTagsInfoForMetadataObjectFailureEvent.java |  55 +++++
 .../listener/api/event/OperationType.java          |  13 ++
 .../listener/api/event/TagFailureEvent.java        |  43 ++++
 .../gravitino/listener/api/info/TagInfo.java       |  78 +++++++
 .../storage/relational/service/TagMetaService.java |   8 +-
 .../java/org/apache/gravitino/tag/TagManager.java  |  45 ++--
 .../apache/gravitino/utils/NameIdentifierUtil.java |  10 +
 .../org/apache/gravitino/utils/NamespaceUtil.java  |  11 +
 .../gravitino/listener/api/event/TestTagEvent.java | 244 +++++++++++++++++++++
 .../storage/relational/TestJDBCBackend.java        |   5 +-
 .../relational/service/TestTagMetaService.java     | 103 +++++----
 docs/gravitino-server-config.md                    |   1 +
 23 files changed, 1178 insertions(+), 94 deletions(-)

diff --git 
a/core/src/main/java/org/apache/gravitino/listener/TagEventDispatcher.java 
b/core/src/main/java/org/apache/gravitino/listener/TagEventDispatcher.java
index 90ca0fda23..302d82a93c 100644
--- a/core/src/main/java/org/apache/gravitino/listener/TagEventDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/listener/TagEventDispatcher.java
@@ -21,9 +21,22 @@ package org.apache.gravitino.listener;
 import java.util.Map;
 import org.apache.gravitino.MetadataObject;
 import org.apache.gravitino.exceptions.NoSuchTagException;
+import org.apache.gravitino.listener.api.event.AlterTagFailureEvent;
+import 
org.apache.gravitino.listener.api.event.AssociateTagsForMetadataObjectFailureEvent;
+import org.apache.gravitino.listener.api.event.CreateTagFailureEvent;
+import org.apache.gravitino.listener.api.event.DeleteTagFailureEvent;
+import org.apache.gravitino.listener.api.event.GetTagFailureEvent;
+import 
org.apache.gravitino.listener.api.event.GetTagForMetadataObjectFailureEvent;
+import 
org.apache.gravitino.listener.api.event.ListMetadataObjectsForTagFailureEvent;
+import org.apache.gravitino.listener.api.event.ListTagsFailureEvent;
+import 
org.apache.gravitino.listener.api.event.ListTagsForMetadataObjectFailureEvent;
+import org.apache.gravitino.listener.api.event.ListTagsInfoFailureEvent;
+import 
org.apache.gravitino.listener.api.event.ListTagsInfoForMetadataObjectFailureEvent;
+import org.apache.gravitino.listener.api.info.TagInfo;
 import org.apache.gravitino.tag.Tag;
 import org.apache.gravitino.tag.TagChange;
 import org.apache.gravitino.tag.TagDispatcher;
+import org.apache.gravitino.utils.PrincipalUtils;
 
 /**
  * {@code TagEventDispatcher} is a decorator for {@link TagDispatcher} that 
not only delegates tag
@@ -32,10 +45,7 @@ import org.apache.gravitino.tag.TagDispatcher;
  * of tag operations.
  */
 public class TagEventDispatcher implements TagDispatcher {
-  @SuppressWarnings("unused")
   private final EventBus eventBus;
-
-  @SuppressWarnings("unused")
   private final TagDispatcher dispatcher;
 
   public TagEventDispatcher(EventBus eventBus, TagDispatcher dispatcher) {
@@ -50,7 +60,8 @@ public class TagEventDispatcher implements TagDispatcher {
       // TODO: listTagsEvent
       return dispatcher.listTags(metalake);
     } catch (Exception e) {
-      // TODO: listTagFailureEvent
+      eventBus.dispatchEvent(
+          new ListTagsFailureEvent(PrincipalUtils.getCurrentUserName(), 
metalake, e));
       throw e;
     }
   }
@@ -62,7 +73,8 @@ public class TagEventDispatcher implements TagDispatcher {
       // TODO: listTagsInfoEvent
       return dispatcher.listTagsInfo(metalake);
     } catch (Exception e) {
-      // TODO: listTagsInfoFailureEvent
+      eventBus.dispatchEvent(
+          new ListTagsInfoFailureEvent(PrincipalUtils.getCurrentUserName(), 
metalake, e));
       throw e;
     }
   }
@@ -73,8 +85,9 @@ public class TagEventDispatcher implements TagDispatcher {
     try {
       // TODO: getTagEvent
       return dispatcher.getTag(metalake, name);
-    } catch (NoSuchTagException e) {
-      // TODO: getTagFailureEvent
+    } catch (Exception e) {
+      eventBus.dispatchEvent(
+          new GetTagFailureEvent(PrincipalUtils.getCurrentUserName(), 
metalake, name, e));
       throw e;
     }
   }
@@ -82,12 +95,14 @@ public class TagEventDispatcher implements TagDispatcher {
   @Override
   public Tag createTag(
       String metalake, String name, String comment, Map<String, String> 
properties) {
+    TagInfo tagInfo = new TagInfo(name, comment, properties);
     // TODO: createTagPreEvent
     try {
       // TODO: createTagEvent
       return dispatcher.createTag(metalake, name, comment, properties);
     } catch (Exception e) {
-      // TODO: createTagFailureEvent
+      eventBus.dispatchEvent(
+          new CreateTagFailureEvent(PrincipalUtils.getCurrentUserName(), 
metalake, tagInfo, e));
       throw e;
     }
   }
@@ -99,7 +114,9 @@ public class TagEventDispatcher implements TagDispatcher {
       // TODO: alterTagEvent
       return dispatcher.alterTag(metalake, name, changes);
     } catch (Exception e) {
-      // TODO: alterTagFailureEvent
+      eventBus.dispatchEvent(
+          new AlterTagFailureEvent(
+              PrincipalUtils.getCurrentUserName(), metalake, name, changes, 
e));
       throw e;
     }
   }
@@ -111,7 +128,8 @@ public class TagEventDispatcher implements TagDispatcher {
       // TODO: deleteTagEvent
       return dispatcher.deleteTag(metalake, name);
     } catch (Exception e) {
-      // TODO: deleteTagFailureEvent
+      eventBus.dispatchEvent(
+          new DeleteTagFailureEvent(PrincipalUtils.getCurrentUserName(), 
metalake, name, e));
       throw e;
     }
   }
@@ -123,7 +141,9 @@ public class TagEventDispatcher implements TagDispatcher {
       // TODO: listMetadataObjectsForTagEvent
       return dispatcher.listMetadataObjectsForTag(metalake, name);
     } catch (Exception e) {
-      // TODO: listMetadataObjectsForTagFailureEvent
+      eventBus.dispatchEvent(
+          new ListMetadataObjectsForTagFailureEvent(
+              PrincipalUtils.getCurrentUserName(), metalake, name, e));
       throw e;
     }
   }
@@ -135,7 +155,9 @@ public class TagEventDispatcher implements TagDispatcher {
       // TODO: listTagsForMetadataObjectEvent
       return dispatcher.listTagsForMetadataObject(metalake, metadataObject);
     } catch (Exception e) {
-      // TODO: listTagsForMetadataObjectFailureEvent
+      eventBus.dispatchEvent(
+          new ListTagsForMetadataObjectFailureEvent(
+              PrincipalUtils.getCurrentUserName(), metalake, metadataObject, 
e));
       throw e;
     }
   }
@@ -147,7 +169,9 @@ public class TagEventDispatcher implements TagDispatcher {
       // TODO: listTagsInfoForMetadataObjectEvent
       return dispatcher.listTagsInfoForMetadataObject(metalake, 
metadataObject);
     } catch (Exception e) {
-      // TODO: listTagsInfoForMetadataObjectFailureEvent
+      eventBus.dispatchEvent(
+          new ListTagsInfoForMetadataObjectFailureEvent(
+              PrincipalUtils.getCurrentUserName(), metalake, metadataObject, 
e));
       throw e;
     }
   }
@@ -161,7 +185,14 @@ public class TagEventDispatcher implements TagDispatcher {
       return dispatcher.associateTagsForMetadataObject(
           metalake, metadataObject, tagsToAdd, tagsToRemove);
     } catch (Exception e) {
-      // TODO: associateTagsForMetadataObjectFailureEvent
+      eventBus.dispatchEvent(
+          new AssociateTagsForMetadataObjectFailureEvent(
+              PrincipalUtils.getCurrentUserName(),
+              metalake,
+              metadataObject,
+              tagsToAdd,
+              tagsToRemove,
+              e));
       throw e;
     }
   }
@@ -173,7 +204,9 @@ public class TagEventDispatcher implements TagDispatcher {
       // TODO: getTagForMetadataObjectEvent
       return dispatcher.getTagForMetadataObject(metalake, metadataObject, 
name);
     } catch (Exception e) {
-      // TODO: getTagForMetadataObjectFailureEvent
+      eventBus.dispatchEvent(
+          new GetTagForMetadataObjectFailureEvent(
+              PrincipalUtils.getCurrentUserName(), metalake, metadataObject, 
name, e));
       throw e;
     }
   }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AlterTagFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AlterTagFailureEvent.java
new file mode 100644
index 0000000000..a15121fda8
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AlterTagFailureEvent.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.tag.TagChange;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to alter a tag in the 
database fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class AlterTagFailureEvent extends TagFailureEvent {
+  private final TagChange[] changes;
+
+  /**
+   * Constructs a new AlterTagFailureEvent.
+   *
+   * @param user the user who attempted to alter the tag
+   * @param metalake the metalake identifier
+   * @param name the name of the tag
+   * @param changes the changes attempted to be made to the tag
+   * @param exception the exception that caused the failure
+   */
+  public AlterTagFailureEvent(
+      String user, String metalake, String name, TagChange[] changes, 
Exception exception) {
+    super(user, NameIdentifierUtil.ofTag(metalake, name), exception);
+    this.changes = changes;
+  }
+
+  /**
+   * Returns the changes attempted to be made to the tag.
+   *
+   * @return the changes attempted to be made to the tag
+   */
+  public TagChange[] changes() {
+    return changes;
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.ALTER_TAG;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AssociateTagsForMetadataObjectFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AssociateTagsForMetadataObjectFailureEvent.java
new file mode 100644
index 0000000000..c196e7f7ed
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AssociateTagsForMetadataObjectFailureEvent.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.MetadataObjectUtil;
+
+/**
+ * Represents an event triggered when an attempt to associate tags for a 
metadata object fails due
+ * to an exception.
+ */
+@DeveloperApi
+public class AssociateTagsForMetadataObjectFailureEvent extends 
TagFailureEvent {
+  private final String[] tagsToAdd;
+  private final String[] tagsToRemove;
+
+  /**
+   * Constructs a new {@code AssociateTagsForMetadataObjectFailureEvent} 
instance.
+   *
+   * @param user The user who initiated the operation.
+   * @param metalake The metalake name where the metadata object resides.
+   * @param metadataObject The metadata object for which tags are being 
associated.
+   * @param tagsToAdd The tags to add.
+   * @param tagsToRemove The tags to remove.
+   * @param exception The exception encountered during the operation, 
providing insights into the
+   *     reasons behind the failure.
+   */
+  public AssociateTagsForMetadataObjectFailureEvent(
+      String user,
+      String metalake,
+      MetadataObject metadataObject,
+      String[] tagsToAdd,
+      String[] tagsToRemove,
+      Exception exception) {
+    super(user, MetadataObjectUtil.toEntityIdent(metalake, metadataObject), 
exception);
+    this.tagsToAdd = tagsToAdd;
+    this.tagsToRemove = tagsToRemove;
+  }
+
+  /**
+   * Returns the tags to add.
+   *
+   * @return The tags to add.
+   */
+  public String[] tagsToAdd() {
+    return tagsToAdd;
+  }
+
+  /**
+   * Returns the tags to remove.
+   *
+   * @return The tags to remove.
+   */
+  public String[] tagsToRemove() {
+    return tagsToRemove;
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.ASSOCIATE_TAGS_FOR_METADATA_OBJECT;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/CreateTagFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/CreateTagFailureEvent.java
new file mode 100644
index 0000000000..0ed1adeee7
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/CreateTagFailureEvent.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.TagInfo;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to create a tag in the 
database fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class CreateTagFailureEvent extends TagFailureEvent {
+  private final TagInfo tagInfo;
+  /**
+   * Constructs a new {@code CreateTagFailureEvent} instance.
+   *
+   * @param user The user who initiated the tag creation operation.
+   * @param metalake The metalake name where the tag resides.
+   * @param tagInfo The information about the tag to be created.
+   * @param exception The exception encountered during the tag creation 
operation, providing
+   *     insights into the reasons behind the operation's failure.
+   */
+  public CreateTagFailureEvent(String user, String metalake, TagInfo tagInfo, 
Exception exception) {
+    super(user, NameIdentifierUtil.ofTag(metalake, tagInfo.name()), exception);
+    this.tagInfo = tagInfo;
+  }
+
+  /**
+   * Returns the information about the tag.
+   *
+   * @return the tag information
+   */
+  public TagInfo tagInfo() {
+    return tagInfo;
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.CREATE_TAG;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteTagFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteTagFailureEvent.java
new file mode 100644
index 0000000000..90e14796c1
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteTagFailureEvent.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to delete a tag in the 
database fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class DeleteTagFailureEvent extends TagFailureEvent {
+  /**
+   * Constructs a new {@code DeleteTagFailureEvent} instance.
+   *
+   * @param user The user who initiated the tag deletion operation.
+   * @param metalake The metalake name where the tag resides.
+   * @param name The name of the tag to delete.
+   * @param exception The exception encountered during the tag deletion 
operation, providing
+   *     insights into the reasons behind the operation's failure.
+   */
+  public DeleteTagFailureEvent(String user, String metalake, String name, 
Exception exception) {
+    super(user, NameIdentifierUtil.ofTag(metalake, name), exception);
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.DELETE_TAG;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetTagFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetTagFailureEvent.java
new file mode 100644
index 0000000000..06650b3b53
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetTagFailureEvent.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to get a tag from the 
database fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class GetTagFailureEvent extends TagFailureEvent {
+  /**
+   * Constructs a new {@code GetTagFailureEvent} instance.
+   *
+   * @param user The user who initiated the get tag operation.
+   * @param metalake The metalake name where the tag resides.
+   * @param name The name of the tag to get.
+   * @param exception The exception encountered during the get tag operation, 
providing insights
+   *     into the reasons behind the operation's failure.
+   */
+  public GetTagFailureEvent(String user, String metalake, String name, 
Exception exception) {
+    super(user, NameIdentifierUtil.ofTag(metalake, name), exception);
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.GET_TAG;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetTagForMetadataObjectFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetTagForMetadataObjectFailureEvent.java
new file mode 100644
index 0000000000..3489ac23bd
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetTagForMetadataObjectFailureEvent.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.MetadataObjectUtil;
+
+/**
+ * Represents an event triggered when an attempt to get a tag for a metadata 
object fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class GetTagForMetadataObjectFailureEvent extends TagFailureEvent {
+
+  /**
+   * Constructs a new {@code GetTagForMetadataObjectFailureEvent} instance.
+   *
+   * @param user The user who initiated the operation.
+   * @param metalake The metalake name where the metadata object resides.
+   * @param metadataObject The metadata object for which the tag is being 
retrieved.
+   * @param name The name of the tag to retrieve.
+   * @param exception The exception encountered during the operation, 
providing insights into the
+   *     reasons behind the failure.
+   */
+  public GetTagForMetadataObjectFailureEvent(
+      String user,
+      String metalake,
+      MetadataObject metadataObject,
+      String name,
+      Exception exception) {
+    super(user, MetadataObjectUtil.toEntityIdent(metalake, metadataObject), 
exception);
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.GET_TAG_FOR_METADATA_OBJECT;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListMetadataObjectsForTagFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListMetadataObjectsForTagFailureEvent.java
new file mode 100644
index 0000000000..fa09c413b3
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListMetadataObjectsForTagFailureEvent.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to list metadata objects for 
a tag fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class ListMetadataObjectsForTagFailureEvent extends TagFailureEvent {
+  /**
+   * Constructs a new {@code ListMetadataObjectsForTagFailureEvent} instance.
+   *
+   * @param user The user who initiated the operation.
+   * @param metalake The metalake name where the tag resides.
+   * @param name The name of the tag.
+   * @param exception The exception encountered during the operation, 
providing insights into the
+   *     reasons behind the failure.
+   */
+  public ListMetadataObjectsForTagFailureEvent(
+      String user, String metalake, String name, Exception exception) {
+    super(user, NameIdentifierUtil.ofTag(metalake, name), exception);
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_METADATA_OBJECTS_FOR_TAG;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsFailureEvent.java
new file mode 100644
index 0000000000..00a3401d14
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsFailureEvent.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/** Represents an event triggered when an attempt to list tags fails due to an 
exception. */
+@DeveloperApi
+public class ListTagsFailureEvent extends TagFailureEvent {
+
+  /**
+   * Constructs a new {@code ListTagFailureEvent} instance.
+   *
+   * @param user The user who initiated the tag listing operation.
+   * @param metalake The metalake name where the tags are being listed.
+   * @param exception The exception encountered during the tag listing 
operation, providing insights
+   *     into the reasons behind the failure.
+   */
+  public ListTagsFailureEvent(String user, String metalake, Exception 
exception) {
+    super(user, NameIdentifier.of(metalake), exception);
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_TAG;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsForMetadataObjectFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsForMetadataObjectFailureEvent.java
new file mode 100644
index 0000000000..3e33c2bbda
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsForMetadataObjectFailureEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.MetadataObjectUtil;
+
+/**
+ * Represents an event triggered when an attempt to list tags for a metadata 
object fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class ListTagsForMetadataObjectFailureEvent extends TagFailureEvent {
+
+  /**
+   * Constructs a new {@code ListTagsForMetadataObjectFailureEvent} instance.
+   *
+   * @param user The user who initiated the operation.
+   * @param metalake The metalake name where the metadata object resides.
+   * @param metadataObject The metadata object for which tags are being listed.
+   * @param exception The exception encountered during the operation, 
providing insights into the
+   *     reasons behind the failure.
+   */
+  public ListTagsForMetadataObjectFailureEvent(
+      String user, String metalake, MetadataObject metadataObject, Exception 
exception) {
+    super(user, MetadataObjectUtil.toEntityIdent(metalake, metadataObject), 
exception);
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_TAGS_FOR_METADATA_OBJECT;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsInfoFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsInfoFailureEvent.java
new file mode 100644
index 0000000000..50bf4a87ca
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsInfoFailureEvent.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/**
+ * Represents an event triggered when an attempt to list tag information fails 
due to an exception.
+ */
+@DeveloperApi
+public class ListTagsInfoFailureEvent extends FailureEvent {
+
+  /**
+   * Constructs a new {@code ListTagsInfoFailureEvent} instance.
+   *
+   * @param user The user who initiated the tag listing operation.
+   * @param metalake The metalake name where the tags are being listed.
+   * @param exception The exception encountered during the tag listing 
operation, providing insights
+   *     into the reasons behind the failure.
+   */
+  public ListTagsInfoFailureEvent(String user, String metalake, Exception 
exception) {
+    super(user, NameIdentifier.of(metalake), exception);
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_TAGS_INFO;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsInfoForMetadataObjectFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsInfoForMetadataObjectFailureEvent.java
new file mode 100644
index 0000000000..948076651b
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListTagsInfoForMetadataObjectFailureEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.MetadataObjectUtil;
+
+/**
+ * Represents an event triggered when an attempt to list tags info for a 
metadata object fails due
+ * to an exception.
+ */
+@DeveloperApi
+public class ListTagsInfoForMetadataObjectFailureEvent extends TagFailureEvent 
{
+  /**
+   * Constructs a new {@code ListTagsInfoForMetadataObjectFailureEvent} 
instance.
+   *
+   * @param user The user who initiated the operation.
+   * @param metalake The metalake name where the metadata object resides.
+   * @param metadataObject The metadata object for which tags info is being 
listed.
+   * @param exception The exception encountered during the operation, 
providing insights into the
+   *     reasons behind the failure.
+   */
+  public ListTagsInfoForMetadataObjectFailureEvent(
+      String user, String metalake, MetadataObject metadataObject, Exception 
exception) {
+    super(user, MetadataObjectUtil.toEntityIdent(metalake, metadataObject), 
exception);
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_TAGS_INFO_FOR_METADATA_OBJECT;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java 
b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
index 00cbf1e1a4..515e63a7c3 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
@@ -31,6 +31,19 @@ public enum OperationType {
   REGISTER_TABLE,
   TABLE_EXISTS,
 
+  // Tag operations
+  CREATE_TAG,
+  GET_TAG,
+  GET_TAG_FOR_METADATA_OBJECT,
+  DELETE_TAG,
+  ALTER_TAG,
+  LIST_TAG,
+  ASSOCIATE_TAGS_FOR_METADATA_OBJECT,
+  LIST_TAGS_FOR_METADATA_OBJECT,
+  LIST_TAGS_INFO_FOR_METADATA_OBJECT,
+  LIST_METADATA_OBJECTS_FOR_TAG,
+  LIST_TAGS_INFO,
+
   // Schema operations
   CREATE_SCHEMA,
   DROP_SCHEMA,
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/TagFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/TagFailureEvent.java
new file mode 100644
index 0000000000..7072cab45d
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/TagFailureEvent.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/**
+ * Represents an event triggered when an attempt to perform a tag operation 
fails due to an
+ * exception.
+ */
+@DeveloperApi
+public abstract class TagFailureEvent extends FailureEvent {
+
+  /**
+   * Constructs a new {@code TagFailureEvent} instance.
+   *
+   * @param user The user who initiated the tag operation.
+   * @param identifier The identifier of the tag involved in the operation.
+   * @param exception The exception encountered during the tag operation, 
providing insights into
+   *     the reasons behind the failure.
+   */
+  protected TagFailureEvent(String user, NameIdentifier identifier, Exception 
exception) {
+    super(user, identifier, exception);
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/info/TagInfo.java 
b/core/src/main/java/org/apache/gravitino/listener/api/info/TagInfo.java
new file mode 100644
index 0000000000..20164f4c93
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/listener/api/info/TagInfo.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.info;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/**
+ * Provides access to metadata about a Tag instance, designed for use by event 
listeners. This class
+ * encapsulates the essential attributes of a Tag, including its name, 
optional description,
+ * properties, and audit information.
+ */
+@DeveloperApi
+public final class TagInfo {
+  private final String name;
+  @Nullable private final String comment;
+  private final Map<String, String> properties;
+
+  /**
+   * Directly constructs TagInfo with specified details.
+   *
+   * @param name The name of the Tag.
+   * @param comment An optional description for the Tag.
+   * @param properties A map of properties associated with the Tag.
+   */
+  public TagInfo(String name, String comment, Map<String, String> properties) {
+    this.name = name;
+    this.comment = comment;
+    this.properties = properties == null ? ImmutableMap.of() : 
ImmutableMap.copyOf(properties);
+  }
+
+  /**
+   * Returns the name of the Tag.
+   *
+   * @return The Tag's name.
+   */
+  public String name() {
+    return name;
+  }
+
+  /**
+   * Returns the optional comment describing the Tag.
+   *
+   * @return The comment, or null if not provided.
+   */
+  @Nullable
+  public String comment() {
+    return comment;
+  }
+
+  /**
+   * Returns the properties of the Tag.
+   *
+   * @return A map of Tag properties.
+   */
+  public Map<String, String> properties() {
+    return properties;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/TagMetaService.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/TagMetaService.java
index 71b8275275..5863877ae7 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/TagMetaService.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/TagMetaService.java
@@ -44,8 +44,8 @@ import org.apache.gravitino.storage.relational.po.TagPO;
 import org.apache.gravitino.storage.relational.utils.ExceptionUtils;
 import org.apache.gravitino.storage.relational.utils.POConverters;
 import org.apache.gravitino.storage.relational.utils.SessionUtils;
-import org.apache.gravitino.tag.TagManager;
 import org.apache.gravitino.utils.NameIdentifierUtil;
+import org.apache.gravitino.utils.NamespaceUtil;
 
 public class TagMetaService {
 
@@ -179,7 +179,7 @@ public class TagMetaService {
     }
 
     return tagPOs.stream()
-        .map(tagPO -> POConverters.fromTagPO(tagPO, 
TagManager.ofTagNamespace(metalake)))
+        .map(tagPO -> POConverters.fromTagPO(tagPO, 
NamespaceUtil.ofTag(metalake)))
         .collect(Collectors.toList());
   }
 
@@ -214,7 +214,7 @@ public class TagMetaService {
           tagIdent.name());
     }
 
-    return POConverters.fromTagPO(tagPO, TagManager.ofTagNamespace(metalake));
+    return POConverters.fromTagPO(tagPO, NamespaceUtil.ofTag(metalake));
   }
 
   public List<MetadataObject> 
listAssociatedMetadataObjectsForTag(NameIdentifier tagIdent)
@@ -327,7 +327,7 @@ public class TagMetaService {
                       metadataObjectId, metadataObject.type().toString()));
 
       return tagPOs.stream()
-          .map(tagPO -> POConverters.fromTagPO(tagPO, 
TagManager.ofTagNamespace(metalake)))
+          .map(tagPO -> POConverters.fromTagPO(tagPO, 
NamespaceUtil.ofTag(metalake)))
           .collect(Collectors.toList());
 
     } catch (RuntimeException e) {
diff --git a/core/src/main/java/org/apache/gravitino/tag/TagManager.java 
b/core/src/main/java/org/apache/gravitino/tag/TagManager.java
index f7932fe260..c03f6392fb 100644
--- a/core/src/main/java/org/apache/gravitino/tag/TagManager.java
+++ b/core/src/main/java/org/apache/gravitino/tag/TagManager.java
@@ -34,7 +34,6 @@ import org.apache.gravitino.EntityAlreadyExistsException;
 import org.apache.gravitino.EntityStore;
 import org.apache.gravitino.MetadataObject;
 import org.apache.gravitino.NameIdentifier;
-import org.apache.gravitino.Namespace;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
 import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
 import org.apache.gravitino.exceptions.NoSuchTagException;
@@ -47,6 +46,8 @@ import org.apache.gravitino.meta.AuditInfo;
 import org.apache.gravitino.meta.TagEntity;
 import org.apache.gravitino.storage.IdGenerator;
 import org.apache.gravitino.utils.MetadataObjectUtil;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+import org.apache.gravitino.utils.NamespaceUtil;
 import org.apache.gravitino.utils.PrincipalUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -82,14 +83,15 @@ public class TagManager implements TagDispatcher {
 
   public Tag[] listTagsInfo(String metalake) {
     return TreeLockUtils.doWithTreeLock(
-        NameIdentifier.of(ofTagNamespace(metalake).levels()),
+        NameIdentifier.of(NamespaceUtil.ofTag(metalake).levels()),
         LockType.READ,
         () -> {
           checkMetalake(NameIdentifier.of(metalake), entityStore);
 
           try {
             return entityStore
-                .list(ofTagNamespace(metalake), TagEntity.class, 
Entity.EntityType.TAG).stream()
+                .list(NamespaceUtil.ofTag(metalake), TagEntity.class, 
Entity.EntityType.TAG)
+                .stream()
                 .toArray(Tag[]::new);
           } catch (IOException ioe) {
             LOG.error("Failed to list tags under metalake {}", metalake, ioe);
@@ -103,7 +105,7 @@ public class TagManager implements TagDispatcher {
     Map<String, String> tagProperties = properties == null ? 
Collections.emptyMap() : properties;
 
     return TreeLockUtils.doWithTreeLock(
-        NameIdentifier.of(ofTagNamespace(metalake).levels()),
+        NameIdentifier.of(NamespaceUtil.ofTag(metalake).levels()),
         LockType.WRITE,
         () -> {
           checkMetalake(NameIdentifier.of(metalake), entityStore);
@@ -112,7 +114,7 @@ public class TagManager implements TagDispatcher {
               TagEntity.builder()
                   .withId(idGenerator.nextId())
                   .withName(name)
-                  .withNamespace(ofTagNamespace(metalake))
+                  .withNamespace(NamespaceUtil.ofTag(metalake))
                   .withComment(comment)
                   .withProperties(tagProperties)
                   .withAuditInfo(
@@ -137,14 +139,14 @@ public class TagManager implements TagDispatcher {
 
   public Tag getTag(String metalake, String name) throws NoSuchTagException {
     return TreeLockUtils.doWithTreeLock(
-        ofTagIdent(metalake, name),
+        NameIdentifierUtil.ofTag(metalake, name),
         LockType.READ,
         () -> {
           checkMetalake(NameIdentifier.of(metalake), entityStore);
 
           try {
             return entityStore.get(
-                ofTagIdent(metalake, name), Entity.EntityType.TAG, 
TagEntity.class);
+                NameIdentifierUtil.ofTag(metalake, name), 
Entity.EntityType.TAG, TagEntity.class);
           } catch (NoSuchEntityException e) {
             throw new NoSuchTagException(
                 "Tag with name %s under metalake %s does not exist", name, 
metalake);
@@ -158,14 +160,14 @@ public class TagManager implements TagDispatcher {
   public Tag alterTag(String metalake, String name, TagChange... changes)
       throws NoSuchTagException, IllegalArgumentException {
     return TreeLockUtils.doWithTreeLock(
-        NameIdentifier.of(ofTagNamespace(metalake).levels()),
+        NameIdentifier.of(NamespaceUtil.ofTag(metalake).levels()),
         LockType.WRITE,
         () -> {
           checkMetalake(NameIdentifier.of(metalake), entityStore);
 
           try {
             return entityStore.update(
-                ofTagIdent(metalake, name),
+                NameIdentifierUtil.ofTag(metalake, name),
                 TagEntity.class,
                 Entity.EntityType.TAG,
                 tagEntity -> updateTagEntity(tagEntity, changes));
@@ -184,13 +186,14 @@ public class TagManager implements TagDispatcher {
 
   public boolean deleteTag(String metalake, String name) {
     return TreeLockUtils.doWithTreeLock(
-        NameIdentifier.of(ofTagNamespace(metalake).levels()),
+        NameIdentifier.of(NamespaceUtil.ofTag(metalake).levels()),
         LockType.WRITE,
         () -> {
           checkMetalake(NameIdentifier.of(metalake), entityStore);
 
           try {
-            return entityStore.delete(ofTagIdent(metalake, name), 
Entity.EntityType.TAG);
+            return entityStore.delete(
+                NameIdentifierUtil.ofTag(metalake, name), 
Entity.EntityType.TAG);
           } catch (IOException ioe) {
             LOG.error("Failed to delete tag {} under metalake {}", name, 
metalake, ioe);
             throw new RuntimeException(ioe);
@@ -200,7 +203,7 @@ public class TagManager implements TagDispatcher {
 
   public MetadataObject[] listMetadataObjectsForTag(String metalake, String 
name)
       throws NoSuchTagException {
-    NameIdentifier tagId = ofTagIdent(metalake, name);
+    NameIdentifier tagId = NameIdentifierUtil.ofTag(metalake, name);
     return TreeLockUtils.doWithTreeLock(
         tagId,
         LockType.READ,
@@ -259,7 +262,7 @@ public class TagManager implements TagDispatcher {
       throws NoSuchMetadataObjectException {
     NameIdentifier entityIdent = MetadataObjectUtil.toEntityIdent(metalake, 
metadataObject);
     Entity.EntityType entityType = 
MetadataObjectUtil.toEntityType(metadataObject);
-    NameIdentifier tagIdent = ofTagIdent(metalake, name);
+    NameIdentifier tagIdent = NameIdentifierUtil.ofTag(metalake, name);
 
     MetadataObjectUtil.checkMetadataObject(metalake, metadataObject);
 
@@ -307,10 +310,12 @@ public class TagManager implements TagDispatcher {
     tagsToRemoveSet.removeAll(common);
 
     NameIdentifier[] tagsToAddIdent =
-        tagsToAddSet.stream().map(tag -> ofTagIdent(metalake, 
tag)).toArray(NameIdentifier[]::new);
+        tagsToAddSet.stream()
+            .map(tag -> NameIdentifierUtil.ofTag(metalake, tag))
+            .toArray(NameIdentifier[]::new);
     NameIdentifier[] tagsToRemoveIdent =
         tagsToRemoveSet.stream()
-            .map(tag -> ofTagIdent(metalake, tag))
+            .map(tag -> NameIdentifierUtil.ofTag(metalake, tag))
             .toArray(NameIdentifier[]::new);
 
     return TreeLockUtils.doWithTreeLock(
@@ -318,7 +323,7 @@ public class TagManager implements TagDispatcher {
         LockType.READ,
         () ->
             TreeLockUtils.doWithTreeLock(
-                NameIdentifier.of(ofTagNamespace(metalake).levels()),
+                NameIdentifier.of(NamespaceUtil.ofTag(metalake).levels()),
                 LockType.WRITE,
                 () -> {
                   try {
@@ -347,14 +352,6 @@ public class TagManager implements TagDispatcher {
                 }));
   }
 
-  public static Namespace ofTagNamespace(String metalake) {
-    return Namespace.of(metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME, 
Entity.TAG_SCHEMA_NAME);
-  }
-
-  public static NameIdentifier ofTagIdent(String metalake, String tagName) {
-    return NameIdentifier.of(ofTagNamespace(metalake), tagName);
-  }
-
   private TagEntity updateTagEntity(TagEntity tagEntity, TagChange... changes) 
{
     Map<String, String> props =
         tagEntity.properties() == null
diff --git 
a/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java 
b/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
index 2b7e69ebee..47b203ed4d 100644
--- a/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
+++ b/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
@@ -93,6 +93,16 @@ public class NameIdentifierUtil {
     return NameIdentifier.of(metalake, catalog, schema, table);
   }
 
+  /**
+   * Create the tag {@link NameIdentifier} with the given metalake and tag 
name.
+   *
+   * @param metalake The metalake name
+   * @param tagName The tag name
+   * @return The created tag {@link NameIdentifier}
+   */
+  public static NameIdentifier ofTag(String metalake, String tagName) {
+    return NameIdentifier.of(NamespaceUtil.ofTag(metalake), tagName);
+  }
   /**
    * Create the column {@link NameIdentifier} with the given metalake, 
catalog, schema, table and
    * column name.
diff --git a/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java 
b/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
index d0e473c501..eebab09346 100644
--- a/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
+++ b/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.utils;
 
 import com.google.errorprone.annotations.FormatMethod;
 import com.google.errorprone.annotations.FormatString;
+import org.apache.gravitino.Entity;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.exceptions.IllegalNamespaceException;
@@ -71,6 +72,16 @@ public class NamespaceUtil {
     return Namespace.of(metalake, catalog, schema);
   }
 
+  /**
+   * Create a namespace for tag.
+   *
+   * @param metalake The metalake name
+   * @return A namespace for tag
+   */
+  public static Namespace ofTag(String metalake) {
+    return Namespace.of(metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME, 
Entity.TAG_SCHEMA_NAME);
+  }
+
   /**
    * Create a namespace for column.
    *
diff --git 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestTagEvent.java 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestTagEvent.java
new file mode 100644
index 0000000000..1ac3001bd2
--- /dev/null
+++ 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestTagEvent.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.listener.api.event;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Arrays;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.exceptions.GravitinoRuntimeException;
+import org.apache.gravitino.listener.DummyEventListener;
+import org.apache.gravitino.listener.EventBus;
+import org.apache.gravitino.listener.TagEventDispatcher;
+import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagChange;
+import org.apache.gravitino.tag.TagDispatcher;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+
+@TestInstance(Lifecycle.PER_CLASS)
+public class TestTagEvent {
+  private TagEventDispatcher failureDispatcher;
+  private DummyEventListener dummyEventListener;
+  private Tag tag;
+
+  @BeforeAll
+  void init() {
+    this.tag = mockTag();
+    this.dummyEventListener = new DummyEventListener();
+    EventBus eventBus = new EventBus(Arrays.asList(dummyEventListener));
+    TagDispatcher tagExceptionDispatcher = mockExceptionTagDispatcher();
+    this.failureDispatcher = new TagEventDispatcher(eventBus, 
tagExceptionDispatcher);
+  }
+
+  @Test
+  void testCreateTagFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.createTag("metalake", tag.name(), 
tag.comment(), tag.properties()));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(CreateTagFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((CreateTagFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(tag.name(), ((CreateTagFailureEvent) 
event).tagInfo().name());
+    Assertions.assertEquals(tag.comment(), ((CreateTagFailureEvent) 
event).tagInfo().comment());
+    Assertions.assertEquals(
+        tag.properties(), ((CreateTagFailureEvent) 
event).tagInfo().properties());
+    Assertions.assertEquals(OperationType.CREATE_TAG, event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testGetTagFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.getTag("metalake", tag.name()));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(GetTagFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((GetTagFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(OperationType.GET_TAG, event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testGetTagForMetadataObjectFailureEvent() {
+    MetadataObject metadataObject =
+        NameIdentifierUtil.toMetadataObject(
+            NameIdentifierUtil.ofCatalog("metalake", "catalog_for_test"),
+            Entity.EntityType.CATALOG);
+
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.getTagForMetadataObject("metalake", 
metadataObject, tag.name()));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(GetTagForMetadataObjectFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class,
+        ((GetTagForMetadataObjectFailureEvent) event).exception().getClass());
+    Assertions.assertEquals(OperationType.GET_TAG_FOR_METADATA_OBJECT, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testDeleteTagFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.deleteTag("metalake", tag.name()));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(DeleteTagFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((DeleteTagFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(OperationType.DELETE_TAG, event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testAlterTagFailureEvent() {
+    TagChange change1 = TagChange.rename("newName");
+    TagChange change2 = TagChange.updateComment("new comment");
+    TagChange change3 = TagChange.setProperty("key", "value");
+    TagChange change4 = TagChange.removeProperty("oldKey");
+    TagChange[] changes = new TagChange[] {change1, change2, change3, change4};
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.alterTag("metalake", tag.name(), changes));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(AlterTagFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((AlterTagFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(changes, ((AlterTagFailureEvent) event).changes());
+    Assertions.assertEquals(OperationType.ALTER_TAG, event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testListTagFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.listTags("metalake"));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(ListTagsFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((ListTagsFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(OperationType.LIST_TAG, event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testListTagsForMetadataObjectFailureEvent() {
+    MetadataObject metadataObject =
+        NameIdentifierUtil.toMetadataObject(
+            NameIdentifierUtil.ofCatalog("metalake", "catalog_for_test"),
+            Entity.EntityType.CATALOG);
+
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.listTagsForMetadataObject("metalake", 
metadataObject));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(ListTagsForMetadataObjectFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class,
+        ((ListTagsForMetadataObjectFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(OperationType.LIST_TAGS_FOR_METADATA_OBJECT, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testListTagsInfoFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.listTagsInfo("metalake"));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(ListTagsInfoFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((ListTagsInfoFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(OperationType.LIST_TAGS_INFO, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testListTagsInfoForMetadataObjectFailureEvent() {
+    MetadataObject metadataObject =
+        NameIdentifierUtil.toMetadataObject(
+            NameIdentifierUtil.ofCatalog("metalake", "catalog_for_test"),
+            Entity.EntityType.CATALOG);
+
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.listTagsInfoForMetadataObject("metalake", 
metadataObject));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(ListTagsInfoForMetadataObjectFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class,
+        ((ListTagsInfoForMetadataObjectFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(
+        OperationType.LIST_TAGS_INFO_FOR_METADATA_OBJECT, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testAssociateTagsForMetadataObjectFailureEvent() {
+    MetadataObject metadataObject =
+        NameIdentifierUtil.toMetadataObject(
+            NameIdentifierUtil.ofCatalog("metalake", "catalog_for_test"),
+            Entity.EntityType.CATALOG);
+
+    String[] tagsToAssociate = new String[] {"tag1", "tag2"};
+    String[] tagsToDisassociate = new String[] {"tag3", "tag4"};
+
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () ->
+            failureDispatcher.associateTagsForMetadataObject(
+                "metalake", metadataObject, tagsToAssociate, 
tagsToDisassociate));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(AssociateTagsForMetadataObjectFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class,
+        ((AssociateTagsForMetadataObjectFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(
+        tagsToAssociate, ((AssociateTagsForMetadataObjectFailureEvent) 
event).tagsToAdd());
+    Assertions.assertEquals(
+        tagsToDisassociate, ((AssociateTagsForMetadataObjectFailureEvent) 
event).tagsToRemove());
+    Assertions.assertEquals(
+        OperationType.ASSOCIATE_TAGS_FOR_METADATA_OBJECT, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  private Tag mockTag() {
+    Tag tag = mock(Tag.class);
+    when(tag.name()).thenReturn("tag");
+    when(tag.comment()).thenReturn("comment");
+    when(tag.properties()).thenReturn(ImmutableMap.of("color", "#FFFFFF"));
+    return tag;
+  }
+
+  private TagDispatcher mockExceptionTagDispatcher() {
+    return mock(
+        TagDispatcher.class,
+        invocation -> {
+          throw new GravitinoRuntimeException("Exception for all methods");
+        });
+  }
+}
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
index 8cd2c802e8..f690a2256b 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
@@ -85,7 +85,6 @@ import 
org.apache.gravitino.storage.relational.service.MetalakeMetaService;
 import org.apache.gravitino.storage.relational.service.RoleMetaService;
 import org.apache.gravitino.storage.relational.session.SqlSessionFactoryHelper;
 import org.apache.gravitino.storage.relational.utils.SessionUtils;
-import org.apache.gravitino.tag.TagManager;
 import org.apache.gravitino.utils.NamespaceUtil;
 import org.apache.ibatis.session.SqlSession;
 import org.junit.jupiter.api.AfterAll;
@@ -657,7 +656,7 @@ public class TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag")
-            .withNamespace(TagManager.ofTagNamespace("metalake"))
+            .withNamespace(NamespaceUtil.ofTag("metalake"))
             .withComment("tag comment")
             .withAuditInfo(auditInfo)
             .build();
@@ -745,7 +744,7 @@ public class TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("another-tag")
-            .withNamespace(TagManager.ofTagNamespace("another-metalake"))
+            .withNamespace(NamespaceUtil.ofTag("another-metalake"))
             .withComment("another-tag comment")
             .withAuditInfo(auditInfo)
             .build();
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestTagMetaService.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestTagMetaService.java
index 8194a17061..a81f222de9 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestTagMetaService.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestTagMetaService.java
@@ -43,7 +43,8 @@ import org.apache.gravitino.meta.TopicEntity;
 import org.apache.gravitino.rel.types.Types;
 import org.apache.gravitino.storage.RandomIdGenerator;
 import org.apache.gravitino.storage.relational.TestJDBCBackend;
-import org.apache.gravitino.tag.TagManager;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+import org.apache.gravitino.utils.NamespaceUtil;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -67,7 +68,8 @@ public class TestTagMetaService extends TestJDBCBackend {
     Exception excep =
         Assertions.assertThrows(
             NoSuchEntityException.class,
-            () -> 
tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName, "tag1")));
+            () ->
+                
tagMetaService.getTagByIdentifier(NameIdentifierUtil.ofTag(metalakeName, 
"tag1")));
     Assertions.assertEquals("No such tag entity: tag1", excep.getMessage());
 
     // Test get tag entity
@@ -75,7 +77,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -83,7 +85,7 @@ public class TestTagMetaService extends TestJDBCBackend {
     tagMetaService.insertTag(tagEntity, false);
 
     TagEntity resultTagEntity =
-        tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName, 
"tag1"));
+        
tagMetaService.getTagByIdentifier(NameIdentifierUtil.ofTag(metalakeName, 
"tag1"));
     Assertions.assertEquals(tagEntity, resultTagEntity);
 
     // Test with null comment and properties.
@@ -91,13 +93,13 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag2")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withAuditInfo(auditInfo)
             .build();
 
     tagMetaService.insertTag(tagEntity1, false);
     TagEntity resultTagEntity1 =
-        tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName, 
"tag2"));
+        
tagMetaService.getTagByIdentifier(NameIdentifierUtil.ofTag(metalakeName, 
"tag2"));
     Assertions.assertEquals(tagEntity1, resultTagEntity1);
     Assertions.assertNull(resultTagEntity1.comment());
     Assertions.assertNull(resultTagEntity1.properties());
@@ -107,7 +109,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(tagEntity1.id())
             .withName("tag3")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -118,7 +120,7 @@ public class TestTagMetaService extends TestJDBCBackend {
     tagMetaService.insertTag(tagEntity2, true);
 
     TagEntity resultTagEntity2 =
-        tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName, 
"tag3"));
+        
tagMetaService.getTagByIdentifier(NameIdentifierUtil.ofTag(metalakeName, 
"tag3"));
     Assertions.assertEquals(tagEntity2, resultTagEntity2);
   }
 
@@ -133,7 +135,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -144,7 +146,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag2")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -152,7 +154,7 @@ public class TestTagMetaService extends TestJDBCBackend {
     tagMetaService.insertTag(tagEntity2, false);
 
     List<TagEntity> tagEntities =
-        
tagMetaService.listTagsByNamespace(TagManager.ofTagNamespace(metalakeName));
+        tagMetaService.listTagsByNamespace(NamespaceUtil.ofTag(metalakeName));
     Assertions.assertEquals(2, tagEntities.size());
     Assertions.assertTrue(tagEntities.contains(tagEntity1));
     Assertions.assertTrue(tagEntities.contains(tagEntity2));
@@ -169,7 +171,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -182,7 +184,7 @@ public class TestTagMetaService extends TestJDBCBackend {
             NoSuchEntityException.class,
             () ->
                 tagMetaService.updateTag(
-                    TagManager.ofTagIdent(metalakeName, "tag2"), tagEntity -> 
tagEntity));
+                    NameIdentifierUtil.ofTag(metalakeName, "tag2"), tagEntity 
-> tagEntity));
     Assertions.assertEquals("No such tag entity: tag2", excep.getMessage());
 
     // Update tag entity.
@@ -190,18 +192,18 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(tagEntity1.id())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment1")
             .withProperties(ImmutableMap.of("k2", "v2"))
             .withAuditInfo(auditInfo)
             .build();
     TagEntity updatedTagEntity =
         tagMetaService.updateTag(
-            TagManager.ofTagIdent(metalakeName, "tag1"), tagEntity -> 
tagEntity2);
+            NameIdentifierUtil.ofTag(metalakeName, "tag1"), tagEntity -> 
tagEntity2);
     Assertions.assertEquals(tagEntity2, updatedTagEntity);
 
     TagEntity loadedTagEntity =
-        tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName, 
"tag1"));
+        
tagMetaService.getTagByIdentifier(NameIdentifierUtil.ofTag(metalakeName, 
"tag1"));
     Assertions.assertEquals(tagEntity2, loadedTagEntity);
 
     // Update with different id.
@@ -209,7 +211,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment1")
             .withProperties(ImmutableMap.of("k2", "v2"))
             .withAuditInfo(auditInfo)
@@ -220,7 +222,7 @@ public class TestTagMetaService extends TestJDBCBackend {
             IllegalArgumentException.class,
             () ->
                 tagMetaService.updateTag(
-                    TagManager.ofTagIdent(metalakeName, "tag1"), tagEntity -> 
tagEntity3));
+                    NameIdentifierUtil.ofTag(metalakeName, "tag1"), tagEntity 
-> tagEntity3));
     Assertions.assertEquals(
         "The updated tag entity id: "
             + tagEntity3.id()
@@ -230,7 +232,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         excep1.getMessage());
 
     TagEntity loadedTagEntity1 =
-        tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName, 
"tag1"));
+        
tagMetaService.getTagByIdentifier(NameIdentifierUtil.ofTag(metalakeName, 
"tag1"));
     Assertions.assertEquals(tagEntity2, loadedTagEntity1);
   }
 
@@ -245,23 +247,24 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
             .build();
     tagMetaService.insertTag(tagEntity1, false);
 
-    boolean deleted = 
tagMetaService.deleteTag(TagManager.ofTagIdent(metalakeName, "tag1"));
+    boolean deleted = 
tagMetaService.deleteTag(NameIdentifierUtil.ofTag(metalakeName, "tag1"));
     Assertions.assertTrue(deleted);
 
-    deleted = tagMetaService.deleteTag(TagManager.ofTagIdent(metalakeName, 
"tag1"));
+    deleted = tagMetaService.deleteTag(NameIdentifierUtil.ofTag(metalakeName, 
"tag1"));
     Assertions.assertFalse(deleted);
 
     Exception excep =
         Assertions.assertThrows(
             NoSuchEntityException.class,
-            () -> 
tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName, "tag1")));
+            () ->
+                
tagMetaService.getTagByIdentifier(NameIdentifierUtil.ofTag(metalakeName, 
"tag1")));
     Assertions.assertEquals("No such tag entity: tag1", excep.getMessage());
   }
 
@@ -276,7 +279,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -287,7 +290,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         
MetalakeMetaService.getInstance().deleteMetalake(metalake.nameIdentifier(), 
false));
     Assertions.assertThrows(
         NoSuchEntityException.class,
-        () -> 
tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName, "tag1")));
+        () -> 
tagMetaService.getTagByIdentifier(NameIdentifierUtil.ofTag(metalakeName, 
"tag1")));
 
     // Test delete metalake with cascade.
     BaseMetalake metalake1 =
@@ -298,7 +301,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag2")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName + "1"))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName + "1"))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -309,7 +312,9 @@ public class TestTagMetaService extends TestJDBCBackend {
         
MetalakeMetaService.getInstance().deleteMetalake(metalake1.nameIdentifier(), 
true));
     Assertions.assertThrows(
         NoSuchEntityException.class,
-        () -> 
tagMetaService.getTagByIdentifier(TagManager.ofTagIdent(metalakeName + "1", 
"tag2")));
+        () ->
+            tagMetaService.getTagByIdentifier(
+                NameIdentifierUtil.ofTag(metalakeName + "1", "tag2")));
   }
 
   @Test
@@ -345,7 +350,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -356,7 +361,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag2")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -367,7 +372,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag3")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
@@ -377,9 +382,9 @@ public class TestTagMetaService extends TestJDBCBackend {
     // Test associate tags with metadata object
     NameIdentifier[] tagsToAdd =
         new NameIdentifier[] {
-          TagManager.ofTagIdent(metalakeName, "tag1"),
-          TagManager.ofTagIdent(metalakeName, "tag2"),
-          TagManager.ofTagIdent(metalakeName, "tag3")
+          NameIdentifierUtil.ofTag(metalakeName, "tag1"),
+          NameIdentifierUtil.ofTag(metalakeName, "tag2"),
+          NameIdentifierUtil.ofTag(metalakeName, "tag3")
         };
 
     List<TagEntity> tagEntities =
@@ -392,7 +397,7 @@ public class TestTagMetaService extends TestJDBCBackend {
 
     // Test disassociate tags with metadata object
     NameIdentifier[] tagsToRemove =
-        new NameIdentifier[] {TagManager.ofTagIdent(metalakeName, "tag1")};
+        new NameIdentifier[] {NameIdentifierUtil.ofTag(metalakeName, "tag1")};
 
     List<TagEntity> tagEntities1 =
         tagMetaService.associateTagsWithMetadataObject(
@@ -425,12 +430,14 @@ public class TestTagMetaService extends TestJDBCBackend {
     // Test associate and disassociate in-existent tags with metadata object
     NameIdentifier[] tagsToAdd1 =
         new NameIdentifier[] {
-          TagManager.ofTagIdent(metalakeName, "tag4"), 
TagManager.ofTagIdent(metalakeName, "tag5")
+          NameIdentifierUtil.ofTag(metalakeName, "tag4"),
+          NameIdentifierUtil.ofTag(metalakeName, "tag5")
         };
 
     NameIdentifier[] tagsToRemove1 =
         new NameIdentifier[] {
-          TagManager.ofTagIdent(metalakeName, "tag6"), 
TagManager.ofTagIdent(metalakeName, "tag7")
+          NameIdentifierUtil.ofTag(metalakeName, "tag6"),
+          NameIdentifierUtil.ofTag(metalakeName, "tag7")
         };
 
     List<TagEntity> tagEntities4 =
@@ -545,7 +552,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         tagMetaService.getTagForMetadataObject(
             NameIdentifier.of(metalakeName, "catalog1"),
             Entity.EntityType.CATALOG,
-            TagManager.ofTagIdent(metalakeName, "tag2"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag2"));
     Assertions.assertEquals("tag2", tagEntity.name());
 
     // Test get tag for schema
@@ -553,7 +560,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         tagMetaService.getTagForMetadataObject(
             NameIdentifier.of(metalakeName, "catalog1", "schema1"),
             Entity.EntityType.SCHEMA,
-            TagManager.ofTagIdent(metalakeName, "tag3"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag3"));
     Assertions.assertEquals("tag3", tagEntity1.name());
 
     // Test get tag for table
@@ -561,7 +568,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         tagMetaService.getTagForMetadataObject(
             NameIdentifier.of(metalakeName, "catalog1", "schema1", "table1"),
             Entity.EntityType.TABLE,
-            TagManager.ofTagIdent(metalakeName, "tag2"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag2"));
     Assertions.assertEquals("tag2", tagEntity2.name());
 
     // Test get tag for non-existent metadata object
@@ -571,7 +578,7 @@ public class TestTagMetaService extends TestJDBCBackend {
             tagMetaService.getTagForMetadataObject(
                 NameIdentifier.of(metalakeName, "catalog1", "schema1", 
"table2"),
                 Entity.EntityType.TABLE,
-                TagManager.ofTagIdent(metalakeName, "tag2")));
+                NameIdentifierUtil.ofTag(metalakeName, "tag2")));
 
     // Test get tag for non-existent tag
     Throwable e =
@@ -581,7 +588,7 @@ public class TestTagMetaService extends TestJDBCBackend {
                 tagMetaService.getTagForMetadataObject(
                     NameIdentifier.of(metalakeName, "catalog1", "schema1", 
"table1"),
                     Entity.EntityType.TABLE,
-                    TagManager.ofTagIdent(metalakeName, "tag4")));
+                    NameIdentifierUtil.ofTag(metalakeName, "tag4")));
     Assertions.assertTrue(e.getMessage().contains("No such tag entity: tag4"));
   }
 
@@ -594,7 +601,7 @@ public class TestTagMetaService extends TestJDBCBackend {
     // Test list associated metadata objects for tag2
     List<MetadataObject> metadataObjects =
         tagMetaService.listAssociatedMetadataObjectsForTag(
-            TagManager.ofTagIdent(metalakeName, "tag2"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag2"));
 
     Assertions.assertEquals(3, metadataObjects.size());
     Assertions.assertTrue(
@@ -609,7 +616,7 @@ public class TestTagMetaService extends TestJDBCBackend {
     // Test list associated metadata objects for tag3
     List<MetadataObject> metadataObjects1 =
         tagMetaService.listAssociatedMetadataObjectsForTag(
-            TagManager.ofTagIdent(metalakeName, "tag3"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag3"));
 
     Assertions.assertEquals(3, metadataObjects1.size());
     Assertions.assertTrue(
@@ -624,7 +631,7 @@ public class TestTagMetaService extends TestJDBCBackend {
     // Test list associated metadata objects for non-existent tag
     List<MetadataObject> metadataObjects2 =
         tagMetaService.listAssociatedMetadataObjectsForTag(
-            TagManager.ofTagIdent(metalakeName, "tag4"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag4"));
     Assertions.assertEquals(0, metadataObjects2.size());
 
     // Test metadata object non-exist scenario.
@@ -635,7 +642,7 @@ public class TestTagMetaService extends TestJDBCBackend {
 
     List<MetadataObject> metadataObjects3 =
         tagMetaService.listAssociatedMetadataObjectsForTag(
-            TagManager.ofTagIdent(metalakeName, "tag2"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag2"));
 
     Assertions.assertEquals(2, metadataObjects3.size());
     Assertions.assertTrue(
@@ -649,7 +656,7 @@ public class TestTagMetaService extends TestJDBCBackend {
 
     List<MetadataObject> metadataObjects4 =
         tagMetaService.listAssociatedMetadataObjectsForTag(
-            TagManager.ofTagIdent(metalakeName, "tag2"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag2"));
 
     Assertions.assertEquals(1, metadataObjects4.size());
     Assertions.assertTrue(
@@ -659,7 +666,7 @@ public class TestTagMetaService extends TestJDBCBackend {
 
     List<MetadataObject> metadataObjects5 =
         tagMetaService.listAssociatedMetadataObjectsForTag(
-            TagManager.ofTagIdent(metalakeName, "tag2"));
+            NameIdentifierUtil.ofTag(metalakeName, "tag2"));
 
     Assertions.assertEquals(0, metadataObjects5.size());
   }
@@ -729,7 +736,7 @@ public class TestTagMetaService extends TestJDBCBackend {
         TagEntity.builder()
             .withId(RandomIdGenerator.INSTANCE.nextId())
             .withName("tag1")
-            .withNamespace(TagManager.ofTagNamespace(metalakeName))
+            .withNamespace(NamespaceUtil.ofTag(metalakeName))
             .withComment("comment")
             .withProperties(props)
             .withAuditInfo(auditInfo)
diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md
index 452fda4f82..957c3edbc3 100644
--- a/docs/gravitino-server-config.md
+++ b/docs/gravitino-server-config.md
@@ -124,6 +124,7 @@ Gravitino triggers a pre-event before the operation, a 
post-event after the comp
 | catalog operation                   | `CreateCatalogEvent`, 
`AlterCatalogEvent`, `DropCatalogEvent`, `LoadCatalogEvent`, 
`ListCatalogEvent`, `CreateCatalogFailureEvent`, `AlterCatalogFailureEvent`, 
`DropCatalogFailureEvent`, `LoadCatalogFailureEvent`, `ListCatalogFailureEvent` 
                                                                                
                                                                                
              | 0.5.0            |
 | metalake operation                  | `CreateMetalakeEvent`, 
`AlterMetalakeEvent`, `DropMetalakeEvent`, `LoadMetalakeEvent`, 
`ListMetalakeEvent`, `CreateMetalakeFailureEvent`, `AlterMetalakeFailureEvent`, 
`DropMetalakeFailureEvent`, `LoadMetalakeFailureEvent`, 
`ListMetalakeFailureEvent`                                                      
                                                                                
                               | 0.5.0            |
 | Iceberg REST server table operation | `IcebergCreateTableEvent`, 
`IcebergUpdateTableEvent`, `IcebergDropTableEvent`, `IcebergLoadTableEvent`, 
`IcebergListTableEvent`, `IcebergTableExistsEvent`, `IcebergRenameTableEvent`, 
`IcebergCreateTableFailureEvent`, `IcebergUpdateTableFailureEvent`, 
`IcebergDropTableFailureEvent`, `IcebergLoadTableFailureEvent`, 
`IcebergListTableFailureEvent`, `IcebergRenameTableFailureEvent`, 
`IcebergTableExistsFailureEvent` | 0.7.0-incubating |
+| tag operation                       | `ListTagsFailureEvent`, 
`ListTagInfoFailureEvent`, `CreateTagFailureEvent`, `GetTagFailureEvent`, 
`AlterTagFailureEvent`, `DeleteTagFailureEvent`, 
`ListMetadataObjectsForTagFailureEvent`, 
`ListTagsForMetadataObjectFailureEvent`, 
`ListTagsInfoForMetadataObjectFailureEvent`, 
`AssociateTagsForMetadataObjectFailureEvent`, 
`GetTagForMetadataObjectFailureEvent`                                           
                                                     [...]
 
 ##### Pre-event
 


Reply via email to