From 4ba6882e88aa556857013712db1ea65ee958cf36 Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Mon, 7 Oct 2024 11:44:03 -0700 Subject: [PATCH 01/11] Add collection of SnippetsFilter count --- internal/mode/static/telemetry/collector.go | 4 ++++ internal/mode/static/telemetry/collector_test.go | 11 +++++++++++ internal/mode/static/telemetry/data.avdl | 3 +++ internal/mode/static/telemetry/data_test.go | 3 +++ .../ngfresourcecounts_attributes_generated.go | 1 + site/content/overview/product-telemetry.md | 2 +- tests/suite/telemetry_test.go | 1 + 7 files changed, 24 insertions(+), 1 deletion(-) diff --git a/internal/mode/static/telemetry/collector.go b/internal/mode/static/telemetry/collector.go index bcfd6fe28..58fb7f74d 100644 --- a/internal/mode/static/telemetry/collector.go +++ b/internal/mode/static/telemetry/collector.go @@ -83,6 +83,8 @@ type NGFResourceCounts struct { ObservabilityPolicyCount int64 // NginxProxyCount is the number of NginxProxies. NginxProxyCount int64 + // SnippetsFilterCount is the number of SnippetsFilters. + SnippetsFilterCount int64 } // DataCollectorConfig holds configuration parameters for DataCollectorImpl. @@ -227,6 +229,8 @@ func collectGraphResourceCount( ngfResourceCounts.NginxProxyCount = 1 } + ngfResourceCounts.SnippetsFilterCount = int64(len(g.SnippetsFilters)) + return ngfResourceCounts, nil } diff --git a/internal/mode/static/telemetry/collector_test.go b/internal/mode/static/telemetry/collector_test.go index 4175524ff..d688f1f58 100644 --- a/internal/mode/static/telemetry/collector_test.go +++ b/internal/mode/static/telemetry/collector_test.go @@ -328,6 +328,11 @@ var _ = Describe("Collector", Ordered, func() { }: {}, }, NginxProxy: &graph.NginxProxy{}, + SnippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{ + {Namespace: "test", Name: "sf-1"}: {}, + {Namespace: "test", Name: "sf-2"}: {}, + {Namespace: "test", Name: "sf-3"}: {}, + }, } config := &dataplane.Configuration{ @@ -379,6 +384,7 @@ var _ = Describe("Collector", Ordered, func() { RouteAttachedClientSettingsPolicyCount: 2, ObservabilityPolicyCount: 1, NginxProxyCount: 1, + SnippetsFilterCount: 3, } expData.ClusterVersion = "1.29.2" expData.ClusterPlatform = "kind" @@ -549,6 +555,9 @@ var _ = Describe("Collector", Ordered, func() { }: {}, }, NginxProxy: &graph.NginxProxy{}, + SnippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{ + {Namespace: "test", Name: "sf-1"}: {}, + }, } config1 = &dataplane.Configuration{ @@ -622,6 +631,7 @@ var _ = Describe("Collector", Ordered, func() { RouteAttachedClientSettingsPolicyCount: 1, ObservabilityPolicyCount: 1, NginxProxyCount: 1, + SnippetsFilterCount: 1, } data, err := dataCollector.Collect(ctx) @@ -647,6 +657,7 @@ var _ = Describe("Collector", Ordered, func() { RouteAttachedClientSettingsPolicyCount: 0, ObservabilityPolicyCount: 0, NginxProxyCount: 0, + SnippetsFilterCount: 0, } data, err := dataCollector.Collect(ctx) diff --git a/internal/mode/static/telemetry/data.avdl b/internal/mode/static/telemetry/data.avdl index 097a9bd68..7c6afa847 100644 --- a/internal/mode/static/telemetry/data.avdl +++ b/internal/mode/static/telemetry/data.avdl @@ -85,6 +85,9 @@ attached at the Gateway level. */ /** NginxProxyCount is the number of NginxProxies. */ long? NginxProxyCount = null; + /** SnippetsFilterCount is the number of SnippetsFilters. */ + long? SnippetsFilterCount = null; + /** NGFReplicaCount is the number of replicas of the NGF Pod. */ long? NGFReplicaCount = null; diff --git a/internal/mode/static/telemetry/data_test.go b/internal/mode/static/telemetry/data_test.go index 893203fd9..8f33a85e4 100644 --- a/internal/mode/static/telemetry/data_test.go +++ b/internal/mode/static/telemetry/data_test.go @@ -38,6 +38,7 @@ func TestDataAttributes(t *testing.T) { RouteAttachedClientSettingsPolicyCount: 10, ObservabilityPolicyCount: 11, NginxProxyCount: 12, + SnippetsFilterCount: 13, }, NGFReplicaCount: 3, } @@ -68,6 +69,7 @@ func TestDataAttributes(t *testing.T) { attribute.Int64("RouteAttachedClientSettingsPolicyCount", 10), attribute.Int64("ObservabilityPolicyCount", 11), attribute.Int64("NginxProxyCount", 12), + attribute.Int64("SnippetsFilterCount", 13), attribute.Int64("NGFReplicaCount", 3), } @@ -107,6 +109,7 @@ func TestDataAttributesWithEmptyData(t *testing.T) { attribute.Int64("RouteAttachedClientSettingsPolicyCount", 0), attribute.Int64("ObservabilityPolicyCount", 0), attribute.Int64("NginxProxyCount", 0), + attribute.Int64("SnippetsFilterCount", 0), attribute.Int64("NGFReplicaCount", 0), } diff --git a/internal/mode/static/telemetry/ngfresourcecounts_attributes_generated.go b/internal/mode/static/telemetry/ngfresourcecounts_attributes_generated.go index 2aa085405..318cbd0b6 100644 --- a/internal/mode/static/telemetry/ngfresourcecounts_attributes_generated.go +++ b/internal/mode/static/telemetry/ngfresourcecounts_attributes_generated.go @@ -25,6 +25,7 @@ func (d *NGFResourceCounts) Attributes() []attribute.KeyValue { attrs = append(attrs, attribute.Int64("RouteAttachedClientSettingsPolicyCount", d.RouteAttachedClientSettingsPolicyCount)) attrs = append(attrs, attribute.Int64("ObservabilityPolicyCount", d.ObservabilityPolicyCount)) attrs = append(attrs, attribute.Int64("NginxProxyCount", d.NginxProxyCount)) + attrs = append(attrs, attribute.Int64("SnippetsFilterCount", d.SnippetsFilterCount)) return attrs } diff --git a/site/content/overview/product-telemetry.md b/site/content/overview/product-telemetry.md index cb13b6997..536e4f8b4 100644 --- a/site/content/overview/product-telemetry.md +++ b/site/content/overview/product-telemetry.md @@ -27,7 +27,7 @@ Telemetry data is collected once every 24 hours and sent to a service managed by - **Deployment Replica Count:** the count of NGINX Gateway Fabric Pods. - **Image Build Source:** whether the image was built by GitHub or locally (values are `gha`, `local`, or `unknown`). The source repository of the images is **not** collected. - **Deployment Flags:** a list of NGINX Gateway Fabric Deployment flags that are specified by a user. The actual values of non-boolean flags are **not** collected; we only record that they are either `true` or `false` for boolean flags and `default` or `user-defined` for the rest. -- **Count of Resources:** the total count of resources related to NGINX Gateway Fabric. This includes `GatewayClasses`, `Gateways`, `HTTPRoutes`,`GRPCRoutes`, `TLSRoutes`, `Secrets`, `Services`, `BackendTLSPolicies`, `ClientSettingsPolicies`, `NginxProxies`, `ObservabilityPolicies`, and `Endpoints`. The data within these resources is **not** collected. +- **Count of Resources:** the total count of resources related to NGINX Gateway Fabric. This includes `GatewayClasses`, `Gateways`, `HTTPRoutes`,`GRPCRoutes`, `TLSRoutes`, `Secrets`, `Services`, `BackendTLSPolicies`, `ClientSettingsPolicies`, `NginxProxies`, `ObservabilityPolicies`, `SnippetsFilters`, and `Endpoints`. The data within these resources is **not** collected. This data is used to identify the following information: diff --git a/tests/suite/telemetry_test.go b/tests/suite/telemetry_test.go index a88cfd3ee..f2f887846 100644 --- a/tests/suite/telemetry_test.go +++ b/tests/suite/telemetry_test.go @@ -85,6 +85,7 @@ var _ = Describe("Telemetry test with OTel collector", Label("telemetry"), func( "RouteAttachedClientSettingsPolicyCount: Int(0)", "ObservabilityPolicyCount: Int(0)", "NginxProxyCount: Int(0)", + "SnippetsFilterCount: Int(0)", "NGFReplicaCount: Int(1)", }, ) From ad56f52731c12246e2d225d82088090edd82068c Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Thu, 10 Oct 2024 14:36:39 -0700 Subject: [PATCH 02/11] Add collection of SnippetsFilter Snippet directive, context, and total count --- internal/mode/static/telemetry/collector.go | 131 +++++++++++++++++- .../mode/static/telemetry/collector_test.go | 67 +++++++-- internal/mode/static/telemetry/data.avdl | 9 ++ .../telemetry/data_attributes_generated.go | 2 + internal/mode/static/telemetry/data_test.go | 11 +- site/content/overview/product-telemetry.md | 2 +- tests/suite/telemetry_test.go | 2 + 7 files changed, 211 insertions(+), 13 deletions(-) diff --git a/internal/mode/static/telemetry/collector.go b/internal/mode/static/telemetry/collector.go index 58fb7f74d..0be797d0a 100644 --- a/internal/mode/static/telemetry/collector.go +++ b/internal/mode/static/telemetry/collector.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "runtime" + "sort" + "strings" tel "github.com/nginxinc/telemetry-exporter/pkg/telemetry" appsv1 "k8s.io/api/apps/v1" @@ -14,6 +16,7 @@ import ( k8sversion "k8s.io/apimachinery/pkg/util/version" "sigs.k8s.io/controller-runtime/pkg/client" + ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1" "github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds" "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/config" "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/dataplane" @@ -46,8 +49,15 @@ type Data struct { // FlagValues contains the values of the command-line flags, where each value corresponds to the flag from FlagNames // at the same index. // Each value is either 'true' or 'false' for boolean flags and 'default' or 'user-defined' for non-boolean flags. - FlagValues []string - NGFResourceCounts // embedding is required by the generator. + FlagValues []string + // SnippetsFiltersContextDirectives contains the context-directive strings of all applied SnippetsFilters. + // Both lists are ordered first by count, then by lexicographical order on the context-directive string. + SnippetsFiltersContextDirectives []string + // SnippetsFiltersContextDirectivesCount contains the count of the context-directive strings, where each count + // corresponds to the string from SnippetsFiltersContextDirectives at the same index. Both lists are ordered + // first by count, then by lexicographical order on the context-directive string. + SnippetsFiltersContextDirectivesCount []int64 + NGFResourceCounts // embedding is required by the generator. // NGFReplicaCount is the number of replicas of the NGF Pod. NGFReplicaCount int64 } @@ -146,6 +156,13 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { return Data{}, fmt.Errorf("failed to get NGF deploymentID: %w", err) } + snippetsFiltersContextDirectives, + snippetsFiltersContextDirectivesCount, + err := collectSnippetsFilterSnippetsInfo(c.cfg.GraphGetter) + if err != nil { + return Data{}, fmt.Errorf("failed to collect snippet filter directive info: %w", err) + } + data := Data{ Data: tel.Data{ ProjectName: "NGF", @@ -162,6 +179,9 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { FlagNames: c.cfg.Flags.Names, FlagValues: c.cfg.Flags.Values, NGFReplicaCount: int64(replicaCount), + // maybe SnippetValues? + SnippetsFiltersContextDirectives: snippetsFiltersContextDirectives, + SnippetsFiltersContextDirectivesCount: snippetsFiltersContextDirectivesCount, } return data, nil @@ -382,3 +402,110 @@ func collectClusterInformation(ctx context.Context, k8sClient client.Reader) (cl return clusterInfo, nil } + +type sfContextDirective struct { + context string + directive string +} + +func collectSnippetsFilterSnippetsInfo(graphGetter GraphGetter) ([]string, []int64, error) { + g := graphGetter.GetLatestGraph() + if g == nil { + return nil, nil, errors.New("latest graph cannot be nil") + } + + contextDirectiveMap := make(map[sfContextDirective]int) + + for name := range g.SnippetsFilters { + sf := g.SnippetsFilters[name] + if sf == nil { + continue + } + + for nginxContext := range sf.Snippets { + snippetValue := sf.Snippets[nginxContext] + + var parsedContext string + switch nginxContext { + case ngfAPI.NginxContextMain: + parsedContext = "main" + case ngfAPI.NginxContextHTTP: + parsedContext = "http" + case ngfAPI.NginxContextHTTPServer: + parsedContext = "server" + case ngfAPI.NginxContextHTTPServerLocation: + parsedContext = "location" + default: + parsedContext = "unknown" + } + + directives := parseSnippetValueIntoDirectives(snippetValue) + + for _, directive := range directives { + contextDirective := sfContextDirective{ + context: parsedContext, + directive: directive, + } + + contextDirectiveMap[contextDirective]++ + } + } + } + + contextDirectiveList, countList := parseContextDirectiveMapIntoLists(contextDirectiveMap) + + return contextDirectiveList, countList, nil +} + +func parseSnippetValueIntoDirectives(snippetValue string) []string { + separatedDirectives := strings.Split(snippetValue, ";") + directives := make([]string, 0, len(separatedDirectives)) + + for _, directive := range separatedDirectives { + // the strings.TrimSpace is needed in the case of multi-line NGINX Snippet values + directive = strings.Split(strings.TrimSpace(directive), " ")[0] + + // splitting on the delimiting character can result in a directive being empty or a space/newline character, + // so we check here to ensure it's not + if directive != "" { + directives = append(directives, directive) + } + } + + return directives +} + +// parseContextDirectiveMapIntoLists returns two same-length lists where the elements at each corresponding index +// are paired together. +// The first list contains strings which are the NGINX context and directive of a Snippet joined with a hyphen. +// The second list contains ints which are the count of total same context-directive values of the first list. +// Both lists are ordered based off of count first, then lexicographically on the context-directive string. +func parseContextDirectiveMapIntoLists(contextDirectiveMap map[sfContextDirective]int) ([]string, []int64) { + type sfContextDirectiveCount struct { + contextDirective string + count int64 + } + + kvPairs := make([]sfContextDirectiveCount, 0, len(contextDirectiveMap)) + + for k, v := range contextDirectiveMap { + kvPairs = append(kvPairs, sfContextDirectiveCount{k.context + "-" + k.directive, int64(v)}) + } + + sort.Slice(kvPairs, func(i, j int) bool { + if kvPairs[i].count == kvPairs[j].count { + return kvPairs[i].contextDirective < kvPairs[j].contextDirective + } + return kvPairs[i].count > kvPairs[j].count + }) + + contextDirectiveList := make([]string, len(kvPairs)) + countList := make([]int64, len(kvPairs)) + + for i, pair := range kvPairs { + contextDirectiveList[i] = pair.contextDirective + countList[i] = pair.count + } + + return contextDirectiveList, countList +} diff --git a/internal/mode/static/telemetry/collector_test.go b/internal/mode/static/telemetry/collector_test.go index d688f1f58..ab9ec915d 100644 --- a/internal/mode/static/telemetry/collector_test.go +++ b/internal/mode/static/telemetry/collector_test.go @@ -17,6 +17,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1" "github.com/nginxinc/nginx-gateway-fabric/internal/framework/events/eventsfakes" "github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds" "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/config" @@ -168,11 +169,13 @@ var _ = Describe("Collector", Ordered, func() { InstallationID: string(ngfReplicaSet.ObjectMeta.OwnerReferences[0].UID), ClusterNodeCount: 1, }, - NGFResourceCounts: telemetry.NGFResourceCounts{}, - NGFReplicaCount: 1, - ImageSource: "local", - FlagNames: flags.Names, - FlagValues: flags.Values, + NGFResourceCounts: telemetry.NGFResourceCounts{}, + NGFReplicaCount: 1, + ImageSource: "local", + FlagNames: flags.Names, + FlagValues: flags.Values, + SnippetsFiltersContextDirectives: []string{}, + SnippetsFiltersContextDirectivesCount: []int64{}, } k8sClientReader = &eventsfakes.FakeReader{} @@ -329,8 +332,26 @@ var _ = Describe("Collector", Ordered, func() { }, NginxProxy: &graph.NginxProxy{}, SnippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{ - {Namespace: "test", Name: "sf-1"}: {}, - {Namespace: "test", Name: "sf-2"}: {}, + {Namespace: "test", Name: "sf-1"}: { + Snippets: map[ngfAPI.NginxContext]string{ + ngfAPI.NginxContextMain: "worker_priority 0;", + ngfAPI.NginxContextHTTP: "aio on;", + ngfAPI.NginxContextHTTPServer: "auth_delay 10s;", + ngfAPI.NginxContextHTTPServerLocation: "keepalive_time 10s;", + }, + }, + {Namespace: "test", Name: "sf-2"}: { + Snippets: map[ngfAPI.NginxContext]string{ + // String representation of multi-line yaml value using > character + ngfAPI.NginxContextMain: "worker_priority 1; worker_rlimit_nofile 50;\n", + // String representation of NGINX values on same line + ngfAPI.NginxContextHTTP: "aio off; client_body_timeout 70s;", + // String representation of multi-line yaml using no special character besides a new line + ngfAPI.NginxContextHTTPServer: "auth_delay 100s; ignore_invalid_headers off;", + // String representation of multi-line yaml value using | character + ngfAPI.NginxContextHTTPServerLocation: "keepalive_time 100s;\nallow 10.0.0.0/8;\n", + }, + }, {Namespace: "test", Name: "sf-3"}: {}, }, } @@ -389,10 +410,38 @@ var _ = Describe("Collector", Ordered, func() { expData.ClusterVersion = "1.29.2" expData.ClusterPlatform = "kind" - data, err := dataCollector.Collect(ctx) + expData.SnippetsFiltersContextDirectives = []string{ + "http-aio", + "location-keepalive_time", + "main-worker_priority", + "server-auth_delay", + "http-client_body_timeout", + "location-allow", + "main-worker_rlimit_nofile", + "server-ignore_invalid_headers", + } + expData.SnippetsFiltersContextDirectivesCount = []int64{ + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + } + data, err := dataCollector.Collect(ctx) Expect(err).ToNot(HaveOccurred()) - Expect(expData).To(Equal(data)) + + Expect(data.Data).To(Equal(expData.Data)) + Expect(data.NGFResourceCounts).To(Equal(expData.NGFResourceCounts)) + Expect(data.ImageSource).To(Equal(expData.ImageSource)) + Expect(data.FlagNames).To(Equal(expData.FlagNames)) + Expect(data.FlagValues).To(Equal(expData.FlagValues)) + Expect(data.NGFReplicaCount).To(Equal(expData.NGFReplicaCount)) + Expect(data.SnippetsFiltersContextDirectives).To(Equal(expData.SnippetsFiltersContextDirectives)) + Expect(data.SnippetsFiltersContextDirectivesCount).To(Equal(expData.SnippetsFiltersContextDirectivesCount)) }) }) }) diff --git a/internal/mode/static/telemetry/data.avdl b/internal/mode/static/telemetry/data.avdl index 7c6afa847..cfa86e94f 100644 --- a/internal/mode/static/telemetry/data.avdl +++ b/internal/mode/static/telemetry/data.avdl @@ -91,5 +91,14 @@ attached at the Gateway level. */ /** NGFReplicaCount is the number of replicas of the NGF Pod. */ long? NGFReplicaCount = null; + /** SnippetsFiltersContextDirectives contains the context-directive strings of all applied SnippetsFilters. +Both lists are ordered first by count, then by lexicographical order on the context-directive string. */ + union {null, array} SnippetsFiltersContextDirectives = null; + + /** SnippetsFiltersContextDirectivesCount contains the count of the context-directive strings, where each count +corresponds to the string from SnippetsFiltersContextDirectives at the same index. Both lists are ordered +first by count, then by lexicographical order on the context-directive string. */ + union {null, array} SnippetsFiltersContextDirectivesCount = null; + } } diff --git a/internal/mode/static/telemetry/data_attributes_generated.go b/internal/mode/static/telemetry/data_attributes_generated.go index 8784b827f..024f94feb 100644 --- a/internal/mode/static/telemetry/data_attributes_generated.go +++ b/internal/mode/static/telemetry/data_attributes_generated.go @@ -19,6 +19,8 @@ func (d *Data) Attributes() []attribute.KeyValue { attrs = append(attrs, attribute.StringSlice("FlagValues", d.FlagValues)) attrs = append(attrs, d.NGFResourceCounts.Attributes()...) attrs = append(attrs, attribute.Int64("NGFReplicaCount", d.NGFReplicaCount)) + attrs = append(attrs, attribute.StringSlice("SnippetsFiltersContextDirectives", d.SnippetsFiltersContextDirectives)) + attrs = append(attrs, attribute.Int64Slice("SnippetsFiltersContextDirectivesCount", d.SnippetsFiltersContextDirectivesCount)) return attrs } diff --git a/internal/mode/static/telemetry/data_test.go b/internal/mode/static/telemetry/data_test.go index 8f33a85e4..8ea63e95a 100644 --- a/internal/mode/static/telemetry/data_test.go +++ b/internal/mode/static/telemetry/data_test.go @@ -40,7 +40,9 @@ func TestDataAttributes(t *testing.T) { NginxProxyCount: 12, SnippetsFilterCount: 13, }, - NGFReplicaCount: 3, + NGFReplicaCount: 3, + SnippetsFiltersContextDirectives: []string{"main-three-count", "http-two-count", "server-one-count"}, + SnippetsFiltersContextDirectivesCount: []int64{3, 2, 1}, } expected := []attribute.KeyValue{ @@ -71,6 +73,11 @@ func TestDataAttributes(t *testing.T) { attribute.Int64("NginxProxyCount", 12), attribute.Int64("SnippetsFilterCount", 13), attribute.Int64("NGFReplicaCount", 3), + attribute.StringSlice( + "SnippetsFiltersContextDirectives", + []string{"main-three-count", "http-two-count", "server-one-count"}, + ), + attribute.IntSlice("SnippetsFiltersContextDirectivesCount", []int{3, 2, 1}), } result := data.Attributes() @@ -111,6 +118,8 @@ func TestDataAttributesWithEmptyData(t *testing.T) { attribute.Int64("NginxProxyCount", 0), attribute.Int64("SnippetsFilterCount", 0), attribute.Int64("NGFReplicaCount", 0), + attribute.StringSlice("SnippetsFiltersContextDirectives", nil), + attribute.IntSlice("SnippetsFiltersContextDirectivesCount", nil), } result := data.Attributes() diff --git a/site/content/overview/product-telemetry.md b/site/content/overview/product-telemetry.md index 536e4f8b4..42a9be637 100644 --- a/site/content/overview/product-telemetry.md +++ b/site/content/overview/product-telemetry.md @@ -28,7 +28,7 @@ Telemetry data is collected once every 24 hours and sent to a service managed by - **Image Build Source:** whether the image was built by GitHub or locally (values are `gha`, `local`, or `unknown`). The source repository of the images is **not** collected. - **Deployment Flags:** a list of NGINX Gateway Fabric Deployment flags that are specified by a user. The actual values of non-boolean flags are **not** collected; we only record that they are either `true` or `false` for boolean flags and `default` or `user-defined` for the rest. - **Count of Resources:** the total count of resources related to NGINX Gateway Fabric. This includes `GatewayClasses`, `Gateways`, `HTTPRoutes`,`GRPCRoutes`, `TLSRoutes`, `Secrets`, `Services`, `BackendTLSPolicies`, `ClientSettingsPolicies`, `NginxProxies`, `ObservabilityPolicies`, `SnippetsFilters`, and `Endpoints`. The data within these resources is **not** collected. - +- **SnippetsFilters Info**a list of context-directive strings from applied SnippetFilters and a total count per strings. The actual value of any NGINX directive is **not** collected. This data is used to identify the following information: - The flavors of Kubernetes environments that are most popular among our users. diff --git a/tests/suite/telemetry_test.go b/tests/suite/telemetry_test.go index f2f887846..7b0a07086 100644 --- a/tests/suite/telemetry_test.go +++ b/tests/suite/telemetry_test.go @@ -87,6 +87,8 @@ var _ = Describe("Telemetry test with OTel collector", Label("telemetry"), func( "NginxProxyCount: Int(0)", "SnippetsFilterCount: Int(0)", "NGFReplicaCount: Int(1)", + "SnippetsFiltersContextDirectives: Slice", + "SnippetsFiltersContextDirectivesCount: Slice", }, ) }) From 0748ba4c1a0ebc3990c5ae2ff72b1d9c398cb567 Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Thu, 10 Oct 2024 15:26:14 -0700 Subject: [PATCH 03/11] Update generated files --- internal/mode/static/telemetry/data.avdl | 18 +++++++++--------- .../telemetry/data_attributes_generated.go | 4 ++-- internal/mode/static/telemetry/data_test.go | 14 +++++++------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/internal/mode/static/telemetry/data.avdl b/internal/mode/static/telemetry/data.avdl index cfa86e94f..675bf284f 100644 --- a/internal/mode/static/telemetry/data.avdl +++ b/internal/mode/static/telemetry/data.avdl @@ -45,6 +45,15 @@ at the same index. Each value is either 'true' or 'false' for boolean flags and 'default' or 'user-defined' for non-boolean flags. */ union {null, array} FlagValues = null; + /** SnippetsFiltersContextDirectives contains the context-directive strings of all applied SnippetsFilters. +Both lists are ordered first by count, then by lexicographical order on the context-directive string. */ + union {null, array} SnippetsFiltersContextDirectives = null; + + /** SnippetsFiltersContextDirectivesCount contains the count of the context-directive strings, where each count +corresponds to the string from SnippetsFiltersContextDirectives at the same index. Both lists are ordered +first by count, then by lexicographical order on the context-directive string. */ + union {null, array} SnippetsFiltersContextDirectivesCount = null; + /** GatewayCount is the number of relevant Gateways. */ long? GatewayCount = null; @@ -91,14 +100,5 @@ attached at the Gateway level. */ /** NGFReplicaCount is the number of replicas of the NGF Pod. */ long? NGFReplicaCount = null; - /** SnippetsFiltersContextDirectives contains the context-directive strings of all applied SnippetsFilters. -Both lists are ordered first by count, then by lexicographical order on the context-directive string. */ - union {null, array} SnippetsFiltersContextDirectives = null; - - /** SnippetsFiltersContextDirectivesCount contains the count of the context-directive strings, where each count -corresponds to the string from SnippetsFiltersContextDirectives at the same index. Both lists are ordered -first by count, then by lexicographical order on the context-directive string. */ - union {null, array} SnippetsFiltersContextDirectivesCount = null; - } } diff --git a/internal/mode/static/telemetry/data_attributes_generated.go b/internal/mode/static/telemetry/data_attributes_generated.go index 024f94feb..6e851e773 100644 --- a/internal/mode/static/telemetry/data_attributes_generated.go +++ b/internal/mode/static/telemetry/data_attributes_generated.go @@ -17,10 +17,10 @@ func (d *Data) Attributes() []attribute.KeyValue { attrs = append(attrs, d.Data.Attributes()...) attrs = append(attrs, attribute.StringSlice("FlagNames", d.FlagNames)) attrs = append(attrs, attribute.StringSlice("FlagValues", d.FlagValues)) - attrs = append(attrs, d.NGFResourceCounts.Attributes()...) - attrs = append(attrs, attribute.Int64("NGFReplicaCount", d.NGFReplicaCount)) attrs = append(attrs, attribute.StringSlice("SnippetsFiltersContextDirectives", d.SnippetsFiltersContextDirectives)) attrs = append(attrs, attribute.Int64Slice("SnippetsFiltersContextDirectivesCount", d.SnippetsFiltersContextDirectivesCount)) + attrs = append(attrs, d.NGFResourceCounts.Attributes()...) + attrs = append(attrs, attribute.Int64("NGFReplicaCount", d.NGFReplicaCount)) return attrs } diff --git a/internal/mode/static/telemetry/data_test.go b/internal/mode/static/telemetry/data_test.go index 8ea63e95a..015e7f248 100644 --- a/internal/mode/static/telemetry/data_test.go +++ b/internal/mode/static/telemetry/data_test.go @@ -58,6 +58,11 @@ func TestDataAttributes(t *testing.T) { attribute.Int64("ClusterNodeCount", 3), attribute.StringSlice("FlagNames", []string{"test-flag"}), attribute.StringSlice("FlagValues", []string{"test-value"}), + attribute.StringSlice( + "SnippetsFiltersContextDirectives", + []string{"main-three-count", "http-two-count", "server-one-count"}, + ), + attribute.IntSlice("SnippetsFiltersContextDirectivesCount", []int{3, 2, 1}), attribute.Int64("GatewayCount", 1), attribute.Int64("GatewayClassCount", 2), attribute.Int64("HTTPRouteCount", 3), @@ -73,11 +78,6 @@ func TestDataAttributes(t *testing.T) { attribute.Int64("NginxProxyCount", 12), attribute.Int64("SnippetsFilterCount", 13), attribute.Int64("NGFReplicaCount", 3), - attribute.StringSlice( - "SnippetsFiltersContextDirectives", - []string{"main-three-count", "http-two-count", "server-one-count"}, - ), - attribute.IntSlice("SnippetsFiltersContextDirectivesCount", []int{3, 2, 1}), } result := data.Attributes() @@ -103,6 +103,8 @@ func TestDataAttributesWithEmptyData(t *testing.T) { attribute.Int64("ClusterNodeCount", 0), attribute.StringSlice("FlagNames", nil), attribute.StringSlice("FlagValues", nil), + attribute.StringSlice("SnippetsFiltersContextDirectives", nil), + attribute.IntSlice("SnippetsFiltersContextDirectivesCount", nil), attribute.Int64("GatewayCount", 0), attribute.Int64("GatewayClassCount", 0), attribute.Int64("HTTPRouteCount", 0), @@ -118,8 +120,6 @@ func TestDataAttributesWithEmptyData(t *testing.T) { attribute.Int64("NginxProxyCount", 0), attribute.Int64("SnippetsFilterCount", 0), attribute.Int64("NGFReplicaCount", 0), - attribute.StringSlice("SnippetsFiltersContextDirectives", nil), - attribute.IntSlice("SnippetsFiltersContextDirectivesCount", nil), } result := data.Attributes() From 1d4792bace375174143167b69f62345a20e24c12 Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Fri, 11 Oct 2024 09:47:02 -0700 Subject: [PATCH 04/11] Add review feedback for collector test --- .../mode/static/telemetry/collector_test.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/internal/mode/static/telemetry/collector_test.go b/internal/mode/static/telemetry/collector_test.go index ab9ec915d..5859328c9 100644 --- a/internal/mode/static/telemetry/collector_test.go +++ b/internal/mode/static/telemetry/collector_test.go @@ -352,7 +352,11 @@ var _ = Describe("Collector", Ordered, func() { ngfAPI.NginxContextHTTPServerLocation: "keepalive_time 100s;\nallow 10.0.0.0/8;\n", }, }, - {Namespace: "test", Name: "sf-3"}: {}, + {Namespace: "test", Name: "sf-3"}: { + Snippets: map[ngfAPI.NginxContext]string{ + ngfAPI.NginxContextHTTPServer: "auth_delay 10s;", + }, + }, }, } @@ -411,17 +415,17 @@ var _ = Describe("Collector", Ordered, func() { expData.ClusterPlatform = "kind" expData.SnippetsFiltersContextDirectives = []string{ + "server-auth_delay", "http-aio", "location-keepalive_time", "main-worker_priority", - "server-auth_delay", "http-client_body_timeout", "location-allow", "main-worker_rlimit_nofile", "server-ignore_invalid_headers", } expData.SnippetsFiltersContextDirectivesCount = []int64{ - 2, + 3, 2, 2, 2, @@ -434,14 +438,7 @@ var _ = Describe("Collector", Ordered, func() { data, err := dataCollector.Collect(ctx) Expect(err).ToNot(HaveOccurred()) - Expect(data.Data).To(Equal(expData.Data)) - Expect(data.NGFResourceCounts).To(Equal(expData.NGFResourceCounts)) - Expect(data.ImageSource).To(Equal(expData.ImageSource)) - Expect(data.FlagNames).To(Equal(expData.FlagNames)) - Expect(data.FlagValues).To(Equal(expData.FlagValues)) - Expect(data.NGFReplicaCount).To(Equal(expData.NGFReplicaCount)) - Expect(data.SnippetsFiltersContextDirectives).To(Equal(expData.SnippetsFiltersContextDirectives)) - Expect(data.SnippetsFiltersContextDirectivesCount).To(Equal(expData.SnippetsFiltersContextDirectivesCount)) + Expect(data).To(Equal(expData)) }) }) }) From 5be547051ee41aafcb76b025504661b638233fc9 Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Fri, 11 Oct 2024 12:54:28 -0700 Subject: [PATCH 05/11] Adjust test case for telemetry functional test --- tests/suite/telemetry_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/suite/telemetry_test.go b/tests/suite/telemetry_test.go index 7b0a07086..25c084f8c 100644 --- a/tests/suite/telemetry_test.go +++ b/tests/suite/telemetry_test.go @@ -72,6 +72,8 @@ var _ = Describe("Telemetry test with OTel collector", Label("telemetry"), func( fmt.Sprintf("ClusterNodeCount: Int(%d)", info.NodeCount), "FlagNames: Slice", "FlagValues: Slice", + "SnippetsFiltersContextDirectives: Slice", + "SnippetsFiltersContextDirectivesCount: Slice", "GatewayCount: Int(0)", "GatewayClassCount: Int(1)", "HTTPRouteCount: Int(0)", @@ -87,8 +89,6 @@ var _ = Describe("Telemetry test with OTel collector", Label("telemetry"), func( "NginxProxyCount: Int(0)", "SnippetsFilterCount: Int(0)", "NGFReplicaCount: Int(1)", - "SnippetsFiltersContextDirectives: Slice", - "SnippetsFiltersContextDirectivesCount: Slice", }, ) }) From 84fa60dc3838a5a1d51eb09089be79e82ce1fcda Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Fri, 11 Oct 2024 14:27:10 -0700 Subject: [PATCH 06/11] Refactor map range cluases --- internal/mode/static/telemetry/collector.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/internal/mode/static/telemetry/collector.go b/internal/mode/static/telemetry/collector.go index 0be797d0a..3c652255d 100644 --- a/internal/mode/static/telemetry/collector.go +++ b/internal/mode/static/telemetry/collector.go @@ -416,16 +416,14 @@ func collectSnippetsFilterSnippetsInfo(graphGetter GraphGetter) ([]string, []int contextDirectiveMap := make(map[sfContextDirective]int) - for name := range g.SnippetsFilters { - sf := g.SnippetsFilters[name] + for _, sf := range g.SnippetsFilters { if sf == nil { continue } - for nginxContext := range sf.Snippets { - snippetValue := sf.Snippets[nginxContext] - + for nginxContext, snippetValue := range sf.Snippets { var parsedContext string + switch nginxContext { case ngfAPI.NginxContextMain: parsedContext = "main" @@ -440,13 +438,11 @@ func collectSnippetsFilterSnippetsInfo(graphGetter GraphGetter) ([]string, []int } directives := parseSnippetValueIntoDirectives(snippetValue) - for _, directive := range directives { contextDirective := sfContextDirective{ context: parsedContext, directive: directive, } - contextDirectiveMap[contextDirective]++ } } From 98e1701e37788b8042a065ea7e555dc5773ed551 Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Fri, 11 Oct 2024 14:47:46 -0700 Subject: [PATCH 07/11] Change all instances of contextDirective to directiveContext naming --- internal/mode/static/telemetry/collector.go | 70 ++++++++++--------- .../mode/static/telemetry/collector_test.go | 28 ++++---- internal/mode/static/telemetry/data.avdl | 18 ++--- .../telemetry/data_attributes_generated.go | 4 +- internal/mode/static/telemetry/data_test.go | 12 ++-- site/content/overview/product-telemetry.md | 2 +- tests/suite/telemetry_test.go | 4 +- 7 files changed, 75 insertions(+), 63 deletions(-) diff --git a/internal/mode/static/telemetry/collector.go b/internal/mode/static/telemetry/collector.go index 3c652255d..c16ce52ea 100644 --- a/internal/mode/static/telemetry/collector.go +++ b/internal/mode/static/telemetry/collector.go @@ -50,13 +50,15 @@ type Data struct { // at the same index. // Each value is either 'true' or 'false' for boolean flags and 'default' or 'user-defined' for non-boolean flags. FlagValues []string - // SnippetsFiltersContextDirectives contains the context-directive strings of all applied SnippetsFilters. - // Both lists are ordered first by count, then by lexicographical order on the context-directive string. - SnippetsFiltersContextDirectives []string - // SnippetsFiltersContextDirectivesCount contains the count of the context-directive strings, where each count - // corresponds to the string from SnippetsFiltersContextDirectives at the same index. Both lists are ordered - // first by count, then by lexicographical order on the context-directive string. - SnippetsFiltersContextDirectivesCount []int64 + // SnippetsFiltersDirectiveContexts contains the context-directive strings of all applied SnippetsFilters. + // Both lists are ordered first by count, then by lexicographical order of the context string, + // then lastly by directive string. + SnippetsFiltersDirectiveContexts []string + // SnippetsFiltersDirectiveContextsCount contains the count of the directive-context strings, where each count + // corresponds to the string from SnippetsFiltersDirectiveContexts at the same index. + // Both lists are ordered first by count, then by lexicographical order of the context string, + // then lastly by directive string. + SnippetsFiltersDirectiveContextsCount []int64 NGFResourceCounts // embedding is required by the generator. // NGFReplicaCount is the number of replicas of the NGF Pod. NGFReplicaCount int64 @@ -156,8 +158,8 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { return Data{}, fmt.Errorf("failed to get NGF deploymentID: %w", err) } - snippetsFiltersContextDirectives, - snippetsFiltersContextDirectivesCount, + snippetsFiltersDirectiveContexts, + snippetsFiltersDirectiveContextsCount, err := collectSnippetsFilterSnippetsInfo(c.cfg.GraphGetter) if err != nil { return Data{}, fmt.Errorf("failed to collect snippet filter directive info: %w", err) @@ -180,8 +182,8 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { FlagValues: c.cfg.Flags.Values, NGFReplicaCount: int64(replicaCount), // maybe SnippetValues? - SnippetsFiltersContextDirectives: snippetsFiltersContextDirectives, - SnippetsFiltersContextDirectivesCount: snippetsFiltersContextDirectivesCount, + SnippetsFiltersDirectiveContexts: snippetsFiltersDirectiveContexts, + SnippetsFiltersDirectiveContextsCount: snippetsFiltersDirectiveContextsCount, } return data, nil @@ -403,7 +405,7 @@ func collectClusterInformation(ctx context.Context, k8sClient client.Reader) (cl return clusterInfo, nil } -type sfContextDirective struct { +type sfDirectiveContext struct { context string directive string } @@ -414,7 +416,7 @@ func collectSnippetsFilterSnippetsInfo(graphGetter GraphGetter) ([]string, []int return nil, nil, errors.New("latest graph cannot be nil") } - contextDirectiveMap := make(map[sfContextDirective]int) + directiveContextMap := make(map[sfDirectiveContext]int) for _, sf := range g.SnippetsFilters { if sf == nil { @@ -439,18 +441,18 @@ func collectSnippetsFilterSnippetsInfo(graphGetter GraphGetter) ([]string, []int directives := parseSnippetValueIntoDirectives(snippetValue) for _, directive := range directives { - contextDirective := sfContextDirective{ + directiveContext := sfDirectiveContext{ context: parsedContext, directive: directive, } - contextDirectiveMap[contextDirective]++ + directiveContextMap[directiveContext]++ } } } - contextDirectiveList, countList := parseContextDirectiveMapIntoLists(contextDirectiveMap) + directiveContextList, countList := parseDirectiveContextMapIntoLists(directiveContextMap) - return contextDirectiveList, countList, nil + return directiveContextList, countList, nil } func parseSnippetValueIntoDirectives(snippetValue string) []string { @@ -471,37 +473,41 @@ func parseSnippetValueIntoDirectives(snippetValue string) []string { return directives } -// parseContextDirectiveMapIntoLists returns two same-length lists where the elements at each corresponding index +// parseDirectiveContextMapIntoLists returns two same-length lists where the elements at each corresponding index // are paired together. -// The first list contains strings which are the NGINX context and directive of a Snippet joined with a hyphen. -// The second list contains ints which are the count of total same context-directive values of the first list. -// Both lists are ordered based off of count first, then lexicographically on the context-directive string. -func parseContextDirectiveMapIntoLists(contextDirectiveMap map[sfContextDirective]int) ([]string, []int64) { - type sfContextDirectiveCount struct { - contextDirective string - count int64 +// The first list contains strings which are the NGINX directive and context of a Snippet joined with a hyphen. +// The second list contains ints which are the count of total same directive-context values of the first list. +// Both lists are ordered first by count, then by lexicographical order of the context string, +// then lastly by directive string. +func parseDirectiveContextMapIntoLists(directiveContextMap map[sfDirectiveContext]int) ([]string, []int64) { + type sfDirectiveContextCount struct { + directive, context string + count int64 } - kvPairs := make([]sfContextDirectiveCount, 0, len(contextDirectiveMap)) + kvPairs := make([]sfDirectiveContextCount, 0, len(directiveContextMap)) - for k, v := range contextDirectiveMap { - kvPairs = append(kvPairs, sfContextDirectiveCount{k.context + "-" + k.directive, int64(v)}) + for k, v := range directiveContextMap { + kvPairs = append(kvPairs, sfDirectiveContextCount{k.directive, k.context, int64(v)}) } sort.Slice(kvPairs, func(i, j int) bool { if kvPairs[i].count == kvPairs[j].count { - return kvPairs[i].contextDirective < kvPairs[j].contextDirective + if kvPairs[i].context == kvPairs[j].context { + return kvPairs[i].directive < kvPairs[j].directive + } + return kvPairs[i].context < kvPairs[j].context } return kvPairs[i].count > kvPairs[j].count }) - contextDirectiveList := make([]string, len(kvPairs)) + directiveContextList := make([]string, len(kvPairs)) countList := make([]int64, len(kvPairs)) for i, pair := range kvPairs { - contextDirectiveList[i] = pair.contextDirective + directiveContextList[i] = pair.directive + "-" + pair.context countList[i] = pair.count } - return contextDirectiveList, countList + return directiveContextList, countList } diff --git a/internal/mode/static/telemetry/collector_test.go b/internal/mode/static/telemetry/collector_test.go index 5859328c9..9f7faea8d 100644 --- a/internal/mode/static/telemetry/collector_test.go +++ b/internal/mode/static/telemetry/collector_test.go @@ -174,8 +174,8 @@ var _ = Describe("Collector", Ordered, func() { ImageSource: "local", FlagNames: flags.Names, FlagValues: flags.Values, - SnippetsFiltersContextDirectives: []string{}, - SnippetsFiltersContextDirectivesCount: []int64{}, + SnippetsFiltersDirectiveContexts: []string{}, + SnippetsFiltersDirectiveContextsCount: []int64{}, } k8sClientReader = &eventsfakes.FakeReader{} @@ -354,6 +354,8 @@ var _ = Describe("Collector", Ordered, func() { }, {Namespace: "test", Name: "sf-3"}: { Snippets: map[ngfAPI.NginxContext]string{ + // Tests lexicographical ordering when count and context is the same + ngfAPI.NginxContextMain: "worker_rlimit_core 1m;", ngfAPI.NginxContextHTTPServer: "auth_delay 10s;", }, }, @@ -414,17 +416,18 @@ var _ = Describe("Collector", Ordered, func() { expData.ClusterVersion = "1.29.2" expData.ClusterPlatform = "kind" - expData.SnippetsFiltersContextDirectives = []string{ - "server-auth_delay", - "http-aio", - "location-keepalive_time", - "main-worker_priority", - "http-client_body_timeout", - "location-allow", - "main-worker_rlimit_nofile", - "server-ignore_invalid_headers", + expData.SnippetsFiltersDirectiveContexts = []string{ + "auth_delay-server", + "aio-http", + "keepalive_time-location", + "worker_priority-main", + "client_body_timeout-http", + "allow-location", + "worker_rlimit_core-main", + "worker_rlimit_nofile-main", + "ignore_invalid_headers-server", } - expData.SnippetsFiltersContextDirectivesCount = []int64{ + expData.SnippetsFiltersDirectiveContextsCount = []int64{ 3, 2, 2, @@ -433,6 +436,7 @@ var _ = Describe("Collector", Ordered, func() { 1, 1, 1, + 1, } data, err := dataCollector.Collect(ctx) diff --git a/internal/mode/static/telemetry/data.avdl b/internal/mode/static/telemetry/data.avdl index 675bf284f..48c3a0a34 100644 --- a/internal/mode/static/telemetry/data.avdl +++ b/internal/mode/static/telemetry/data.avdl @@ -45,14 +45,16 @@ at the same index. Each value is either 'true' or 'false' for boolean flags and 'default' or 'user-defined' for non-boolean flags. */ union {null, array} FlagValues = null; - /** SnippetsFiltersContextDirectives contains the context-directive strings of all applied SnippetsFilters. -Both lists are ordered first by count, then by lexicographical order on the context-directive string. */ - union {null, array} SnippetsFiltersContextDirectives = null; - - /** SnippetsFiltersContextDirectivesCount contains the count of the context-directive strings, where each count -corresponds to the string from SnippetsFiltersContextDirectives at the same index. Both lists are ordered -first by count, then by lexicographical order on the context-directive string. */ - union {null, array} SnippetsFiltersContextDirectivesCount = null; + /** SnippetsFiltersDirectiveContexts contains the context-directive strings of all applied SnippetsFilters. +Both lists are ordered first by count, then by lexicographical order of the context string, +then lastly by directive string. */ + union {null, array} SnippetsFiltersDirectiveContexts = null; + + /** SnippetsFiltersDirectiveContextsCount contains the count of the directive-context strings, where each count +corresponds to the string from SnippetsFiltersDirectiveContexts at the same index. +Both lists are ordered first by count, then by lexicographical order of the context string, +then lastly by directive string. */ + union {null, array} SnippetsFiltersDirectiveContextsCount = null; /** GatewayCount is the number of relevant Gateways. */ long? GatewayCount = null; diff --git a/internal/mode/static/telemetry/data_attributes_generated.go b/internal/mode/static/telemetry/data_attributes_generated.go index 6e851e773..b2dc22c79 100644 --- a/internal/mode/static/telemetry/data_attributes_generated.go +++ b/internal/mode/static/telemetry/data_attributes_generated.go @@ -17,8 +17,8 @@ func (d *Data) Attributes() []attribute.KeyValue { attrs = append(attrs, d.Data.Attributes()...) attrs = append(attrs, attribute.StringSlice("FlagNames", d.FlagNames)) attrs = append(attrs, attribute.StringSlice("FlagValues", d.FlagValues)) - attrs = append(attrs, attribute.StringSlice("SnippetsFiltersContextDirectives", d.SnippetsFiltersContextDirectives)) - attrs = append(attrs, attribute.Int64Slice("SnippetsFiltersContextDirectivesCount", d.SnippetsFiltersContextDirectivesCount)) + attrs = append(attrs, attribute.StringSlice("SnippetsFiltersDirectiveContexts", d.SnippetsFiltersDirectiveContexts)) + attrs = append(attrs, attribute.Int64Slice("SnippetsFiltersDirectiveContextsCount", d.SnippetsFiltersDirectiveContextsCount)) attrs = append(attrs, d.NGFResourceCounts.Attributes()...) attrs = append(attrs, attribute.Int64("NGFReplicaCount", d.NGFReplicaCount)) diff --git a/internal/mode/static/telemetry/data_test.go b/internal/mode/static/telemetry/data_test.go index 015e7f248..9d4219a5e 100644 --- a/internal/mode/static/telemetry/data_test.go +++ b/internal/mode/static/telemetry/data_test.go @@ -41,8 +41,8 @@ func TestDataAttributes(t *testing.T) { SnippetsFilterCount: 13, }, NGFReplicaCount: 3, - SnippetsFiltersContextDirectives: []string{"main-three-count", "http-two-count", "server-one-count"}, - SnippetsFiltersContextDirectivesCount: []int64{3, 2, 1}, + SnippetsFiltersDirectiveContexts: []string{"main-three-count", "http-two-count", "server-one-count"}, + SnippetsFiltersDirectiveContextsCount: []int64{3, 2, 1}, } expected := []attribute.KeyValue{ @@ -59,10 +59,10 @@ func TestDataAttributes(t *testing.T) { attribute.StringSlice("FlagNames", []string{"test-flag"}), attribute.StringSlice("FlagValues", []string{"test-value"}), attribute.StringSlice( - "SnippetsFiltersContextDirectives", + "SnippetsFiltersDirectiveContexts", []string{"main-three-count", "http-two-count", "server-one-count"}, ), - attribute.IntSlice("SnippetsFiltersContextDirectivesCount", []int{3, 2, 1}), + attribute.IntSlice("SnippetsFiltersDirectiveContextsCount", []int{3, 2, 1}), attribute.Int64("GatewayCount", 1), attribute.Int64("GatewayClassCount", 2), attribute.Int64("HTTPRouteCount", 3), @@ -103,8 +103,8 @@ func TestDataAttributesWithEmptyData(t *testing.T) { attribute.Int64("ClusterNodeCount", 0), attribute.StringSlice("FlagNames", nil), attribute.StringSlice("FlagValues", nil), - attribute.StringSlice("SnippetsFiltersContextDirectives", nil), - attribute.IntSlice("SnippetsFiltersContextDirectivesCount", nil), + attribute.StringSlice("SnippetsFiltersDirectiveContexts", nil), + attribute.IntSlice("SnippetsFiltersDirectiveContextsCount", nil), attribute.Int64("GatewayCount", 0), attribute.Int64("GatewayClassCount", 0), attribute.Int64("HTTPRouteCount", 0), diff --git a/site/content/overview/product-telemetry.md b/site/content/overview/product-telemetry.md index 42a9be637..237abb130 100644 --- a/site/content/overview/product-telemetry.md +++ b/site/content/overview/product-telemetry.md @@ -28,7 +28,7 @@ Telemetry data is collected once every 24 hours and sent to a service managed by - **Image Build Source:** whether the image was built by GitHub or locally (values are `gha`, `local`, or `unknown`). The source repository of the images is **not** collected. - **Deployment Flags:** a list of NGINX Gateway Fabric Deployment flags that are specified by a user. The actual values of non-boolean flags are **not** collected; we only record that they are either `true` or `false` for boolean flags and `default` or `user-defined` for the rest. - **Count of Resources:** the total count of resources related to NGINX Gateway Fabric. This includes `GatewayClasses`, `Gateways`, `HTTPRoutes`,`GRPCRoutes`, `TLSRoutes`, `Secrets`, `Services`, `BackendTLSPolicies`, `ClientSettingsPolicies`, `NginxProxies`, `ObservabilityPolicies`, `SnippetsFilters`, and `Endpoints`. The data within these resources is **not** collected. -- **SnippetsFilters Info**a list of context-directive strings from applied SnippetFilters and a total count per strings. The actual value of any NGINX directive is **not** collected. +- **SnippetsFilters Info**a list of directive-context strings from applied SnippetFilters and a total count per strings. The actual value of any NGINX directive is **not** collected. This data is used to identify the following information: - The flavors of Kubernetes environments that are most popular among our users. diff --git a/tests/suite/telemetry_test.go b/tests/suite/telemetry_test.go index 25c084f8c..57cc63835 100644 --- a/tests/suite/telemetry_test.go +++ b/tests/suite/telemetry_test.go @@ -72,8 +72,8 @@ var _ = Describe("Telemetry test with OTel collector", Label("telemetry"), func( fmt.Sprintf("ClusterNodeCount: Int(%d)", info.NodeCount), "FlagNames: Slice", "FlagValues: Slice", - "SnippetsFiltersContextDirectives: Slice", - "SnippetsFiltersContextDirectivesCount: Slice", + "SnippetsFiltersDirectiveContexts: Slice", + "SnippetsFiltersDirectiveContextsCount: Slice", "GatewayCount: Int(0)", "GatewayClassCount: Int(1)", "HTTPRouteCount: Int(0)", From 1520005fb7d87ef6f18200c422d309dc6b5ad598 Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Fri, 11 Oct 2024 14:49:05 -0700 Subject: [PATCH 08/11] Fix instance of naming --- internal/mode/static/telemetry/collector.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/mode/static/telemetry/collector.go b/internal/mode/static/telemetry/collector.go index c16ce52ea..fbc7c7fa9 100644 --- a/internal/mode/static/telemetry/collector.go +++ b/internal/mode/static/telemetry/collector.go @@ -50,7 +50,7 @@ type Data struct { // at the same index. // Each value is either 'true' or 'false' for boolean flags and 'default' or 'user-defined' for non-boolean flags. FlagValues []string - // SnippetsFiltersDirectiveContexts contains the context-directive strings of all applied SnippetsFilters. + // SnippetsFiltersDirectiveContexts contains the directive-context strings of all applied SnippetsFilters. // Both lists are ordered first by count, then by lexicographical order of the context string, // then lastly by directive string. SnippetsFiltersDirectiveContexts []string From a87a6f522cb17e850161a3e7bbc1cac664a804eb Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Fri, 11 Oct 2024 15:00:30 -0700 Subject: [PATCH 09/11] Add small refactoring --- internal/mode/static/telemetry/collector.go | 35 +++++++------------ .../mode/static/telemetry/collector_test.go | 2 +- internal/mode/static/telemetry/data.avdl | 2 +- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/internal/mode/static/telemetry/collector.go b/internal/mode/static/telemetry/collector.go index fbc7c7fa9..7e5a1cfba 100644 --- a/internal/mode/static/telemetry/collector.go +++ b/internal/mode/static/telemetry/collector.go @@ -133,12 +133,17 @@ func NewDataCollectorImpl( // Collect collects and returns telemetry Data. func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { + g := c.cfg.GraphGetter.GetLatestGraph() + if g == nil { + return Data{}, errors.New("failed to collect telemetry data: latest graph cannot be nil") + } + clusterInfo, err := collectClusterInformation(ctx, c.cfg.K8sClientReader) if err != nil { return Data{}, fmt.Errorf("failed to collect cluster information: %w", err) } - graphResourceCount, err := collectGraphResourceCount(c.cfg.GraphGetter, c.cfg.ConfigurationGetter) + graphResourceCount, err := collectGraphResourceCount(g, c.cfg.ConfigurationGetter) if err != nil { return Data{}, fmt.Errorf("failed to collect NGF resource counts: %w", err) } @@ -158,12 +163,7 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { return Data{}, fmt.Errorf("failed to get NGF deploymentID: %w", err) } - snippetsFiltersDirectiveContexts, - snippetsFiltersDirectiveContextsCount, - err := collectSnippetsFilterSnippetsInfo(c.cfg.GraphGetter) - if err != nil { - return Data{}, fmt.Errorf("failed to collect snippet filter directive info: %w", err) - } + snippetsFiltersDirectiveContexts, snippetsFiltersDirectiveContextsCount := collectSnippetsFilterSnippetsInfo(g) data := Data{ Data: tel.Data{ @@ -190,16 +190,12 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { } func collectGraphResourceCount( - graphGetter GraphGetter, + g *graph.Graph, configurationGetter ConfigurationGetter, ) (NGFResourceCounts, error) { ngfResourceCounts := NGFResourceCounts{} - g := graphGetter.GetLatestGraph() cfg := configurationGetter.GetLatestConfiguration() - if g == nil { - return ngfResourceCounts, errors.New("latest graph cannot be nil") - } if cfg == nil { return ngfResourceCounts, errors.New("latest configuration cannot be nil") } @@ -406,16 +402,11 @@ func collectClusterInformation(ctx context.Context, k8sClient client.Reader) (cl } type sfDirectiveContext struct { - context string directive string + context string } -func collectSnippetsFilterSnippetsInfo(graphGetter GraphGetter) ([]string, []int64, error) { - g := graphGetter.GetLatestGraph() - if g == nil { - return nil, nil, errors.New("latest graph cannot be nil") - } - +func collectSnippetsFilterSnippetsInfo(g *graph.Graph) ([]string, []int64) { directiveContextMap := make(map[sfDirectiveContext]int) for _, sf := range g.SnippetsFilters { @@ -442,17 +433,15 @@ func collectSnippetsFilterSnippetsInfo(graphGetter GraphGetter) ([]string, []int directives := parseSnippetValueIntoDirectives(snippetValue) for _, directive := range directives { directiveContext := sfDirectiveContext{ - context: parsedContext, directive: directive, + context: parsedContext, } directiveContextMap[directiveContext]++ } } } - directiveContextList, countList := parseDirectiveContextMapIntoLists(directiveContextMap) - - return directiveContextList, countList, nil + return parseDirectiveContextMapIntoLists(directiveContextMap) } func parseSnippetValueIntoDirectives(snippetValue string) []string { diff --git a/internal/mode/static/telemetry/collector_test.go b/internal/mode/static/telemetry/collector_test.go index 9f7faea8d..2538e8a51 100644 --- a/internal/mode/static/telemetry/collector_test.go +++ b/internal/mode/static/telemetry/collector_test.go @@ -722,7 +722,7 @@ var _ = Describe("Collector", Ordered, func() { fakeConfigurationGetter.GetLatestConfigurationReturns(&dataplane.Configuration{}) }) It("should error on nil latest graph", func(ctx SpecContext) { - expectedError := errors.New("latest graph cannot be nil") + expectedError := errors.New("failed to collect telemetry data: latest graph cannot be nil") fakeGraphGetter.GetLatestGraphReturns(nil) _, err := dataCollector.Collect(ctx) diff --git a/internal/mode/static/telemetry/data.avdl b/internal/mode/static/telemetry/data.avdl index 48c3a0a34..f5d70d1c0 100644 --- a/internal/mode/static/telemetry/data.avdl +++ b/internal/mode/static/telemetry/data.avdl @@ -45,7 +45,7 @@ at the same index. Each value is either 'true' or 'false' for boolean flags and 'default' or 'user-defined' for non-boolean flags. */ union {null, array} FlagValues = null; - /** SnippetsFiltersDirectiveContexts contains the context-directive strings of all applied SnippetsFilters. + /** SnippetsFiltersDirectiveContexts contains the directive-context strings of all applied SnippetsFilters. Both lists are ordered first by count, then by lexicographical order of the context string, then lastly by directive string. */ union {null, array} SnippetsFiltersDirectiveContexts = null; From 2c39f831874caf3ece1617d74e4a9160b839f3db Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Mon, 14 Oct 2024 11:32:06 -0700 Subject: [PATCH 10/11] Change naming of directiveContext and count variables --- internal/mode/static/telemetry/collector.go | 31 +++++++++---------- .../mode/static/telemetry/collector_test.go | 18 +++++------ internal/mode/static/telemetry/data.avdl | 10 +++--- .../telemetry/data_attributes_generated.go | 4 +-- internal/mode/static/telemetry/data_test.go | 14 ++++----- tests/suite/telemetry_test.go | 4 +-- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/internal/mode/static/telemetry/collector.go b/internal/mode/static/telemetry/collector.go index 7e5a1cfba..a9defb587 100644 --- a/internal/mode/static/telemetry/collector.go +++ b/internal/mode/static/telemetry/collector.go @@ -50,16 +50,16 @@ type Data struct { // at the same index. // Each value is either 'true' or 'false' for boolean flags and 'default' or 'user-defined' for non-boolean flags. FlagValues []string - // SnippetsFiltersDirectiveContexts contains the directive-context strings of all applied SnippetsFilters. + // SnippetsFiltersDirectives contains the directive-context strings of all applied SnippetsFilters. // Both lists are ordered first by count, then by lexicographical order of the context string, // then lastly by directive string. - SnippetsFiltersDirectiveContexts []string - // SnippetsFiltersDirectiveContextsCount contains the count of the directive-context strings, where each count - // corresponds to the string from SnippetsFiltersDirectiveContexts at the same index. + SnippetsFiltersDirectives []string + // SnippetsFiltersDirectivesCount contains the count of the directive-context strings, where each count + // corresponds to the string from SnippetsFiltersDirectives at the same index. // Both lists are ordered first by count, then by lexicographical order of the context string, // then lastly by directive string. - SnippetsFiltersDirectiveContextsCount []int64 - NGFResourceCounts // embedding is required by the generator. + SnippetsFiltersDirectivesCount []int64 + NGFResourceCounts // embedding is required by the generator. // NGFReplicaCount is the number of replicas of the NGF Pod. NGFReplicaCount int64 } @@ -163,7 +163,7 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { return Data{}, fmt.Errorf("failed to get NGF deploymentID: %w", err) } - snippetsFiltersDirectiveContexts, snippetsFiltersDirectiveContextsCount := collectSnippetsFilterSnippetsInfo(g) + snippetsFiltersDirectives, snippetsFiltersDirectivesCount := collectSnippetsFilterDirectives(g) data := Data{ Data: tel.Data{ @@ -176,14 +176,13 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) { InstallationID: deploymentID, ClusterNodeCount: int64(clusterInfo.NodeCount), }, - NGFResourceCounts: graphResourceCount, - ImageSource: c.cfg.ImageSource, - FlagNames: c.cfg.Flags.Names, - FlagValues: c.cfg.Flags.Values, - NGFReplicaCount: int64(replicaCount), - // maybe SnippetValues? - SnippetsFiltersDirectiveContexts: snippetsFiltersDirectiveContexts, - SnippetsFiltersDirectiveContextsCount: snippetsFiltersDirectiveContextsCount, + NGFResourceCounts: graphResourceCount, + ImageSource: c.cfg.ImageSource, + FlagNames: c.cfg.Flags.Names, + FlagValues: c.cfg.Flags.Values, + NGFReplicaCount: int64(replicaCount), + SnippetsFiltersDirectives: snippetsFiltersDirectives, + SnippetsFiltersDirectivesCount: snippetsFiltersDirectivesCount, } return data, nil @@ -406,7 +405,7 @@ type sfDirectiveContext struct { context string } -func collectSnippetsFilterSnippetsInfo(g *graph.Graph) ([]string, []int64) { +func collectSnippetsFilterDirectives(g *graph.Graph) ([]string, []int64) { directiveContextMap := make(map[sfDirectiveContext]int) for _, sf := range g.SnippetsFilters { diff --git a/internal/mode/static/telemetry/collector_test.go b/internal/mode/static/telemetry/collector_test.go index 2538e8a51..dd42b2265 100644 --- a/internal/mode/static/telemetry/collector_test.go +++ b/internal/mode/static/telemetry/collector_test.go @@ -169,13 +169,13 @@ var _ = Describe("Collector", Ordered, func() { InstallationID: string(ngfReplicaSet.ObjectMeta.OwnerReferences[0].UID), ClusterNodeCount: 1, }, - NGFResourceCounts: telemetry.NGFResourceCounts{}, - NGFReplicaCount: 1, - ImageSource: "local", - FlagNames: flags.Names, - FlagValues: flags.Values, - SnippetsFiltersDirectiveContexts: []string{}, - SnippetsFiltersDirectiveContextsCount: []int64{}, + NGFResourceCounts: telemetry.NGFResourceCounts{}, + NGFReplicaCount: 1, + ImageSource: "local", + FlagNames: flags.Names, + FlagValues: flags.Values, + SnippetsFiltersDirectives: []string{}, + SnippetsFiltersDirectivesCount: []int64{}, } k8sClientReader = &eventsfakes.FakeReader{} @@ -416,7 +416,7 @@ var _ = Describe("Collector", Ordered, func() { expData.ClusterVersion = "1.29.2" expData.ClusterPlatform = "kind" - expData.SnippetsFiltersDirectiveContexts = []string{ + expData.SnippetsFiltersDirectives = []string{ "auth_delay-server", "aio-http", "keepalive_time-location", @@ -427,7 +427,7 @@ var _ = Describe("Collector", Ordered, func() { "worker_rlimit_nofile-main", "ignore_invalid_headers-server", } - expData.SnippetsFiltersDirectiveContextsCount = []int64{ + expData.SnippetsFiltersDirectivesCount = []int64{ 3, 2, 2, diff --git a/internal/mode/static/telemetry/data.avdl b/internal/mode/static/telemetry/data.avdl index f5d70d1c0..71515e0e5 100644 --- a/internal/mode/static/telemetry/data.avdl +++ b/internal/mode/static/telemetry/data.avdl @@ -45,16 +45,16 @@ at the same index. Each value is either 'true' or 'false' for boolean flags and 'default' or 'user-defined' for non-boolean flags. */ union {null, array} FlagValues = null; - /** SnippetsFiltersDirectiveContexts contains the directive-context strings of all applied SnippetsFilters. + /** SnippetsFiltersDirectives contains the directive-context strings of all applied SnippetsFilters. Both lists are ordered first by count, then by lexicographical order of the context string, then lastly by directive string. */ - union {null, array} SnippetsFiltersDirectiveContexts = null; + union {null, array} SnippetsFiltersDirectives = null; - /** SnippetsFiltersDirectiveContextsCount contains the count of the directive-context strings, where each count -corresponds to the string from SnippetsFiltersDirectiveContexts at the same index. + /** SnippetsFiltersDirectivesCount contains the count of the directive-context strings, where each count +corresponds to the string from SnippetsFiltersDirectives at the same index. Both lists are ordered first by count, then by lexicographical order of the context string, then lastly by directive string. */ - union {null, array} SnippetsFiltersDirectiveContextsCount = null; + union {null, array} SnippetsFiltersDirectivesCount = null; /** GatewayCount is the number of relevant Gateways. */ long? GatewayCount = null; diff --git a/internal/mode/static/telemetry/data_attributes_generated.go b/internal/mode/static/telemetry/data_attributes_generated.go index b2dc22c79..da061512a 100644 --- a/internal/mode/static/telemetry/data_attributes_generated.go +++ b/internal/mode/static/telemetry/data_attributes_generated.go @@ -17,8 +17,8 @@ func (d *Data) Attributes() []attribute.KeyValue { attrs = append(attrs, d.Data.Attributes()...) attrs = append(attrs, attribute.StringSlice("FlagNames", d.FlagNames)) attrs = append(attrs, attribute.StringSlice("FlagValues", d.FlagValues)) - attrs = append(attrs, attribute.StringSlice("SnippetsFiltersDirectiveContexts", d.SnippetsFiltersDirectiveContexts)) - attrs = append(attrs, attribute.Int64Slice("SnippetsFiltersDirectiveContextsCount", d.SnippetsFiltersDirectiveContextsCount)) + attrs = append(attrs, attribute.StringSlice("SnippetsFiltersDirectives", d.SnippetsFiltersDirectives)) + attrs = append(attrs, attribute.Int64Slice("SnippetsFiltersDirectivesCount", d.SnippetsFiltersDirectivesCount)) attrs = append(attrs, d.NGFResourceCounts.Attributes()...) attrs = append(attrs, attribute.Int64("NGFReplicaCount", d.NGFReplicaCount)) diff --git a/internal/mode/static/telemetry/data_test.go b/internal/mode/static/telemetry/data_test.go index 9d4219a5e..cb8f084b3 100644 --- a/internal/mode/static/telemetry/data_test.go +++ b/internal/mode/static/telemetry/data_test.go @@ -40,9 +40,9 @@ func TestDataAttributes(t *testing.T) { NginxProxyCount: 12, SnippetsFilterCount: 13, }, - NGFReplicaCount: 3, - SnippetsFiltersDirectiveContexts: []string{"main-three-count", "http-two-count", "server-one-count"}, - SnippetsFiltersDirectiveContextsCount: []int64{3, 2, 1}, + NGFReplicaCount: 3, + SnippetsFiltersDirectives: []string{"main-three-count", "http-two-count", "server-one-count"}, + SnippetsFiltersDirectivesCount: []int64{3, 2, 1}, } expected := []attribute.KeyValue{ @@ -59,10 +59,10 @@ func TestDataAttributes(t *testing.T) { attribute.StringSlice("FlagNames", []string{"test-flag"}), attribute.StringSlice("FlagValues", []string{"test-value"}), attribute.StringSlice( - "SnippetsFiltersDirectiveContexts", + "SnippetsFiltersDirectives", []string{"main-three-count", "http-two-count", "server-one-count"}, ), - attribute.IntSlice("SnippetsFiltersDirectiveContextsCount", []int{3, 2, 1}), + attribute.IntSlice("SnippetsFiltersDirectivesCount", []int{3, 2, 1}), attribute.Int64("GatewayCount", 1), attribute.Int64("GatewayClassCount", 2), attribute.Int64("HTTPRouteCount", 3), @@ -103,8 +103,8 @@ func TestDataAttributesWithEmptyData(t *testing.T) { attribute.Int64("ClusterNodeCount", 0), attribute.StringSlice("FlagNames", nil), attribute.StringSlice("FlagValues", nil), - attribute.StringSlice("SnippetsFiltersDirectiveContexts", nil), - attribute.IntSlice("SnippetsFiltersDirectiveContextsCount", nil), + attribute.StringSlice("SnippetsFiltersDirectives", nil), + attribute.IntSlice("SnippetsFiltersDirectivesCount", nil), attribute.Int64("GatewayCount", 0), attribute.Int64("GatewayClassCount", 0), attribute.Int64("HTTPRouteCount", 0), diff --git a/tests/suite/telemetry_test.go b/tests/suite/telemetry_test.go index 57cc63835..ac8f84267 100644 --- a/tests/suite/telemetry_test.go +++ b/tests/suite/telemetry_test.go @@ -72,8 +72,8 @@ var _ = Describe("Telemetry test with OTel collector", Label("telemetry"), func( fmt.Sprintf("ClusterNodeCount: Int(%d)", info.NodeCount), "FlagNames: Slice", "FlagValues: Slice", - "SnippetsFiltersDirectiveContexts: Slice", - "SnippetsFiltersDirectiveContextsCount: Slice", + "SnippetsFiltersDirectives: Slice", + "SnippetsFiltersDirectivesCount: Slice", "GatewayCount: Int(0)", "GatewayClassCount: Int(1)", "HTTPRouteCount: Int(0)", From ab3bcb78f1454a52284376b76fca5e45925cbed8 Mon Sep 17 00:00:00 2001 From: Benjamin Jee Date: Mon, 14 Oct 2024 11:43:11 -0700 Subject: [PATCH 11/11] Add edge case tests --- .../mode/static/telemetry/collector_test.go | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/internal/mode/static/telemetry/collector_test.go b/internal/mode/static/telemetry/collector_test.go index dd42b2265..59bee05aa 100644 --- a/internal/mode/static/telemetry/collector_test.go +++ b/internal/mode/static/telemetry/collector_test.go @@ -918,4 +918,44 @@ var _ = Describe("Collector", Ordered, func() { }) }) }) + + Describe("snippetsFilters collector", func() { + When("collecting snippetsFilters data", func() { + It("collects correct data for nil snippetsFilters", func(ctx SpecContext) { + fakeGraphGetter.GetLatestGraphReturns(&graph.Graph{ + SnippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{ + {Namespace: "test", Name: "sf-1"}: nil, + }, + }) + + expData.SnippetsFilterCount = 1 + + data, err := dataCollector.Collect(ctx) + + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(expData)) + }) + + It("collects correct data when snippetsFilters context is not supported", func(ctx SpecContext) { + fakeGraphGetter.GetLatestGraphReturns(&graph.Graph{ + SnippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{ + {Namespace: "test", Name: "sf-1"}: { + Snippets: map[ngfAPI.NginxContext]string{ + "unsupportedContext": "worker_priority 0;", + }, + }, + }, + }) + + expData.SnippetsFilterCount = 1 + expData.SnippetsFiltersDirectives = []string{"worker_priority-unknown"} + expData.SnippetsFiltersDirectivesCount = []int64{1} + + data, err := dataCollector.Collect(ctx) + + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(expData)) + }) + }) + }) })