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

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


The following commit(s) were added to refs/heads/master by this push:
     new a4dbf0b9bc [fix] persist custom monitor labels when writing to 
GreptimeDB (#4151)
a4dbf0b9bc is described below

commit a4dbf0b9bcd9d1e376855236319db2159c6bc006
Author: wilmerdooley <[email protected]>
AuthorDate: Fri Jul 3 08:51:56 2026 -0400

    [fix] persist custom monitor labels when writing to GreptimeDB (#4151)
    
    Signed-off-by: wilmerdooley <[email protected]>
    Co-authored-by: Tomsun28 <[email protected]>
---
 .../tsdb/greptime/GreptimeDbDataStorage.java       | 19 +++++-
 .../tsdb/greptime/GreptimeDbDataStorageTest.java   | 70 ++++++++++++++++++++++
 2 files changed, 88 insertions(+), 1 deletion(-)

diff --git 
a/hertzbeat-warehouse/src/main/java/org/apache/hertzbeat/warehouse/store/history/tsdb/greptime/GreptimeDbDataStorage.java
 
b/hertzbeat-warehouse/src/main/java/org/apache/hertzbeat/warehouse/store/history/tsdb/greptime/GreptimeDbDataStorage.java
index a3130736bc..387698ea1d 100644
--- 
a/hertzbeat-warehouse/src/main/java/org/apache/hertzbeat/warehouse/store/history/tsdb/greptime/GreptimeDbDataStorage.java
+++ 
b/hertzbeat-warehouse/src/main/java/org/apache/hertzbeat/warehouse/store/history/tsdb/greptime/GreptimeDbDataStorage.java
@@ -95,6 +95,7 @@ public class GreptimeDbDataStorage extends 
AbstractHistoryDataStorage {
     private static final String LOG_TABLE_NAME = 
WarehouseConstants.LOG_TABLE_NAME;
     private static final String LABEL_KEY_START_TIME = "start";
     private static final String LABEL_KEY_END_TIME = "end";
+    private static final String LABEL_KEY_TS = "ts";
     private static final int LOG_BATCH_SIZE = 500;
 
     private GreptimeDB greptimeDb;
@@ -151,6 +152,8 @@ public class GreptimeDbDataStorage extends 
AbstractHistoryDataStorage {
         tableSchemaBuilder.addTag("instance", DataType.String)
                 .addTimestamp("ts", DataType.TimestampMillisecond);
         List<CollectRep.Field> fields = metricsData.getFields();
+        Map<String, String> customLabels = metricsData.getLabels();
+        List<String> fieldNames = 
fields.stream().map(CollectRep.Field::getName).collect(Collectors.toList());
         fields.forEach(field -> {
             if (field.getLabel()) {
                 tableSchemaBuilder.addTag(field.getName(), DataType.String);
@@ -162,9 +165,19 @@ public class GreptimeDbDataStorage extends 
AbstractHistoryDataStorage {
                 }
             }
         });
+        List<String> labelKeys = new LinkedList<>();
+        if (!Objects.isNull(customLabels) && !customLabels.isEmpty()) {
+            for (Map.Entry<String, String> label : customLabels.entrySet()) {
+                String key = label.getKey();
+                if (!LABEL_KEY_INSTANCE.equals(key) && 
!LABEL_KEY_TS.equals(key) && !fieldNames.contains(key)) {
+                    tableSchemaBuilder.addTag(key, DataType.String);
+                    labelKeys.add(key);
+                }
+            }
+        }
         Table table = Table.from(tableSchemaBuilder.build());
         long now = System.currentTimeMillis();
-        Object[] values = new Object[2 + fields.size()];
+        Object[] values = new Object[2 + fields.size() + labelKeys.size()];
         values[0] = instance;
         values[1] = now;
         RowWrapper rowWrapper = metricsData.readRow();
@@ -194,6 +207,10 @@ public class GreptimeDbDataStorage extends 
AbstractHistoryDataStorage {
                 }
             });
 
+            for (int i = 0; i < labelKeys.size(); i++) {
+                values[2 + fields.size() + i] = 
customLabels.get(labelKeys.get(i));
+            }
+
             table.addRow(values);
         }
 
diff --git 
a/hertzbeat-warehouse/src/test/java/org/apache/hertzbeat/warehouse/store/history/tsdb/greptime/GreptimeDbDataStorageTest.java
 
b/hertzbeat-warehouse/src/test/java/org/apache/hertzbeat/warehouse/store/history/tsdb/greptime/GreptimeDbDataStorageTest.java
index c28130c493..3de76446b6 100644
--- 
a/hertzbeat-warehouse/src/test/java/org/apache/hertzbeat/warehouse/store/history/tsdb/greptime/GreptimeDbDataStorageTest.java
+++ 
b/hertzbeat-warehouse/src/test/java/org/apache/hertzbeat/warehouse/store/history/tsdb/greptime/GreptimeDbDataStorageTest.java
@@ -38,12 +38,17 @@ import io.greptime.models.Err;
 import io.greptime.models.Result;
 import io.greptime.models.Table;
 import io.greptime.models.WriteOk;
+import io.greptime.v1.Common;
+import io.greptime.v1.RowData;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
 import org.apache.hertzbeat.common.constants.CommonConstants;
 import org.apache.hertzbeat.common.entity.arrow.ArrowCell;
 import org.apache.hertzbeat.common.entity.arrow.RowWrapper;
@@ -150,6 +155,55 @@ class GreptimeDbDataStorageTest {
         }
     }
 
