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

wusheng pushed a commit to branch oal-v2
in repository https://gitbox.apache.org/repos/asf/skywalking.git

commit 86c4b4b4f8f19730c2f339aae544fe6ed3de0f28
Author: Wu Sheng <[email protected]>
AuthorDate: Tue Feb 10 09:05:23 2026 +0800

    Fix critical V1 vs V2 template differences
    
    Critical fixes found by comparing V1 and V2 templates:
    
    1. doMetrics.ftl - MISSING filter execution (CRITICAL!)
       V1 checks filter expressions before creating metrics object:
       ```
       if (!new ${filterExpression.expressionObject}().match(...)) {
           return;
       }
       ```
       V2 was completely missing this - filters like
       filter(detectPoint == DetectPoint.CLIENT) wouldn't work!
    
       Added filterExpressions list to CodeGenModel and
       convertFilters() method to MetricDefinitionEnricher.
    
    2. toDay.ftl/toHour.ftl - Missing copyFrom for complex objects
       V1 creates new instance and calls copyFrom() for non-primitive types.
       V2 was directly assigning which could cause mutable object issues.
    
    3. deserialize.ftl - Missing empty string check
       V1: if (remoteData.getDataStrings(${field?index}) != "")
       V2 was setting values even for empty strings.
    
    4. serialize.ftl - Remove incorrect setDataLongs override
       V2 had extra line: remoteBuilder.setDataLongs(0, getTimeBucket())
       This would overwrite the first long field with timeBucket,
       corrupting data. V1 doesn't have this line.
    
    Co-Authored-By: Claude Opus 4.5 <[email protected]>
---
 .../skywalking/oal/v2/generator/CodeGenModel.java  |  9 +++++++-
 .../oal/v2/generator/MetricDefinitionEnricher.java | 24 +++++++++++++++++++++-
 .../code-templates-v2/dispatcher/doMetrics.ftl     |  8 ++++++++
 .../code-templates-v2/metrics/deserialize.ftl      | 10 ++++-----
 .../code-templates-v2/metrics/serialize.ftl        |  1 -
 .../resources/code-templates-v2/metrics/toDay.ftl  | 22 +++++++++++++++++---
 .../resources/code-templates-v2/metrics/toHour.ftl | 22 +++++++++++++++++---
 7 files changed, 81 insertions(+), 15 deletions(-)

diff --git 
a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/CodeGenModel.java
 
