From e89af1a919210dbf869594b4921aa84b64152f04 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Fri, 14 Jun 2024 10:22:00 -0700 Subject: [PATCH] [chore] use mdatagen for internal telemetry (#33569) Update k8sattributesprocessor to migrate from opencensus to otel with mdatagen. Closes #33466 --------- Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- cmd/otelcontribcol/go.mod | 2 +- cmd/otelcontribcol/go.sum | 4 +- connector/datadogconnector/go.mod | 5 +- connector/datadogconnector/go.sum | 4 +- exporter/datadogexporter/go.mod | 2 +- exporter/datadogexporter/go.sum | 4 +- .../datadogexporter/integrationtest/go.mod | 5 +- .../datadogexporter/integrationtest/go.sum | 4 +- go.mod | 2 +- go.sum | 4 +- .../k8sattributesprocessor/client_test.go | 4 +- .../k8sattributesprocessor/documentation.md | 147 +++++++++++++ .../generated_component_telemetry_test.go | 76 +++++++ processor/k8sattributesprocessor/go.mod | 14 +- processor/k8sattributesprocessor/go.sum | 15 +- .../internal/kube/client.go | 65 +++--- .../internal/kube/client_test.go | 14 +- .../internal/kube/kube.go | 4 +- .../internal/metadata/generated_telemetry.go | 138 ++++++++++++- .../metadata/generated_telemetry_test.go | 13 ++ .../internal/observability/empty_test.go | 4 - .../internal/observability/observability.go | 194 ------------------ .../observability/observability_test.go | 161 --------------- .../k8sattributesprocessor/metadata.yaml | 100 +++++++++ processor/k8sattributesprocessor/processor.go | 6 +- .../k8sattributesprocessor/processor_test.go | 5 +- 26 files changed, 550 insertions(+), 446 deletions(-) create mode 100644 processor/k8sattributesprocessor/documentation.md create mode 100644 processor/k8sattributesprocessor/generated_component_telemetry_test.go delete mode 100644 processor/k8sattributesprocessor/internal/observability/empty_test.go delete mode 100644 processor/k8sattributesprocessor/internal/observability/observability.go delete mode 100644 processor/k8sattributesprocessor/internal/observability/observability_test.go diff --git a/cmd/otelcontribcol/go.mod b/cmd/otelcontribcol/go.mod index 7828090b6cb5..caa7f28a46f6 100644 --- a/cmd/otelcontribcol/go.mod +++ b/cmd/otelcontribcol/go.mod @@ -361,7 +361,7 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.47.0 // indirect github.com/IBM/sarama v1.43.2 // indirect github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ReneKroon/ttlcache/v2 v2.11.0 // indirect github.com/SAP/go-hdb v1.9.8 // indirect github.com/SermoDigital/jose v0.9.2-0.20180104203859-803625baeddc // indirect diff --git a/cmd/otelcontribcol/go.sum b/cmd/otelcontribcol/go.sum index 53f0cb08ec2b..2c251f458399 100644 --- a/cmd/otelcontribcol/go.sum +++ b/cmd/otelcontribcol/go.sum @@ -896,8 +896,8 @@ github.com/IBM/sarama v1.43.2/go.mod h1:Kyo4WkF24Z+1nz7xeVUFWIuKVV8RS3wM8mkvPKMd github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= diff --git a/connector/datadogconnector/go.mod b/connector/datadogconnector/go.mod index c22be6ebed40..afb52644c61b 100644 --- a/connector/datadogconnector/go.mod +++ b/connector/datadogconnector/go.mod @@ -96,7 +96,7 @@ require ( github.com/DataDog/viper v1.13.3 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.23.0 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/aws/aws-sdk-go v1.53.11 // indirect github.com/benbjohnson/clock v1.3.5 // indirect @@ -249,15 +249,12 @@ require ( go.uber.org/fx v1.18.2 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect - golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.15.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect diff --git a/connector/datadogconnector/go.sum b/connector/datadogconnector/go.sum index cea9f9e91b78..0a581eb789a8 100644 --- a/connector/datadogconnector/go.sum +++ b/connector/datadogconnector/go.sum @@ -214,8 +214,8 @@ github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwS github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.23.0 h1:yRhWveg9NbJcJYoJL4FoSauT2dxnt4N9MIAJ7tvU/mQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.23.0/go.mod h1:p2puVVSKjQ84Qb1gzw2XHLs34WQyHTYFZLaVxypAFYs= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= diff --git a/exporter/datadogexporter/go.mod b/exporter/datadogexporter/go.mod index f3c77b77ed94..6d94c2f2f7dc 100644 --- a/exporter/datadogexporter/go.mod +++ b/exporter/datadogexporter/go.mod @@ -131,7 +131,7 @@ require ( github.com/DataDog/go-tuf v1.1.0-0.5.2 // indirect github.com/DataDog/viper v1.13.3 // indirect github.com/DataDog/zstd v1.5.2 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Showmax/go-fqdn v1.0.0 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect diff --git a/exporter/datadogexporter/go.sum b/exporter/datadogexporter/go.sum index 4159953147ea..493c70aec1b8 100644 --- a/exporter/datadogexporter/go.sum +++ b/exporter/datadogexporter/go.sum @@ -223,8 +223,8 @@ github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwS github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.23.0 h1:yRhWveg9NbJcJYoJL4FoSauT2dxnt4N9MIAJ7tvU/mQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.23.0/go.mod h1:p2puVVSKjQ84Qb1gzw2XHLs34WQyHTYFZLaVxypAFYs= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= diff --git a/exporter/datadogexporter/integrationtest/go.mod b/exporter/datadogexporter/integrationtest/go.mod index 96ab696567f1..6f3e949e4a1f 100644 --- a/exporter/datadogexporter/integrationtest/go.mod +++ b/exporter/datadogexporter/integrationtest/go.mod @@ -96,7 +96,7 @@ require ( github.com/DataDog/viper v1.13.3 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.23.0 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/aws/aws-sdk-go v1.53.11 // indirect github.com/benbjohnson/clock v1.3.5 // indirect @@ -249,15 +249,12 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect - golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.15.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect diff --git a/exporter/datadogexporter/integrationtest/go.sum b/exporter/datadogexporter/integrationtest/go.sum index cea9f9e91b78..0a581eb789a8 100644 --- a/exporter/datadogexporter/integrationtest/go.sum +++ b/exporter/datadogexporter/integrationtest/go.sum @@ -214,8 +214,8 @@ github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwS github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.23.0 h1:yRhWveg9NbJcJYoJL4FoSauT2dxnt4N9MIAJ7tvU/mQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.23.0/go.mod h1:p2puVVSKjQ84Qb1gzw2XHLs34WQyHTYFZLaVxypAFYs= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= diff --git a/go.mod b/go.mod index d77127245605..ab636d52ed48 100644 --- a/go.mod +++ b/go.mod @@ -318,7 +318,7 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.47.0 // indirect github.com/IBM/sarama v1.43.2 // indirect github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ReneKroon/ttlcache/v2 v2.11.0 // indirect github.com/SAP/go-hdb v1.9.8 // indirect github.com/SermoDigital/jose v0.9.2-0.20180104203859-803625baeddc // indirect diff --git a/go.sum b/go.sum index 426fdbb36bfc..bde788383431 100644 --- a/go.sum +++ b/go.sum @@ -897,8 +897,8 @@ github.com/IBM/sarama v1.43.2/go.mod h1:Kyo4WkF24Z+1nz7xeVUFWIuKVV8RS3wM8mkvPKMd github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= diff --git a/processor/k8sattributesprocessor/client_test.go b/processor/k8sattributesprocessor/client_test.go index 0ab0d830d28f..2a893e52790c 100644 --- a/processor/k8sattributesprocessor/client_test.go +++ b/processor/k8sattributesprocessor/client_test.go @@ -4,7 +4,7 @@ package k8sattributesprocessor import ( - "go.uber.org/zap" + "go.opentelemetry.io/collector/component" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes/fake" @@ -35,7 +35,7 @@ func selectors() (labels.Selector, fields.Selector) { } // newFakeClient instantiates a new FakeClient object and satisfies the ClientProvider type -func newFakeClient(_ *zap.Logger, _ k8sconfig.APIConfig, rules kube.ExtractionRules, filters kube.Filters, associations []kube.Association, _ kube.Excludes, _ kube.APIClientsetProvider, _ kube.InformerProvider, _ kube.InformerProviderNamespace, _ kube.InformerProviderReplicaSet) (kube.Client, error) { +func newFakeClient(_ component.TelemetrySettings, _ k8sconfig.APIConfig, rules kube.ExtractionRules, filters kube.Filters, associations []kube.Association, _ kube.Excludes, _ kube.APIClientsetProvider, _ kube.InformerProvider, _ kube.InformerProviderNamespace, _ kube.InformerProviderReplicaSet) (kube.Client, error) { cs := fake.NewSimpleClientset() ls, fs := selectors() diff --git a/processor/k8sattributesprocessor/documentation.md b/processor/k8sattributesprocessor/documentation.md new file mode 100644 index 000000000000..ce3d52558c56 --- /dev/null +++ b/processor/k8sattributesprocessor/documentation.md @@ -0,0 +1,147 @@ +[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) + +# k8sattributes + +## Resource Attributes + +| Name | Description | Values | Enabled | +| ---- | ----------- | ------ | ------- | +| container.id | Container ID. Usually a UUID, as for example used to identify Docker containers. The UUID might be abbreviated. Requires k8s.container.restart_count. | Any Str | false | +| container.image.name | Name of the image the container was built on. Requires container.id or k8s.container.name. | Any Str | true | +| container.image.tag | Container image tag. Requires container.id or k8s.container.name. | Any Str | true | +| k8s.cluster.uid | Gives cluster uid identified with kube-system namespace | Any Str | false | +| k8s.container.name | The name of the Container in a Pod template. Requires container.id. | Any Str | false | +| k8s.cronjob.name | The name of the CronJob. | Any Str | false | +| k8s.daemonset.name | The name of the DaemonSet. | Any Str | false | +| k8s.daemonset.uid | The UID of the DaemonSet. | Any Str | false | +| k8s.deployment.name | The name of the Deployment. | Any Str | true | +| k8s.deployment.uid | The UID of the Deployment. | Any Str | false | +| k8s.job.name | The name of the Job. | Any Str | false | +| k8s.job.uid | The UID of the Job. | Any Str | false | +| k8s.namespace.name | The name of the namespace that the pod is running in. | Any Str | true | +| k8s.node.name | The name of the Node. | Any Str | true | +| k8s.node.uid | The UID of the Node. | Any Str | false | +| k8s.pod.hostname | The hostname of the Pod. | Any Str | false | +| k8s.pod.name | The name of the Pod. | Any Str | true | +| k8s.pod.start_time | The start time of the Pod. | Any Str | true | +| k8s.pod.uid | The UID of the Pod. | Any Str | true | +| k8s.replicaset.name | The name of the ReplicaSet. | Any Str | false | +| k8s.replicaset.uid | The UID of the ReplicaSet. | Any Str | false | +| k8s.statefulset.name | The name of the StatefulSet. | Any Str | false | +| k8s.statefulset.uid | The UID of the StatefulSet. | Any Str | false | + +## Internal Telemetry + +The following telemetry is emitted by this component. + +### otelsvc_k8s_ip_lookup_miss + +Number of times pod by IP lookup failed. + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_namespace_added + +Number of namespace add events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_namespace_deleted + +Number of namespace delete events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_namespace_updated + +Number of namespace update events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_node_added + +Number of node add events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_node_deleted + +Number of node delete events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_node_updated + +Number of node update events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_pod_added + +Number of pod add events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_pod_deleted + +Number of pod delete events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_pod_table_size + +Size of table containing pod info + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| 1 | Gauge | Int | + +### otelsvc_k8s_pod_updated + +Number of pod update events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_replicaset_added + +Number of ReplicaSet add events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_replicaset_deleted + +Number of ReplicaSet delete events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | + +### otelsvc_k8s_replicaset_updated + +Number of ReplicaSet update events received + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| 1 | Sum | Int | true | diff --git a/processor/k8sattributesprocessor/generated_component_telemetry_test.go b/processor/k8sattributesprocessor/generated_component_telemetry_test.go new file mode 100644 index 000000000000..f9dd7763b623 --- /dev/null +++ b/processor/k8sattributesprocessor/generated_component_telemetry_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package k8sattributesprocessor + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/processor" + "go.opentelemetry.io/collector/processor/processortest" +) + +type componentTestTelemetry struct { + reader *sdkmetric.ManualReader + meterProvider *sdkmetric.MeterProvider +} + +func (tt *componentTestTelemetry) NewSettings() processor.Settings { + settings := processortest.NewNopSettings() + settings.MeterProvider = tt.meterProvider + settings.ID = component.NewID(component.MustNewType("k8sattributes")) + + return settings +} + +func setupTestTelemetry() componentTestTelemetry { + reader := sdkmetric.NewManualReader() + return componentTestTelemetry{ + reader: reader, + meterProvider: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)), + } +} + +func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { + var md metricdata.ResourceMetrics + require.NoError(t, tt.reader.Collect(context.Background(), &md)) + // ensure all required metrics are present + for _, want := range expected { + got := tt.getMetric(want.Name, md) + metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) + } + + // ensure no additional metrics are emitted + require.Equal(t, len(expected), tt.len(md)) +} + +func (tt *componentTestTelemetry) getMetric(name string, got metricdata.ResourceMetrics) metricdata.Metrics { + for _, sm := range got.ScopeMetrics { + for _, m := range sm.Metrics { + if m.Name == name { + return m + } + } + } + + return metricdata.Metrics{} +} + +func (tt *componentTestTelemetry) len(got metricdata.ResourceMetrics) int { + metricsCount := 0 + for _, sm := range got.ScopeMetrics { + metricsCount += len(sm.Metrics) + } + + return metricsCount +} + +func (tt *componentTestTelemetry) Shutdown(ctx context.Context) error { + return tt.meterProvider.Shutdown(ctx) +} diff --git a/processor/k8sattributesprocessor/go.mod b/processor/k8sattributesprocessor/go.mod index 28e5ea1fc273..3188251e60ac 100644 --- a/processor/k8sattributesprocessor/go.mod +++ b/processor/k8sattributesprocessor/go.mod @@ -8,9 +8,9 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig v0.102.0 github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8stest v0.102.0 github.com/stretchr/testify v1.9.0 - go.opencensus.io v0.24.0 go.opentelemetry.io/collector v0.102.2-0.20240611143128-7dfb57b9ad1c go.opentelemetry.io/collector/component v0.102.2-0.20240611143128-7dfb57b9ad1c + go.opentelemetry.io/collector/config/configtelemetry v0.102.2-0.20240611143128-7dfb57b9ad1c go.opentelemetry.io/collector/confmap v0.102.2-0.20240611143128-7dfb57b9ad1c go.opentelemetry.io/collector/consumer v0.102.2-0.20240611143128-7dfb57b9ad1c go.opentelemetry.io/collector/featuregate v1.9.1-0.20240611143128-7dfb57b9ad1c @@ -20,6 +20,7 @@ require ( go.opentelemetry.io/collector/receiver/otlpreceiver v0.102.2-0.20240611143128-7dfb57b9ad1c go.opentelemetry.io/collector/semconv v0.102.2-0.20240611143128-7dfb57b9ad1c go.opentelemetry.io/otel/metric v1.27.0 + go.opentelemetry.io/otel/sdk/metric v1.27.0 go.opentelemetry.io/otel/trace v1.27.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 @@ -31,7 +32,7 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -50,7 +51,6 @@ require ( github.com/go-openapi/swag v0.22.3 // indirect github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect @@ -71,7 +71,7 @@ require ( github.com/mostynb/go-grpc-compression v1.2.3 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc5 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/openshift/api v3.9.0+incompatible // indirect github.com/openshift/client-go v0.0.0-20210521082421-73d9475a9142 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -81,7 +81,6 @@ require ( github.com/prometheus/common v0.54.0 // indirect github.com/prometheus/procfs v0.15.0 // indirect github.com/rs/cors v1.10.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect go.opentelemetry.io/collector/config/configauth v0.102.2-0.20240611143128-7dfb57b9ad1c // indirect go.opentelemetry.io/collector/config/configcompression v1.9.1-0.20240611143128-7dfb57b9ad1c // indirect @@ -89,7 +88,6 @@ require ( go.opentelemetry.io/collector/config/confighttp v0.102.2-0.20240611143128-7dfb57b9ad1c // indirect go.opentelemetry.io/collector/config/confignet v0.102.2-0.20240611143128-7dfb57b9ad1c // indirect go.opentelemetry.io/collector/config/configopaque v1.9.1-0.20240611143128-7dfb57b9ad1c // indirect - go.opentelemetry.io/collector/config/configtelemetry v0.102.2-0.20240611143128-7dfb57b9ad1c // indirect go.opentelemetry.io/collector/config/configtls v0.102.2-0.20240611143128-7dfb57b9ad1c // indirect go.opentelemetry.io/collector/config/internal v0.102.2-0.20240611143128-7dfb57b9ad1c // indirect go.opentelemetry.io/collector/extension v0.102.2-0.20240611143128-7dfb57b9ad1c // indirect @@ -100,16 +98,12 @@ require ( go.opentelemetry.io/otel v1.27.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.49.0 // indirect go.opentelemetry.io/otel/sdk v1.27.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect - golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.19.0 // indirect - golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.4.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect google.golang.org/grpc v1.64.0 // indirect google.golang.org/protobuf v1.34.2 // indirect diff --git a/processor/k8sattributesprocessor/go.sum b/processor/k8sattributesprocessor/go.sum index 75e039b7db99..1e2ded230267 100644 --- a/processor/k8sattributesprocessor/go.sum +++ b/processor/k8sattributesprocessor/go.sum @@ -767,8 +767,8 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -921,7 +921,6 @@ github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -1142,8 +1141,8 @@ github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= -github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/openshift/api v0.0.0-20180801171038-322a19404e37 h1:05irGU4HK4IauGGDbsk+ZHrm1wOzMLYjMlfaiqMrBYc= github.com/openshift/api v0.0.0-20180801171038-322a19404e37/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= github.com/openshift/api v0.0.0-20210521075222-e273a339932a/go.mod h1:izBmoXbUu3z5kUa4FjZhvekTsyzIWiOoaIgJiZBBMQs= @@ -1230,7 +1229,6 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/collector v0.102.2-0.20240611143128-7dfb57b9ad1c h1:UmlCWoLNgxxN906BHOXH06/TMeumOrDqdTXeRkYD6d4= go.opentelemetry.io/collector v0.102.2-0.20240611143128-7dfb57b9ad1c/go.mod h1:gKjweCX6ve4F7X4RGV3kDN24Bg2eyV6MTCncnaPfRPA= @@ -1398,8 +1396,6 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1519,8 +1515,6 @@ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1590,7 +1584,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/processor/k8sattributesprocessor/internal/kube/client.go b/processor/k8sattributesprocessor/internal/kube/client.go index 7488519dd925..19ba3fedfdd3 100644 --- a/processor/k8sattributesprocessor/internal/kube/client.go +++ b/processor/k8sattributesprocessor/internal/kube/client.go @@ -4,12 +4,14 @@ package kube // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor/internal/kube" import ( + "context" "fmt" "regexp" "strings" "sync" "time" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/featuregate" conventions "go.opentelemetry.io/collector/semconv/v1.6.1" "go.uber.org/zap" @@ -23,7 +25,7 @@ import ( "k8s.io/client-go/tools/cache" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig" - "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor/internal/observability" + "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor/internal/metadata" ) var enableRFC3339Timestamp = featuregate.GlobalRegistry().MustRegister( @@ -68,6 +70,8 @@ type WatchClient struct { // A map containing ReplicaSets related data, used to associate them with resources. // Key is replicaset uid ReplicaSets map[string]*ReplicaSet + + telemetryBuilder *metadata.TelemetryBuilder } // Extract replicaset name from the pod name. Pod name is created using @@ -79,16 +83,21 @@ var rRegex = regexp.MustCompile(`^(.*)-[0-9a-zA-Z]+$`) var cronJobRegex = regexp.MustCompile(`^(.*)-[0-9]+$`) // New initializes a new k8s Client. -func New(logger *zap.Logger, apiCfg k8sconfig.APIConfig, rules ExtractionRules, filters Filters, associations []Association, exclude Excludes, newClientSet APIClientsetProvider, newInformer InformerProvider, newNamespaceInformer InformerProviderNamespace, newReplicaSetInformer InformerProviderReplicaSet) (Client, error) { +func New(set component.TelemetrySettings, apiCfg k8sconfig.APIConfig, rules ExtractionRules, filters Filters, associations []Association, exclude Excludes, newClientSet APIClientsetProvider, newInformer InformerProvider, newNamespaceInformer InformerProviderNamespace, newReplicaSetInformer InformerProviderReplicaSet) (Client, error) { + telemetryBuilder, err := metadata.NewTelemetryBuilder(set) + if err != nil { + return nil, err + } c := &WatchClient{ - logger: logger, - Rules: rules, - Filters: filters, - Associations: associations, - Exclude: exclude, - replicasetRegex: rRegex, - cronJobRegex: cronJobRegex, - stopCh: make(chan struct{}), + logger: set.Logger, + Rules: rules, + Filters: filters, + Associations: associations, + Exclude: exclude, + replicasetRegex: rRegex, + cronJobRegex: cronJobRegex, + stopCh: make(chan struct{}), + telemetryBuilder: telemetryBuilder, } go c.deleteLoop(time.Second*30, defaultPodDeleteGracePeriod) @@ -110,7 +119,7 @@ func New(logger *zap.Logger, apiCfg k8sconfig.APIConfig, rules ExtractionRules, if err != nil { return nil, err } - logger.Info( + set.Logger.Info( "k8s filtering", zap.String("labelSelector", labelSelector.String()), zap.String("fieldSelector", fieldSelector.String()), @@ -231,18 +240,18 @@ func (c *WatchClient) Stop() { } func (c *WatchClient) handlePodAdd(obj any) { - observability.RecordPodAdded() + c.telemetryBuilder.OtelsvcK8sPodAdded.Add(context.Background(), 1) if pod, ok := obj.(*api_v1.Pod); ok { c.addOrUpdatePod(pod) } else { c.logger.Error("object received was not of type api_v1.Pod", zap.Any("received", obj)) } podTableSize := len(c.Pods) - observability.RecordPodTableSize(int64(podTableSize)) + c.telemetryBuilder.OtelsvcK8sPodTableSize.Record(context.Background(), int64(podTableSize)) } func (c *WatchClient) handlePodUpdate(_, newPod any) { - observability.RecordPodUpdated() + c.telemetryBuilder.OtelsvcK8sPodUpdated.Add(context.Background(), 1) if pod, ok := newPod.(*api_v1.Pod); ok { // TODO: update or remove based on whether container is ready/unready?. c.addOrUpdatePod(pod) @@ -250,22 +259,22 @@ func (c *WatchClient) handlePodUpdate(_, newPod any) { c.logger.Error("object received was not of type api_v1.Pod", zap.Any("received", newPod)) } podTableSize := len(c.Pods) - observability.RecordPodTableSize(int64(podTableSize)) + c.telemetryBuilder.OtelsvcK8sPodTableSize.Record(context.Background(), int64(podTableSize)) } func (c *WatchClient) handlePodDelete(obj any) { - observability.RecordPodDeleted() + c.telemetryBuilder.OtelsvcK8sPodDeleted.Add(context.Background(), 1) if pod, ok := ignoreDeletedFinalStateUnknown(obj).(*api_v1.Pod); ok { c.forgetPod(pod) } else { c.logger.Error("object received was not of type api_v1.Pod", zap.Any("received", obj)) } podTableSize := len(c.Pods) - observability.RecordPodTableSize(int64(podTableSize)) + c.telemetryBuilder.OtelsvcK8sPodTableSize.Record(context.Background(), int64(podTableSize)) } func (c *WatchClient) handleNamespaceAdd(obj any) { - observability.RecordNamespaceAdded() + c.telemetryBuilder.OtelsvcK8sNamespaceAdded.Add(context.Background(), 1) if namespace, ok := obj.(*api_v1.Namespace); ok { c.addOrUpdateNamespace(namespace) } else { @@ -274,7 +283,7 @@ func (c *WatchClient) handleNamespaceAdd(obj any) { } func (c *WatchClient) handleNamespaceUpdate(_, newNamespace any) { - observability.RecordNamespaceUpdated() + c.telemetryBuilder.OtelsvcK8sNamespaceUpdated.Add(context.Background(), 1) if namespace, ok := newNamespace.(*api_v1.Namespace); ok { c.addOrUpdateNamespace(namespace) } else { @@ -283,7 +292,7 @@ func (c *WatchClient) handleNamespaceUpdate(_, newNamespace any) { } func (c *WatchClient) handleNamespaceDelete(obj any) { - observability.RecordNamespaceDeleted() + c.telemetryBuilder.OtelsvcK8sNamespaceDeleted.Add(context.Background(), 1) if namespace, ok := ignoreDeletedFinalStateUnknown(obj).(*api_v1.Namespace); ok { c.m.Lock() if ns, ok := c.Namespaces[namespace.Name]; ok { @@ -299,7 +308,7 @@ func (c *WatchClient) handleNamespaceDelete(obj any) { } func (c *WatchClient) handleNodeAdd(obj any) { - observability.RecordNodeAdded() + c.telemetryBuilder.OtelsvcK8sNodeAdded.Add(context.Background(), 1) if node, ok := obj.(*api_v1.Node); ok { c.addOrUpdateNode(node) } else { @@ -308,7 +317,7 @@ func (c *WatchClient) handleNodeAdd(obj any) { } func (c *WatchClient) handleNodeUpdate(_, newNode any) { - observability.RecordNodeUpdated() + c.telemetryBuilder.OtelsvcK8sNodeUpdated.Add(context.Background(), 1) if node, ok := newNode.(*api_v1.Node); ok { c.addOrUpdateNode(node) } else { @@ -317,7 +326,7 @@ func (c *WatchClient) handleNodeUpdate(_, newNode any) { } func (c *WatchClient) handleNodeDelete(obj any) { - observability.RecordNodeDeleted() + c.telemetryBuilder.OtelsvcK8sNodeDeleted.Add(context.Background(), 1) if node, ok := ignoreDeletedFinalStateUnknown(obj).(*api_v1.Node); ok { c.m.Lock() if n, ok := c.Nodes[node.Name]; ok { @@ -360,7 +369,7 @@ func (c *WatchClient) deleteLoop(interval time.Duration, gracePeriod time.Durati } } podTableSize := len(c.Pods) - observability.RecordPodTableSize(int64(podTableSize)) + c.telemetryBuilder.OtelsvcK8sPodTableSize.Record(context.Background(), int64(podTableSize)) c.m.Unlock() case <-c.stopCh: @@ -380,7 +389,7 @@ func (c *WatchClient) GetPod(identifier PodIdentifier) (*Pod, bool) { } return pod, ok } - observability.RecordIPLookupMiss() + c.telemetryBuilder.OtelsvcK8sIPLookupMiss.Add(context.Background(), 1) return nil, false } @@ -956,7 +965,7 @@ func needContainerAttributes(rules ExtractionRules) bool { } func (c *WatchClient) handleReplicaSetAdd(obj any) { - observability.RecordReplicaSetAdded() + c.telemetryBuilder.OtelsvcK8sReplicasetAdded.Add(context.Background(), 1) if replicaset, ok := obj.(*apps_v1.ReplicaSet); ok { c.addOrUpdateReplicaSet(replicaset) } else { @@ -965,7 +974,7 @@ func (c *WatchClient) handleReplicaSetAdd(obj any) { } func (c *WatchClient) handleReplicaSetUpdate(_, newRS any) { - observability.RecordReplicaSetUpdated() + c.telemetryBuilder.OtelsvcK8sReplicasetUpdated.Add(context.Background(), 1) if replicaset, ok := newRS.(*apps_v1.ReplicaSet); ok { c.addOrUpdateReplicaSet(replicaset) } else { @@ -974,7 +983,7 @@ func (c *WatchClient) handleReplicaSetUpdate(_, newRS any) { } func (c *WatchClient) handleReplicaSetDelete(obj any) { - observability.RecordReplicaSetDeleted() + c.telemetryBuilder.OtelsvcK8sReplicasetDeleted.Add(context.Background(), 1) if replicaset, ok := ignoreDeletedFinalStateUnknown(obj).(*apps_v1.ReplicaSet); ok { c.m.Lock() key := string(replicaset.UID) diff --git a/processor/k8sattributesprocessor/internal/kube/client_test.go b/processor/k8sattributesprocessor/internal/kube/client_test.go index e92d47fa3f38..ff18fb59c405 100644 --- a/processor/k8sattributesprocessor/internal/kube/client_test.go +++ b/processor/k8sattributesprocessor/internal/kube/client_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component/componenttest" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" @@ -143,19 +144,19 @@ func nodeAddAndUpdateTest(t *testing.T, c *WatchClient, handler func(obj any)) { } func TestDefaultClientset(t *testing.T) { - c, err := New(zap.NewNop(), k8sconfig.APIConfig{}, ExtractionRules{}, Filters{}, []Association{}, Excludes{}, nil, nil, nil, nil) + c, err := New(componenttest.NewNopTelemetrySettings(), k8sconfig.APIConfig{}, ExtractionRules{}, Filters{}, []Association{}, Excludes{}, nil, nil, nil, nil) assert.Error(t, err) assert.Equal(t, "invalid authType for kubernetes: ", err.Error()) assert.Nil(t, c) - c, err = New(zap.NewNop(), k8sconfig.APIConfig{}, ExtractionRules{}, Filters{}, []Association{}, Excludes{}, newFakeAPIClientset, nil, nil, nil) + c, err = New(componenttest.NewNopTelemetrySettings(), k8sconfig.APIConfig{}, ExtractionRules{}, Filters{}, []Association{}, Excludes{}, newFakeAPIClientset, nil, nil, nil) assert.NoError(t, err) assert.NotNil(t, c) } func TestBadFilters(t *testing.T) { c, err := New( - zap.NewNop(), + componenttest.NewNopTelemetrySettings(), k8sconfig.APIConfig{}, ExtractionRules{}, Filters{Fields: []FieldFilter{{Op: selection.Exists}}}, @@ -201,7 +202,7 @@ func TestConstructorErrors(t *testing.T) { gotAPIConfig = c return nil, fmt.Errorf("error creating k8s client") } - c, err := New(zap.NewNop(), apiCfg, er, ff, []Association{}, Excludes{}, clientProvider, NewFakeInformer, NewFakeNamespaceInformer, nil) + c, err := New(componenttest.NewNopTelemetrySettings(), apiCfg, er, ff, []Association{}, Excludes{}, clientProvider, NewFakeInformer, NewFakeNamespaceInformer, nil) assert.Nil(t, c) assert.Error(t, err) assert.Equal(t, "error creating k8s client", err.Error()) @@ -1807,8 +1808,9 @@ func TestExtractNamespaceLabelsAnnotations(t *testing.T) { } func newTestClientWithRulesAndFilters(t *testing.T, f Filters) (*WatchClient, *observer.ObservedLogs) { + set := componenttest.NewNopTelemetrySettings() observedLogger, logs := observer.New(zapcore.WarnLevel) - logger := zap.New(observedLogger) + set.Logger = zap.New(observedLogger) exclude := Excludes{ Pods: []ExcludePods{ {Name: regexp.MustCompile(`jaeger-agent`)}, @@ -1832,7 +1834,7 @@ func newTestClientWithRulesAndFilters(t *testing.T, f Filters) (*WatchClient, *o }, }, } - c, err := New(logger, k8sconfig.APIConfig{}, ExtractionRules{}, f, associations, exclude, newFakeAPIClientset, NewFakeInformer, NewFakeNamespaceInformer, NewFakeReplicaSetInformer) + c, err := New(set, k8sconfig.APIConfig{}, ExtractionRules{}, f, associations, exclude, newFakeAPIClientset, NewFakeInformer, NewFakeNamespaceInformer, NewFakeReplicaSetInformer) require.NoError(t, err) return c.(*WatchClient), logs } diff --git a/processor/k8sattributesprocessor/internal/kube/kube.go b/processor/k8sattributesprocessor/internal/kube/kube.go index 06d025ca21fa..45a98c586a16 100644 --- a/processor/k8sattributesprocessor/internal/kube/kube.go +++ b/processor/k8sattributesprocessor/internal/kube/kube.go @@ -8,7 +8,7 @@ import ( "regexp" "time" - "go.uber.org/zap" + "go.opentelemetry.io/collector/component" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/selection" "k8s.io/client-go/kubernetes" @@ -96,7 +96,7 @@ type Client interface { } // ClientProvider defines a func type that returns a new Client. -type ClientProvider func(*zap.Logger, k8sconfig.APIConfig, ExtractionRules, Filters, []Association, Excludes, APIClientsetProvider, InformerProvider, InformerProviderNamespace, InformerProviderReplicaSet) (Client, error) +type ClientProvider func(component.TelemetrySettings, k8sconfig.APIConfig, ExtractionRules, Filters, []Association, Excludes, APIClientsetProvider, InformerProvider, InformerProviderNamespace, InformerProviderReplicaSet) (Client, error) // APIClientsetProvider defines a func type that initializes and return a new kubernetes // Clientset object. diff --git a/processor/k8sattributesprocessor/internal/metadata/generated_telemetry.go b/processor/k8sattributesprocessor/internal/metadata/generated_telemetry.go index f8e7479c749e..74590006cbba 100644 --- a/processor/k8sattributesprocessor/internal/metadata/generated_telemetry.go +++ b/processor/k8sattributesprocessor/internal/metadata/generated_telemetry.go @@ -3,9 +3,14 @@ package metadata import ( - "go.opentelemetry.io/collector/component" + "errors" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configtelemetry" ) func Meter(settings component.TelemetrySettings) metric.Meter { @@ -15,3 +20,134 @@ func Meter(settings component.TelemetrySettings) metric.Meter { func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("otelcol/k8sattributes") } + +// TelemetryBuilder provides an interface for components to report telemetry +// as defined in metadata and user config. +type TelemetryBuilder struct { + meter metric.Meter + OtelsvcK8sIPLookupMiss metric.Int64Counter + OtelsvcK8sNamespaceAdded metric.Int64Counter + OtelsvcK8sNamespaceDeleted metric.Int64Counter + OtelsvcK8sNamespaceUpdated metric.Int64Counter + OtelsvcK8sNodeAdded metric.Int64Counter + OtelsvcK8sNodeDeleted metric.Int64Counter + OtelsvcK8sNodeUpdated metric.Int64Counter + OtelsvcK8sPodAdded metric.Int64Counter + OtelsvcK8sPodDeleted metric.Int64Counter + OtelsvcK8sPodTableSize metric.Int64Gauge + OtelsvcK8sPodUpdated metric.Int64Counter + OtelsvcK8sReplicasetAdded metric.Int64Counter + OtelsvcK8sReplicasetDeleted metric.Int64Counter + OtelsvcK8sReplicasetUpdated metric.Int64Counter + level configtelemetry.Level +} + +// telemetryBuilderOption applies changes to default builder. +type telemetryBuilderOption func(*TelemetryBuilder) + +// WithLevel sets the current telemetry level for the component. +func WithLevel(lvl configtelemetry.Level) telemetryBuilderOption { + return func(builder *TelemetryBuilder) { + builder.level = lvl + } +} + +// NewTelemetryBuilder provides a struct with methods to update all internal telemetry +// for a component +func NewTelemetryBuilder(settings component.TelemetrySettings, options ...telemetryBuilderOption) (*TelemetryBuilder, error) { + builder := TelemetryBuilder{level: configtelemetry.LevelBasic} + for _, op := range options { + op(&builder) + } + var err, errs error + if builder.level >= configtelemetry.LevelBasic { + builder.meter = Meter(settings) + } else { + builder.meter = noop.Meter{} + } + builder.OtelsvcK8sIPLookupMiss, err = builder.meter.Int64Counter( + "otelsvc_k8s_ip_lookup_miss", + metric.WithDescription("Number of times pod by IP lookup failed."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sNamespaceAdded, err = builder.meter.Int64Counter( + "otelsvc_k8s_namespace_added", + metric.WithDescription("Number of namespace add events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sNamespaceDeleted, err = builder.meter.Int64Counter( + "otelsvc_k8s_namespace_deleted", + metric.WithDescription("Number of namespace delete events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sNamespaceUpdated, err = builder.meter.Int64Counter( + "otelsvc_k8s_namespace_updated", + metric.WithDescription("Number of namespace update events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sNodeAdded, err = builder.meter.Int64Counter( + "otelsvc_k8s_node_added", + metric.WithDescription("Number of node add events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sNodeDeleted, err = builder.meter.Int64Counter( + "otelsvc_k8s_node_deleted", + metric.WithDescription("Number of node delete events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sNodeUpdated, err = builder.meter.Int64Counter( + "otelsvc_k8s_node_updated", + metric.WithDescription("Number of node update events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sPodAdded, err = builder.meter.Int64Counter( + "otelsvc_k8s_pod_added", + metric.WithDescription("Number of pod add events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sPodDeleted, err = builder.meter.Int64Counter( + "otelsvc_k8s_pod_deleted", + metric.WithDescription("Number of pod delete events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sPodTableSize, err = builder.meter.Int64Gauge( + "otelsvc_k8s_pod_table_size", + metric.WithDescription("Size of table containing pod info"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sPodUpdated, err = builder.meter.Int64Counter( + "otelsvc_k8s_pod_updated", + metric.WithDescription("Number of pod update events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sReplicasetAdded, err = builder.meter.Int64Counter( + "otelsvc_k8s_replicaset_added", + metric.WithDescription("Number of ReplicaSet add events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sReplicasetDeleted, err = builder.meter.Int64Counter( + "otelsvc_k8s_replicaset_deleted", + metric.WithDescription("Number of ReplicaSet delete events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.OtelsvcK8sReplicasetUpdated, err = builder.meter.Int64Counter( + "otelsvc_k8s_replicaset_updated", + metric.WithDescription("Number of ReplicaSet update events received"), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + return &builder, errs +} diff --git a/processor/k8sattributesprocessor/internal/metadata/generated_telemetry_test.go b/processor/k8sattributesprocessor/internal/metadata/generated_telemetry_test.go index 9c549be7840f..85f43c5c3bba 100644 --- a/processor/k8sattributesprocessor/internal/metadata/generated_telemetry_test.go +++ b/processor/k8sattributesprocessor/internal/metadata/generated_telemetry_test.go @@ -61,3 +61,16 @@ func TestProviders(t *testing.T) { require.Fail(t, "returned Meter not mockTracer") } } + +func TestNewTelemetryBuilder(t *testing.T) { + set := component.TelemetrySettings{ + MeterProvider: mockMeterProvider{}, + TracerProvider: mockTracerProvider{}, + } + applied := false + _, err := NewTelemetryBuilder(set, func(b *TelemetryBuilder) { + applied = true + }) + require.NoError(t, err) + require.True(t, applied) +} diff --git a/processor/k8sattributesprocessor/internal/observability/empty_test.go b/processor/k8sattributesprocessor/internal/observability/empty_test.go deleted file mode 100644 index 71526f6d1b28..000000000000 --- a/processor/k8sattributesprocessor/internal/observability/empty_test.go +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package observability diff --git a/processor/k8sattributesprocessor/internal/observability/observability.go b/processor/k8sattributesprocessor/internal/observability/observability.go deleted file mode 100644 index 749b801f03f4..000000000000 --- a/processor/k8sattributesprocessor/internal/observability/observability.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package observability // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor/internal/observability" - -import ( - "context" - - "go.opencensus.io/stats" - "go.opencensus.io/stats/view" -) - -// TODO: re-think if processor should register it's own telemetry views or if some other -// mechanism should be used by the collector to discover views from all components - -func init() { - _ = view.Register( - viewPodsUpdated, - viewPodsAdded, - viewPodsDeleted, - viewIPLookupMiss, - viewPodTableSize, - viewNamespacesAdded, - viewNamespacesUpdated, - viewNamespacesDeleted, - viewNodesAdded, - viewNodesUpdated, - viewNodesDeleted, - ) -} - -var ( - mPodsUpdated = stats.Int64("otelsvc/k8s/pod_updated", "Number of pod update events received", "1") - mPodsAdded = stats.Int64("otelsvc/k8s/pod_added", "Number of pod add events received", "1") - mPodsDeleted = stats.Int64("otelsvc/k8s/pod_deleted", "Number of pod delete events received", "1") - mPodTableSize = stats.Int64("otelsvc/k8s/pod_table_size", "Size of table containing pod info", "1") - mIPLookupMiss = stats.Int64("otelsvc/k8s/ip_lookup_miss", "Number of times pod by IP lookup failed.", "1") - mNamespacesUpdated = stats.Int64("otelsvc/k8s/namespace_updated", "Number of namespace update events received", "1") - mNamespacesAdded = stats.Int64("otelsvc/k8s/namespace_added", "Number of namespace add events received", "1") - mNamespacesDeleted = stats.Int64("otelsvc/k8s/namespace_deleted", "Number of namespace delete events received", "1") - mNodesUpdated = stats.Int64("otelsvc/k8s/node_updated", "Number of node update events received", "1") - mNodesAdded = stats.Int64("otelsvc/k8s/node_added", "Number of node add events received", "1") - mNodesDeleted = stats.Int64("otelsvc/k8s/node_deleted", "Number of node delete events received", "1") - mReplicaSetsUpdated = stats.Int64("otelsvc/k8s/replicaset_updated", "Number of ReplicaSet update events received", "1") - mReplicaSetsAdded = stats.Int64("otelsvc/k8s/replicaset_added", "Number of ReplicaSet add events received", "1") - mReplicaSetsDeleted = stats.Int64("otelsvc/k8s/replicaset_deleted", "Number of ReplicaSet delete events received", "1") -) - -var viewPodsUpdated = &view.View{ - Name: mPodsUpdated.Name(), - Description: mPodsUpdated.Description(), - Measure: mPodsUpdated, - Aggregation: view.Sum(), -} - -var viewPodsAdded = &view.View{ - Name: mPodsAdded.Name(), - Description: mPodsAdded.Description(), - Measure: mPodsAdded, - Aggregation: view.Sum(), -} - -var viewPodsDeleted = &view.View{ - Name: mPodsDeleted.Name(), - Description: mPodsDeleted.Description(), - Measure: mPodsDeleted, - Aggregation: view.Sum(), -} - -var viewIPLookupMiss = &view.View{ - Name: mIPLookupMiss.Name(), - Description: mIPLookupMiss.Description(), - Measure: mIPLookupMiss, - Aggregation: view.Sum(), -} - -var viewPodTableSize = &view.View{ - Name: mPodTableSize.Name(), - Description: mPodTableSize.Description(), - Measure: mPodTableSize, - Aggregation: view.LastValue(), -} - -var viewNamespacesUpdated = &view.View{ - Name: mNamespacesUpdated.Name(), - Description: mNamespacesUpdated.Description(), - Measure: mNamespacesUpdated, - Aggregation: view.Sum(), -} - -var viewNamespacesAdded = &view.View{ - Name: mNamespacesAdded.Name(), - Description: mNamespacesAdded.Description(), - Measure: mNamespacesAdded, - Aggregation: view.Sum(), -} - -var viewNamespacesDeleted = &view.View{ - Name: mNamespacesDeleted.Name(), - Description: mNamespacesDeleted.Description(), - Measure: mNamespacesDeleted, - Aggregation: view.Sum(), -} - -var viewNodesUpdated = &view.View{ - Name: mNodesUpdated.Name(), - Description: mNodesUpdated.Description(), - Measure: mNodesUpdated, - Aggregation: view.Sum(), -} - -var viewNodesAdded = &view.View{ - Name: mNodesAdded.Name(), - Description: mNodesAdded.Description(), - Measure: mNodesAdded, - Aggregation: view.Sum(), -} - -var viewNodesDeleted = &view.View{ - Name: mNodesDeleted.Name(), - Description: mNodesDeleted.Description(), - Measure: mNodesDeleted, - Aggregation: view.Sum(), -} - -// RecordPodUpdated increments the metric that records pod update events received. -func RecordPodUpdated() { - stats.Record(context.Background(), mPodsUpdated.M(int64(1))) -} - -// RecordPodAdded increments the metric that records pod add events receiver. -func RecordPodAdded() { - stats.Record(context.Background(), mPodsAdded.M(int64(1))) -} - -// RecordPodDeleted increments the metric that records pod events deleted. -func RecordPodDeleted() { - stats.Record(context.Background(), mPodsDeleted.M(int64(1))) -} - -// RecordIPLookupMiss increments the metric that records Pod lookup by IP misses. -func RecordIPLookupMiss() { - stats.Record(context.Background(), mIPLookupMiss.M(int64(1))) -} - -// RecordPodTableSize store size of pod table field in WatchClient -func RecordPodTableSize(podTableSize int64) { - stats.Record(context.Background(), mPodTableSize.M(podTableSize)) -} - -// RecordNamespaceUpdated increments the metric that records namespace update events received. -func RecordNamespaceUpdated() { - stats.Record(context.Background(), mNamespacesUpdated.M(int64(1))) -} - -// RecordNamespaceAdded increments the metric that records namespace add events receiver. -func RecordNamespaceAdded() { - stats.Record(context.Background(), mNamespacesAdded.M(int64(1))) -} - -// RecordNamespaceDeleted increments the metric that records namespace events deleted. -func RecordNamespaceDeleted() { - stats.Record(context.Background(), mNamespacesDeleted.M(int64(1))) -} - -// RecordNodeUpdated increments the metric that records node update events received. -func RecordNodeUpdated() { - stats.Record(context.Background(), mNodesUpdated.M(int64(1))) -} - -// RecordNodeAdded increments the metric that records node add events receiver. -func RecordNodeAdded() { - stats.Record(context.Background(), mNodesAdded.M(int64(1))) -} - -// RecordNodeDeleted increments the metric that records node events deleted. -func RecordNodeDeleted() { - stats.Record(context.Background(), mNodesDeleted.M(int64(1))) -} - -// RecordReplicaSetUpdated increments the metric that records ReplicaSet update events received. -func RecordReplicaSetUpdated() { - stats.Record(context.Background(), mReplicaSetsUpdated.M(int64(1))) -} - -// RecordReplicaSetAdded increments the metric that records ReplicaSet add events receiver. -func RecordReplicaSetAdded() { - stats.Record(context.Background(), mReplicaSetsAdded.M(int64(1))) -} - -// RecordReplicaSetDeleted increments the metric that records ReplicaSet events deleted. -func RecordReplicaSetDeleted() { - stats.Record(context.Background(), mReplicaSetsDeleted.M(int64(1))) -} diff --git a/processor/k8sattributesprocessor/internal/observability/observability_test.go b/processor/k8sattributesprocessor/internal/observability/observability_test.go deleted file mode 100644 index 70567a7b9827..000000000000 --- a/processor/k8sattributesprocessor/internal/observability/observability_test.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package observability - -import ( - "context" - "sort" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "go.opencensus.io/metric/metricdata" - "go.opencensus.io/metric/metricexport" -) - -type exporter struct { - pipe chan *metricdata.Metric -} - -func newExporter() *exporter { - return &exporter{make(chan *metricdata.Metric)} -} - -func (e *exporter) ReturnAfter(after int) chan []*metricdata.Metric { - ch := make(chan []*metricdata.Metric) - go func() { - // Sometimes we can get only subset of all metrics, so lets make sure - // we look at unique records - receivedUnique := map[string]*metricdata.Metric{} - for m := range e.pipe { - receivedUnique[m.Descriptor.Name] = m - if len(receivedUnique) >= after { - break - } - } - - var received []*metricdata.Metric - for _, value := range receivedUnique { - received = append(received, value) - } - ch <- received - }() - return ch -} - -func (e *exporter) ExportMetrics(_ context.Context, data []*metricdata.Metric) error { - for _, m := range data { - e.pipe <- m - } - return nil -} - -// NOTE: -// This test can only be run with -count 1 because of static -// metricproducer.GlobalManager() used in metricexport.NewReader(). -func TestMetrics(t *testing.T) { - type testCase struct { - name string - recordFunc func() - } - tests := []testCase{ - { - "otelsvc/k8s/pod_added", - RecordPodAdded, - }, - { - "otelsvc/k8s/pod_deleted", - RecordPodDeleted, - }, - { - "otelsvc/k8s/pod_updated", - RecordPodUpdated, - }, - { - "otelsvc/k8s/ip_lookup_miss", - RecordIPLookupMiss, - }, - { - "otelsvc/k8s/namespace_added", - RecordNamespaceAdded, - }, - { - "otelsvc/k8s/namespace_updated", - RecordNamespaceUpdated, - }, - { - "otelsvc/k8s/namespace_deleted", - RecordNamespaceDeleted, - }, - { - "otelsvc/k8s/node_added", - RecordNodeAdded, - }, - { - "otelsvc/k8s/node_updated", - RecordNodeUpdated, - }, - { - "otelsvc/k8s/node_deleted", - RecordNodeDeleted, - }, - } - - var ( - fail = make(chan struct{}) - chData = make(chan []*metricdata.Metric) - ) - - go func() { - reader := metricexport.NewReader() - e := newExporter() - ch := e.ReturnAfter(len(tests)) - - // Add a manual retry mechanism in case there's a hiccup reading the - // metrics from producers in ReadAndExport(): we can wait for the metrics - // to come instead of failing because they didn't come right away. - for i := 0; i < 10; i++ { - go reader.ReadAndExport(e) - - select { - case <-time.After(500 * time.Millisecond): - - case data := <-ch: - chData <- data - return - } - } - - fail <- struct{}{} - }() - - for _, tt := range tests { - tt.recordFunc() - } - - var data []*metricdata.Metric - select { - case <-fail: - t.Fatalf("timedout waiting for metrics to arrive") - case data = <-chData: - } - - sort.Slice(tests, func(i, j int) bool { - return tests[i].name < tests[j].name - }) - - sort.Slice(data, func(i, j int) bool { - return data[i].Descriptor.Name < data[j].Descriptor.Name - }) - - assert.Len(t, data, len(tests)) - - for i, tt := range tests { - d := data[i] - assert.Equal(t, tt.name, d.Descriptor.Name) - assert.Len(t, d.TimeSeries, 1) - assert.Len(t, d.TimeSeries[0].Points, 1) - assert.Equal(t, int64(1), d.TimeSeries[0].Points[0].Value) - } -} diff --git a/processor/k8sattributesprocessor/metadata.yaml b/processor/k8sattributesprocessor/metadata.yaml index 50ee16e37f51..3b1e0330074c 100644 --- a/processor/k8sattributesprocessor/metadata.yaml +++ b/processor/k8sattributesprocessor/metadata.yaml @@ -107,3 +107,103 @@ tests: config: goleak: skip: true + +telemetry: + metrics: + otelsvc_k8s_pod_updated: + enabled: true + description: Number of pod update events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_pod_added: + enabled: true + description: Number of pod add events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_pod_deleted: + enabled: true + description: Number of pod delete events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_pod_table_size: + enabled: true + description: Size of table containing pod info + unit: "1" + gauge: + value_type: int + otelsvc_k8s_ip_lookup_miss: + enabled: true + description: Number of times pod by IP lookup failed. + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_namespace_updated: + enabled: true + description: Number of namespace update events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_namespace_added: + enabled: true + description: Number of namespace add events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_namespace_deleted: + enabled: true + description: Number of namespace delete events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_node_updated: + enabled: true + description: Number of node update events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_node_added: + enabled: true + description: Number of node add events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_node_deleted: + enabled: true + description: Number of node delete events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_replicaset_updated: + enabled: true + description: Number of ReplicaSet update events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_replicaset_added: + enabled: true + description: Number of ReplicaSet add events received + unit: "1" + sum: + value_type: int + monotonic: true + otelsvc_k8s_replicaset_deleted: + enabled: true + description: Number of ReplicaSet delete events received + unit: "1" + sum: + value_type: int + monotonic: true diff --git a/processor/k8sattributesprocessor/processor.go b/processor/k8sattributesprocessor/processor.go index b2c4e82490f0..b77b02b0407c 100644 --- a/processor/k8sattributesprocessor/processor.go +++ b/processor/k8sattributesprocessor/processor.go @@ -38,12 +38,12 @@ type kubernetesprocessor struct { podIgnore kube.Excludes } -func (kp *kubernetesprocessor) initKubeClient(logger *zap.Logger, kubeClient kube.ClientProvider) error { +func (kp *kubernetesprocessor) initKubeClient(set component.TelemetrySettings, kubeClient kube.ClientProvider) error { if kubeClient == nil { kubeClient = kube.New } if !kp.passthroughMode { - kc, err := kubeClient(logger, kp.apiConfig, kp.rules, kp.filters, kp.podAssociations, kp.podIgnore, nil, nil, nil, nil) + kc, err := kubeClient(set, kp.apiConfig, kp.rules, kp.filters, kp.podAssociations, kp.podIgnore, nil, nil, nil, nil) if err != nil { return err } @@ -64,7 +64,7 @@ func (kp *kubernetesprocessor) Start(_ context.Context, _ component.Host) error // This might have been set by an option already if kp.kc == nil { - err := kp.initKubeClient(kp.logger, kubeClientProvider) + err := kp.initKubeClient(kp.telemetrySettings, kubeClientProvider) if err != nil { kp.telemetrySettings.ReportStatus(component.NewFatalErrorEvent(err)) return nil diff --git a/processor/k8sattributesprocessor/processor_test.go b/processor/k8sattributesprocessor/processor_test.go index ba04b3a0f85e..5236d0a8b8d6 100644 --- a/processor/k8sattributesprocessor/processor_test.go +++ b/processor/k8sattributesprocessor/processor_test.go @@ -24,7 +24,6 @@ import ( "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" conventions "go.opentelemetry.io/collector/semconv/v1.8.0" - "go.uber.org/zap" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor/internal/kube" @@ -93,7 +92,7 @@ func newLogsProcessor(cfg component.Config, nextLogsConsumer consumer.Logs, errF // withKubeClientProvider sets the specific implementation for getting K8s Client instances func withKubeClientProvider(kcp kube.ClientProvider) option { return func(p *kubernetesprocessor) error { - return p.initKubeClient(p.logger, kcp) + return p.initKubeClient(p.telemetrySettings, kcp) } } @@ -224,7 +223,7 @@ func TestNewProcessor(t *testing.T) { } func TestProcessorBadClientProvider(t *testing.T) { - clientProvider := func(_ *zap.Logger, _ k8sconfig.APIConfig, _ kube.ExtractionRules, _ kube.Filters, _ []kube.Association, _ kube.Excludes, _ kube.APIClientsetProvider, _ kube.InformerProvider, _ kube.InformerProviderNamespace, _ kube.InformerProviderReplicaSet) (kube.Client, error) { + clientProvider := func(_ component.TelemetrySettings, _ k8sconfig.APIConfig, _ kube.ExtractionRules, _ kube.Filters, _ []kube.Association, _ kube.Excludes, _ kube.APIClientsetProvider, _ kube.InformerProvider, _ kube.InformerProviderNamespace, _ kube.InformerProviderReplicaSet) (kube.Client, error) { return nil, fmt.Errorf("bad client error") }