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;