b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/CodeGenModel.java
index 8e13a3395e..3f92016763 100644
--- 
a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/CodeGenModel.java
+++ 
b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/CodeGenModel.java
@@ -103,11 +103,18 @@ public class CodeGenModel {
     private String metricsClassName;
 
     /**
-     * Filter expressions from OAL script.
+     * Filter expressions from OAL script (raw V2 model).
      */
     @Builder.Default
     private List<FilterExpression> filters = new ArrayList<>();
 
+    /**
+     * Filter expressions converted for template use.
+     * Each contains expressionObject, left, right for filter checks.
+     */
+    @Builder.Default
+    private List<FilterExpressionV2> filterExpressions = new ArrayList<>();
+
     /**
      * Fields extracted from source (for ID, persistence).
      */
diff --git 
a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/MetricDefinitionEnricher.java
 
b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/MetricDefinitionEnricher.java
index 8a01871113..3778355986 100644
--- 
a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/MetricDefinitionEnricher.java
+++ 
b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/MetricDefinitionEnricher.java
@@ -98,7 +98,10 @@ public class MetricDefinitionEnricher {
         // 6. Generate serialization fields
         CodeGenModel.SerializeFieldsV2 serializeFields = 
generateSerializeFields(fieldsFromSource, persistentFields);
 
-        // 7. Build CodeGenModel
+        // 7. Convert filter expressions to template format
+        List<CodeGenModel.FilterExpressionV2> filterExpressions = 
convertFilters(metric.getFilters());
+
+        // 8. Build CodeGenModel
         return CodeGenModel.builder()
             .metricDefinition(metric)
             .varName(metric.getName())
@@ -115,6 +118,7 @@ public class MetricDefinitionEnricher {
             .functionName(metric.getAggregationFunction().getName())
             .metricsClassName(metricsClassName)
             .filters(metric.getFilters())
+            .filterExpressions(filterExpressions)
             .fieldsFromSource(fieldsFromSource)
             .persistentFields(persistentFields)
             .serializeFields(serializeFields)
@@ -425,6 +429,24 @@ public class MetricDefinitionEnricher {
         return serializeFields;
     }
 
+    /**
+     * Convert filter expressions to template-ready format.
+     */
+    private List<CodeGenModel.FilterExpressionV2> 
convertFilters(List<FilterExpression> filters) {
+        List<CodeGenModel.FilterExpressionV2> result = new ArrayList<>();
+        for (FilterExpression filter : filters) {
+            String matcherClass = getMatcherClassName(filter);
+            String left = buildFilterLeft(filter);
+            String right = buildFilterRight(filter);
+            result.add(CodeGenModel.FilterExpressionV2.builder()
+                .expressionObject(matcherClass)
+                .left(left)
+                .right(right)
+                .build());
+        }
+        return result;
+    }
+
     /**
      * Format metrics name (convert snake_case to PascalCase).
      */
diff --git 
a/oap-server/oal-rt/src/main/resources/code-templates-v2/dispatcher/doMetrics.ftl
 
b/oap-server/oal-rt/src/main/resources/code-templates-v2/dispatcher/doMetrics.ftl
index 59948cd360..a6e9bf4583 100644
--- 
a/oap-server/oal-rt/src/main/resources/code-templates-v2/dispatcher/doMetrics.ftl
+++ 
b/oap-server/oal-rt/src/main/resources/code-templates-v2/dispatcher/doMetrics.ftl
@@ -1,5 +1,13 @@
 private void do${metricsName}(${sourcePackage}${sourceName} source) {
 
+<#if filterExpressions?? && filterExpressions?size gt 0>
+    <#list filterExpressions as filterExpression>
+        if (!new 
${filterExpression.expressionObject}().match(${filterExpression.left}, 
${filterExpression.right})) {
+        return;
+        }
+    </#list>
+</#if>
+
 ${metricsClassPackage}${metricsName}Metrics metrics = new 
${metricsClassPackage}${metricsName}Metrics();
 <#if sourceDecorator??>
     source.decorate("${sourceDecorator}");
diff --git 
a/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/deserialize.ftl
 
b/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/deserialize.ftl
index 5af5a8cdf8..fc1c582f90 100644
--- 
a/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/deserialize.ftl
+++ 
b/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/deserialize.ftl
@@ -1,16 +1,14 @@
 public void 
deserialize(org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData 
remoteData) {
 <#if serializeFields.stringFields?? && serializeFields.stringFields?size gt 0>
     <#list serializeFields.stringFields as field>
-        ${field.setter}(remoteData.getDataStrings(${field_index}));
+        if (remoteData.getDataStrings(${field_index}) != "") {
+            ${field.setter}(remoteData.getDataStrings(${field_index}));
+        }
     </#list>
 </#if>
 <#if serializeFields.longFields?? && serializeFields.longFields?size gt 0>
     <#list serializeFields.longFields as field>
-        <#if field_index == 0>
-            setTimeBucket(remoteData.getDataLongs(${field_index}));
-        <#else>
-            ${field.setter}(remoteData.getDataLongs(${field_index}));
-        </#if>
+        ${field.setter}(remoteData.getDataLongs(${field_index}));
     </#list>
 </#if>
 <#if serializeFields.doubleFields?? && serializeFields.doubleFields?size gt 0>
diff --git 
a/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/serialize.ftl 
b/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/serialize.ftl
index 8ff9223474..8080003cbc 100644
--- 
a/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/serialize.ftl
+++ 
b/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/serialize.ftl
@@ -25,6 +25,5 @@ 
org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData.Builder remot
         remoteBuilder.addDataObjectStrings(${field.getter}().toStorageData());
     </#list>
 </#if>
-remoteBuilder.setDataLongs(0, getTimeBucket());
 return remoteBuilder;
 }
diff --git 
a/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/toDay.ftl 
b/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/toDay.ftl
index 12496f03dd..6560639606 100644
--- a/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/toDay.ftl
+++ b/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/toDay.ftl
@@ -1,10 +1,26 @@
 public org.apache.skywalking.oap.server.core.analysis.metrics.Metrics toDay() {
 ${metricsClassPackage}${metricsName}Metrics metrics = new 
${metricsClassPackage}${metricsName}Metrics();
-<#list fieldsFromSource as sourceField>
-    metrics.${sourceField.fieldSetter}(this.${sourceField.fieldGetter}());
+<#list fieldsFromSource as field>
+    <#if field.columnName == "time_bucket">
+        <#-- Skip, will set at end -->
+    <#elseif field.typeName == "java.lang.String" || field.typeName == "long" 
|| field.typeName == "int" || field.typeName == "double" || field.typeName == 
"float">
+        metrics.${field.fieldSetter}(this.${field.fieldGetter}());
+    <#else>
+        ${field.typeName} newValue = new ${field.typeName}();
+        newValue.copyFrom(this.${field.fieldGetter}());
+        metrics.${field.fieldSetter}(newValue);
+    </#if>
 </#list>
 <#list persistentFields as field>
-    metrics.${field.fieldSetter}(this.${field.fieldGetter}());
+    <#if field.columnName == "time_bucket">
+        <#-- Skip, will set at end -->
+    <#elseif field.typeName == "java.lang.String" || field.typeName == "long" 
|| field.typeName == "int" || field.typeName == "double" || field.typeName == 
"float">
+        metrics.${field.fieldSetter}(this.${field.fieldGetter}());
+    <#else>
+        ${field.typeName} newValue = new ${field.typeName}();
+        newValue.copyFrom(this.${field.fieldGetter}());
+        metrics.${field.fieldSetter}(newValue);
+    </#if>
 </#list>
 metrics.setTimeBucket(this.toTimeBucketInDay());
 return metrics;
diff --git 
a/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/toHour.ftl 
b/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/toHour.ftl
index 0eebac015b..062d17eef7 100644
--- a/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/toHour.ftl
+++ b/oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/toHour.ftl
@@ -1,10 +1,26 @@
 public org.apache.skywalking.oap.server.core.analysis.metrics.Metrics toHour() 
{
 ${metricsClassPackage}${metricsName}Metrics metrics = new 
${metricsClassPackage}${metricsName}Metrics();
-<#list fieldsFromSource as sourceField>
-    metrics.${sourceField.fieldSetter}(this.${sourceField.fieldGetter}());
+<#list fieldsFromSource as field>
+    <#if field.columnName == "time_bucket">
+        <#-- Skip, will set at end -->
+    <#elseif field.typeName == "java.lang.String" || field.typeName == "long" 
|| field.typeName == "int" || field.typeName == "double" || field.typeName == 
"float">
+        metrics.${field.fieldSetter}(this.${field.fieldGetter}());
+    <#else>
+        ${field.typeName} newValue = new ${field.typeName}();
+        newValue.copyFrom(this.${field.fieldGetter}());
+        metrics.${field.fieldSetter}(newValue);
+    </#if>
 </#list>
 <#list persistentFields as field>
-    metrics.${field.fieldSetter}(this.${field.fieldGetter}());
+    <#if field.columnName == "time_bucket">
+        <#-- Skip, will set at end -->
+    <#elseif field.typeName == "java.lang.String" || field.typeName == "long" 
|| field.typeName == "int" || field.typeName == "double" || field.typeName == 
"float">
+        metrics.${field.fieldSetter}(this.${field.fieldGetter}());
+    <#else>
+        ${field.typeName} newValue = new ${field.typeName}();
+        newValue.copyFrom(this.${field.fieldGetter}());
+        metrics.${field.fieldSetter}(newValue);
+    </#if>
 </#list>
 metrics.setTimeBucket(this.toTimeBucketInHour());
 return metrics;

Reply via email to