From d2f746985f6cd59409fc05d971f05eff444a884b Mon Sep 17 00:00:00 2001 From: mattcasters Date: Sat, 29 Aug 2026 21:35:08 +0200 Subject: [PATCH] Issue #3003 : Add Output transform metrics transform --- assemblies/debug/pom.xml | 6 + assemblies/plugins/pom.xml | 6 + .../transforms/icons/transformsmetrics.svg | 23 ++ ...ut-transform-metrics-dialog-fields-tab.png | Bin 0 -> 99459 bytes ...ransform-metrics-dialog-transforms-tab.png | Bin 0 -> 76419 bytes docs/hop-user-manual/modules/ROOT/nav.adoc | 1 + .../ROOT/pages/pipeline/transforms.adoc | 1 + .../transforms/outputtransformmetrics.adoc | 91 +++++ .../0110-output-transform-metrics.hpl | 254 +++++++++++++ .../golden-output-transform-metrics.csv | 3 + .../main-0110-output-transform-metrics.hwf | 80 ++++ .../golden-output-transform-metrics.json | 32 ++ .../0110-output-transform-metrics UNIT.json | 36 ++ .../hop/imports/kettle/KettleConst.java | 12 + .../KettleImportTransformsMetricsTest.java | 128 +++++++ plugins/transforms/pom.xml | 1 + plugins/transforms/transformsmetrics/pom.xml | 32 ++ .../src/assembly/assembly.xml | 46 +++ .../transformsmetrics/MetricTransform.java | 58 +++ .../transformsmetrics/TransformsMetrics.java | 203 ++++++++++ .../TransformsMetricsData.java | 45 +++ .../TransformsMetricsDialog.java | 253 +++++++++++++ .../TransformsMetricsMeta.java | 358 ++++++++++++++++++ .../messages/messages_en_US.properties | 68 ++++ .../src/main/resources/transformsmetrics.svg | 23 ++ .../src/main/resources/version.xml | 20 + .../output-transform-metrics-basic.hpl | 201 ++++++++++ .../TransformsMetricsMetaTest.java | 151 ++++++++ 28 files changed, 2132 insertions(+) create mode 100644 docs/hop-user-manual/modules/ROOT/assets/images/transforms/icons/transformsmetrics.svg create mode 100644 docs/hop-user-manual/modules/ROOT/assets/images/transforms/output-transform-metrics-dialog-fields-tab.png create mode 100644 docs/hop-user-manual/modules/ROOT/assets/images/transforms/output-transform-metrics-dialog-transforms-tab.png create mode 100644 docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/outputtransformmetrics.adoc create mode 100644 integration-tests/transforms/0110-output-transform-metrics.hpl create mode 100644 integration-tests/transforms/datasets/golden-output-transform-metrics.csv create mode 100644 integration-tests/transforms/main-0110-output-transform-metrics.hwf create mode 100644 integration-tests/transforms/metadata/dataset/golden-output-transform-metrics.json create mode 100644 integration-tests/transforms/metadata/unit-test/0110-output-transform-metrics UNIT.json create mode 100644 plugins/misc/import/src/test/java/org/apache/hop/imports/kettle/KettleImportTransformsMetricsTest.java create mode 100644 plugins/transforms/transformsmetrics/pom.xml create mode 100644 plugins/transforms/transformsmetrics/src/assembly/assembly.xml create mode 100644 plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/MetricTransform.java create mode 100644 plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetrics.java create mode 100644 plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsData.java create mode 100644 plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsDialog.java create mode 100644 plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsMeta.java create mode 100644 plugins/transforms/transformsmetrics/src/main/resources/org/apache/hop/pipeline/transforms/transformsmetrics/messages/messages_en_US.properties create mode 100644 plugins/transforms/transformsmetrics/src/main/resources/transformsmetrics.svg create mode 100644 plugins/transforms/transformsmetrics/src/main/resources/version.xml create mode 100644 plugins/transforms/transformsmetrics/src/main/samples/transforms/output-transform-metrics-basic.hpl create mode 100644 plugins/transforms/transformsmetrics/src/test/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsMetaTest.java diff --git a/assemblies/debug/pom.xml b/assemblies/debug/pom.xml index dd528af8b82..d87ba26f14e 100644 --- a/assemblies/debug/pom.xml +++ b/assemblies/debug/pom.xml @@ -553,6 +553,12 @@ ${project.version} provided + + org.apache.hop + hop-transform-transformsmetrics + ${project.version} + provided + org.apache.hop hop-transform-validator diff --git a/assemblies/plugins/pom.xml b/assemblies/plugins/pom.xml index 3d3fe213e91..69000d8f745 100644 --- a/assemblies/plugins/pom.xml +++ b/assemblies/plugins/pom.xml @@ -1530,6 +1530,12 @@ ${project.version} zip + + org.apache.hop + hop-transform-transformsmetrics + ${project.version} + zip + org.apache.hop hop-transform-uniquerows diff --git a/docs/hop-user-manual/modules/ROOT/assets/images/transforms/icons/transformsmetrics.svg b/docs/hop-user-manual/modules/ROOT/assets/images/transforms/icons/transformsmetrics.svg new file mode 100644 index 00000000000..6829085d350 --- /dev/null +++ b/docs/hop-user-manual/modules/ROOT/assets/images/transforms/icons/transformsmetrics.svg @@ -0,0 +1,23 @@ + + + + + + + diff --git a/docs/hop-user-manual/modules/ROOT/assets/images/transforms/output-transform-metrics-dialog-fields-tab.png b/docs/hop-user-manual/modules/ROOT/assets/images/transforms/output-transform-metrics-dialog-fields-tab.png new file mode 100644 index 0000000000000000000000000000000000000000..c54e155179e5588dc14ffafe5da5048696af923c GIT binary patch literal 99459 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πXeYd5&bS)d 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 M`0hy4;WIz{2jn=SkpKVy literal 0 HcmV?d00001 diff --git a/docs/hop-user-manual/modules/ROOT/assets/images/transforms/output-transform-metrics-dialog-transforms-tab.png b/docs/hop-user-manual/modules/ROOT/assets/images/transforms/output-transform-metrics-dialog-transforms-tab.png new file mode 100644 index 0000000000000000000000000000000000000000..5d46bf31b78f8a348224645ba5a6d3f195dcf647 GIT binary patch literal 76419 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 Hr-UW|9dnDs literal 0 HcmV?d00001 diff --git a/docs/hop-user-manual/modules/ROOT/nav.adoc b/docs/hop-user-manual/modules/ROOT/nav.adoc index 7e3762a5806..5c7aeeca614 100644 --- a/docs/hop-user-manual/modules/ROOT/nav.adoc +++ b/docs/hop-user-manual/modules/ROOT/nav.adoc @@ -227,6 +227,7 @@ under the License. *** xref:pipeline/transforms/numberrange.adoc[Number range] *** xref:pipeline/transforms/odata-input.adoc[OData input] *** xref:pipeline/transforms/orabulkloader.adoc[Oracle Bulk Loader] +*** xref:pipeline/transforms/outputtransformmetrics.adoc[Output transform metrics] *** xref:pipeline/transforms/parquet-file-input.adoc[Parquet file input] *** xref:pipeline/transforms/parquet-file-output.adoc[Parquet file output] *** xref:pipeline/transforms/pipeline-data-probe.adoc[Pipeline Data Probe] diff --git a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms.adoc b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms.adoc index 15f47959a23..b4e71ff8023 100644 --- a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms.adoc +++ b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms.adoc @@ -177,6 +177,7 @@ Those are explained once in xref:pipeline/formatting-values.adoc[Formatting numb * xref:pipeline/transforms/numberrange.adoc[Number range] * xref:pipeline/transforms/odata-input.adoc[OData input] * xref:pipeline/transforms/orabulkloader.adoc[Oracle Bulk Loader] +* xref:pipeline/transforms/outputtransformmetrics.adoc[Output transform metrics] * xref:pipeline/transforms/parquet-file-input.adoc[Parquet file input] * xref:pipeline/transforms/parquet-file-output.adoc[Parquet file output] * xref:pipeline/transforms/pipeline-data-probe.adoc[Pipeline Data Probe] diff --git a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/outputtransformmetrics.adoc b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/outputtransformmetrics.adoc new file mode 100644 index 00000000000..db5fd7ac81a --- /dev/null +++ b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/outputtransformmetrics.adoc @@ -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. +//// +:documentationPath: /pipeline/transforms/ +:language: en_US +:description: Wait for selected transforms to finish and output their metrics as rows. + += image:transforms/icons/transformsmetrics.svg[Output transform metrics Icon, role="image-doc-icon"] Output transform metrics + +[%noheader,cols="3a,1a", role="table-no-borders" ] +|=== +| +== Description + +Output transform metrics waits until the listed transform copies in the same pipeline have finished, then emits *one output row per watched copy* with the requested counters. + +This transform is a *row generator*. It does not consume incoming rows and must not have incoming hops. Connecting an upstream hop can deadlock the pipeline: the watched transform cannot finish while its output buffer is full, and this transform never drains that buffer. + +Use this transform when a pipeline itself needs metrics (for example after a Kettle/PDI import, or to feed Write to log). For project-wide monitoring, prefer xref:metadata-types/pipeline-log.adoc[Pipeline logging] or xref:pipeline/transforms/execinfo.adoc[Execution information]. + +| +== Supported Engines +[%noheader,cols="2,1a",frame=none, role="table-supported-engines"] +!=== +!Hop Engine! image:check_mark.svg[Supported, 24] +!Single Threaded! image:cross.svg[Not Supported, 24] +!Native Spark! image:cross.svg[Not Supported, 24] +!Beam Spark! image:cross.svg[Not Supported, 24] +!Beam Flink! image:cross.svg[Not Supported, 24] +!Beam Dataflow! image:cross.svg[Not Supported, 24] +!=== +|=== + +== Options + +=== Transforms + +image:transforms/output-transform-metrics-dialog-transforms-tab.png[Output transform metrics Transforms tab, width="90%"] + +[options="header"] +|=== +|Option|Description +|Transform name|Name of this transform. +|Metrics for the following transforms|The transform copies to wait for. You cannot watch this transform itself or a downstream target of it. +|Get Fields|Fill the grid with every other transform that is not a downstream target. +|=== + +[options="header"] +|=== +|Column|Description +|Transform name|Name of the transform to watch. +|Copy Nr|0-based copy number. Use one grid row per copy if the transform runs multiple copies. Variables are allowed. +|Required|When Yes, the pipeline fails if that copy cannot be found. When No, a missing copy is skipped. +|=== + +=== Fields + +image:transforms/output-transform-metrics-dialog-fields-tab.png[Output transform metrics Fields tab, width="90%"] + +Leave a field name empty to omit that column from the output. + +[options="header"] +|=== +|Option|Description +|Transform name|Name of the watched transform. +|Transform id|Plugin id of the watched transform. +|Lines input|Rows read from an external source. +|Lines output|Rows written to an external destination. +|Lines read|Rows read from previous transforms. +|Lines updated|Rows updated. +|Lines written|Rows written to the next transforms. +|Lines rejected|Rows sent to an error hop (`getLinesRejected()`). This is *not* the error count. +|Duration (ms)|Execution duration in milliseconds. +|=== + +== Kettle / PDI import + +Kettle called this transform *Output steps metrics* (`StepsMetrics`). Hop import rewrites the plugin type to `TransformsMetrics` and the XML tags from `step*` to `transform*`. Stored *values* of output field names (for example `Step name`) are left unchanged so existing pipelines keep their column names. diff --git a/integration-tests/transforms/0110-output-transform-metrics.hpl b/integration-tests/transforms/0110-output-transform-metrics.hpl new file mode 100644 index 00000000000..0f3a5808bcb --- /dev/null +++ b/integration-tests/transforms/0110-output-transform-metrics.hpl @@ -0,0 +1,254 @@ + + + + + 0110-output-transform-metrics + Y + + + + Normal + + + N + 1000 + 100 + - + 2026/08/29 12:00:00.000 + - + 2026/08/29 12:00:00.000 + + N + + + + + + 10 rows + Dummy A + Y + + + 5 rows + Dummy B + Y + + + Output transform metrics + Sort + Y + + + Sort + Verify + Y + + + + 10 rows + RowGenerator + + Y + + 1 + + none + + + + + value + Integer + # + + + + 1 + -1 + -1 + N + + + 10 + N + 5000 + now + FiveSecondsAgo + + + 80 + 80 + + + + 5 rows + RowGenerator + + Y + + 1 + + none + + + + + value + Integer + # + + + + 1 + -1 + -1 + N + + + 5 + N + 5000 + now + FiveSecondsAgo + + + 80 + 224 + + + + Dummy A + Dummy + + Y + + 1 + + none + + + + + 256 + 80 + + + + Dummy B + Dummy + + Y + + 1 + + none + + + + + 256 + 224 + + + + Output transform metrics + TransformsMetrics + + Y + + 1 + + none + + + + + Dummy A + 0 + Y + + + Dummy B + 0 + Y + + + Transform name + Transform id + Lines written + + + 448 + 152 + + + + Sort + SortRows + + Y + + 1 + + none + + + N + ${java.io.tmpdir} + + + Y + Y + N + 0 + Transform name + N + + + out + 1000000 + N + + + 656 + 152 + + + + Verify + Dummy + + Y + + 1 + + none + + + + + 832 + 152 + + + + + + diff --git a/integration-tests/transforms/datasets/golden-output-transform-metrics.csv b/integration-tests/transforms/datasets/golden-output-transform-metrics.csv new file mode 100644 index 00000000000..333ac5e5823 --- /dev/null +++ b/integration-tests/transforms/datasets/golden-output-transform-metrics.csv @@ -0,0 +1,3 @@ +Transform name,Transform id,Lines written +Dummy A,Dummy,10 +Dummy B,Dummy,5 diff --git a/integration-tests/transforms/main-0110-output-transform-metrics.hwf b/integration-tests/transforms/main-0110-output-transform-metrics.hwf new file mode 100644 index 00000000000..ea2a6011d3f --- /dev/null +++ b/integration-tests/transforms/main-0110-output-transform-metrics.hwf @@ -0,0 +1,80 @@ + + + + main-0110-output-transform-metrics + Y + + + + 0 + - + 2026/08/29 12:00:00.000 + - + 2026/08/29 12:00:00.000 + + + + + Start + + SPECIAL + + N + 0 + 0 + 60 + 12 + 0 + 1 + 1 + N + 128 + 112 + + + + Run Pipeline Unit Tests + + RunPipelineTests + + + + 0110-output-transform-metrics UNIT + + + N + 320 + 112 + + + + + + Start + Run Pipeline Unit Tests + Y + Y + Y + + + + + + diff --git a/integration-tests/transforms/metadata/dataset/golden-output-transform-metrics.json b/integration-tests/transforms/metadata/dataset/golden-output-transform-metrics.json new file mode 100644 index 00000000000..14d7ea83d02 --- /dev/null +++ b/integration-tests/transforms/metadata/dataset/golden-output-transform-metrics.json @@ -0,0 +1,32 @@ +{ + "base_filename": "golden-output-transform-metrics.csv", + "name": "golden-output-transform-metrics", + "description": "", + "dataset_fields": [ + { + "field_comment": "", + "field_length": -1, + "field_type": 2, + "field_precision": -1, + "field_format": "", + "field_name": "Transform name" + }, + { + "field_comment": "", + "field_length": -1, + "field_type": 2, + "field_precision": -1, + "field_format": "", + "field_name": "Transform id" + }, + { + "field_comment": "", + "field_length": 10, + "field_type": 5, + "field_precision": 0, + "field_format": "#", + "field_name": "Lines written" + } + ], + "folder_name": "" +} diff --git a/integration-tests/transforms/metadata/unit-test/0110-output-transform-metrics UNIT.json b/integration-tests/transforms/metadata/unit-test/0110-output-transform-metrics UNIT.json new file mode 100644 index 00000000000..4943dc65fc5 --- /dev/null +++ b/integration-tests/transforms/metadata/unit-test/0110-output-transform-metrics UNIT.json @@ -0,0 +1,36 @@ +{ + "variableValues": [], + "database_replacements": [], + "autoOpening": true, + "basePath": "", + "golden_data_sets": [ + { + "field_mappings": [ + { + "transform_field": "Transform name", + "data_set_field": "Transform name" + }, + { + "transform_field": "Transform id", + "data_set_field": "Transform id" + }, + { + "transform_field": "Lines written", + "data_set_field": "Lines written" + } + ], + "field_order": [ + "Transform name" + ], + "transform_name": "Verify", + "data_set_name": "golden-output-transform-metrics" + } + ], + "input_data_sets": [], + "name": "0110-output-transform-metrics UNIT", + "description": "", + "trans_test_tweaks": [], + "persist_filename": "", + "pipeline_filename": "./0110-output-transform-metrics.hpl", + "test_type": "UNIT_TEST" +} diff --git a/plugins/misc/import/src/main/java/org/apache/hop/imports/kettle/KettleConst.java b/plugins/misc/import/src/main/java/org/apache/hop/imports/kettle/KettleConst.java index 1c80f671697..92f5ce4461e 100644 --- a/plugins/misc/import/src/main/java/org/apache/hop/imports/kettle/KettleConst.java +++ b/plugins/misc/import/src/main/java/org/apache/hop/imports/kettle/KettleConst.java @@ -87,6 +87,17 @@ public class KettleConst { {"step7", "transform7"}, {"step8", "transform8"}, {"step9", "transform9"}, + // Output transform metrics (Kettle: Output steps metrics) + {"stepRequired", "transformRequired"}, + {"stepnamefield", "transformnamefield"}, + {"stepidfield", "transformidfield"}, + {"steplinesinputfield", "transformlinesinputfield"}, + {"steplinesoutputfield", "transformlinesoutputfield"}, + {"steplinesreadfield", "transformlinesreadfield"}, + {"steplinesupdatedfield", "transformlinesupdatedfield"}, + {"steplineswrittentfield", "transformlineswrittenfield"}, + {"steplineserrorsfield", "transformlineserrorsfield"}, + {"stepsecondsfield", "transformsecondsfield"}, }) .collect(Collectors.toMap(data -> (String) data[0], data -> (String) data[1])); @@ -160,6 +171,7 @@ public class KettleConst { {"ROOT_JOB", "ROOT_WORKFLOW"}, {"BlockingStep", "BlockingTransform"}, {"BlockUntilStepsFinish", "BlockUntilTransformsFinish"}, + {"StepsMetrics", "TransformsMetrics"}, {"TypeExitExcelWriterStep", "TypeExitExcelWriterTransform"}, {"StepMetastructure", "TransformMetaStructure"}, {"JobExecutor", "WorkflowExecutor"}, diff --git a/plugins/misc/import/src/test/java/org/apache/hop/imports/kettle/KettleImportTransformsMetricsTest.java b/plugins/misc/import/src/test/java/org/apache/hop/imports/kettle/KettleImportTransformsMetricsTest.java new file mode 100644 index 00000000000..21594944b04 --- /dev/null +++ b/plugins/misc/import/src/test/java/org/apache/hop/imports/kettle/KettleImportTransformsMetricsTest.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.hop.imports.kettle; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.ByteArrayInputStream; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import org.apache.hop.core.HopClientEnvironment; +import org.apache.hop.core.xml.XmlHandler; +import org.apache.hop.core.xml.XmlParserFactoryProducer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +class KettleImportTransformsMetricsTest { + + private KettleImport kettleImport; + + @BeforeAll + static void setUpBeforeClass() throws Exception { + HopClientEnvironment.init(); + } + + @BeforeEach + void setUp() { + kettleImport = new KettleImport(); + } + + @Test + void testStepsMetricsBecomesTransformsMetrics() throws Exception { + Document doc = parse(kettleSnippet()); + processNode(doc); + + Node pipeline = XmlHandler.getSubNode(doc, "pipeline"); + assertNotNull(pipeline); + Node transform = XmlHandler.getSubNode(pipeline, "transform"); + assertNotNull(transform); + assertEquals("TransformsMetrics", XmlHandler.getTagValue(transform, "type")); + + Node list = XmlHandler.getSubNode(transform, "transforms"); + assertNotNull(list, "nested steps list should become transforms"); + Node watched = XmlHandler.getSubNode(list, "transform"); + assertNotNull(watched); + assertEquals("A", XmlHandler.getTagValue(watched, "name")); + assertEquals("0", XmlHandler.getTagValue(watched, "copyNr")); + assertEquals("Y", XmlHandler.getTagValue(watched, "transformRequired")); + assertNull(XmlHandler.getTagValue(watched, "stepRequired")); + + assertEquals("Step name", XmlHandler.getTagValue(transform, "transformnamefield")); + assertNull(XmlHandler.getTagValue(transform, "stepnamefield")); + assertEquals("Lines written", XmlHandler.getTagValue(transform, "transformlineswrittenfield")); + assertNull(XmlHandler.getTagValue(transform, "steplineswrittentfield")); + assertEquals("Lines rejected", XmlHandler.getTagValue(transform, "transformlineserrorsfield")); + assertNull(XmlHandler.getTagValue(transform, "steplineserrorsfield")); + } + + private String kettleSnippet() { + return "" + + "" + + "metrics" + + "StepsMetrics" + + "" + + "" + + "A" + + "0" + + "Y" + + "" + + "" + + "Step name" + + "Lines written" + + "Lines rejected" + + "" + + ""; + } + + private void processNode(Document doc) throws Exception { + Method method = + KettleImport.class.getDeclaredMethod( + "processNode", + Document.class, + Node.class, + Class.forName(entryTypeClassName()), + int.class); + method.setAccessible(true); + method.invoke(kettleImport, doc, doc, otherEntryType(), 0); + } + + private static String entryTypeClassName() { + return "org.apache.hop.imports.kettle.KettleImport$EntryType"; + } + + private Object otherEntryType() throws Exception { + Class entryTypeClass = Class.forName(entryTypeClassName()); + for (Object constant : entryTypeClass.getEnumConstants()) { + if ("OTHER".equals(constant.toString())) { + return constant; + } + } + throw new IllegalStateException("No OTHER entry type"); + } + + private static Document parse(String xml) throws Exception { + return XmlParserFactoryProducer.createSecureDocBuilderFactory() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/plugins/transforms/pom.xml b/plugins/transforms/pom.xml index c8ad5a2c5f6..29ecd883875 100644 --- a/plugins/transforms/pom.xml +++ b/plugins/transforms/pom.xml @@ -163,6 +163,7 @@ textfile tika tokenreplacement + transformsmetrics uniquerows uniquerowsbyhashset update diff --git a/plugins/transforms/transformsmetrics/pom.xml b/plugins/transforms/transformsmetrics/pom.xml new file mode 100644 index 00000000000..e46e5045e16 --- /dev/null +++ b/plugins/transforms/transformsmetrics/pom.xml @@ -0,0 +1,32 @@ + + + + 4.0.0 + + + org.apache.hop + hop-plugins-transforms + 2.20.0-SNAPSHOT + + + hop-transform-transformsmetrics + jar + Hop Plugins Transforms Output Transform Metrics + + diff --git a/plugins/transforms/transformsmetrics/src/assembly/assembly.xml b/plugins/transforms/transformsmetrics/src/assembly/assembly.xml new file mode 100644 index 00000000000..098027e8bb8 --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/assembly/assembly.xml @@ -0,0 +1,46 @@ + + + + hop-transform-transformsmetrics + + zip + + . + + + ${project.basedir}/src/main/resources/version.xml + ${hop.plugin.libdir} + true + + + + + + ${project.basedir}/src/main/samples + config/projects/samples/ + + + + + + ${maven.multiModuleProjectDirectory}/assemblies/shared/hop-plugin-libs.xml + + diff --git a/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/MetricTransform.java b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/MetricTransform.java new file mode 100644 index 00000000000..5be783f370d --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/MetricTransform.java @@ -0,0 +1,58 @@ +/* + * 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.hop.pipeline.transforms.transformsmetrics; + +import lombok.Getter; +import lombok.Setter; +import org.apache.hop.metadata.api.HopMetadataProperty; + +@Getter +@Setter +public class MetricTransform { + + @HopMetadataProperty( + injectionKey = "TRANSFORM_NAME", + injectionKeyDescription = "TransformsMetricsMeta.Injection.TRANSFORM_NAME") + private String name; + + @HopMetadataProperty( + key = "copyNr", + injectionKey = "TRANSFORM_COPY_NR", + injectionKeyDescription = "TransformsMetricsMeta.Injection.TRANSFORM_COPY_NR") + private String copyNr; + + @HopMetadataProperty( + key = "transformRequired", + injectionKey = "TRANSFORM_REQUIRED", + injectionKeyDescription = "TransformsMetricsMeta.Injection.TRANSFORM_REQUIRED") + private boolean required; + + public MetricTransform() {} + + public MetricTransform(String name, String copyNr, boolean required) { + this.name = name; + this.copyNr = copyNr; + this.required = required; + } + + public MetricTransform(MetricTransform other) { + this.name = other.name; + this.copyNr = other.copyNr; + this.required = other.required; + } +} diff --git a/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetrics.java b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetrics.java new file mode 100644 index 00000000000..efc5ab56277 --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetrics.java @@ -0,0 +1,203 @@ +/* + * 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.hop.pipeline.transforms.transformsmetrics; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.row.RowDataUtil; +import org.apache.hop.core.row.RowMeta; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.engine.EngineComponent.ComponentExecutionStatus; +import org.apache.hop.pipeline.engine.IEngineComponent; +import org.apache.hop.pipeline.transform.BaseTransform; +import org.apache.hop.pipeline.transform.TransformMeta; + +/** + * Wait for selected sibling transforms to finish, then output one metrics row per watched copy. + * This transform does not consume incoming rows. + */ +public class TransformsMetrics extends BaseTransform { + + private static final Class PKG = TransformsMetricsMeta.class; + private static final long POLL_SLEEP_MS = 20L; + + public TransformsMetrics( + TransformMeta transformMeta, + TransformsMetricsMeta meta, + TransformsMetricsData data, + int copyNr, + PipelineMeta pipelineMeta, + Pipeline pipeline) { + super(transformMeta, meta, data, copyNr, pipelineMeta, pipeline); + } + + @Override + public boolean processRow() throws HopException { + if (first) { + first = false; + initializeWatchedTransforms(); + } + + List remaining = data.getRemaining(); + while (!remaining.isEmpty() && !isStopped()) { + boolean waiting = false; + Iterator iterator = remaining.iterator(); + while (iterator.hasNext()) { + IEngineComponent component = iterator.next(); + if (isStillRunning(component)) { + waiting = true; + } else { + iterator.remove(); + if (isDetailed()) { + logDetailed( + BaseMessages.getString( + PKG, + "TransformsMetrics.Log.Finished", + component.getName(), + String.valueOf(component.getCopyNr()))); + } + emitMetricsRow(component); + } + } + if (waiting && !remaining.isEmpty() && !isStopped()) { + try { + TimeUnit.MILLISECONDS.sleep(POLL_SLEEP_MS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + setStopped(true); + } + } + } + + setOutputDone(); + return false; + } + + private void initializeWatchedTransforms() throws HopException { + if (meta.getMetricTransforms() == null || meta.getMetricTransforms().isEmpty()) { + throw new HopException(BaseMessages.getString(PKG, "TransformsMetrics.Error.NotTransforms")); + } + + data.setTransformNameField(resolve(meta.getTransformNameField())); + data.setTransformIdField(resolve(meta.getTransformIdField())); + data.setLinesInputField(resolve(meta.getLinesInputField())); + data.setLinesOutputField(resolve(meta.getLinesOutputField())); + data.setLinesReadField(resolve(meta.getLinesReadField())); + data.setLinesUpdatedField(resolve(meta.getLinesUpdatedField())); + data.setLinesWrittenField(resolve(meta.getLinesWrittenField())); + data.setLinesRejectedField(resolve(meta.getLinesRejectedField())); + data.setDurationField(resolve(meta.getDurationField())); + + String[] nextTransforms = getPipelineMeta().getNextTransformNames(getTransformMeta()); + List remaining = new ArrayList<>(); + + for (MetricTransform metricTransform : meta.getMetricTransforms()) { + String name = metricTransform.getName(); + if (StringUtils.isEmpty(name)) { + continue; + } + if (name.equals(getTransformName())) { + throw new HopException( + BaseMessages.getString(PKG, "TransformsMetrics.Error.CannotWatchSelf", name)); + } + if (nextTransforms != null) { + for (String nextTransform : nextTransforms) { + if (name.equals(nextTransform)) { + throw new HopException( + BaseMessages.getString( + PKG, "TransformsMetrics.Error.CannotWatchTarget", nextTransform)); + } + } + } + + int copyNr = Const.toInt(resolve(metricTransform.getCopyNr()), 0); + IEngineComponent component = getDispatcher().findComponent(name, copyNr); + if (component == null) { + if (metricTransform.isRequired()) { + throw new HopException( + BaseMessages.getString( + PKG, "TransformsMetrics.Error.TransformNotFound", name, String.valueOf(copyNr))); + } + continue; + } + remaining.add(component); + } + + data.setRemaining(remaining); + + data.setOutputRowMeta(new RowMeta()); + meta.getFields( + data.getOutputRowMeta(), getTransformName(), null, null, this, getMetadataProvider()); + } + + private boolean isStillRunning(IEngineComponent component) { + ComponentExecutionStatus status = component.getStatus(); + return status == ComponentExecutionStatus.STATUS_RUNNING + || status == ComponentExecutionStatus.STATUS_IDLE + || status == ComponentExecutionStatus.STATUS_INIT + || status == ComponentExecutionStatus.STATUS_PAUSED; + } + + private void emitMetricsRow(IEngineComponent component) throws HopException { + Object[] rowData = RowDataUtil.allocateRowData(data.getOutputRowMeta().size()); + incrementLinesRead(); + + int index = 0; + if (StringUtils.isNotBlank(data.getTransformNameField())) { + rowData[index++] = component.getName(); + } + if (StringUtils.isNotBlank(data.getTransformIdField())) { + rowData[index++] = pluginIdOf(component); + } + if (StringUtils.isNotBlank(data.getLinesInputField())) { + rowData[index++] = component.getLinesInput(); + } + if (StringUtils.isNotBlank(data.getLinesOutputField())) { + rowData[index++] = component.getLinesOutput(); + } + if (StringUtils.isNotBlank(data.getLinesReadField())) { + rowData[index++] = component.getLinesRead(); + } + if (StringUtils.isNotBlank(data.getLinesUpdatedField())) { + rowData[index++] = component.getLinesUpdated(); + } + if (StringUtils.isNotBlank(data.getLinesWrittenField())) { + rowData[index++] = component.getLinesWritten(); + } + if (StringUtils.isNotBlank(data.getLinesRejectedField())) { + rowData[index++] = component.getLinesRejected(); + } + if (StringUtils.isNotBlank(data.getDurationField())) { + rowData[index] = component.getExecutionDuration(); + } + + putRow(data.getOutputRowMeta(), rowData); + } + + private String pluginIdOf(IEngineComponent component) { + TransformMeta watched = getPipelineMeta().findTransform(component.getName()); + return watched == null ? null : watched.getTransformPluginId(); + } +} diff --git a/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsData.java b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsData.java new file mode 100644 index 00000000000..4019a0422bb --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsData.java @@ -0,0 +1,45 @@ +/* + * 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.hop.pipeline.transforms.transformsmetrics; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.pipeline.engine.IEngineComponent; +import org.apache.hop.pipeline.transform.BaseTransformData; +import org.apache.hop.pipeline.transform.ITransformData; + +@Getter +@Setter +public class TransformsMetricsData extends BaseTransformData implements ITransformData { + + private List remaining = new ArrayList<>(); + private IRowMeta outputRowMeta; + + private String transformNameField; + private String transformIdField; + private String linesInputField; + private String linesOutputField; + private String linesReadField; + private String linesUpdatedField; + private String linesWrittenField; + private String linesRejectedField; + private String durationField; +} diff --git a/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsDialog.java b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsDialog.java new file mode 100644 index 00000000000..ad0914119da --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsDialog.java @@ -0,0 +1,253 @@ +/* + * 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.hop.pipeline.transforms.transformsmetrics; + +import java.util.ArrayList; +import java.util.List; +import org.apache.hop.core.Const; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.apache.hop.ui.core.PropsUi; +import org.apache.hop.ui.core.dialog.BaseDialog; +import org.apache.hop.ui.core.gui.GuiCompositeWidgets; +import org.apache.hop.ui.core.gui.GuiCompositeWidgetsAdapter; +import org.apache.hop.ui.core.widget.ColumnInfo; +import org.apache.hop.ui.core.widget.TableView; +import org.apache.hop.ui.pipeline.transform.BaseTransformDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +public class TransformsMetricsDialog extends BaseTransformDialog { + private static final Class PKG = TransformsMetricsMeta.class; + + private final TransformsMetricsMeta input; + private GuiCompositeWidgets widgets; + private TableView wFields; + private String[] previousTransforms; + + public TransformsMetricsDialog( + Shell parent, + IVariables variables, + TransformsMetricsMeta transformMeta, + PipelineMeta pipelineMeta) { + super(parent, variables, transformMeta, pipelineMeta); + input = transformMeta; + } + + @Override + public String open() { + createShell(BaseMessages.getString(PKG, "TransformsMetricsDialog.Shell.Title")); + + changed = input.hasChanged(); + + buildButtonBar().ok(e -> ok()).get(e -> get()).cancel(e -> cancel()).build(); + + setTransformNames(); + + Composite area = new Composite(shell, SWT.NONE); + PropsUi.setLook(area); + area.setLayout(new FormLayout()); + FormData fdArea = new FormData(); + fdArea.left = new FormAttachment(0, 0); + fdArea.top = new FormAttachment(wSpacer, margin); + fdArea.right = new FormAttachment(100, 0); + fdArea.bottom = new FormAttachment(wOk, -2 * margin); + area.setLayoutData(fdArea); + + widgets = new GuiCompositeWidgets(variables); + widgets.registerExtraGroup( + BaseMessages.getString(PKG, "TransformsMetricsMeta.Group.Transforms"), + "10", + null, + this::addTransformsTable); + widgets.setWidgetsListener( + new GuiCompositeWidgetsAdapter() { + @Override + public void widgetModified( + GuiCompositeWidgets compositeWidgets, Control changedWidget, String widgetId) { + input.setChanged(); + } + }); + widgets.createCompositeWidgets( + input, null, area, TransformsMetricsMeta.GUI_PLUGIN_ELEMENT_PARENT_ID, null); + + getData(); + input.setChanged(changed); + focusTransformName(); + BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel()); + return transformName; + } + + private void addTransformsTable(Composite parent) { + Label wlFields = new Label(parent, SWT.NONE); + wlFields.setText(BaseMessages.getString(PKG, "TransformsMetricsDialog.Fields.Label")); + PropsUi.setLook(wlFields); + FormData fdlFields = new FormData(); + fdlFields.left = new FormAttachment(0, 0); + fdlFields.top = new FormAttachment(0, 0); + wlFields.setLayoutData(fdlFields); + + String[] yesNo = + new String[] { + BaseMessages.getString(PKG, "System.Combo.No"), + BaseMessages.getString(PKG, "System.Combo.Yes") + }; + + ColumnInfo[] colinf = new ColumnInfo[3]; + colinf[0] = + new ColumnInfo( + BaseMessages.getString(PKG, "TransformsMetricsDialog.Fieldname.Transform"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + previousTransforms, + false); + colinf[1] = + new ColumnInfo( + BaseMessages.getString(PKG, "TransformsMetricsDialog.Fieldname.CopyNr"), + ColumnInfo.COLUMN_TYPE_TEXT, + false); + colinf[1].setUsingVariables(true); + colinf[2] = + new ColumnInfo( + BaseMessages.getString(PKG, "TransformsMetricsDialog.Fieldname.Required"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + yesNo); + + wFields = + new TableView( + variables, + parent, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinf, + input.getMetricTransforms() == null ? 0 : input.getMetricTransforms().size(), + e -> input.setChanged(), + props); + + FormData fdFields = new FormData(); + fdFields.left = new FormAttachment(0, 0); + fdFields.top = new FormAttachment(wlFields, margin); + fdFields.right = new FormAttachment(100, 0); + fdFields.bottom = new FormAttachment(100, 0); + wFields.setLayoutData(fdFields); + } + + private void setTransformNames() { + previousTransforms = pipelineMeta.getTransformNames(); + List nextTransforms = getNextTransforms(new ArrayList<>(), transformMeta); + + List entries = new ArrayList<>(); + for (String previousTransform : previousTransforms) { + if (!previousTransform.equals(transformName) && !nextTransforms.contains(previousTransform)) { + entries.add(previousTransform); + } + } + previousTransforms = entries.toArray(new String[0]); + } + + private List getNextTransforms(List transformNames, TransformMeta transformMeta) { + List nextTransformMeta = pipelineMeta.findNextTransforms(transformMeta); + for (TransformMeta nextTransform : nextTransformMeta) { + transformNames.add(nextTransform.getName()); + getNextTransforms(transformNames, nextTransform); + } + return transformNames.stream().distinct().toList(); + } + + private void get() { + wFields.removeAll(); + Table table = wFields.table; + for (int i = 0; i < previousTransforms.length; i++) { + TableItem ti = new TableItem(table, SWT.NONE); + ti.setText(0, "" + (i + 1)); + ti.setText(1, previousTransforms[i]); + ti.setText(2, "0"); + ti.setText(3, BaseMessages.getString(PKG, "System.Combo.No")); + } + wFields.removeEmptyRows(); + wFields.setRowNums(); + wFields.optWidth(true); + input.setChanged(); + } + + private void getData() { + widgets.setWidgetsContents(input, shell, TransformsMetricsMeta.GUI_PLUGIN_ELEMENT_PARENT_ID); + + Table table = wFields.table; + if (input.getMetricTransforms() != null && !input.getMetricTransforms().isEmpty()) { + table.removeAll(); + } + if (input.getMetricTransforms() != null) { + for (MetricTransform metricTransform : input.getMetricTransforms()) { + TableItem ti = new TableItem(table, SWT.NONE); + ti.setText(1, Const.NVL(metricTransform.getName(), "")); + ti.setText(2, Const.NVL(metricTransform.getCopyNr(), "")); + ti.setText( + 3, + metricTransform.isRequired() + ? BaseMessages.getString(PKG, "System.Combo.Yes") + : BaseMessages.getString(PKG, "System.Combo.No")); + } + } + wFields.removeEmptyRows(); + wFields.setRowNums(); + wFields.optWidth(true); + } + + private void cancel() { + transformName = null; + input.setChanged(changed); + dispose(); + } + + private void ok() { + if (Utils.isEmpty(wTransformName.getText())) { + return; + } + + widgets.getWidgetsContents(input, TransformsMetricsMeta.GUI_PLUGIN_ELEMENT_PARENT_ID); + transformName = wTransformName.getText(); + + if (input.getMetricTransforms() == null) { + input.setMetricTransforms(new ArrayList<>()); + } else { + input.getMetricTransforms().clear(); + } + String yes = BaseMessages.getString(PKG, "System.Combo.Yes"); + for (TableItem item : wFields.getNonEmptyItems()) { + String name = item.getText(1); + if (Utils.isEmpty(name)) { + continue; + } + input + .getMetricTransforms() + .add(new MetricTransform(name, item.getText(2), yes.equalsIgnoreCase(item.getText(3)))); + } + input.setChanged(); + dispose(); + } +} diff --git a/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsMeta.java b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsMeta.java new file mode 100644 index 00000000000..2a1177628e0 --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsMeta.java @@ -0,0 +1,358 @@ +/* + * 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.hop.pipeline.transforms.transformsmetrics; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.apache.hop.core.CheckResult; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.annotations.Transform; +import org.apache.hop.core.exception.HopTransformException; +import org.apache.hop.core.gui.plugin.GuiElementType; +import org.apache.hop.core.gui.plugin.GuiPlugin; +import org.apache.hop.core.gui.plugin.GuiWidgetElement; +import org.apache.hop.core.gui.plugin.GuiWidgetGroupType; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.core.row.value.ValueMetaInteger; +import org.apache.hop.core.row.value.ValueMetaString; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.HopMetadataProperty; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.PipelineMeta.PipelineType; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.TransformMeta; + +@Getter +@Setter +@Transform( + id = "TransformsMetrics,StepsMetrics", + image = "transformsmetrics.svg", + name = "i18n::TransformsMetrics.Name", + description = "i18n::TransformsMetrics.Description", + categoryDescription = + "i18n:org.apache.hop.pipeline.transform:BaseTransform.Category.Statistics", + keywords = "i18n::TransformsMetricsMeta.keyword", + documentationUrl = "/pipeline/transforms/outputtransformmetrics.html") +@GuiPlugin +public class TransformsMetricsMeta + extends BaseTransformMeta { + private static final Class PKG = TransformsMetricsMeta.class; + + public static final String GUI_PLUGIN_ELEMENT_PARENT_ID = "TRANSFORMS_METRICS_DIALOG_OPTIONS"; + public static final String GROUP_FIELDS = "i18n::TransformsMetricsMeta.Group.Fields"; + public static final String WIDGET_TRANSFORM_NAME_FIELD = "TRANSFORM_NAME_FIELD"; + public static final String WIDGET_TRANSFORM_ID_FIELD = "TRANSFORM_ID_FIELD"; + public static final String WIDGET_LINES_INPUT_FIELD = "LINES_INPUT_FIELD"; + public static final String WIDGET_LINES_OUTPUT_FIELD = "LINES_OUTPUT_FIELD"; + public static final String WIDGET_LINES_READ_FIELD = "LINES_READ_FIELD"; + public static final String WIDGET_LINES_UPDATED_FIELD = "LINES_UPDATED_FIELD"; + public static final String WIDGET_LINES_WRITTEN_FIELD = "LINES_WRITTEN_FIELD"; + public static final String WIDGET_LINES_REJECTED_FIELD = "LINES_REJECTED_FIELD"; + public static final String WIDGET_DURATION_FIELD = "DURATION_FIELD"; + + public static final String DEFAULT_TRANSFORM_NAME_FIELD = "Transform name"; + public static final String DEFAULT_TRANSFORM_ID_FIELD = "Transform id"; + public static final String DEFAULT_LINES_INPUT_FIELD = "Lines input"; + public static final String DEFAULT_LINES_OUTPUT_FIELD = "Lines output"; + public static final String DEFAULT_LINES_READ_FIELD = "Lines read"; + public static final String DEFAULT_LINES_UPDATED_FIELD = "Lines updated"; + public static final String DEFAULT_LINES_WRITTEN_FIELD = "Lines written"; + public static final String DEFAULT_LINES_REJECTED_FIELD = "Lines rejected"; + public static final String DEFAULT_DURATION_FIELD = "Duration"; + + @HopMetadataProperty( + groupKey = "transforms", + key = "transform", + injectionGroupKey = "TRANSFORMS", + injectionGroupDescription = "TransformsMetricsMeta.Injection.TRANSFORMS") + private List metricTransforms; + + @GuiWidgetElement( + id = WIDGET_TRANSFORM_NAME_FIELD, + order = "0100", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.TransformNameField.Label", + toolTip = "i18n::TransformsMetricsMeta.TransformNameField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformnamefield", + injectionKey = "TRANSFORM_NAME_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.TRANSFORM_NAME_FIELD") + private String transformNameField; + + @GuiWidgetElement( + id = WIDGET_TRANSFORM_ID_FIELD, + order = "0200", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.TransformIdField.Label", + toolTip = "i18n::TransformsMetricsMeta.TransformIdField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformidfield", + injectionKey = "TRANSFORM_ID_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.TRANSFORM_ID_FIELD") + private String transformIdField; + + @GuiWidgetElement( + id = WIDGET_LINES_INPUT_FIELD, + order = "0300", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.LinesInputField.Label", + toolTip = "i18n::TransformsMetricsMeta.LinesInputField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformlinesinputfield", + injectionKey = "LINES_INPUT_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.LINES_INPUT_FIELD") + private String linesInputField; + + @GuiWidgetElement( + id = WIDGET_LINES_OUTPUT_FIELD, + order = "0400", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.LinesOutputField.Label", + toolTip = "i18n::TransformsMetricsMeta.LinesOutputField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformlinesoutputfield", + injectionKey = "LINES_OUTPUT_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.LINES_OUTPUT_FIELD") + private String linesOutputField; + + @GuiWidgetElement( + id = WIDGET_LINES_READ_FIELD, + order = "0500", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.LinesReadField.Label", + toolTip = "i18n::TransformsMetricsMeta.LinesReadField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformlinesreadfield", + injectionKey = "LINES_READ_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.LINES_READ_FIELD") + private String linesReadField; + + @GuiWidgetElement( + id = WIDGET_LINES_UPDATED_FIELD, + order = "0600", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.LinesUpdatedField.Label", + toolTip = "i18n::TransformsMetricsMeta.LinesUpdatedField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformlinesupdatedfield", + injectionKey = "LINES_UPDATED_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.LINES_UPDATED_FIELD") + private String linesUpdatedField; + + @GuiWidgetElement( + id = WIDGET_LINES_WRITTEN_FIELD, + order = "0700", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.LinesWrittenField.Label", + toolTip = "i18n::TransformsMetricsMeta.LinesWrittenField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformlineswrittenfield", + injectionKey = "LINES_WRITTEN_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.LINES_WRITTEN_FIELD") + private String linesWrittenField; + + @GuiWidgetElement( + id = WIDGET_LINES_REJECTED_FIELD, + order = "0800", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.LinesRejectedField.Label", + toolTip = "i18n::TransformsMetricsMeta.LinesRejectedField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformlineserrorsfield", + injectionKey = "LINES_REJECTED_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.LINES_REJECTED_FIELD") + private String linesRejectedField; + + @GuiWidgetElement( + id = WIDGET_DURATION_FIELD, + order = "0900", + type = GuiElementType.TEXT, + label = "i18n::TransformsMetricsMeta.DurationField.Label", + toolTip = "i18n::TransformsMetricsMeta.DurationField.Tooltip", + parentId = GUI_PLUGIN_ELEMENT_PARENT_ID, + group = GROUP_FIELDS, + groupOrder = "20", + groupType = GuiWidgetGroupType.TABS) + @HopMetadataProperty( + key = "transformsecondsfield", + injectionKey = "DURATION_FIELD", + injectionKeyDescription = "TransformsMetricsMeta.Injection.DURATION_FIELD") + private String durationField; + + public TransformsMetricsMeta() { + metricTransforms = new ArrayList<>(); + } + + @Override + public void setDefault() { + metricTransforms = new ArrayList<>(); + transformNameField = DEFAULT_TRANSFORM_NAME_FIELD; + transformIdField = DEFAULT_TRANSFORM_ID_FIELD; + linesInputField = DEFAULT_LINES_INPUT_FIELD; + linesOutputField = DEFAULT_LINES_OUTPUT_FIELD; + linesReadField = DEFAULT_LINES_READ_FIELD; + linesUpdatedField = DEFAULT_LINES_UPDATED_FIELD; + linesWrittenField = DEFAULT_LINES_WRITTEN_FIELD; + linesRejectedField = DEFAULT_LINES_REJECTED_FIELD; + durationField = DEFAULT_DURATION_FIELD; + } + + @Override + public void getFields( + IRowMeta inputRowMeta, + String name, + IRowMeta[] info, + TransformMeta nextTransform, + IVariables variables, + IHopMetadataProvider metadataProvider) + throws HopTransformException { + inputRowMeta.clear(); + addStringField(inputRowMeta, variables.resolve(transformNameField), name); + addStringField(inputRowMeta, variables.resolve(transformIdField), name); + addIntegerField(inputRowMeta, variables.resolve(linesInputField), name); + addIntegerField(inputRowMeta, variables.resolve(linesOutputField), name); + addIntegerField(inputRowMeta, variables.resolve(linesReadField), name); + addIntegerField(inputRowMeta, variables.resolve(linesUpdatedField), name); + addIntegerField(inputRowMeta, variables.resolve(linesWrittenField), name); + addIntegerField(inputRowMeta, variables.resolve(linesRejectedField), name); + addIntegerField(inputRowMeta, variables.resolve(durationField), name); + } + + private void addStringField(IRowMeta rowMeta, String fieldName, String origin) { + if (StringUtils.isBlank(fieldName)) { + return; + } + ValueMetaString valueMeta = new ValueMetaString(fieldName); + valueMeta.setOrigin(origin); + rowMeta.addValueMeta(valueMeta); + } + + private void addIntegerField(IRowMeta rowMeta, String fieldName, String origin) { + if (StringUtils.isBlank(fieldName)) { + return; + } + ValueMetaInteger valueMeta = + new ValueMetaInteger(fieldName, IValueMeta.DEFAULT_INTEGER_LENGTH, 0); + valueMeta.setOrigin(origin); + rowMeta.addValueMeta(valueMeta); + } + + @Override + public void check( + List remarks, + PipelineMeta pipelineMeta, + TransformMeta transformMeta, + IRowMeta prev, + String[] input, + String[] output, + IRowMeta info, + IVariables variables, + IHopMetadataProvider metadataProvider) { + if (input.length > 0) { + remarks.add( + new CheckResult( + ICheckResult.TYPE_RESULT_ERROR, + BaseMessages.getString( + PKG, "TransformsMetricsMeta.CheckResult.IncomingHopsNotSupported"), + transformMeta)); + } else { + remarks.add( + new CheckResult( + ICheckResult.TYPE_RESULT_OK, + BaseMessages.getString(PKG, "TransformsMetricsMeta.CheckResult.NoIncomingHops"), + transformMeta)); + } + + if (metricTransforms == null || metricTransforms.isEmpty()) { + remarks.add( + new CheckResult( + ICheckResult.TYPE_RESULT_ERROR, + BaseMessages.getString(PKG, "TransformsMetricsMeta.CheckResult.NoTransformsEntered"), + transformMeta)); + return; + } + + boolean allFound = true; + for (MetricTransform metricTransform : metricTransforms) { + if (StringUtils.isEmpty(metricTransform.getName())) { + continue; + } + if (pipelineMeta.findTransform(metricTransform.getName()) == null) { + allFound = false; + remarks.add( + new CheckResult( + ICheckResult.TYPE_RESULT_WARNING, + BaseMessages.getString( + PKG, + "TransformsMetricsMeta.CheckResult.TransformNotFound", + metricTransform.getName()), + transformMeta)); + } + } + if (allFound) { + remarks.add( + new CheckResult( + ICheckResult.TYPE_RESULT_OK, + BaseMessages.getString(PKG, "TransformsMetricsMeta.CheckResult.AllTransformsFound"), + transformMeta)); + } + } + + @Override + public PipelineType[] getSupportedPipelineTypes() { + return new PipelineType[] {PipelineType.Normal}; + } +} diff --git a/plugins/transforms/transformsmetrics/src/main/resources/org/apache/hop/pipeline/transforms/transformsmetrics/messages/messages_en_US.properties b/plugins/transforms/transformsmetrics/src/main/resources/org/apache/hop/pipeline/transforms/transformsmetrics/messages/messages_en_US.properties new file mode 100644 index 00000000000..3e4f3ff9b39 --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/resources/org/apache/hop/pipeline/transforms/transformsmetrics/messages/messages_en_US.properties @@ -0,0 +1,68 @@ +# +# 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. +# + +TransformsMetrics.Name=Output transform metrics +TransformsMetrics.Description=Wait for selected transforms to finish and output their metrics +TransformsMetricsMeta.keyword=metrics,statistics,wait,transform,output +TransformsMetrics.Error.NotTransforms=You must define at least one transform for which metrics will be returned. +TransformsMetrics.Error.CannotWatchSelf=You can not get metrics for the current transform [{0}]. +TransformsMetrics.Error.CannotWatchTarget=You can not get metrics for the target transform [{0}]. +TransformsMetrics.Error.TransformNotFound=We cannot get transform [{0}] copyNr={1}. +TransformsMetrics.Log.Finished=Finished running transform [{0} ({1})]. +TransformsMetricsDialog.Shell.Title=Output transform metrics +TransformsMetricsDialog.Fields.Label=Metrics for the following transforms +TransformsMetricsDialog.Fieldname.Transform=Transform name +TransformsMetricsDialog.Fieldname.CopyNr=Copy Nr +TransformsMetricsDialog.Fieldname.Required=Required +TransformsMetricsMeta.Group.Transforms=Transforms +TransformsMetricsMeta.Group.Fields=Fields +TransformsMetricsMeta.TransformNameField.Label=Transform name +TransformsMetricsMeta.TransformNameField.Tooltip=Output field for the watched transform name. Leave empty to omit this field. +TransformsMetricsMeta.TransformIdField.Label=Transform id +TransformsMetricsMeta.TransformIdField.Tooltip=Output field for the watched transform plugin id. Leave empty to omit this field. +TransformsMetricsMeta.LinesInputField.Label=Lines input +TransformsMetricsMeta.LinesInputField.Tooltip=Output field for lines input. Leave empty to omit this field. +TransformsMetricsMeta.LinesOutputField.Label=Lines output +TransformsMetricsMeta.LinesOutputField.Tooltip=Output field for lines output. Leave empty to omit this field. +TransformsMetricsMeta.LinesReadField.Label=Lines read +TransformsMetricsMeta.LinesReadField.Tooltip=Output field for lines read. Leave empty to omit this field. +TransformsMetricsMeta.LinesUpdatedField.Label=Lines updated +TransformsMetricsMeta.LinesUpdatedField.Tooltip=Output field for lines updated. Leave empty to omit this field. +TransformsMetricsMeta.LinesWrittenField.Label=Lines written +TransformsMetricsMeta.LinesWrittenField.Tooltip=Output field for lines written. Leave empty to omit this field. +TransformsMetricsMeta.LinesRejectedField.Label=Lines rejected +TransformsMetricsMeta.LinesRejectedField.Tooltip=Output field for lines rejected (error hop). Leave empty to omit this field. +TransformsMetricsMeta.DurationField.Label=Duration (ms) +TransformsMetricsMeta.DurationField.Tooltip=Output field for execution duration in milliseconds. Leave empty to omit this field. +TransformsMetricsMeta.CheckResult.IncomingHopsNotSupported=Incoming hops are not supported and would deadlock this transform. Remove them. +TransformsMetricsMeta.CheckResult.NoIncomingHops=Not receiving input from other transforms. +TransformsMetricsMeta.CheckResult.NoTransformsEntered=No transforms are entered. +TransformsMetricsMeta.CheckResult.TransformNotFound=Watched transform [{0}] was not found in the pipeline. +TransformsMetricsMeta.CheckResult.AllTransformsFound=All watched transforms were found. +TransformsMetricsMeta.Injection.TRANSFORMS=Transforms to watch +TransformsMetricsMeta.Injection.TRANSFORM_NAME=Transform name +TransformsMetricsMeta.Injection.TRANSFORM_COPY_NR=Copy number +TransformsMetricsMeta.Injection.TRANSFORM_REQUIRED=Required +TransformsMetricsMeta.Injection.TRANSFORM_NAME_FIELD=Transform name field +TransformsMetricsMeta.Injection.TRANSFORM_ID_FIELD=Transform id field +TransformsMetricsMeta.Injection.LINES_INPUT_FIELD=Lines input field +TransformsMetricsMeta.Injection.LINES_OUTPUT_FIELD=Lines output field +TransformsMetricsMeta.Injection.LINES_READ_FIELD=Lines read field +TransformsMetricsMeta.Injection.LINES_UPDATED_FIELD=Lines updated field +TransformsMetricsMeta.Injection.LINES_WRITTEN_FIELD=Lines written field +TransformsMetricsMeta.Injection.LINES_REJECTED_FIELD=Lines rejected field +TransformsMetricsMeta.Injection.DURATION_FIELD=Duration field diff --git a/plugins/transforms/transformsmetrics/src/main/resources/transformsmetrics.svg b/plugins/transforms/transformsmetrics/src/main/resources/transformsmetrics.svg new file mode 100644 index 00000000000..6829085d350 --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/resources/transformsmetrics.svg @@ -0,0 +1,23 @@ + + + + + + + diff --git a/plugins/transforms/transformsmetrics/src/main/resources/version.xml b/plugins/transforms/transformsmetrics/src/main/resources/version.xml new file mode 100644 index 00000000000..36ab20e22eb --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/resources/version.xml @@ -0,0 +1,20 @@ + + + +${project.version} diff --git a/plugins/transforms/transformsmetrics/src/main/samples/transforms/output-transform-metrics-basic.hpl b/plugins/transforms/transformsmetrics/src/main/samples/transforms/output-transform-metrics-basic.hpl new file mode 100644 index 00000000000..1fa7eb8363d --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/main/samples/transforms/output-transform-metrics-basic.hpl @@ -0,0 +1,201 @@ + + + + + output-transform-metrics-basic + Y + Wait for sibling transforms to finish and output their metrics + + + Normal + + + N + 1000 + 100 + - + 2026/08/29 12:00:00.000 + - + 2026/08/29 12:00:00.000 + + N + + + + + + 10 rows + Dummy A + Y + + + 5 rows + Dummy B + Y + + + + 10 rows + RowGenerator + + Y + + 1 + + none + + + + + value + Integer + # + + + + 1 + -1 + -1 + N + + + 10 + N + 5000 + now + FiveSecondsAgo + + + 80 + 80 + + + + 5 rows + RowGenerator + + Y + + 1 + + none + + + + + value + Integer + # + + + + 1 + -1 + -1 + N + + + 5 + N + 5000 + now + FiveSecondsAgo + + + 80 + 224 + + + + Dummy A + Dummy + + Y + + 1 + + none + + + + + 256 + 80 + + + + Dummy B + Dummy + + Y + + 1 + + none + + + + + 256 + 224 + + + + Output transform metrics + TransformsMetrics + + Y + + 1 + + none + + + + + Dummy A + 0 + Y + + + Dummy B + 0 + Y + + + Transform name + Transform id + Lines input + Lines output + Lines read + Lines updated + Lines written + Lines rejected + Duration + + + 448 + 152 + + + + + + diff --git a/plugins/transforms/transformsmetrics/src/test/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsMetaTest.java b/plugins/transforms/transformsmetrics/src/test/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsMetaTest.java new file mode 100644 index 00000000000..7231bbb5a44 --- /dev/null +++ b/plugins/transforms/transformsmetrics/src/test/java/org/apache/hop/pipeline/transforms/transformsmetrics/TransformsMetricsMetaTest.java @@ -0,0 +1,151 @@ +/* + * 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.hop.pipeline.transforms.transformsmetrics; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.apache.hop.core.HopClientEnvironment; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.core.row.RowMeta; +import org.apache.hop.core.row.value.ValueMetaString; +import org.apache.hop.core.variables.Variables; +import org.apache.hop.core.xml.XmlHandler; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class TransformsMetricsMetaTest { + + @BeforeAll + static void beforeAll() throws Exception { + HopClientEnvironment.init(); + } + + @Test + void testXmlRoundTrip() throws Exception { + TransformsMetricsMeta meta = new TransformsMetricsMeta(); + meta.setDefault(); + meta.getMetricTransforms().add(new MetricTransform("A", "0", true)); + meta.getMetricTransforms().add(new MetricTransform("B", "1", false)); + meta.setTransformNameField("Transform name"); + meta.setLinesWrittenField("Lines written"); + meta.setDurationField(""); + + String transformXml = + XmlHandler.openTag(TransformMeta.XML_TAG) + + meta.getXml() + + XmlHandler.closeTag(TransformMeta.XML_TAG); + TransformsMetricsMeta loaded = new TransformsMetricsMeta(); + loaded.loadXml(XmlHandler.loadXmlString(transformXml, TransformMeta.XML_TAG), null); + + assertEquals(2, loaded.getMetricTransforms().size()); + assertEquals("A", loaded.getMetricTransforms().get(0).getName()); + assertEquals("0", loaded.getMetricTransforms().get(0).getCopyNr()); + assertTrue(loaded.getMetricTransforms().get(0).isRequired()); + assertEquals("B", loaded.getMetricTransforms().get(1).getName()); + assertFalse(loaded.getMetricTransforms().get(1).isRequired()); + assertEquals("Transform name", loaded.getTransformNameField()); + assertEquals("Lines written", loaded.getLinesWrittenField()); + assertTrue(StringUtils.isBlank(loaded.getDurationField())); + assertTrue(transformXml.contains("")); + assertTrue(transformXml.contains("")); + assertTrue(transformXml.contains("")); + } + + @Test + void testGetFieldsClearsIncomingAndOmitsEmptyNames() throws Exception { + TransformsMetricsMeta meta = new TransformsMetricsMeta(); + meta.setDefault(); + meta.setTransformIdField(""); + meta.setLinesInputField(null); + meta.setDurationField(" "); + + IRowMeta rowMeta = new RowMeta(); + rowMeta.addValueMeta(new ValueMetaString("incoming")); + meta.getFields(rowMeta, "metrics", null, null, new Variables(), null); + + List names = new ArrayList<>(); + for (int i = 0; i < rowMeta.size(); i++) { + names.add(rowMeta.getValueMeta(i).getName()); + } + assertFalse(names.contains("incoming")); + assertTrue(names.contains(TransformsMetricsMeta.DEFAULT_TRANSFORM_NAME_FIELD)); + assertFalse(names.contains(TransformsMetricsMeta.DEFAULT_TRANSFORM_ID_FIELD)); + assertFalse(names.contains(TransformsMetricsMeta.DEFAULT_LINES_INPUT_FIELD)); + assertTrue(names.contains(TransformsMetricsMeta.DEFAULT_LINES_WRITTEN_FIELD)); + assertEquals(IValueMeta.TYPE_INTEGER, rowMeta.searchValueMeta("Lines written").getType()); + } + + @Test + void testCheckEmptyListAndIncomingHops() { + TransformsMetricsMeta meta = new TransformsMetricsMeta(); + meta.setDefault(); + TransformMeta transformMeta = new TransformMeta(); + transformMeta.setName("metrics"); + PipelineMeta pipelineMeta = new PipelineMeta(); + + List remarks = new ArrayList<>(); + meta.check( + remarks, + pipelineMeta, + transformMeta, + new RowMeta(), + new String[] {"upstream"}, + new String[0], + new RowMeta(), + new Variables(), + null); + assertTrue( + remarks.stream().anyMatch(r -> r.getType() == ICheckResult.TYPE_RESULT_ERROR), + "incoming hops should be an error"); + assertTrue( + remarks.stream().anyMatch(r -> r.getType() == ICheckResult.TYPE_RESULT_ERROR), + "empty watch list should be an error"); + } + + @Test + void testCheckMissingWatchedTransformIsWarning() { + TransformsMetricsMeta meta = new TransformsMetricsMeta(); + meta.setDefault(); + meta.getMetricTransforms().add(new MetricTransform("missing", "0", false)); + TransformMeta transformMeta = new TransformMeta(); + transformMeta.setName("metrics"); + PipelineMeta pipelineMeta = new PipelineMeta(); + + List remarks = new ArrayList<>(); + meta.check( + remarks, + pipelineMeta, + transformMeta, + new RowMeta(), + new String[0], + new String[0], + new RowMeta(), + new Variables(), + null); + assertTrue(remarks.stream().anyMatch(r -> r.getType() == ICheckResult.TYPE_RESULT_WARNING)); + } +}