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

morrysnow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 14e208354d [Feature](Nereids) support nereids event for logging the 
cascades states and transformation.  (#13659)
14e208354d is described below

commit 14e208354de12395b31d142e9f325f3ad5c8dd94
Author: mch_ucchi <[email protected]>
AuthorDate: Thu Dec 1 21:42:40 2022 +0800

    [Feature](Nereids) support nereids event for logging the cascades states 
and transformation.  (#13659)
    
    Add an event producer, channel, consumer system to support the feature as 
title and you can turn it on using set
    enable_nereids_event = true;
    For more information, please see 
fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/README.md
---
 .../org/apache/doris/nereids/NereidsPlanner.java   |   9 +-
 .../java/org/apache/doris/nereids/jobs/Job.java    |  77 ++++++------
 .../doris/nereids/jobs/cascades/ApplyRuleJob.java  |  19 ++-
 .../nereids/jobs/cascades/CostAndEnforcerJob.java  |   1 +
 .../nereids/jobs/cascades/DeriveStatsJob.java      |  10 ++
 .../jobs/cascades/OptimizeGroupExpressionJob.java  |   1 +
 .../nereids/jobs/cascades/OptimizeGroupJob.java    |   4 +
 .../nereids/jobs/rewrite/RewriteBottomUpJob.java   |  13 ++
 .../nereids/jobs/rewrite/RewriteTopDownJob.java    |  15 ++-
 .../nereids/jobs/rewrite/VisitorRewriteJob.java    |   5 +
 .../apache/doris/nereids/memo/GroupExpression.java |   8 ++
 .../java/org/apache/doris/nereids/memo/Memo.java   |  28 ++++-
 .../apache/doris/nereids/metrics/CounterType.java  |  29 +++++
 .../org/apache/doris/nereids/metrics/Event.java    |  56 +++++++++
 .../apache/doris/nereids/metrics/EventChannel.java | 128 +++++++++++++++++++
 .../doris/nereids/metrics/EventConsumer.java       |  56 +++++++++
 .../doris/nereids/metrics/EventEnhancer.java       |  54 +++++++++
 .../apache/doris/nereids/metrics/EventFilter.java  |  37 ++++++
 .../doris/nereids/metrics/EventProducer.java       |  71 +++++++++++
 .../doris/nereids/metrics/EventSwitchParser.java   |  91 ++++++++++++++
 .../org/apache/doris/nereids/metrics/README.md     |  60 +++++++++
 .../doris/nereids/metrics/TracerSupplier.java      |  25 ++++
 .../nereids/metrics/consumer/FileDumpConsumer.java |  60 +++++++++
 .../nereids/metrics/consumer/LogConsumer.java      |  40 ++++++
 .../nereids/metrics/consumer/PrintConsumer.java    |  40 ++++++
 .../metrics/enhancer/AddCounterEventEnhancer.java  |  36 ++++++
 .../metrics/event/CostStateUpdateEvent.java        |  48 ++++++++
 .../doris/nereids/metrics/event/CounterEvent.java  |  77 ++++++++++++
 .../doris/nereids/metrics/event/EnforcerEvent.java |  56 +++++++++
 .../nereids/metrics/event/FunctionCallEvent.java   |  41 +++++++
 .../nereids/metrics/event/GroupMergeEvent.java     |  53 ++++++++
 .../doris/nereids/metrics/event/StateEvent.java    |  36 ++++++
 .../nereids/metrics/event/StatsStateEvent.java     |  44 +++++++
 .../nereids/metrics/event/TransformEvent.java      |  59 +++++++++
 .../properties/EnforceMissingPropertiesHelper.java |  10 +-
 .../doris/nereids/trees/plans/AbstractPlan.java    |  13 +-
 .../java/org/apache/doris/qe/SessionVariable.java  |  41 +++++++
 .../main/java/org/apache/doris/qe/VariableMgr.java |  13 ++
 .../apache/doris/nereids/metrics/EventTest.java    | 135 +++++++++++++++++++++
 39 files changed, 1539 insertions(+), 60 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
index 35a41b9e1f..aa381445dd 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
@@ -30,6 +30,7 @@ import org.apache.doris.nereids.jobs.batch.OptimizeRulesJob;
 import org.apache.doris.nereids.jobs.cascades.DeriveStatsJob;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.event.CounterEvent;
 import org.apache.doris.nereids.processor.post.PlanPostProcessors;
 import org.apache.doris.nereids.processor.pre.PlanPreprocessors;
 import org.apache.doris.nereids.properties.PhysicalProperties;
@@ -58,7 +59,6 @@ import java.util.stream.Collectors;
  */
 public class NereidsPlanner extends Planner {
     public static final Logger LOG = 
LogManager.getLogger(NereidsPlanner.class);
-
     private CascadesContext cascadesContext;
     private final StatementContext statementContext;
     private List<ScanNode> scanNodeList = null;
@@ -90,12 +90,7 @@ public class NereidsPlanner extends Planner {
         PhysicalPlanTranslator physicalPlanTranslator = new 
PhysicalPlanTranslator();
         PlanTranslatorContext planTranslatorContext = new 
PlanTranslatorContext(cascadesContext);
         if (ConnectContext.get().getSessionVariable().isEnableNereidsTrace()) {
-            String tree = physicalPlan.treeString();
-            System.out.println(tree);
-            LOG.info(tree);
-            String memo = cascadesContext.getMemo().toString();
-            System.out.println(memo);
-            LOG.info(memo);
+            CounterEvent.clearCounter();
         }
         PlanFragment root = physicalPlanTranslator.translatePlan(physicalPlan, 
planTranslatorContext);
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/Job.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/Job.java
index c6e1a4edd3..a0e45e1796 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/Job.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/Job.java
@@ -21,10 +21,18 @@ import 
org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.memo.CopyInResult;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.memo.Memo;
+import org.apache.doris.nereids.metrics.CounterType;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.TracerSupplier;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.enhancer.AddCounterEventEnhancer;
+import org.apache.doris.nereids.metrics.event.CounterEvent;
+import org.apache.doris.nereids.metrics.event.TransformEvent;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleSet;
 import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.qe.ConnectContext;
 
 import com.google.common.base.Preconditions;
 import org.apache.logging.log4j.LogManager;
@@ -38,13 +46,17 @@ import java.util.stream.Collectors;
 /**
  * Abstract class for all job using for analyze and optimize query plan in 
Nereids.
  */
-public abstract class Job {
+public abstract class Job implements TracerSupplier {
+    // counter tracer to count expression transform times.
+    protected static final EventProducer COUNTER_TRACER = new 
EventProducer(CounterEvent.class,
+            EventChannel.getDefaultChannel()
+                    .addEnhancers(new AddCounterEventEnhancer())
+                    .addConsumers(new LogConsumer(CounterEvent.class, 
EventChannel.LOG)));
     public final Logger logger = LogManager.getLogger(getClass());
 
     protected JobType type;
     protected JobContext context;
     protected boolean once;
-    protected final boolean enableTrace;
 
     public Job(JobType type, JobContext context) {
         this(type, context, true);
@@ -55,10 +67,6 @@ public abstract class Job {
         this.type = type;
         this.context = context;
         this.once = once;
-        ConnectContext connectContext = ConnectContext.get();
-        this.enableTrace = connectContext == null
-                ? false
-                : connectContext.getSessionVariable().isEnableNereidsTrace();
     }
 
     public void pushJob(Job job) {
@@ -88,48 +96,41 @@ public abstract class Job {
 
     public abstract void execute() throws AnalysisException;
 
+    public EventProducer getEventTracer() {
+        throw new UnsupportedOperationException("get_event_tracer is 
unsupported");
+    }
+
     protected Optional<CopyInResult> invokeRewriteRuleWithTrace(Rule rule, 
Plan before, Group targetGroup) {
         context.onInvokeRule(rule.getRuleType());
-
-        String traceBefore = enableTrace ? getPlanTraceLog() : null;
+        COUNTER_TRACER.log(CounterEvent.of(Memo.getStateId(),
+                CounterType.EXPRESSION_TRANSFORM, targetGroup, 
targetGroup.getLogicalExpression(), before));
 
         List<Plan> afters = rule.transform(before, 
context.getCascadesContext());
         Preconditions.checkArgument(afters.size() == 1);
         Plan after = afters.get(0);
-
-        if (after != before) {
-            CopyInResult result = context.getCascadesContext()
-                    .getMemo()
-                    .copyIn(after, targetGroup, rule.isRewrite());
-
-            if ((result.generateNewExpression || 
result.correspondingExpression.getOwnerGroup() != targetGroup)
-                    && enableTrace) {
-                String traceAfter = getPlanTraceLog();
-                printTraceLog(rule, traceBefore, traceAfter);
-            }
-
-            return Optional.of(result);
+        if (after == before) {
+            return Optional.empty();
         }
 
-        return Optional.empty();
-    }
-
-    protected String getPlanTraceLog() {
-        return context.getCascadesContext()
+        CopyInResult result = context.getCascadesContext()
                 .getMemo()
-                .copyOut(false)
-                .treeString();
-    }
+                .copyIn(after, targetGroup, rule.isRewrite());
 
-    protected String getMemoTraceLog() {
-        return context.getCascadesContext()
-                .getMemo()
-                .getRoot()
-                .treeString();
+        if (result.generateNewExpression || 
result.correspondingExpression.getOwnerGroup() != targetGroup) {
+            
getEventTracer().log(TransformEvent.of(targetGroup.getLogicalExpression(), 
before, afters,
+                            rule.getRuleType()), rule::isRewrite);
+        }
+
+        return Optional.of(result);
     }
 
-    protected void printTraceLog(Rule rule, String traceBefore, String 
traceAfter) {
-        logger.info("========== {} {} ==========\nbefore:\n{}\n\nafter:\n{}\n",
-                getClass().getSimpleName(), rule.getRuleType(), traceBefore, 
traceAfter);
+    /**
+     * count the job execution times of groupExpressions, all groupExpressions 
will be inclusive.
+     * TODO: count a specific groupExpression.
+     * @param groupExpression the groupExpression at current job.
+     */
+    protected void countJobExecutionTimesOfGroupExpressions(GroupExpression 
groupExpression) {
+        COUNTER_TRACER.log(CounterEvent.of(Memo.getStateId(), 
CounterType.JOB_EXECUTION,
+                groupExpression.getOwnerGroup(), groupExpression, 
groupExpression.getPlan()));
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
index 40cdfe1a64..31117c0507 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
@@ -23,6 +23,10 @@ import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.jobs.JobType;
 import org.apache.doris.nereids.memo.CopyInResult;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.event.TransformEvent;
 import org.apache.doris.nereids.pattern.GroupExpressionMatching;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.trees.plans.Plan;
@@ -34,6 +38,8 @@ import java.util.List;
  * Job to apply rule on {@link GroupExpression}.
  */
 public class ApplyRuleJob extends Job {
+    private static final EventProducer APPLY_RULE_TRACER = new 
EventProducer(TransformEvent.class,
+            EventChannel.getDefaultChannel().addConsumers(new 
LogConsumer(TransformEvent.class, EventChannel.LOG)));
     private final GroupExpression groupExpression;
     private final Rule rule;
 
@@ -55,14 +61,11 @@ public class ApplyRuleJob extends Job {
         if (groupExpression.hasApplied(rule)) {
             return;
         }
+        countJobExecutionTimesOfGroupExpressions(groupExpression);
 
         GroupExpressionMatching groupExpressionMatching
                 = new GroupExpressionMatching(rule.getPattern(), 
groupExpression);
         for (Plan plan : groupExpressionMatching) {
-            String traceBefore = enableTrace ? getMemoTraceLog() : null;
-            context.onInvokeRule(rule.getRuleType());
-
-            boolean changed = false;
             List<Plan> newPlans = rule.transform(plan, 
context.getCascadesContext());
             for (Plan newPlan : newPlans) {
                 CopyInResult result = context.getCascadesContext()
@@ -71,8 +74,6 @@ public class ApplyRuleJob extends Job {
                 if (!result.generateNewExpression) {
                     continue;
                 }
-
-                changed = true;
                 GroupExpression newGroupExpression = 
result.correspondingExpression;
                 if (newPlan instanceof LogicalPlan) {
                     pushJob(new OptimizeGroupExpressionJob(newGroupExpression, 
context));
@@ -80,10 +81,8 @@ public class ApplyRuleJob extends Job {
                 } else {
                     pushJob(new CostAndEnforcerJob(newGroupExpression, 
context));
                 }
-            }
-            if (changed && enableTrace) {
-                String traceAfter = getMemoTraceLog();
-                printTraceLog(rule, traceBefore, traceAfter);
+                APPLY_RULE_TRACER.log(TransformEvent.of(groupExpression, plan, 
newPlans, rule.getRuleType()),
+                        rule::isRewrite);
             }
         }
         groupExpression.setApplied(rule);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/CostAndEnforcerJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/CostAndEnforcerJob.java
index f684e9430d..f11f693cf7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/CostAndEnforcerJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/CostAndEnforcerJob.java
@@ -101,6 +101,7 @@ public class CostAndEnforcerJob extends Job implements 
Cloneable {
      */
     @Override
     public void execute() {
+        countJobExecutionTimesOfGroupExpressions(groupExpression);
         // Do init logic of root plan/groupExpr of `subplan`, only run once 
per task.
         if (curChildIndex == -1) {
             curNodeCost = 0;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/DeriveStatsJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/DeriveStatsJob.java
index 8797327311..f274f5e6eb 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/DeriveStatsJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/DeriveStatsJob.java
@@ -22,12 +22,19 @@ import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.jobs.JobType;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.event.StatsStateEvent;
 import org.apache.doris.nereids.stats.StatsCalculator;
 
 /**
  * Job to derive stats for {@link GroupExpression} in {@link 
org.apache.doris.nereids.memo.Memo}.
  */
 public class DeriveStatsJob extends Job {
+    private static final EventProducer STATS_STATE_TRACER = new EventProducer(
+            StatsStateEvent.class,
+            EventChannel.getDefaultChannel().addConsumers(new 
LogConsumer(StatsStateEvent.class, EventChannel.LOG)));
     private final GroupExpression groupExpression;
     private boolean deriveChildren;
 
@@ -56,6 +63,7 @@ public class DeriveStatsJob extends Job {
 
     @Override
     public void execute() {
+        countJobExecutionTimesOfGroupExpressions(groupExpression);
         if (!deriveChildren) {
             deriveChildren = true;
             pushJob(new DeriveStatsJob(this));
@@ -66,6 +74,8 @@ public class DeriveStatsJob extends Job {
             }
         } else {
             StatsCalculator.estimate(groupExpression);
+            STATS_STATE_TRACER.log(StatsStateEvent.of(groupExpression,
+                    groupExpression.getOwnerGroup().getStatistics()));
         }
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java
index c530bb2b4f..18e53463ea 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java
@@ -40,6 +40,7 @@ public class OptimizeGroupExpressionJob extends Job {
 
     @Override
     public void execute() {
+        countJobExecutionTimesOfGroupExpressions(groupExpression);
         List<Rule> validRules = new ArrayList<>();
         List<Rule> implementationRules = getRuleSet().getImplementationRules();
         List<Rule> explorationRules = getRuleSet().getExplorationRules();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
index 8395adfebe..2bda4ce569 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
@@ -22,6 +22,9 @@ import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.jobs.JobType;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.memo.Memo;
+import org.apache.doris.nereids.metrics.CounterType;
+import org.apache.doris.nereids.metrics.event.CounterEvent;
 
 import java.util.List;
 
@@ -38,6 +41,7 @@ public class OptimizeGroupJob extends Job {
 
     @Override
     public void execute() {
+        COUNTER_TRACER.log(CounterEvent.of(Memo.getStateId(), 
CounterType.JOB_EXECUTION, group, null, null));
         if (group.getCostLowerBound() > context.getCostUpperBound()
                 || 
group.getLowestCostPlan(context.getRequiredProperties()).isPresent()) {
             return;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
index f9f74e5b81..22a1fb7f26 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
@@ -24,6 +24,10 @@ import org.apache.doris.nereids.jobs.JobType;
 import org.apache.doris.nereids.memo.CopyInResult;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.event.TransformEvent;
 import org.apache.doris.nereids.pattern.GroupExpressionMatching;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleFactory;
@@ -38,6 +42,9 @@ import java.util.stream.Collectors;
  * Bottom up job for rewrite, use pattern match.
  */
 public class RewriteBottomUpJob extends Job {
+    private static final EventProducer RULE_TRANSFORM_TRACER = new 
EventProducer(
+            TransformEvent.class,
+            EventChannel.getDefaultChannel().addConsumers(new 
LogConsumer(TransformEvent.class, EventChannel.LOG)));
     private final Group group;
     private final List<Rule> rules;
     private final boolean childrenOptimized;
@@ -60,6 +67,11 @@ public class RewriteBottomUpJob extends Job {
         this.childrenOptimized = childrenOptimized;
     }
 
+    @Override
+    public EventProducer getEventTracer() {
+        return RULE_TRANSFORM_TRACER;
+    }
+
     @Override
     public void execute() throws AnalysisException {
         GroupExpression logicalExpression = group.getLogicalExpression();
@@ -72,6 +84,7 @@ public class RewriteBottomUpJob extends Job {
             return;
         }
 
+        countJobExecutionTimesOfGroupExpressions(logicalExpression);
         List<Rule> validRules = getValidRules(logicalExpression, rules);
         for (Rule rule : validRules) {
             GroupExpressionMatching groupExpressionMatching
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
index fe9fdcf747..6baa6b1e5a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
@@ -17,12 +17,17 @@
 
 package org.apache.doris.nereids.jobs.rewrite;
 
+import org.apache.doris.nereids.NereidsPlanner;
 import org.apache.doris.nereids.jobs.Job;
 import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.jobs.JobType;
 import org.apache.doris.nereids.memo.CopyInResult;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.event.TransformEvent;
 import org.apache.doris.nereids.pattern.GroupExpressionMatching;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleFactory;
@@ -39,6 +44,9 @@ import java.util.stream.Collectors;
  * Top down job for rewrite, use pattern match.
  */
 public class RewriteTopDownJob extends Job {
+    private static final EventProducer RULE_TRANSFORM_TRACER = new 
EventProducer(
+            TransformEvent.class,
+            EventChannel.getDefaultChannel().addConsumers(new 
LogConsumer(TransformEvent.class, NereidsPlanner.LOG)));
     private final Group group;
     private final List<Rule> rules;
 
@@ -65,10 +73,15 @@ public class RewriteTopDownJob extends Job {
         this.rules = Objects.requireNonNull(rules, "rules cannot be null");
     }
 
+    @Override
+    public EventProducer getEventTracer() {
+        return RULE_TRANSFORM_TRACER;
+    }
+
     @Override
     public void execute() {
         GroupExpression logicalExpression = group.getLogicalExpression();
-
+        countJobExecutionTimesOfGroupExpressions(logicalExpression);
         List<Rule> validRules = getValidRules(logicalExpression, rules);
         for (Rule rule : validRules) {
             Preconditions.checkArgument(rule.isRewrite(),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/VisitorRewriteJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/VisitorRewriteJob.java
index f579de23ad..9510a4147c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/VisitorRewriteJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/VisitorRewriteJob.java
@@ -23,6 +23,9 @@ import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.jobs.JobType;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.memo.Memo;
+import org.apache.doris.nereids.metrics.CounterType;
+import org.apache.doris.nereids.metrics.event.CounterEvent;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter;
 
@@ -49,6 +52,8 @@ public class VisitorRewriteJob extends Job {
     public void execute() {
         GroupExpression logicalExpression = group.getLogicalExpression();
         Plan root = 
context.getCascadesContext().getMemo().copyOut(logicalExpression, true);
+        COUNTER_TRACER.log(CounterEvent.of(Memo.getStateId(), 
CounterType.JOB_EXECUTION, group, logicalExpression,
+                root));
         Plan rewrittenRoot = root.accept(planRewriter, context);
         context.getCascadesContext().getMemo().copyIn(rewrittenRoot, group, 
true);
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java
index 9fedd98523..d7c3631ed8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java
@@ -20,6 +20,10 @@ package org.apache.doris.nereids.memo;
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.analyzer.UnboundRelation;
 import org.apache.doris.nereids.cost.CostEstimate;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.event.CostStateUpdateEvent;
 import org.apache.doris.nereids.properties.PhysicalProperties;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleType;
@@ -41,6 +45,9 @@ import java.util.Optional;
  * Representation for group expression in cascades optimizer.
  */
 public class GroupExpression {
+    private static final EventProducer COST_STATE_TRACER = new 
EventProducer(CostStateUpdateEvent.class,
+            EventChannel.getDefaultChannel().addConsumers(new 
LogConsumer(CostStateUpdateEvent.class,
+                    EventChannel.LOG)));
     private double cost = 0.0;
     private CostEstimate costEstimate = null;
     private Group ownerGroup;
@@ -172,6 +179,7 @@ public class GroupExpression {
      */
     public boolean updateLowestCostTable(PhysicalProperties outputProperties,
             List<PhysicalProperties> childrenInputProperties, double cost) {
+        COST_STATE_TRACER.log(CostStateUpdateEvent.of(this, cost, 
outputProperties));
         if (lowestCostTable.containsKey(outputProperties)) {
             if (lowestCostTable.get(outputProperties).first > cost) {
                 lowestCostTable.put(outputProperties, Pair.of(cost, 
childrenInputProperties));
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
index 2fa73db681..1c24ed1772 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
@@ -20,6 +20,10 @@ package org.apache.doris.nereids.memo;
 import org.apache.doris.common.IdGenerator;
 import org.apache.doris.nereids.CascadesContext;
 import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.event.GroupMergeEvent;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.rules.analysis.CTEContext;
 import org.apache.doris.nereids.trees.expressions.Expression;
@@ -28,6 +32,7 @@ import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.statistics.StatsDeriveResult;
 
 import com.google.common.base.Preconditions;
@@ -48,6 +53,9 @@ import javax.annotation.Nullable;
  */
 public class Memo {
     // generate group id in memo is better for test, since we can reproduce 
exactly same Memo.
+    private static final EventProducer GROUP_MERGE_TRACER = new 
EventProducer(GroupMergeEvent.class,
+            EventChannel.getDefaultChannel().addConsumers(new 
LogConsumer(GroupMergeEvent.class, EventChannel.LOG)));
+    private static long stateId = 0;
     private final IdGenerator<GroupId> groupIdGenerator = 
GroupId.createGenerator();
     private final Map<GroupId, Group> groups = Maps.newLinkedHashMap();
     // we could not use Set, because Set does not have get method.
@@ -75,6 +83,10 @@ public class Memo {
         return groupExpressions;
     }
 
+    public static long getStateId() {
+        return stateId;
+    }
+
     /**
      * Add plan to Memo.
      *
@@ -86,10 +98,21 @@ public class Memo {
      *                       is the corresponding group expression of the plan
      */
     public CopyInResult copyIn(Plan plan, @Nullable Group target, boolean 
rewrite) {
+        CopyInResult result;
         if (rewrite) {
-            return doRewrite(plan, target);
+            result = doRewrite(plan, target);
         } else {
-            return doCopyIn(plan, target);
+            result = doCopyIn(plan, target);
+        }
+        maybeAddStateId(result);
+        return result;
+    }
+
+    private void maybeAddStateId(CopyInResult result) {
+        if (ConnectContext.get() != null
+                && 
ConnectContext.get().getSessionVariable().isEnableNereidsTrace()
+                && result.generateNewExpression) {
+            stateId++;
         }
     }
 
@@ -407,6 +430,7 @@ public class Memo {
                 needReplaceChild.add(groupExpression);
             }
         }
+        GROUP_MERGE_TRACER.log(GroupMergeEvent.of(source, destination, 
needReplaceChild));
         for (GroupExpression groupExpression : needReplaceChild) {
             // After change GroupExpression children, the hashcode will change,
             // so need to reinsert into map.
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/CounterType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/CounterType.java
new file mode 100644
index 0000000000..c5ded21a27
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/CounterType.java
@@ -0,0 +1,29 @@
+// 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.doris.nereids.metrics;
+
+/**
+ * counter type
+ */
+public enum CounterType {
+    PLAN_CONSTRUCTOR,
+    EXPRESSION_TRANSFORM,
+    JOB_EXECUTION,
+    EXPRESSION_CONSTRUCTOR,
+    FUNCTION_CALL,
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/Event.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/Event.java
new file mode 100644
index 0000000000..1a31076658
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/Event.java
@@ -0,0 +1,56 @@
+// 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.doris.nereids.metrics;
+
+import org.apache.doris.nereids.util.Utils;
+import org.apache.doris.qe.ConnectContext;
+
+/**
+ * event
+ */
+public abstract class Event implements Cloneable {
+    private final long stateId;
+
+    protected Event() {
+        this.stateId = -1;
+    }
+
+    protected Event(long stateId) {
+        this.stateId = stateId;
+    }
+
+    protected static boolean checkConnectContext(Class<? extends Event> 
targetClass) {
+        return ConnectContext.get() != null
+                && 
ConnectContext.get().getSessionVariable().isEnableNereidsTrace()
+                && 
ConnectContext.get().getSessionVariable().getParsedNereidsEventMode().contains(targetClass);
+    }
+
+    public final String toJson() {
+        return Utils.toSqlString("Event", "StateId", stateId);
+    }
+
+    @Override
+    public String toString() {
+        return toJson();
+    }
+
+    @Override
+    public Event clone() throws CloneNotSupportedException {
+        return (Event) super.clone();
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventChannel.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventChannel.java
new file mode 100644
index 0000000000..83e844a0b1
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventChannel.java
@@ -0,0 +1,128 @@
+// 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.doris.nereids.metrics;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * event channel
+ */
+public class EventChannel {
+    public static final Logger LOG = LogManager.getLogger(EventChannel.class);
+    private static final EventChannel DEFAULT_CHANNEL = new 
EventChannel().start();
+    private final Map<Class<? extends Event>, List<EventConsumer>> consumers = 
Maps.newHashMap();
+    private final Map<Class<? extends Event>, EventEnhancer> enhancers = 
Maps.newHashMap();
+    private final BlockingQueue<Event> queue = new LinkedBlockingQueue<>(4096);
+    private final AtomicBoolean isStop = new AtomicBoolean(false);
+    private Thread thread = null;
+
+    public void add(Event e) {
+        try {
+            queue.put(e);
+        } catch (Exception exception) {
+            LOG.warn("Exception when put event: ", exception);
+        }
+    }
+
+    public synchronized EventChannel addConsumers(EventConsumer ...consumers) {
+        for (EventConsumer consumer : consumers) {
+            this.consumers.computeIfAbsent(consumer.getTargetClass(), k -> 
Lists.newArrayList()).add(consumer);
+        }
+        return this;
+    }
+
+    public synchronized EventChannel addEnhancers(EventEnhancer ...enhancers) {
+        for (EventEnhancer enhancer : enhancers) {
+            this.enhancers.putIfAbsent(enhancer.getTargetClass(), enhancer);
+        }
+        return this;
+    }
+
+    public static EventChannel getDefaultChannel() {
+        return DEFAULT_CHANNEL;
+    }
+
+    private class Worker implements Runnable {
+        @Override
+        public void run() {
+            while (!isStop.get() || !queue.isEmpty()) {
+                try {
+                    Event e = queue.poll();
+                    if (e == null) {
+                        continue;
+                    }
+                    for (EventConsumer consumer : consumers.get(e.getClass())) 
{
+                        if (enhancers.containsKey(e.getClass())) {
+                            enhancers.get(e.getClass()).enhance(e);
+                        }
+                        consumer.consume(e);
+                    }
+                } catch (Exception exception) {
+                    LOG.warn("encounter exception when push event: ", 
exception);
+                }
+            }
+            for (List<EventConsumer> consumerList : consumers.values()) {
+                for (EventConsumer consumer : consumerList) {
+                    consumer.close();
+                }
+            }
+        }
+    }
+
+    /**
+     * worker thread start.
+     */
+    public EventChannel start() {
+        isStop.set(false);
+        if (thread == null) {
+            thread = new Thread(new Worker(), "nereids_event");
+            thread.setDaemon(true);
+            try {
+                thread.start();
+            } catch (IllegalThreadStateException e) {
+                LOG.warn("start worker failed: ", e);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * stop channel
+     */
+    public void stop() {
+        isStop.set(true);
+        if (thread != null) {
+            try {
+                thread.join();
+            } catch (InterruptedException e) {
+                LOG.warn("join worker failed.", e);
+            } finally {
+                thread = null;
+            }
+        }
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventConsumer.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventConsumer.java
new file mode 100644
index 0000000000..9979c322c7
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventConsumer.java
@@ -0,0 +1,56 @@
+// 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.doris.nereids.metrics;
+
+import java.util.Objects;
+
+/**
+ * consumer
+ */
+public abstract class EventConsumer {
+    private final Class<? extends Event> targetClass;
+
+    protected EventConsumer(Class<? extends Event> targetClass) {
+        this.targetClass = targetClass;
+    }
+
+    public abstract void consume(Event event);
+
+    public Class<? extends Event> getTargetClass() {
+        return targetClass;
+    }
+
+    public void close() {}
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        EventConsumer consumer = (EventConsumer) o;
+        return Objects.equals(targetClass, consumer.targetClass);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(targetClass);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventEnhancer.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventEnhancer.java
new file mode 100644
index 0000000000..86c89d0fca
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventEnhancer.java
@@ -0,0 +1,54 @@
+// 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.doris.nereids.metrics;
+
+import java.util.Objects;
+
+/**
+ * event enhancer
+ */
+public abstract class EventEnhancer {
+    private final Class<? extends Event> targetClass;
+
+    public EventEnhancer(Class<? extends Event> targetClass) {
+        this.targetClass = targetClass;
+    }
+
+    public Class<? extends Event> getTargetClass() {
+        return targetClass;
+    }
+
+    public abstract void enhance(Event e);
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        EventEnhancer enhancer = (EventEnhancer) o;
+        return Objects.equals(targetClass, enhancer.targetClass);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(targetClass);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventFilter.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventFilter.java
new file mode 100644
index 0000000000..1bc9fe6554
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventFilter.java
@@ -0,0 +1,37 @@
+// 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.doris.nereids.metrics;
+
+/**
+ * event filter
+ */
+public abstract class EventFilter {
+    private final Class<? extends Event> targetClass;
+
+    public EventFilter(Class<? extends Event> targetClass) {
+        this.targetClass = targetClass;
+    }
+
+    public Event checkEvent(Event event) {
+        return event;
+    }
+
+    public Class<? extends Event> getTargetClass() {
+        return targetClass;
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventProducer.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventProducer.java
new file mode 100644
index 0000000000..67b9bcfaef
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventProducer.java
@@ -0,0 +1,71 @@
+// 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.doris.nereids.metrics;
+
+import com.google.common.base.Preconditions;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * event producer
+ */
+public class EventProducer {
+    private final EventChannel channel;
+    private final List<EventFilter> filters;
+    private final Class<? extends Event> eventClass;
+
+    /**
+     * constructor
+     * @param eventClass event's class info for the producer, a producer can 
only supply one type of event.
+     * @param filters event's filter, the event that satisfy the filter's 
condition can be submitted to the channel.
+     *        the filters are AND in logic, see checkAndLog for detail.
+     * @param channel the channel to transport event to consumer.
+     */
+    public EventProducer(Class<? extends Event> eventClass, EventChannel 
channel, EventFilter ...filters) {
+        this.channel = channel;
+        Preconditions.checkArgument(Arrays.stream(filters).allMatch(f -> 
f.getTargetClass().equals(eventClass)));
+        this.filters = Arrays.asList(filters);
+        this.eventClass = eventClass;
+    }
+
+    private void checkAndLog(Event event) {
+        for (EventFilter filter : filters) {
+            event = filter.checkEvent(event);
+            if (event == null) {
+                return;
+            }
+        }
+        channel.add(event);
+    }
+
+    public void log(Event event) {
+        if (event == null || channel == null) {
+            return;
+        }
+        Preconditions.checkArgument(event.getClass().equals(eventClass));
+        checkAndLog(event);
+    }
+
+    public void log(Event event, Supplier<Boolean> f) {
+        if (f.get()) {
+            log(event);
+        }
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventSwitchParser.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventSwitchParser.java
new file mode 100644
index 0000000000..2bd5287b0e
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/EventSwitchParser.java
@@ -0,0 +1,91 @@
+// 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.doris.nereids.metrics;
+
+import org.apache.doris.nereids.metrics.event.CostStateUpdateEvent;
+import org.apache.doris.nereids.metrics.event.CounterEvent;
+import org.apache.doris.nereids.metrics.event.EnforcerEvent;
+import org.apache.doris.nereids.metrics.event.FunctionCallEvent;
+import org.apache.doris.nereids.metrics.event.GroupMergeEvent;
+import org.apache.doris.nereids.metrics.event.StatsStateEvent;
+import org.apache.doris.nereids.metrics.event.TransformEvent;
+
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * parser
+ */
+public class EventSwitchParser {
+    private static final Map<String, Class<? extends Event>> EVENT_TYPE_SET =
+            new Builder<String, Class<? extends Event>>()
+            .put("costState", CostStateUpdateEvent.class)
+            .put("counter", CounterEvent.class)
+            .put("enforcer", EnforcerEvent.class)
+            .put("functionCall", FunctionCallEvent.class)
+            .put("groupMerge", GroupMergeEvent.class)
+            .put("statsState", StatsStateEvent.class)
+            .put("transform", TransformEvent.class)
+            .build();
+
+    /**
+     * parse
+     */
+    public static Set<Class<? extends Event>> parse(List<String> 
eventTypeMode) {
+        if ("all".equals(eventTypeMode.get(0))) {
+            if (eventTypeMode.size() == 1) {
+                return ImmutableSet.copyOf(EVENT_TYPE_SET.values());
+            }
+            Map targetClasses = Maps.newHashMap(EVENT_TYPE_SET);
+            for (String str : eventTypeMode.subList(2, eventTypeMode.size())) {
+                targetClasses.remove(str);
+            }
+            return ImmutableSet.copyOf(targetClasses.values());
+        }
+        return eventTypeMode.stream()
+                .filter(EVENT_TYPE_SET::containsKey)
+                .map(str -> ((Class<? extends Event>) EVENT_TYPE_SET.get(str)))
+                .collect(ImmutableSet.toImmutableSet());
+    }
+
+    /**
+     * check
+     */
+    public static List<String> checkEventModeStringAndSplit(String 
eventTypeMode) {
+        List<String> strings = 
Arrays.stream(eventTypeMode.toLowerCase().split("[\\s+,]"))
+                .map(String::trim)
+                .collect(Collectors.toList());
+        if (strings.size() == 0) {
+            return null;
+        } else if ("all".equals(strings.get(0))) {
+            if (strings.size() == 1) {
+                return strings;
+            } else if (strings.size() == 2 || 
!"except".equals(strings.get(1))) {
+                return null;
+            }
+        }
+        return strings;
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/README.md 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/README.md
new file mode 100644
index 0000000000..8660e6cc09
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/README.md
@@ -0,0 +1,60 @@
+# Docs of Event System
+
+## Introduction
+
+Event System is designed for log the event when cascades running like: rule 
transformation and cost calculation for specific physical properties, see event 
module detailed.
+
+## Usage
+
+Data Streaming Graph:
+
+```
+EventProducer::log() --> create an event and try to log it to channel
+        │
+        ▼
+EventFilter::checkEvent() --> check an event with the condition in filter, 
return nullif failed.
+        │
+        ▼
+EventChannel::add() --> add the event to channel
+        │
+        ▼
+EventChannel::Worker::run() --> a while loop to consume the event
+        │
+        ▼
+EventEnhancer::enhance() --> do something before consume the event
+        │
+        ▼
+EventConsumer::consume() --> consume the event.
+```
+
+- Use it in your program
+
+1. Set NereidsEventMode, see format below.
+2. Create a public static EventChannel and add enhancers and consumers, lastly 
set connectContext.
+3. Create a static EventProducer at the class where you want to submit event.
+4. Set the class info of an event to the EventProducer.
+5. Register the channel and filter to the EventProducer.
+6. Call EventProducer::log to submit event.
+
+- Create a new type of Consumer
+
+Write a new class override the Consumer and implement consume method.
+
+- Create a new type of Event
+
+Write a new class override the Event is ok.
+
+- Create a new type of Enhancer
+
+Write a new class override the Enhancer and implement enhance method.
+
+- Create a new type of Filter
+
+Write a new class override the Filter and implement filter method.
+
+See the classes have written as example for detail.
+
+NereidsEventMode format
+all -> use all event
+all except event_1, event_2, ..., event_n -> use all events excluding the 
event_1~n
+event_1, event_2, ..., event_n -> use event_1~n
\ No newline at end of file
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/TracerSupplier.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/TracerSupplier.java
new file mode 100644
index 0000000000..b423b6528e
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/TracerSupplier.java
@@ -0,0 +1,25 @@
+// 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.doris.nereids.metrics;
+
+/**
+ * tracer supplier
+ */
+public interface TracerSupplier {
+    EventProducer getEventTracer();
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/FileDumpConsumer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/FileDumpConsumer.java
new file mode 100644
index 0000000000..ea71d041b4
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/FileDumpConsumer.java
@@ -0,0 +1,60 @@
+// 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.doris.nereids.metrics.consumer;
+
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.metrics.EventConsumer;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * file dump consumer
+ */
+public class FileDumpConsumer extends EventConsumer {
+    private static final Logger LOG = 
LogManager.getLogger(FileDumpConsumer.class);
+    private final FileOutputStream fs;
+
+    public FileDumpConsumer(Class<? extends Event> eventClass, String 
fileName) throws FileNotFoundException {
+        super(eventClass);
+        this.fs = new FileOutputStream(fileName);
+    }
+
+    @Override
+    public void consume(Event event) {
+        try {
+            fs.write(event.toString().getBytes(StandardCharsets.UTF_8));
+        } catch (IOException e) {
+            LOG.warn("write to file encounter exception: ", e);
+        }
+    }
+
+    @Override
+    public void close() {
+        try {
+            fs.close();
+        } catch (IOException e) {
+            LOG.warn("close file output stream encounter: ", e);
+        }
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/LogConsumer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/LogConsumer.java
new file mode 100644
index 0000000000..679b8ff442
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/LogConsumer.java
@@ -0,0 +1,40 @@
+// 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.doris.nereids.metrics.consumer;
+
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.metrics.EventConsumer;
+
+import org.apache.logging.log4j.Logger;
+
+/**
+ * log consumer
+ */
+public class LogConsumer extends EventConsumer {
+    private final Logger logger;
+
+    public LogConsumer(Class<? extends Event> targetClass, Logger logger) {
+        super(targetClass);
+        this.logger = logger;
+    }
+
+    @Override
+    public void consume(Event e) {
+        logger.info(e.toString());
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/PrintConsumer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/PrintConsumer.java
new file mode 100644
index 0000000000..16e65fc747
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/consumer/PrintConsumer.java
@@ -0,0 +1,40 @@
+// 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.doris.nereids.metrics.consumer;
+
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.metrics.EventConsumer;
+
+import java.io.PrintStream;
+
+/**
+ * print consumer
+ */
+public class PrintConsumer extends EventConsumer {
+    private final PrintStream printStream;
+
+    public PrintConsumer(Class<? extends Event> targetClass, PrintStream 
printStream) {
+        super(targetClass);
+        this.printStream = printStream;
+    }
+
+    @Override
+    public void consume(Event event) {
+        printStream.println(event.toString());
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/enhancer/AddCounterEventEnhancer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/enhancer/AddCounterEventEnhancer.java
new file mode 100644
index 0000000000..90d442d510
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/enhancer/AddCounterEventEnhancer.java
@@ -0,0 +1,36 @@
+// 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.doris.nereids.metrics.enhancer;
+
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.metrics.EventEnhancer;
+import org.apache.doris.nereids.metrics.event.CounterEvent;
+
+/**
+ * add counter event enhancer
+ */
+public class AddCounterEventEnhancer extends EventEnhancer {
+    public AddCounterEventEnhancer() {
+        super(CounterEvent.class);
+    }
+
+    @Override
+    public void enhance(Event e) {
+        CounterEvent.updateCounter(((CounterEvent) e).getCounterType());
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/CostStateUpdateEvent.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/CostStateUpdateEvent.java
new file mode 100644
index 0000000000..312fc60d2a
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/CostStateUpdateEvent.java
@@ -0,0 +1,48 @@
+// 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.doris.nereids.metrics.event;
+
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.util.Utils;
+
+/**
+ * cost state event
+ */
+public class CostStateUpdateEvent extends StateEvent {
+    private final double cost;
+    private final PhysicalProperties physicalProperties;
+
+    private CostStateUpdateEvent(GroupExpression groupExpression, double cost, 
PhysicalProperties physicalProperties) {
+        super(groupExpression);
+        this.cost = cost;
+        this.physicalProperties = physicalProperties;
+    }
+
+    public static CostStateUpdateEvent of(GroupExpression groupExpression, 
double cost,
+            PhysicalProperties physicalProperties) {
+        return checkConnectContext(CostStateUpdateEvent.class)
+                ? new CostStateUpdateEvent(groupExpression, cost, 
physicalProperties) : null;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.toSqlString("CostStateEvent", "groupExpression", 
getGroupExpression(),
+                "cost", cost, "physicalProperties", physicalProperties);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/CounterEvent.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/CounterEvent.java
new file mode 100644
index 0000000000..024dd53941
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/CounterEvent.java
@@ -0,0 +1,77 @@
+// 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.doris.nereids.metrics.event;
+
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.CounterType;
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.util.Utils;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * counter event
+ */
+public class CounterEvent extends Event {
+    private static final Map<CounterType, Long> COUNTER_MAP = 
Maps.newHashMap();
+    private final CounterType counterType;
+    private final Group group;
+    private final GroupExpression groupExpression;
+    private final Plan plan;
+
+    /**
+     * counter event
+     */
+    private CounterEvent(long stateId, CounterType counterType, Group group,
+            GroupExpression groupExpression, Plan plan) {
+        super(stateId);
+        this.counterType = counterType;
+        this.group = group;
+        this.groupExpression = groupExpression;
+        this.plan = plan;
+    }
+
+    public static CounterEvent of(long stateId, CounterType counterType, Group 
group,
+            GroupExpression groupExpression, Plan plan) {
+        return checkConnectContext(CounterEvent.class)
+                ? new CounterEvent(stateId, counterType, group, 
groupExpression, plan) : null;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.toSqlString("CounterEvent", "count", 
COUNTER_MAP.get(counterType),
+                "count", counterType, "group", group,
+                "groupExpression", groupExpression, "plan", plan);
+    }
+
+    public static void updateCounter(CounterType counterType) {
+        COUNTER_MAP.compute(counterType, (t, l) -> l == null ? 1L : l + 1);
+    }
+
+    public static void clearCounter() {
+        COUNTER_MAP.clear();
+    }
+
+    public CounterType getCounterType() {
+        return counterType;
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/EnforcerEvent.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/EnforcerEvent.java
new file mode 100644
index 0000000000..50f085295e
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/EnforcerEvent.java
@@ -0,0 +1,56 @@
+// 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.doris.nereids.metrics.event;
+
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
+import org.apache.doris.nereids.util.Utils;
+
+/**
+ * enforcer event
+ */
+public class EnforcerEvent extends Event {
+    private final GroupExpression groupExpression;
+    private final PhysicalPlan enforce;
+    private final PhysicalProperties before;
+    private final PhysicalProperties after;
+
+    private EnforcerEvent(GroupExpression groupExpression, PhysicalPlan 
enforce, PhysicalProperties before,
+            PhysicalProperties after) {
+        this.groupExpression = groupExpression;
+        this.enforce = enforce;
+        this.before = before;
+        this.after = after;
+    }
+
+    public static EnforcerEvent of(GroupExpression groupExpression, 
PhysicalPlan enforce, PhysicalProperties before,
+            PhysicalProperties after) {
+        return checkConnectContext(EnforcerEvent.class)
+                ? new EnforcerEvent(groupExpression, enforce, before, after) : 
null;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.toSqlString("EnforcerEvent", "groupExpression", 
groupExpression,
+                "enforce", enforce,
+                "before", before,
+                "after", after);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/FunctionCallEvent.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/FunctionCallEvent.java
new file mode 100644
index 0000000000..775f0990da
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/FunctionCallEvent.java
@@ -0,0 +1,41 @@
+// 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.doris.nereids.metrics.event;
+
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.util.Utils;
+
+/**
+ * function call event
+ */
+public class FunctionCallEvent extends Event {
+    private final String callFuncNameAndLine;
+
+    private FunctionCallEvent(String callFuncNameAndLine) {
+        this.callFuncNameAndLine = callFuncNameAndLine;
+    }
+
+    public static FunctionCallEvent of(String callFuncNameAndLine) {
+        return checkConnectContext(FunctionCallEvent.class) ? new 
FunctionCallEvent(callFuncNameAndLine) : null;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.toSqlString("FunctionCallEvent", "callFuncNameAndLine='", 
callFuncNameAndLine);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/GroupMergeEvent.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/GroupMergeEvent.java
new file mode 100644
index 0000000000..b0ec57be03
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/GroupMergeEvent.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.doris.nereids.metrics.event;
+
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.util.Utils;
+
+import java.util.List;
+
+/**
+ * group merge event
+ */
+public class GroupMergeEvent extends Event {
+    private final Group source;
+    private final Group destination;
+    private final List<GroupExpression> needReplaceGroupExpressions;
+
+    private GroupMergeEvent(Group source, Group destination, 
List<GroupExpression> needReplaceGroupExpressions) {
+        this.source = source;
+        this.destination = destination;
+        this.needReplaceGroupExpressions = needReplaceGroupExpressions;
+    }
+
+    public static GroupMergeEvent of(Group source, Group destination,
+            List<GroupExpression> needReplaceGroupExpressions) {
+        return checkConnectContext(GroupMergeEvent.class)
+                ? new GroupMergeEvent(source, destination, 
needReplaceGroupExpressions) : null;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.toSqlString("GroupMergeEvent", "source", source,
+                "destination", destination,
+                "needReplaceGroupExpressions", needReplaceGroupExpressions);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/StateEvent.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/StateEvent.java
new file mode 100644
index 0000000000..21f415768c
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/StateEvent.java
@@ -0,0 +1,36 @@
+// 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.doris.nereids.metrics.event;
+
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.Event;
+
+/**
+ * state event
+ */
+public abstract class StateEvent extends Event {
+    private final GroupExpression groupExpression;
+
+    protected StateEvent(GroupExpression groupExpression) {
+        this.groupExpression = groupExpression;
+    }
+
+    protected GroupExpression getGroupExpression() {
+        return groupExpression;
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/StatsStateEvent.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/StatsStateEvent.java
new file mode 100644
index 0000000000..2dd420ef4f
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/StatsStateEvent.java
@@ -0,0 +1,44 @@
+// 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.doris.nereids.metrics.event;
+
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.util.Utils;
+import org.apache.doris.statistics.StatsDeriveResult;
+
+/**
+ * stats state event
+ */
+public class StatsStateEvent extends StateEvent {
+    private final StatsDeriveResult statsDeriveResult;
+
+    private StatsStateEvent(GroupExpression groupExpression, StatsDeriveResult 
statsDeriveResult) {
+        super(groupExpression);
+        this.statsDeriveResult = statsDeriveResult;
+    }
+
+    public static StatsStateEvent of(GroupExpression groupExpression, 
StatsDeriveResult statsDeriveResult) {
+        return checkConnectContext(StatsStateEvent.class)
+                ? new StatsStateEvent(groupExpression, statsDeriveResult) : 
null;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.toSqlString("StatsStateEvent", "statsDeriveResult", 
statsDeriveResult);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/TransformEvent.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/TransformEvent.java
new file mode 100644
index 0000000000..4ebd593dc5
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/metrics/event/TransformEvent.java
@@ -0,0 +1,59 @@
+// 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.doris.nereids.metrics.event;
+
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.util.Utils;
+
+import java.util.List;
+
+/**
+ * transform event
+ */
+public class TransformEvent extends Event {
+    private final GroupExpression groupExpression;
+    private final Plan before;
+    private final List<Plan> afters;
+    private final RuleType ruleType;
+
+    private TransformEvent(GroupExpression groupExpression, Plan before, 
List<Plan> afters, RuleType ruleType) {
+        this.groupExpression = groupExpression;
+        this.before = before;
+        this.afters = afters;
+        this.ruleType = ruleType;
+    }
+
+    public static TransformEvent of(GroupExpression groupExpression, Plan 
before, List<Plan> afters,
+            RuleType ruleType) {
+        return checkConnectContext(TransformEvent.class)
+                ? new TransformEvent(groupExpression, before, afters, 
ruleType) : null;
+    }
+
+    public GroupExpression getGroupExpression() {
+        return groupExpression;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.toSqlString("TransformEvent", "groupExpression", 
groupExpression,
+                "before", before, "afters", afters, "ruleType", ruleType);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/EnforceMissingPropertiesHelper.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/EnforceMissingPropertiesHelper.java
index 2ce69854c0..b8e0fecc38 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/EnforceMissingPropertiesHelper.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/EnforceMissingPropertiesHelper.java
@@ -20,7 +20,12 @@ package org.apache.doris.nereids.properties;
 import org.apache.doris.nereids.cost.CostCalculator;
 import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.event.EnforcerEvent;
 import org.apache.doris.nereids.properties.DistributionSpecHash.ShuffleType;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
 
 import com.google.common.collect.Lists;
 
@@ -29,7 +34,8 @@ import com.google.common.collect.Lists;
  * Enforce add missing properties for child.
  */
 public class EnforceMissingPropertiesHelper {
-
+    private static final EventProducer ENFORCER_TRACER = new 
EventProducer(EnforcerEvent.class,
+            EventChannel.getDefaultChannel().addConsumers(new 
LogConsumer(EnforcerEvent.class, EventChannel.LOG)));
     private final JobContext context;
     private final GroupExpression groupExpression;
     private double curTotalCost;
@@ -138,6 +144,8 @@ public class EnforceMissingPropertiesHelper {
             PhysicalProperties oldOutputProperty,
             PhysicalProperties newOutputProperty) {
         context.getCascadesContext().getMemo().addEnforcerPlan(enforcer, 
groupExpression.getOwnerGroup());
+        ENFORCER_TRACER.log(EnforcerEvent.of(groupExpression, ((PhysicalPlan) 
enforcer.getPlan()),
+                oldOutputProperty, newOutputProperty));
         curTotalCost += CostCalculator.calculateCost(enforcer);
 
         if (enforcer.updateLowestCostTable(newOutputProperty,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
index b266a554de..253678e48d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
@@ -19,6 +19,13 @@ package org.apache.doris.nereids.trees.plans;
 
 import org.apache.doris.nereids.analyzer.Unbound;
 import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.memo.Memo;
+import org.apache.doris.nereids.metrics.CounterType;
+import org.apache.doris.nereids.metrics.EventChannel;
+import org.apache.doris.nereids.metrics.EventProducer;
+import org.apache.doris.nereids.metrics.consumer.LogConsumer;
+import org.apache.doris.nereids.metrics.enhancer.AddCounterEventEnhancer;
+import org.apache.doris.nereids.metrics.event.CounterEvent;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.AbstractTreeNode;
 import org.apache.doris.nereids.trees.expressions.ExprId;
@@ -39,7 +46,10 @@ import javax.annotation.Nullable;
  * Abstract class for all concrete plan node.
  */
 public abstract class AbstractPlan extends AbstractTreeNode<Plan> implements 
Plan {
-
+    private static final EventProducer PLAN_CONSTRUCT_TRACER = new 
EventProducer(CounterEvent.class,
+            EventChannel.getDefaultChannel()
+                    .addEnhancers(new AddCounterEventEnhancer())
+                    .addConsumers(new LogConsumer(CounterEvent.class, 
EventChannel.LOG)));
     protected final StatsDeriveResult statsDeriveResult;
     protected final PlanType type;
     protected final Optional<GroupExpression> groupExpression;
@@ -66,6 +76,7 @@ public abstract class AbstractPlan extends 
AbstractTreeNode<Plan> implements Pla
         this.logicalPropertiesSupplier = Suppliers.memoize(() -> 
optLogicalProperties.orElseGet(
                 this::computeLogicalProperties));
         this.statsDeriveResult = statsDeriveResult;
+        PLAN_CONSTRUCT_TRACER.log(CounterEvent.of(Memo.getStateId(), 
CounterType.PLAN_CONSTRUCTOR, null, null, null));
     }
 
     @Override
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
index ded896d24b..a46e2a2999 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
@@ -21,11 +21,14 @@ import org.apache.doris.common.Config;
 import org.apache.doris.common.io.Text;
 import org.apache.doris.common.io.Writable;
 import org.apache.doris.common.util.TimeUtils;
+import org.apache.doris.nereids.metrics.Event;
+import org.apache.doris.nereids.metrics.EventSwitchParser;
 import org.apache.doris.qe.VariableMgr.VarAttr;
 import org.apache.doris.thrift.TQueryOptions;
 import org.apache.doris.thrift.TResourceLimit;
 
 import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.json.simple.JSONObject;
@@ -37,8 +40,10 @@ import java.io.IOException;
 import java.io.Serializable;
 import java.lang.reflect.Field;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Random;
+import java.util.Set;
 
 /**
  * System variable.
@@ -232,6 +237,8 @@ public class SessionVariable implements Serializable, 
Writable {
 
     public static final String ENABLE_ELIMINATE_SORT_NODE = 
"enable_eliminate_sort_node";
 
+    public static final String NEREIDS_TRACE_EVENT_MODE = 
"nereids_trace_event_mode";
+
     public static final String INTERNAL_SESSION = "internal_session";
 
     public static final String PARTITIONED_HASH_JOIN_ROWS_THRESHOLD = 
"partitioned_hash_join_rows_threshold";
@@ -643,6 +650,40 @@ public class SessionVariable implements Serializable, 
Writable {
         this.enableShareHashTableForBroadcastJoin = random.nextBoolean();
     }
 
+    /**
+     * syntax:
+     * all -> use all event
+     * all except event_1, event_2, ..., event_n -> use all events excluding 
the event_1~n
+     * event_1, event_2, ..., event_n -> use event_1~n
+     */
+    @VariableMgr.VarAttr(name = NEREIDS_TRACE_EVENT_MODE, checker = 
"checkNereidsTraceEventMode")
+    public String nereidsTraceEventMode = "all";
+
+    private Set<Class<? extends Event>> parsedNereidsEventMode = 
EventSwitchParser.parse(Lists.newArrayList("all"));
+
+    public void setEnableNereidsTrace(boolean enableNereidsTrace) {
+        this.enableNereidsTrace = enableNereidsTrace;
+    }
+
+    public void setNereidsTraceEventMode(String nereidsTraceEventMode) {
+        checkNereidsTraceEventMode(nereidsTraceEventMode);
+        this.nereidsTraceEventMode = nereidsTraceEventMode;
+    }
+
+    public void checkNereidsTraceEventMode(String nereidsTraceEventMode) {
+        List<String> strings = 
EventSwitchParser.checkEventModeStringAndSplit(nereidsTraceEventMode);
+        if (strings != null) {
+            parsedNereidsEventMode = EventSwitchParser.parse(strings);
+        }
+        if (parsedNereidsEventMode == null) {
+            throw new UnsupportedOperationException("nereids_trace_event_mode 
syntax error, please check");
+        }
+    }
+
+    public Set<Class<? extends Event>> getParsedNereidsEventMode() {
+        return parsedNereidsEventMode;
+    }
+
     public String getBlockEncryptionMode() {
         return blockEncryptionMode;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java
index d6c224e68c..214f983c8b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java
@@ -29,6 +29,7 @@ import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.PatternMatcher;
 import org.apache.doris.persist.GlobalVarPersistInfo;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSortedMap;
 import com.google.common.collect.Lists;
@@ -140,6 +141,14 @@ public class VariableMgr {
         if (VariableVarConverters.hasConverter(attr.name())) {
             value = VariableVarConverters.encode(attr.name(), 
value).toString();
         }
+        if (!attr.checker().equals("")) {
+            Preconditions.checkArgument(obj instanceof SessionVariable);
+            try {
+                
SessionVariable.class.getDeclaredMethod(attr.checker()).invoke(obj);
+            } catch (Exception e) {
+                ErrorReport.reportDdlException(ErrorCode.ERR_INVALID_VALUE, 
attr.name(), value, e.getMessage());
+            }
+        }
         try {
             switch (field.getType().getSimpleName()) {
                 case "boolean":
@@ -516,6 +525,10 @@ public class VariableMgr {
 
         String maxValue() default "0";
 
+        // the function name that check the VarAttr before setting it to 
sessionVariable
+        // only support check function: 0 argument and 0 return value, if an 
error occurs, throw an exception.
+        String checker() default "";
+
         // Set to true if the variables need to be forwarded along with 
forward statement.
         boolean needForward() default false;
     }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/metrics/EventTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/metrics/EventTest.java
new file mode 100644
index 0000000000..94efff68d0
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/metrics/EventTest.java
@@ -0,0 +1,135 @@
+// 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.doris.nereids.metrics;
+
+import org.apache.doris.nereids.metrics.consumer.PrintConsumer;
+import org.apache.doris.nereids.metrics.event.CounterEvent;
+import org.apache.doris.nereids.metrics.event.EnforcerEvent;
+import org.apache.doris.nereids.metrics.event.GroupMergeEvent;
+import org.apache.doris.nereids.metrics.event.TransformEvent;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.utframe.TestWithFeService;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+public class EventTest extends TestWithFeService {
+    private EventChannel channel;
+    private List<EventProducer> producers;
+
+    private final StringBuilder builder = new StringBuilder();
+    private final PrintStream printStream = new PrintStream(new OutputStream() 
{
+        @Override
+        public void write(int b) {
+            builder.append((char) b);
+        }
+    });
+
+    @Override
+    public void runBeforeAll() {
+        connectContext.getSessionVariable().setEnableNereidsTrace(true);
+        connectContext.getSessionVariable().setEnableNereidsPlanner(true);
+        channel = new EventChannel()
+                .addConsumers(
+                        new PrintConsumer(CounterEvent.class, printStream),
+                        new PrintConsumer(TransformEvent.class, printStream),
+                        new PrintConsumer(EnforcerEvent.class, printStream),
+                        new PrintConsumer(GroupMergeEvent.class, printStream))
+                .addEnhancers(
+                        new EventEnhancer(CounterEvent.class) {
+                            @Override
+                            public void enhance(Event e) {
+                                CounterEvent.updateCounter(((CounterEvent) 
e).getCounterType());
+                            }
+                        }
+                );
+        producers = ImmutableList.of(
+                new EventProducer(CounterEvent.class, channel,
+                        new EventFilter(CounterEvent.class) { },
+                        new EventFilter(CounterEvent.class) { }),
+                new EventProducer(TransformEvent.class, channel,
+                        new EventFilter(TransformEvent.class) {
+                            @Override
+                            public Event checkEvent(Event event) {
+                                return ((TransformEvent) 
event).getGroupExpression() == null ? event : null;
+                            }
+                        })
+        );
+        channel.start();
+    }
+
+    @Override
+    public void runAfterAll() {
+        channel.stop();
+        Assertions.assertEquals(
+                "CounterEvent ( count=1, count=PLAN_CONSTRUCTOR, group=null, 
groupExpression=null, plan=null )\n"
+                        + "CounterEvent ( count=2, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "CounterEvent ( count=3, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "CounterEvent ( count=4, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "CounterEvent ( count=5, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "CounterEvent ( count=6, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=7, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=8, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=9, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=10, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=11, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=12, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=13, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=14, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n"
+                        + "CounterEvent ( count=15, count=PLAN_CONSTRUCTOR, 
group=null, groupExpression=null, plan=null )\n"
+                        + "TransformEvent ( groupExpression=null, before=null, 
afters=[], ruleType=AGGREGATE_DISASSEMBLE )\n",
+                        builder.toString());
+        CounterEvent.clearCounter();
+    }
+
+    @Test
+    public void testEvent() {
+        connectContext.getSessionVariable().setNereidsTraceEventMode("all 
except transform");
+        for (int i = 0; i < 10; ++i) {
+            producers.get(i % 2).log(i % 2 == 0
+                    ? CounterEvent.of(0, CounterType.PLAN_CONSTRUCTOR, null, 
null, null)
+                    : TransformEvent.of(null, null, ImmutableList.of(), 
RuleType.AGGREGATE_DISASSEMBLE));
+        }
+        connectContext.getSessionVariable().setNereidsTraceEventMode("all");
+        for (int i = 0; i < 10; ++i) {
+            producers.get(i % 2).log(i % 2 == 0
+                    ? CounterEvent.of(0, CounterType.PLAN_CONSTRUCTOR, null, 
null, null)
+                    : TransformEvent.of(null, null, ImmutableList.of(), 
RuleType.AGGREGATE_DISASSEMBLE));
+        }
+        connectContext.getSessionVariable().setNereidsTraceEventMode("counter, 
transform");
+        for (int i = 0; i < 10; ++i) {
+            producers.get(i % 2).log(i % 2 == 0
+                    ? CounterEvent.of(0, CounterType.PLAN_CONSTRUCTOR, null, 
null, null)
+                    : TransformEvent.of(null, null, ImmutableList.of(), 
RuleType.AGGREGATE_DISASSEMBLE));
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to