From 4920ea0f5ae57350026e388b848ca6e67de0c7b3 Mon Sep 17 00:00:00 2001 From: Raj Kamal Singh <1133322+raj-k-singh@users.noreply.github.com> Date: Wed, 18 Sep 2024 11:26:59 +0530 Subject: [PATCH] feat: resource hierarchy: add helper for finding synonyms of an attribute in a hierarchy (#404) This helper will be used for identifying synonyms of `service.name` and `deployment.environment` to help rank those attributes higher in logs filter suggestions --- .../logsv2/fingerprint.go | 21 ++++++++++ .../logsv2/fingerprint_test.go | 41 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/exporter/clickhouselogsexporter/logsv2/fingerprint.go b/exporter/clickhouselogsexporter/logsv2/fingerprint.go index 9bb55666..ba8cf3a8 100644 --- a/exporter/clickhouselogsexporter/logsv2/fingerprint.go +++ b/exporter/clickhouselogsexporter/logsv2/fingerprint.go @@ -2,6 +2,7 @@ package logsv2 import ( "fmt" + "slices" "strings" ) @@ -45,6 +46,26 @@ func (node *DimensionHierarchyNode) Identifier(attributes map[string]any) []IdLa return result } +// Get list of synonymous labels in a hierarchy for `attribute` or `nil` +func (node *DimensionHierarchyNode) Synonyms(attribute string) []string { + if node == nil { + return nil + } + + if slices.Contains(node.labels, attribute) { + return node.labels[:] + } + + for _, h := range node.subHierachies { + synonyms := h.Synonyms(attribute) + if len(synonyms) > 0 { + return synonyms + } + } + + return nil +} + // TODO(Raj/Nitya): Consider parsing this stuff out from json func ResourceHierarchy() *DimensionHierarchyNode { return &DimensionHierarchyNode{ diff --git a/exporter/clickhouselogsexporter/logsv2/fingerprint_test.go b/exporter/clickhouselogsexporter/logsv2/fingerprint_test.go index 65f55086..ca9d40ac 100644 --- a/exporter/clickhouselogsexporter/logsv2/fingerprint_test.go +++ b/exporter/clickhouselogsexporter/logsv2/fingerprint_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCalculateFingerprint(t *testing.T) { @@ -39,3 +40,43 @@ func TestCalculateFingerprint(t *testing.T) { assert.Equal(t, ts.FingerPrint, res) } } + +func TestFindAttributeSynonyms(t *testing.T) { + testHierarchy := &DimensionHierarchyNode{ + labels: []string{"1.a", "1.b"}, + + subHierachies: []DimensionHierarchyNode{{ + labels: []string{"1.1.a", "1.1.b"}, + + subHierachies: []DimensionHierarchyNode{{ + labels: []string{"1.1.1.a", "1.1.1.b"}, + }}, + }, { + labels: []string{"1.2.a", "1.2.b"}, + }}, + } + + for _, tc := range []struct { + Attribute string + ExpectedSynonyms []string + }{ + { + Attribute: "non-existent-attribute", + ExpectedSynonyms: nil, + }, { + Attribute: "1.b", + ExpectedSynonyms: []string{"1.a", "1.b"}, + }, { + Attribute: "1.2.a", + ExpectedSynonyms: []string{"1.2.a", "1.2.b"}, + }, { + Attribute: "1.1.1.b", + ExpectedSynonyms: []string{"1.1.1.a", "1.1.1.b"}, + }, + } { + + synonyms := testHierarchy.Synonyms(tc.Attribute) + require.Equal(t, tc.ExpectedSynonyms, synonyms) + } + +}