+    @Test
+    void testSaveDataWithCustomLabels() throws Exception {
+        try (MockedStatic<GreptimeDB> mockedStatic = 
mockStatic(GreptimeDB.class)) {
+            mockedStatic.when(() -> 
GreptimeDB.create(any())).thenReturn(greptimeDb);
+
+            Result<WriteOk, Err> mockResult = mock(Result.class);
+            when(mockResult.isOk()).thenReturn(true);
+            CompletableFuture<Result<WriteOk, Err>> mockFuture = 
CompletableFuture.completedFuture(mockResult);
+            when(greptimeDb.write(any(Table.class))).thenReturn(mockFuture);
+
+            greptimeDbDataStorage = new 
GreptimeDbDataStorage(greptimeProperties, restTemplate, 
greptimeSqlQueryExecutor);
+
+            CollectRep.MetricsData metricsData = createMockMetricsData(true);
+            Map<String, String> customLabels = new LinkedHashMap<>();
+            customLabels.put("instance", "bad_instance");
+            customLabels.put("ts", "bad_ts");
+            customLabels.put("usage", "bad_usage");
+            customLabels.put("env", "prod");
+            when(metricsData.getLabels()).thenReturn(customLabels);
+            when(metricsData.getInstance()).thenReturn("server1");
+
+            ArgumentCaptor<Table> tableCaptor = 
ArgumentCaptor.forClass(Table.class);
+            greptimeDbDataStorage.saveData(metricsData);
+
+            verify(greptimeDb).write(tableCaptor.capture());
+            Table capturedTable = tableCaptor.getValue();
+
+            List<RowData.ColumnSchema> columnSchemas = 
getColumnSchemas(capturedTable);
+            List<String> columnNames = columnSchemas.stream()
+                    .map(RowData.ColumnSchema::getColumnName)
+                    .collect(Collectors.toList());
+            assertEquals(5, columnNames.size());
+            assertEquals(2, Collections.frequency(columnNames, "instance"));
+            assertEquals(1, Collections.frequency(columnNames, "ts"));
+            assertEquals(1, Collections.frequency(columnNames, "usage"));
+
+            List<RowData.ColumnSchema> envColumnSchemas = 
columnSchemas.stream()
+                    .filter(columnSchema -> 
"env".equals(columnSchema.getColumnName()))
+                    .collect(Collectors.toList());
+            assertEquals(1, envColumnSchemas.size());
+            assertEquals(Common.SemanticType.TAG, 
envColumnSchemas.get(0).getSemanticType());
+
+            List<RowData.Row> rows = getRows(capturedTable);
+            assertEquals(1, rows.size());
+            RowData.Row row = rows.get(0);
+            assertEquals("prod", row.getValuesList().get(4).getStringValue());
+        }
+    }
+
     @Test
     void testGetHistoryMetricData() {
         greptimeDbDataStorage = new GreptimeDbDataStorage(greptimeProperties, 
restTemplate, greptimeSqlQueryExecutor);
@@ -387,4 +441,20 @@ class GreptimeDbDataStorageTest {
 
         return List.of(row);
     }
+
+    private List<RowData.ColumnSchema> getColumnSchemas(Table table) throws 
Exception {
+        Field columnSchemasField = 
table.getClass().getDeclaredField("columnSchemas");
+        columnSchemasField.setAccessible(true);
+        @SuppressWarnings("unchecked")
+        List<RowData.ColumnSchema> columnSchemas = 
(List<RowData.ColumnSchema>) columnSchemasField.get(table);
+        return columnSchemas;
+    }
+
+    private List<RowData.Row> getRows(Table table) throws Exception {
+        Field rowsField = table.getClass().getDeclaredField("rows");
+        rowsField.setAccessible(true);
+        @SuppressWarnings("unchecked")
+        List<RowData.Row> rows = (List<RowData.Row>) rowsField.get(table);
+        return rows;
+    }
 }


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

Reply via email to