From 0628ad4b1eb69fce6ab9b75f27e967a41795b024 Mon Sep 17 00:00:00 2001 From: Mario Macias Date: Wed, 27 Nov 2024 15:54:23 +0100 Subject: [PATCH 1/8] Allow setting otel name/ns from annotations too --- pkg/beyla/config.go | 2 + pkg/beyla/config_test.go | 7 + pkg/components/beyla.go | 2 +- pkg/internal/discover/watcher_kube_test.go | 4 +- pkg/internal/kube/informer_provider.go | 2 +- pkg/internal/kube/store.go | 66 +++++-- pkg/internal/kube/store_test.go | 8 +- pkg/kubecache/informer/informer.pb.go | 176 ++++++++++-------- pkg/kubecache/meta/informers_init.go | 15 +- pkg/transform/k8s.go | 7 +- pkg/transform/k8s_test.go | 47 ++++- pkg/transform/name_resolver_test.go | 6 +- proto/informer.proto | 1 + .../manifests/06-beyla-external-informer.yml | 6 +- 14 files changed, 226 insertions(+), 123 deletions(-) diff --git a/pkg/beyla/config.go b/pkg/beyla/config.go index cb55fba08..e4d0088b8 100644 --- a/pkg/beyla/config.go +++ b/pkg/beyla/config.go @@ -19,6 +19,7 @@ import ( "github.com/grafana/beyla/pkg/internal/filter" "github.com/grafana/beyla/pkg/internal/imetrics" "github.com/grafana/beyla/pkg/internal/infraolly/process" + "github.com/grafana/beyla/pkg/internal/kube" "github.com/grafana/beyla/pkg/internal/traces" "github.com/grafana/beyla/pkg/kubeflags" "github.com/grafana/beyla/pkg/services" @@ -110,6 +111,7 @@ var DefaultConfig = Config{ Enable: kubeflags.EnabledDefault, InformersSyncTimeout: 30 * time.Second, InformersResyncPeriod: 30 * time.Minute, + MetadataSources: kube.DefaultMetadataSources, }, HostID: HostIDConfig{ FetchTimeout: 500 * time.Millisecond, diff --git a/pkg/beyla/config_test.go b/pkg/beyla/config_test.go index edf78d06a..51f98bca9 100644 --- a/pkg/beyla/config_test.go +++ b/pkg/beyla/config_test.go @@ -22,6 +22,7 @@ import ( "github.com/grafana/beyla/pkg/export/prom" "github.com/grafana/beyla/pkg/internal/imetrics" "github.com/grafana/beyla/pkg/internal/infraolly/process" + "github.com/grafana/beyla/pkg/internal/kube" "github.com/grafana/beyla/pkg/internal/netolly/transform/cidr" "github.com/grafana/beyla/pkg/internal/traces" "github.com/grafana/beyla/pkg/kubeflags" @@ -53,6 +54,8 @@ attributes: kubeconfig_path: /foo/bar enable: true informers_sync_timeout: 30s + meta_naming_sources: + service_name_labels: ["titi.com/lala"] instance_id: dns: true host_id: @@ -101,6 +104,9 @@ network: nc.AgentIP = "1.2.3.4" nc.CIDRs = cidr.Definitions{"10.244.0.0/16"} + metaSources := kube.DefaultMetadataSources + metaSources.ServiceNameLabels = []string{"titi.com/lala"} + assert.Equal(t, &Config{ Exec: cfg.Exec, Port: cfg.Port, @@ -176,6 +182,7 @@ network: Enable: kubeflags.EnabledTrue, InformersSyncTimeout: 30 * time.Second, InformersResyncPeriod: 30 * time.Minute, + MetadataSources: metaSources, }, HostID: HostIDConfig{ Override: "the-host-id", diff --git a/pkg/components/beyla.go b/pkg/components/beyla.go index 99f714137..526208a24 100644 --- a/pkg/components/beyla.go +++ b/pkg/components/beyla.go @@ -113,7 +113,7 @@ func buildCommonContextInfo( ResyncPeriod: config.Attributes.Kubernetes.InformersResyncPeriod, DisabledInformers: config.Attributes.Kubernetes.DisableInformers, MetaCacheAddr: config.Attributes.Kubernetes.MetaCacheAddress, - MetaSourceLabels: config.Attributes.Kubernetes.MetaSourceLabels, + MetaSourceLabels: config.Attributes.Kubernetes.MetadataSources, }), } switch { diff --git a/pkg/internal/discover/watcher_kube_test.go b/pkg/internal/discover/watcher_kube_test.go index 6c8d0c3df..2df9b3c4e 100644 --- a/pkg/internal/discover/watcher_kube_test.go +++ b/pkg/internal/discover/watcher_kube_test.go @@ -67,7 +67,7 @@ func TestWatcherKubeEnricher(t *testing.T) { // Setup a fake K8s API connected to the watcherKubeEnricher fInformer := &fakeInformer{} - store := kube.NewStore(fInformer, kube.MetaSourceLabels{}) + store := kube.NewStore(fInformer, kube.MetadataSources{}) wkeNodeFunc, err := WatcherKubeEnricherProvider(context.TODO(), &fakeMetadataProvider{store: store})() require.NoError(t, err) inputCh, outputCh := make(chan []Event[processAttrs], 10), make(chan []Event[processAttrs], 10) @@ -107,7 +107,7 @@ func TestWatcherKubeEnricherWithMatcher(t *testing.T) { processInfo = fakeProcessInfo // Setup a fake K8s API connected to the watcherKubeEnricher fInformer := &fakeInformer{} - store := kube.NewStore(fInformer, kube.MetaSourceLabels{}) + store := kube.NewStore(fInformer, kube.MetadataSources{}) wkeNodeFunc, err := WatcherKubeEnricherProvider(context.TODO(), &fakeMetadataProvider{store: store})() require.NoError(t, err) pipeConfig := beyla.Config{} diff --git a/pkg/internal/kube/informer_provider.go b/pkg/internal/kube/informer_provider.go index 1a6518bbb..bc9bfb432 100644 --- a/pkg/internal/kube/informer_provider.go +++ b/pkg/internal/kube/informer_provider.go @@ -34,7 +34,7 @@ type MetadataConfig struct { SyncTimeout time.Duration ResyncPeriod time.Duration MetaCacheAddr string - MetaSourceLabels MetaSourceLabels + MetaSourceLabels MetadataSources } type MetadataProvider struct { diff --git a/pkg/internal/kube/store.go b/pkg/internal/kube/store.go index 86238e6b8..211cb6034 100644 --- a/pkg/internal/kube/store.go +++ b/pkg/internal/kube/store.go @@ -36,10 +36,29 @@ func qName(om *informer.ObjectMeta) qualifiedName { return qualifiedName{name: om.Name, namespace: om.Namespace, kind: om.Kind} } -// MetaSourceLabels allow overriding some metadata from kubernetes labels -type MetaSourceLabels struct { - ServiceName string `yaml:"service_name" env:"BEYLA_KUBE_META_SOURCE_LABEL_SERVICE_NAME"` - ServiceNamespace string `yaml:"service_namespace" env:"BEYLA_KUBE_META_SOURCE_LABEL_SERVICE_NAMESPACE"` +// MetadataSources allow overriding some metadata from kubernetes labels and annotations +type MetadataSources struct { + ServiceNameAnnotations []string `yaml:"service_name_annotations" env:"BEYLA_KUBE_ANNOTATION_SERVICE_NAME" envSeparator:","` + ServiceNamespaceAnnotations []string `yaml:"service_namespace_annotations" env:"BEYLA_KUBE_ANNOTATION_SERVICE_NAMESPACE" envSeparator:","` + ServiceNameLabels []string `yaml:"service_name_labels" env:"BEYLA_KUBE_LABEL_SERVICE_NAME" envSeparator:","` + ServiceNamespaceLabels []string `yaml:"service_namespace_labels" env:"BEYLA_KUBE_LABEL_SERVICE_NAMESPACE" envSeparator:","` +} + +var DefaultMetadataSources = MetadataSources{ + ServiceNameAnnotations: []string{ + "resource.opentelemetry.io/service.name", + }, + ServiceNamespaceAnnotations: []string{ + "resource.opentelemetry.io/service.namespace", + }, + // default by empty. If the OTEL operator Instrumentation CRD sets useLabelsForResourceAttributes: true, + // the values below should be populated so: + // - `app.kubernetes.io/name` becomes `service.name` + // - `app.kubernetes.io/version` becomes `service.version` + // - `app.kubernetes.io/part-of` becomes `service.namespace` + // - `app.kubernetes.io/instance` becomes `service.instance.id` + ServiceNameLabels: nil, + ServiceNamespaceLabels: nil, } // Store aggregates Kubernetes information from multiple sources: @@ -79,10 +98,10 @@ type Store struct { // they receive is already present in the store meta.BaseNotifier - sourceLabels MetaSourceLabels + metadataSources MetadataSources } -func NewStore(kubeMetadata meta.Notifier, sourceLabels MetaSourceLabels) *Store { +func NewStore(kubeMetadata meta.Notifier, metadataSources MetadataSources) *Store { log := dblog() db := &Store{ log: log, @@ -96,7 +115,7 @@ func NewStore(kubeMetadata meta.Notifier, sourceLabels MetaSourceLabels) *Store otelServiceInfoByIP: map[string]OTelServiceNamePair{}, metadataNotifier: kubeMetadata, BaseNotifier: meta.NewBaseNotifier(log), - sourceLabels: sourceLabels, + metadataSources: metadataSources, } kubeMetadata.Subscribe(db) return db @@ -289,17 +308,36 @@ func (s *Store) serviceNameNamespaceForMetadata(om *informer.ObjectMeta) (string } else { name, namespace = s.serviceNameNamespaceForOwner(om) } - if s.sourceLabels.ServiceName != "" { - if on, ok := om.Labels[s.sourceLabels.ServiceName]; ok { - name = on + if nameFromMeta := s.valueFromMetadata(om, + s.metadataSources.ServiceNameAnnotations, + s.metadataSources.ServiceNameLabels, + ); nameFromMeta != "" { + name = nameFromMeta + } + if nsFromMeta := s.valueFromMetadata(om, + s.metadataSources.ServiceNamespaceAnnotations, + s.metadataSources.ServiceNamespaceLabels, + ); nsFromMeta != "" { + namespace = nsFromMeta + } + return name, namespace +} + +// function implemented to provide consistent service metadata naming across multiple +// OTEL implementations: OTEL operator, Loki and Beyla +// https://github.com/grafana/k8s-monitoring-helm/issues/942 +func (s *Store) valueFromMetadata(om *informer.ObjectMeta, annotationNames, labelNames []string) string { + for _, key := range annotationNames { + if val, ok := om.Annotations[key]; ok { + return val } } - if s.sourceLabels.ServiceNamespace != "" { - if ons, ok := om.Labels[s.sourceLabels.ServiceNamespace]; ok { - namespace = ons + for _, key := range labelNames { + if val, ok := om.Labels[key]; ok { + return val } } - return name, namespace + return "" } // ServiceNameNamespaceForIP returns the service name and namespace for a given IP address diff --git a/pkg/internal/kube/store_test.go b/pkg/internal/kube/store_test.go index 4f72b7de3..3cc3605da 100644 --- a/pkg/internal/kube/store_test.go +++ b/pkg/internal/kube/store_test.go @@ -90,7 +90,7 @@ func TestContainerInfo(t *testing.T) { fInformer := &fakeInformer{} - store := NewStore(fInformer, MetaSourceLabels{}) + store := NewStore(fInformer, MetadataSources{}) _ = store.On(&informer.Event{Type: informer.EventType_CREATED, Resource: &service}) _ = store.On(&informer.Event{Type: informer.EventType_CREATED, Resource: &podMetaA}) @@ -257,7 +257,7 @@ func TestMemoryCleanedUp(t *testing.T) { fInformer := &fakeInformer{} - store := NewStore(fInformer, MetaSourceLabels{}) + store := NewStore(fInformer, MetadataSources{}) _ = store.On(&informer.Event{Type: informer.EventType_CREATED, Resource: &service}) _ = store.On(&informer.Event{Type: informer.EventType_CREATED, Resource: &podMetaA}) @@ -281,7 +281,7 @@ func TestMemoryCleanedUp(t *testing.T) { // Fixes a memory leak in the store where the objectMetaByIP map was not cleaned up func TestMetaByIPEntryRemovedIfIPGroupChanges(t *testing.T) { // GIVEN a store with - store := NewStore(&fakeInformer{}, MetaSourceLabels{}) + store := NewStore(&fakeInformer{}, MetadataSources{}) // WHEN an object is created with several IPs _ = store.On(&informer.Event{ Type: informer.EventType_CREATED, @@ -326,7 +326,7 @@ func TestMetaByIPEntryRemovedIfIPGroupChanges(t *testing.T) { } func TestNoLeakOnUpdateOrDeletion(t *testing.T) { - store := NewStore(&fakeInformer{}, MetaSourceLabels{}) + store := NewStore(&fakeInformer{}, MetadataSources{}) topOwner := &informer.Owner{Name: "foo", Kind: "Deployment"} require.NoError(t, store.On(&informer.Event{ Type: informer.EventType_CREATED, diff --git a/pkg/kubecache/informer/informer.pb.go b/pkg/kubecache/informer/informer.pb.go index a3d4c6a1a..db79f0b1b 100644 --- a/pkg/kubecache/informer/informer.pb.go +++ b/pkg/kubecache/informer/informer.pb.go @@ -78,11 +78,12 @@ type ObjectMeta struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` - Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Ips []string `protobuf:"bytes,4,rep,name=ips,proto3" json:"ips,omitempty"` - Kind string `protobuf:"bytes,5,opt,name=kind,proto3" json:"kind,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Annotations map[string]string `protobuf:"bytes,8,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Ips []string `protobuf:"bytes,4,rep,name=ips,proto3" json:"ips,omitempty"` + Kind string `protobuf:"bytes,5,opt,name=kind,proto3" json:"kind,omitempty"` // If the Kube object is not a Pod, this field will be empty. Pod *PodInfo `protobuf:"bytes,6,opt,name=pod,proto3,oneof" json:"pod,omitempty"` } @@ -138,6 +139,13 @@ func (x *ObjectMeta) GetLabels() map[string]string { return nil } +func (x *ObjectMeta) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + func (x *ObjectMeta) GetIps() []string { if x != nil { return x.Ips @@ -457,70 +465,78 @@ var File_proto_informer_proto protoreflect.FileDescriptor var file_proto_informer_proto_rawDesc = []byte{ 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, - 0x22, 0x8b, 0x02, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, + 0x22, 0x94, 0x03, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x69, - 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x70, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, - 0x64, 0x12, 0x28, 0x0a, 0x03, 0x70, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, - 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x64, 0x49, 0x6e, 0x66, - 0x6f, 0x48, 0x00, 0x52, 0x03, 0x70, 0x6f, 0x64, 0x88, 0x01, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, - 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x64, 0x22, 0xd9, - 0x01, 0x0a, 0x07, 0x50, 0x6f, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, - 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x72, 0x12, - 0x17, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x70, 0x12, 0x37, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, - 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x73, 0x12, 0x27, 0x0a, 0x06, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x4f, 0x77, 0x6e, - 0x65, 0x72, 0x52, 0x06, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x9f, 0x01, 0x0a, 0x0d, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x32, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x03, 0x65, 0x6e, 0x76, 0x1a, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2f, 0x0a, 0x05, - 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x74, 0x0a, - 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x35, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x45, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x53, - 0x59, 0x4e, 0x43, 0x5f, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x03, 0x32, 0x50, - 0x0a, 0x12, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x12, 0x1a, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0f, 0x2e, - 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, - 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x47, 0x0a, 0x0b, 0x61, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x03, 0x69, 0x70, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x28, 0x0a, 0x03, 0x70, 0x6f, + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, + 0x65, 0x72, 0x2e, 0x50, 0x6f, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x03, 0x70, 0x6f, + 0x64, 0x88, 0x01, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, + 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, + 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x64, 0x22, 0xd9, 0x01, 0x0a, 0x07, 0x50, 0x6f, 0x64, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x73, 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, + 0x5f, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, + 0x70, 0x12, 0x37, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, + 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x27, 0x0a, 0x06, 0x6f, 0x77, + 0x6e, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x69, 0x6e, 0x66, + 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x52, 0x06, 0x6f, 0x77, 0x6e, + 0x65, 0x72, 0x73, 0x22, 0x9f, 0x01, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x03, 0x65, 0x6e, 0x76, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, + 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, + 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x1a, 0x36, 0x0a, + 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2f, 0x0a, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x74, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x27, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, + 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6e, 0x66, + 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x88, 0x01, 0x01, 0x42, + 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2a, 0x45, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, + 0x07, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x50, + 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x46, 0x49, 0x4e, + 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x03, 0x32, 0x50, 0x0a, 0x12, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a, + 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x1a, 0x2e, 0x69, 0x6e, 0x66, + 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0f, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, + 0x72, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x69, + 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -536,7 +552,7 @@ func file_proto_informer_proto_rawDescGZIP() []byte { } var file_proto_informer_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_informer_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_proto_informer_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_proto_informer_proto_goTypes = []any{ (EventType)(0), // 0: informer.EventType (*ObjectMeta)(nil), // 1: informer.ObjectMeta @@ -546,23 +562,25 @@ var file_proto_informer_proto_goTypes = []any{ (*Event)(nil), // 5: informer.Event (*SubscribeMessage)(nil), // 6: informer.SubscribeMessage nil, // 7: informer.ObjectMeta.LabelsEntry - nil, // 8: informer.ContainerInfo.EnvEntry + nil, // 8: informer.ObjectMeta.AnnotationsEntry + nil, // 9: informer.ContainerInfo.EnvEntry } var file_proto_informer_proto_depIdxs = []int32{ 7, // 0: informer.ObjectMeta.labels:type_name -> informer.ObjectMeta.LabelsEntry - 2, // 1: informer.ObjectMeta.pod:type_name -> informer.PodInfo - 3, // 2: informer.PodInfo.containers:type_name -> informer.ContainerInfo - 4, // 3: informer.PodInfo.owners:type_name -> informer.Owner - 8, // 4: informer.ContainerInfo.env:type_name -> informer.ContainerInfo.EnvEntry - 0, // 5: informer.Event.type:type_name -> informer.EventType - 1, // 6: informer.Event.resource:type_name -> informer.ObjectMeta - 6, // 7: informer.EventStreamService.Subscribe:input_type -> informer.SubscribeMessage - 5, // 8: informer.EventStreamService.Subscribe:output_type -> informer.Event - 8, // [8:9] is the sub-list for method output_type - 7, // [7:8] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 8, // 1: informer.ObjectMeta.annotations:type_name -> informer.ObjectMeta.AnnotationsEntry + 2, // 2: informer.ObjectMeta.pod:type_name -> informer.PodInfo + 3, // 3: informer.PodInfo.containers:type_name -> informer.ContainerInfo + 4, // 4: informer.PodInfo.owners:type_name -> informer.Owner + 9, // 5: informer.ContainerInfo.env:type_name -> informer.ContainerInfo.EnvEntry + 0, // 6: informer.Event.type:type_name -> informer.EventType + 1, // 7: informer.Event.resource:type_name -> informer.ObjectMeta + 6, // 8: informer.EventStreamService.Subscribe:input_type -> informer.SubscribeMessage + 5, // 9: informer.EventStreamService.Subscribe:output_type -> informer.Event + 9, // [9:10] is the sub-list for method output_type + 8, // [8:9] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_proto_informer_proto_init() } @@ -578,7 +596,7 @@ func file_proto_informer_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_informer_proto_rawDesc, NumEnums: 1, - NumMessages: 8, + NumMessages: 9, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/kubecache/meta/informers_init.go b/pkg/kubecache/meta/informers_init.go index 4b603cd06..8c0499302 100644 --- a/pkg/kubecache/meta/informers_init.go +++ b/pkg/kubecache/meta/informers_init.go @@ -255,7 +255,7 @@ func (inf *Informers) initPodInformer(ctx context.Context, informerFactory infor } for i := range pod.Status.EphemeralContainerStatuses { ecs := &pod.Status.EphemeralContainerStatuses[i] - envs := []v1.EnvVar{} + var envs []v1.EnvVar for i := range pod.Spec.EphemeralContainers { c := &pod.Spec.EphemeralContainers[i] if c.Name == ecs.Name { @@ -285,11 +285,12 @@ func (inf *Informers) initPodInformer(ctx context.Context, informerFactory infor return &indexableEntity{ ObjectMeta: minimalIndex(&pod.ObjectMeta), EncodedMeta: &informer.ObjectMeta{ - Name: pod.Name, - Namespace: pod.Namespace, - Labels: pod.Labels, - Ips: ips, - Kind: typePod, + Name: pod.Name, + Namespace: pod.Namespace, + Labels: pod.Labels, + Annotations: pod.Annotations, + Ips: ips, + Kind: typePod, Pod: &informer.PodInfo{ Uid: string(pod.UID), NodeName: pod.Spec.NodeName, @@ -335,7 +336,7 @@ func envToMap(kc kubernetes.Interface, objMeta metav1.ObjectMeta, containerEnv [ } func envsFromContainerSpec(containerName string, containers []v1.Container) []v1.EnvVar { - envs := []v1.EnvVar{} + var envs []v1.EnvVar for i := range containers { c := &containers[i] if c.Name == containerName { diff --git a/pkg/transform/k8s.go b/pkg/transform/k8s.go index fdd343aea..10e14573e 100644 --- a/pkg/transform/k8s.go +++ b/pkg/transform/k8s.go @@ -49,12 +49,9 @@ type KubernetesDecorator struct { // MetaCacheAddress is the host:port address of the beyla-k8s-cache service instance MetaCacheAddress string `yaml:"meta_cache_address" env:"BEYLA_KUBE_META_CACHE_ADDRESS"` - // MetaSourceLabels allows Beyla overriding the service name and namespace of an application from + // MetadataSources allows Beyla overriding the service name and namespace of an application from // the given labels. - // TODO Beyla 2.0. Consider defaulting to (and report as a breaking change): - // Name: "app.kubernetes.io/name", - // Namespace: "app.kubernetes.io/part-of", - MetaSourceLabels kube.MetaSourceLabels `yaml:"meta_source_labels"` + MetadataSources kube.MetadataSources `yaml:"meta_naming_sources"` } const ( diff --git a/pkg/transform/k8s_test.go b/pkg/transform/k8s_test.go index 7d05fdc0f..b99fcfc65 100644 --- a/pkg/transform/k8s_test.go +++ b/pkg/transform/k8s_test.go @@ -22,9 +22,11 @@ const timeout = 5 * time.Second func TestDecoration(t *testing.T) { inf := &fakeInformer{} - store := kube.NewStore(inf, kube.MetaSourceLabels{ - ServiceName: "app.kubernetes.io/name", - ServiceNamespace: "app.kubernetes.io/part-of", + store := kube.NewStore(inf, kube.MetadataSources{ + ServiceNameAnnotations: []string{"resource.opentelemetry.io/service.name"}, + ServiceNamespaceAnnotations: []string{"resource.opentelemetry.io/service.namespace"}, + ServiceNameLabels: []string{"app.kubernetes.io/name"}, + ServiceNamespaceLabels: []string{"app.kubernetes.io/part-of"}, }) // pre-populated kubernetes metadata database inf.Notify(&informer.Event{Type: informer.EventType_CREATED, Resource: &informer.ObjectMeta{ @@ -69,6 +71,23 @@ func TestDecoration(t *testing.T) { Containers: []*informer.ContainerInfo{{Name: "a-container", Id: "container-78"}}, }, }}) + inf.Notify(&informer.Event{Type: informer.EventType_CREATED, Resource: &informer.ObjectMeta{ + Name: "overridden-meta-annots", Namespace: "the-ns", Kind: "Pod", + Annotations: map[string]string{ + "resource.opentelemetry.io/service.name": "otel-override-name", + "resource.opentelemetry.io/service.namespace": "otel-override-ns", + }, + Labels: map[string]string{ + "app.kubernetes.io/name": "a-cool-name", + "app.kubernetes.io/part-of": "a-cool-namespace", + }, + Pod: &informer.PodInfo{ + NodeName: "the-node", + Uid: "uid-33", + StartTimeStr: "2020-01-02 12:56:56", + Containers: []*informer.ContainerInfo{{Name: "a-container", Id: "container-33"}}, + }, + }}) kube.InfoForPID = func(pid uint32) (container.Info, error) { return container.Info{ ContainerID: fmt.Sprintf("container-%d", pid), @@ -79,6 +98,7 @@ func TestDecoration(t *testing.T) { store.AddProcess(34) store.AddProcess(56) store.AddProcess(78) + store.AddProcess(33) dec := metadataDecorator{db: store, clusterName: "the-cluster"} inputCh, outputhCh := make(chan []request.Span, 10), make(chan []request.Span, 10) @@ -149,7 +169,7 @@ func TestDecoration(t *testing.T) { "k8s.cluster.name": "the-cluster", }, deco[0].Service.Metadata) }) - t.Run("user can override service name and annotations via labels", func(t *testing.T) { + t.Run("user can override service name and ns via labels", func(t *testing.T) { inputCh <- []request.Span{{ Pid: request.PidInfo{Namespace: 1078}, Service: autoNameSvc, }} @@ -168,6 +188,25 @@ func TestDecoration(t *testing.T) { "k8s.cluster.name": "the-cluster", }, deco[0].Service.Metadata) }) + t.Run("user can override service name and ns via annotations", func(t *testing.T) { + inputCh <- []request.Span{{ + Pid: request.PidInfo{Namespace: 1033}, Service: autoNameSvc, + }} + deco := testutil.ReadChannel(t, outputhCh, timeout) + require.Len(t, deco, 1) + assert.Equal(t, "otel-override-ns", deco[0].Service.UID.Namespace) + assert.Equal(t, "otel-override-name", deco[0].Service.UID.Name) + assert.EqualValues(t, "overridden-meta-annots:a-container", deco[0].Service.UID.Instance) + assert.Equal(t, map[attr.Name]string{ + "k8s.node.name": "the-node", + "k8s.namespace.name": "the-ns", + "k8s.pod.name": "overridden-meta-annots", + "k8s.container.name": "a-container", + "k8s.pod.uid": "uid-33", + "k8s.pod.start_time": "2020-01-02 12:56:56", + "k8s.cluster.name": "the-cluster", + }, deco[0].Service.Metadata) + }) t.Run("process without pod Info won't be decorated", func(t *testing.T) { svc := svc.Attrs{UID: svc.UID{Name: "exec"}} svc.SetAutoName() diff --git a/pkg/transform/name_resolver_test.go b/pkg/transform/name_resolver_test.go index 43b650844..37ae0ed4e 100644 --- a/pkg/transform/name_resolver_test.go +++ b/pkg/transform/name_resolver_test.go @@ -32,7 +32,7 @@ func TestSuffixPrefix(t *testing.T) { func TestResolvePodsFromK8s(t *testing.T) { inf := &fakeInformer{} - db := kube2.NewStore(inf, kube2.MetaSourceLabels{}) + db := kube2.NewStore(inf, kube2.MetadataSources{}) pod1 := &informer.ObjectMeta{Name: "pod1", Kind: "Pod", Ips: []string{"10.0.0.1", "10.1.0.1"}} pod2 := &informer.ObjectMeta{Name: "pod2", Namespace: "something", Kind: "Pod", Ips: []string{"10.0.0.2", "10.1.0.2"}} pod3 := &informer.ObjectMeta{Name: "pod3", Kind: "Pod", Ips: []string{"10.0.0.3", "10.1.0.3"}} @@ -104,7 +104,7 @@ func TestResolvePodsFromK8s(t *testing.T) { func TestResolveServiceFromK8s(t *testing.T) { inf := &fakeInformer{} - db := kube2.NewStore(inf, kube2.MetaSourceLabels{}) + db := kube2.NewStore(inf, kube2.MetadataSources{}) pod1 := &informer.ObjectMeta{Name: "pod1", Kind: "Service", Ips: []string{"10.0.0.1", "10.1.0.1"}} pod2 := &informer.ObjectMeta{Name: "pod2", Namespace: "something", Kind: "Service", Ips: []string{"10.0.0.2", "10.1.0.2"}} pod3 := &informer.ObjectMeta{Name: "pod3", Kind: "Service", Ips: []string{"10.0.0.3", "10.1.0.3"}} @@ -196,7 +196,7 @@ func TestCleanName(t *testing.T) { func TestResolveNodesFromK8s(t *testing.T) { inf := &fakeInformer{} - db := kube2.NewStore(inf, kube2.MetaSourceLabels{}) + db := kube2.NewStore(inf, kube2.MetadataSources{}) node1 := &informer.ObjectMeta{Name: "node1", Kind: "Node", Ips: []string{"10.0.0.1", "10.1.0.1"}} node2 := &informer.ObjectMeta{Name: "node2", Namespace: "something", Kind: "Node", Ips: []string{"10.0.0.2", "10.1.0.2"}} node3 := &informer.ObjectMeta{Name: "node3", Kind: "Node", Ips: []string{"10.0.0.3", "10.1.0.3"}} diff --git a/proto/informer.proto b/proto/informer.proto index 83071af38..d5018c0c3 100644 --- a/proto/informer.proto +++ b/proto/informer.proto @@ -16,6 +16,7 @@ message ObjectMeta { string name = 1; string namespace = 2; map labels = 3; + map annotations = 8; repeated string ips = 4; string kind = 5; diff --git a/test/integration/k8s/manifests/06-beyla-external-informer.yml b/test/integration/k8s/manifests/06-beyla-external-informer.yml index 438b32fc1..fe8f344ca 100644 --- a/test/integration/k8s/manifests/06-beyla-external-informer.yml +++ b/test/integration/k8s/manifests/06-beyla-external-informer.yml @@ -17,9 +17,9 @@ data: enable: true cluster_name: my-kube meta_cache_address: k8s-cache:50055 - meta_source_labels: - service_name: "app.kubernetes.io/name" - service_namespace: "app.kubernetes.io/part-of" + meta_naming_sources: + service_name_labels: [ "app.kubernetes.io/name" ] + service_namespace_labels: [ "app.kubernetes.io/part-of" ] select: "*": include: [ "*" ] From 0ad9414c59560308774b5f3f79bd1dba72872207 Mon Sep 17 00:00:00 2001 From: Mario Macias Date: Wed, 27 Nov 2024 16:01:50 +0100 Subject: [PATCH 2/8] rename env vars --- pkg/internal/kube/store.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/internal/kube/store.go b/pkg/internal/kube/store.go index 211cb6034..d43f6242f 100644 --- a/pkg/internal/kube/store.go +++ b/pkg/internal/kube/store.go @@ -38,10 +38,10 @@ func qName(om *informer.ObjectMeta) qualifiedName { // MetadataSources allow overriding some metadata from kubernetes labels and annotations type MetadataSources struct { - ServiceNameAnnotations []string `yaml:"service_name_annotations" env:"BEYLA_KUBE_ANNOTATION_SERVICE_NAME" envSeparator:","` - ServiceNamespaceAnnotations []string `yaml:"service_namespace_annotations" env:"BEYLA_KUBE_ANNOTATION_SERVICE_NAMESPACE" envSeparator:","` - ServiceNameLabels []string `yaml:"service_name_labels" env:"BEYLA_KUBE_LABEL_SERVICE_NAME" envSeparator:","` - ServiceNamespaceLabels []string `yaml:"service_namespace_labels" env:"BEYLA_KUBE_LABEL_SERVICE_NAMESPACE" envSeparator:","` + ServiceNameAnnotations []string `yaml:"service_name_annotations" env:"BEYLA_KUBE_ANNOTATIONS_SERVICE_NAME" envSeparator:","` + ServiceNamespaceAnnotations []string `yaml:"service_namespace_annotations" env:"BEYLA_KUBE_ANNOTATIONS_SERVICE_NAMESPACE" envSeparator:","` + ServiceNameLabels []string `yaml:"service_name_labels" env:"BEYLA_KUBE_LABELS_SERVICE_NAME" envSeparator:","` + ServiceNamespaceLabels []string `yaml:"service_namespace_labels" env:"BEYLA_KUBE_LABELS_SERVICE_NAMESPACE" envSeparator:","` } var DefaultMetadataSources = MetadataSources{ From 1e34053911b5c3ec955a760fbcc6beb9a34cc2a0 Mon Sep 17 00:00:00 2001 From: Mario Macias Date: Wed, 27 Nov 2024 16:31:44 +0100 Subject: [PATCH 3/8] Change instance id value --- pkg/transform/k8s.go | 4 +++- pkg/transform/k8s_test.go | 12 ++++++------ .../k8s/daemonset/k8s_daemonset_traces_test.go | 4 ++-- .../k8s_daemonset_multi_node_traces_test.go | 2 +- .../k8s_daemonset_multi_node_traces_test.go | 2 +- .../daemonset_python/k8s_daemonset_traces_test.go | 8 ++++---- .../informer_cache/k8s_informer_cache_main_test.go | 4 ++-- .../k8s/owners/k8s_daemonset_metadata_test.go | 4 ++-- .../k8s/owners/k8s_statefulset_metadata_test.go | 4 ++-- 9 files changed, 23 insertions(+), 21 deletions(-) diff --git a/pkg/transform/k8s.go b/pkg/transform/k8s.go index 10e14573e..df899a34a 100644 --- a/pkg/transform/k8s.go +++ b/pkg/transform/k8s.go @@ -132,7 +132,9 @@ func (md *metadataDecorator) appendMetadata(span *request.Span, meta *informer.O // if the application/process was discovered and reported information // before the kubernetes metadata was available // (related issue: https://github.com/grafana/beyla/issues/1124) - span.Service.UID.Instance = meta.Name + ":" + containerName + // Service Instance ID is set according to OTEL collector conventions: + // (related issue: https://github.com/grafana/k8s-monitoring-helm/issues/942) + span.Service.UID.Instance = meta.Namespace + "." + meta.Name + "." + containerName // if, in the future, other pipeline steps modify the service metadata, we should // replace the map literal by individual entry insertions diff --git a/pkg/transform/k8s_test.go b/pkg/transform/k8s_test.go index b99fcfc65..b0383a2b9 100644 --- a/pkg/transform/k8s_test.go +++ b/pkg/transform/k8s_test.go @@ -116,7 +116,7 @@ func TestDecoration(t *testing.T) { require.Len(t, deco, 1) assert.Equal(t, "the-ns", deco[0].Service.UID.Namespace) assert.Equal(t, "deployment-12", deco[0].Service.UID.Name) - assert.EqualValues(t, "pod-12:a-container", deco[0].Service.UID.Instance) + assert.EqualValues(t, "the-ns.pod-12.a-container", deco[0].Service.UID.Instance) assert.Equal(t, map[attr.Name]string{ "k8s.node.name": "the-node", "k8s.namespace.name": "the-ns", @@ -137,7 +137,7 @@ func TestDecoration(t *testing.T) { require.Len(t, deco, 1) assert.Equal(t, "the-ns", deco[0].Service.UID.Namespace) assert.Equal(t, "rs", deco[0].Service.UID.Name) - assert.EqualValues(t, "pod-34:a-container", deco[0].Service.UID.Instance) + assert.EqualValues(t, "the-ns.pod-34.a-container", deco[0].Service.UID.Instance) assert.Equal(t, map[attr.Name]string{ "k8s.node.name": "the-node", "k8s.namespace.name": "the-ns", @@ -158,7 +158,7 @@ func TestDecoration(t *testing.T) { require.Len(t, deco, 1) assert.Equal(t, "the-ns", deco[0].Service.UID.Namespace) assert.Equal(t, "the-pod", deco[0].Service.UID.Name) - assert.EqualValues(t, "the-pod:a-container", deco[0].Service.UID.Instance) + assert.EqualValues(t, "the-ns.the-pod.a-container", deco[0].Service.UID.Instance) assert.Equal(t, map[attr.Name]string{ "k8s.node.name": "the-node", "k8s.namespace.name": "the-ns", @@ -177,7 +177,7 @@ func TestDecoration(t *testing.T) { require.Len(t, deco, 1) assert.Equal(t, "a-cool-namespace", deco[0].Service.UID.Namespace) assert.Equal(t, "a-cool-name", deco[0].Service.UID.Name) - assert.EqualValues(t, "overridden-meta:a-container", deco[0].Service.UID.Instance) + assert.EqualValues(t, "the-ns.overridden-meta.a-container", deco[0].Service.UID.Instance) assert.Equal(t, map[attr.Name]string{ "k8s.node.name": "the-node", "k8s.namespace.name": "the-ns", @@ -196,7 +196,7 @@ func TestDecoration(t *testing.T) { require.Len(t, deco, 1) assert.Equal(t, "otel-override-ns", deco[0].Service.UID.Namespace) assert.Equal(t, "otel-override-name", deco[0].Service.UID.Name) - assert.EqualValues(t, "overridden-meta-annots:a-container", deco[0].Service.UID.Instance) + assert.EqualValues(t, "the-ns.overridden-meta-annots.a-container", deco[0].Service.UID.Instance) assert.Equal(t, map[attr.Name]string{ "k8s.node.name": "the-node", "k8s.namespace.name": "the-ns", @@ -227,7 +227,7 @@ func TestDecoration(t *testing.T) { require.Len(t, deco, 1) assert.Equal(t, "tralara", deco[0].Service.UID.Namespace) assert.Equal(t, "tralari", deco[0].Service.UID.Name) - assert.EqualValues(t, "pod-12:a-container", deco[0].Service.UID.Instance) + assert.EqualValues(t, "the-ns.pod-12.a-container", deco[0].Service.UID.Instance) assert.Equal(t, map[attr.Name]string{ "k8s.node.name": "the-node", "k8s.namespace.name": "the-ns", diff --git a/test/integration/k8s/daemonset/k8s_daemonset_traces_test.go b/test/integration/k8s/daemonset/k8s_daemonset_traces_test.go index e8216c2ca..c5d07fd60 100644 --- a/test/integration/k8s/daemonset/k8s_daemonset_traces_test.go +++ b/test/integration/k8s/daemonset/k8s_daemonset_traces_test.go @@ -57,7 +57,7 @@ func TestBasicTracing(t *testing.T) { for _, proc := range trace.Processes { sd := jaeger.DiffAsRegexp([]jaeger.Tag{ {Key: "service.namespace", Type: "string", Value: "^default$"}, - {Key: "service.instance.id", Type: "string", Value: "^otherinstance-.+:otherinstance"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.otherinstance-.+\\.otherinstance"}, }, proc.Tags) require.Empty(t, sd) } @@ -133,7 +133,7 @@ func TestBasicTracing(t *testing.T) { for _, proc := range trace.Processes { sd := jaeger.DiffAsRegexp([]jaeger.Tag{ {Key: "service.namespace", Type: "string", Value: "^default$"}, - {Key: "service.instance.id", Type: "string", Value: "^otherinstance-.+:otherinstance"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.otherinstance-.+\\.otherinstance"}, }, proc.Tags) require.Empty(t, sd) } diff --git a/test/integration/k8s/daemonset_multi_node/k8s_daemonset_multi_node_traces_test.go b/test/integration/k8s/daemonset_multi_node/k8s_daemonset_multi_node_traces_test.go index 45b6444a6..22734b4c2 100644 --- a/test/integration/k8s/daemonset_multi_node/k8s_daemonset_multi_node_traces_test.go +++ b/test/integration/k8s/daemonset_multi_node/k8s_daemonset_multi_node_traces_test.go @@ -64,7 +64,7 @@ func TestMultiNodeTracing(t *testing.T) { sd := jaeger.DiffAsRegexp([]jaeger.Tag{ {Key: "service.namespace", Type: "string", Value: "^integration-test$"}, {Key: "telemetry.sdk.language", Type: "string", Value: "^go$"}, - {Key: "service.instance.id", Type: "string", Value: "^testserver-.+:testserver$"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.testserver-.+\\.testserver$"}, }, trace.Processes[parent.ProcessID].Tags) require.Empty(t, sd, sd.String()) diff --git a/test/integration/k8s/daemonset_multi_node_l7/k8s_daemonset_multi_node_traces_test.go b/test/integration/k8s/daemonset_multi_node_l7/k8s_daemonset_multi_node_traces_test.go index f7fc0242a..8d92bac0f 100644 --- a/test/integration/k8s/daemonset_multi_node_l7/k8s_daemonset_multi_node_traces_test.go +++ b/test/integration/k8s/daemonset_multi_node_l7/k8s_daemonset_multi_node_traces_test.go @@ -64,7 +64,7 @@ func TestMultiNodeTracingL7(t *testing.T) { sd := jaeger.DiffAsRegexp([]jaeger.Tag{ {Key: "service.namespace", Type: "string", Value: "^integration-test$"}, {Key: "telemetry.sdk.language", Type: "string", Value: "^go$"}, - {Key: "service.instance.id", Type: "string", Value: "^testserver-.+:testserver"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.testserver-.+\\.testserver"}, }, trace.Processes[parent.ProcessID].Tags) require.Empty(t, sd, sd.String()) diff --git a/test/integration/k8s/daemonset_python/k8s_daemonset_traces_test.go b/test/integration/k8s/daemonset_python/k8s_daemonset_traces_test.go index 4243ed442..1c5fe2e02 100644 --- a/test/integration/k8s/daemonset_python/k8s_daemonset_traces_test.go +++ b/test/integration/k8s/daemonset_python/k8s_daemonset_traces_test.go @@ -54,7 +54,7 @@ func TestPythonBasicTracing(t *testing.T) { sd := jaeger.DiffAsRegexp([]jaeger.Tag{ {Key: "service.namespace", Type: "string", Value: "^integration-test$"}, {Key: "telemetry.sdk.language", Type: "string", Value: "^python$"}, - {Key: "service.instance.id", Type: "string", Value: "^pytestserver-.+:pytestserver$"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.pytestserver-.+\\.pytestserver$"}, }, trace.Processes[parent.ProcessID].Tags) require.Empty(t, sd, sd.String()) @@ -67,7 +67,7 @@ func TestPythonBasicTracing(t *testing.T) { {Key: "k8s.pod.start_time", Type: "string", Value: k8s.TimeRegex}, {Key: "k8s.namespace.name", Type: "string", Value: "^default$"}, {Key: "k8s.cluster.name", Type: "string", Value: "^beyla$"}, - {Key: "service.instance.id", Type: "string", Value: "^pytestserver-.+:pytestserver"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.pytestserver-.+\\.pytestserver"}, }, trace.Processes[parent.ProcessID].Tags) require.Empty(t, sd, sd.String()) @@ -112,7 +112,7 @@ func TestPythonBasicTracing(t *testing.T) { sd := jaeger.DiffAsRegexp([]jaeger.Tag{ {Key: "service.namespace", Type: "string", Value: "^integration-test$"}, {Key: "telemetry.sdk.language", Type: "string", Value: "^python$"}, - {Key: "service.instance.id", Type: "string", Value: "^pytestserver-.+:pytestserver$"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.pytestserver-.+\\.pytestserver$"}, }, trace.Processes[parent.ProcessID].Tags) require.Empty(t, sd, sd.String()) @@ -125,7 +125,7 @@ func TestPythonBasicTracing(t *testing.T) { {Key: "k8s.pod.start_time", Type: "string", Value: k8s.TimeRegex}, {Key: "k8s.namespace.name", Type: "string", Value: "^default$"}, {Key: "k8s.cluster.name", Type: "string", Value: "^beyla$"}, - {Key: "service.instance.id", Type: "string", Value: "^pytestserver-.+:pytestserver"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.pytestserver-.+\\.pytestserver"}, }, trace.Processes[parent.ProcessID].Tags) require.Empty(t, sd, sd.String()) diff --git a/test/integration/k8s/informer_cache/k8s_informer_cache_main_test.go b/test/integration/k8s/informer_cache/k8s_informer_cache_main_test.go index dace50eba..223709ebd 100644 --- a/test/integration/k8s/informer_cache/k8s_informer_cache_main_test.go +++ b/test/integration/k8s/informer_cache/k8s_informer_cache_main_test.go @@ -68,7 +68,7 @@ func TestInformersCache_MetricsDecoration_HTTP(t *testing.T) { "k8s_cluster_name": "my-kube", "service_name": "overridden-testserver-name", "service_namespace": "overridden-testserver-namespace", - "service_instance_id": "testserver-.+:testserver", + "service_instance_id": "default.testserver-.+\\.testserver", })) } @@ -76,7 +76,7 @@ func TestInformersCache_ProcessMetrics(t *testing.T) { cluster.TestEnv().Test(t, k8s.FeatureProcessMetricsDecoration( map[string]string{ "k8s_cluster_name": "my-kube", - "instance": "testserver-.+:testserver", + "instance": "default\\.testserver-.+\\.testserver", })) } diff --git a/test/integration/k8s/owners/k8s_daemonset_metadata_test.go b/test/integration/k8s/owners/k8s_daemonset_metadata_test.go index 2591cef78..9dffef8d1 100644 --- a/test/integration/k8s/owners/k8s_daemonset_metadata_test.go +++ b/test/integration/k8s/owners/k8s_daemonset_metadata_test.go @@ -51,7 +51,7 @@ func TestDaemonSetMetadata(t *testing.T) { for _, proc := range trace.Processes { sd := jaeger.DiffAsRegexp([]jaeger.Tag{ {Key: "service.namespace", Type: "string", Value: "^default$"}, - {Key: "service.instance.id", Type: "string", Value: "^dsservice-.+:dsservice"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.dsservice-.+\\.dsservice"}, }, proc.Tags) require.Empty(t, sd) } @@ -70,7 +70,7 @@ func TestDaemonSetMetadata(t *testing.T) { {Key: "k8s.namespace.name", Type: "string", Value: "^default$"}, {Key: "k8s.cluster.name", Type: "string", Value: "^beyla$"}, {Key: "service.namespace", Type: "string", Value: "^default$"}, - {Key: "service.instance.id", Type: "string", Value: "^dsservice-.+:dsservice"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.dsservice-.+\\.dsservice"}, }, trace.Processes[parent.ProcessID].Tags) require.Empty(t, sd) diff --git a/test/integration/k8s/owners/k8s_statefulset_metadata_test.go b/test/integration/k8s/owners/k8s_statefulset_metadata_test.go index 9521d4190..6d1342565 100644 --- a/test/integration/k8s/owners/k8s_statefulset_metadata_test.go +++ b/test/integration/k8s/owners/k8s_statefulset_metadata_test.go @@ -51,7 +51,7 @@ func TestStatefulSetMetadata(t *testing.T) { for _, proc := range trace.Processes { sd := jaeger.DiffAsRegexp([]jaeger.Tag{ {Key: "service.namespace", Type: "string", Value: "^default$"}, - {Key: "service.instance.id", Type: "string", Value: "^statefulservice-.+:statefulservice"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.statefulservice-.+\\.statefulservice"}, }, proc.Tags) require.Empty(t, sd) } @@ -70,7 +70,7 @@ func TestStatefulSetMetadata(t *testing.T) { {Key: "k8s.namespace.name", Type: "string", Value: "^default$"}, {Key: "k8s.cluster.name", Type: "string", Value: "^beyla$"}, {Key: "service.namespace", Type: "string", Value: "^default$"}, - {Key: "service.instance.id", Type: "string", Value: "^statefulservice-.+:statefulservice"}, + {Key: "service.instance.id", Type: "string", Value: "^default\\.statefulservice-.+\\.statefulservice"}, }, trace.Processes[parent.ProcessID].Tags) require.Empty(t, sd) From 72c6c6d53e1bb5c3f8619960a94cb974e330217e Mon Sep 17 00:00:00 2001 From: Mario Macias Date: Wed, 27 Nov 2024 16:44:03 +0100 Subject: [PATCH 4/8] rename metasourcelabels to metadatasources --- pkg/components/beyla.go | 2 +- pkg/internal/kube/informer_provider.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/components/beyla.go b/pkg/components/beyla.go index 526208a24..3eb7d11ae 100644 --- a/pkg/components/beyla.go +++ b/pkg/components/beyla.go @@ -113,7 +113,7 @@ func buildCommonContextInfo( ResyncPeriod: config.Attributes.Kubernetes.InformersResyncPeriod, DisabledInformers: config.Attributes.Kubernetes.DisableInformers, MetaCacheAddr: config.Attributes.Kubernetes.MetaCacheAddress, - MetaSourceLabels: config.Attributes.Kubernetes.MetadataSources, + MetadataSources: config.Attributes.Kubernetes.MetadataSources, }), } switch { diff --git a/pkg/internal/kube/informer_provider.go b/pkg/internal/kube/informer_provider.go index bc9bfb432..5e4d431bb 100644 --- a/pkg/internal/kube/informer_provider.go +++ b/pkg/internal/kube/informer_provider.go @@ -34,7 +34,7 @@ type MetadataConfig struct { SyncTimeout time.Duration ResyncPeriod time.Duration MetaCacheAddr string - MetaSourceLabels MetadataSources + MetadataSources MetadataSources } type MetadataProvider struct { @@ -104,7 +104,7 @@ func (mp *MetadataProvider) Get(ctx context.Context) (*Store, error) { return nil, err } - mp.metadata = NewStore(informer, mp.cfg.MetaSourceLabels) + mp.metadata = NewStore(informer, mp.cfg.MetadataSources) return mp.metadata, nil } From 152d49db75c9172ec42eb0db2b530558ac5bfca8 Mon Sep 17 00:00:00 2001 From: Mario Macias Date: Wed, 27 Nov 2024 16:46:07 +0100 Subject: [PATCH 5/8] fix misleading comment --- pkg/internal/kube/store.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/internal/kube/store.go b/pkg/internal/kube/store.go index d43f6242f..c5d32ac72 100644 --- a/pkg/internal/kube/store.go +++ b/pkg/internal/kube/store.go @@ -51,12 +51,10 @@ var DefaultMetadataSources = MetadataSources{ ServiceNamespaceAnnotations: []string{ "resource.opentelemetry.io/service.namespace", }, - // default by empty. If the OTEL operator Instrumentation CRD sets useLabelsForResourceAttributes: true, + // empty by default. If a user sets useLabelsForResourceAttributes: true it its OTEL operator, also // the values below should be populated so: // - `app.kubernetes.io/name` becomes `service.name` - // - `app.kubernetes.io/version` becomes `service.version` - // - `app.kubernetes.io/part-of` becomes `service.namespace` - // - `app.kubernetes.io/instance` becomes `service.instance.id` + // - `app.kubernetes.io/part-of` becomes `service.namespace` ServiceNameLabels: nil, ServiceNamespaceLabels: nil, } From 2d5be7aa8964ab135b8651234bc62bb7bf7dacfd Mon Sep 17 00:00:00 2001 From: Mario Macias Date: Wed, 27 Nov 2024 16:54:39 +0100 Subject: [PATCH 6/8] Modify integration test to test annotation forwarding from Beyla cache service --- test/integration/k8s/manifests/05-uninstrumented-service.yml | 4 +++- test/integration/k8s/manifests/06-beyla-external-informer.yml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/integration/k8s/manifests/05-uninstrumented-service.yml b/test/integration/k8s/manifests/05-uninstrumented-service.yml index 8c3d06cf4..3a6fea56e 100644 --- a/test/integration/k8s/manifests/05-uninstrumented-service.yml +++ b/test/integration/k8s/manifests/05-uninstrumented-service.yml @@ -31,9 +31,11 @@ apiVersion: apps/v1 kind: Deployment metadata: name: testserver + annotations: + my.custom/name: 'overridden-testserver-name' labels: app: testserver - app.kubernetes.io/name: 'overridden-testserver-name' + app.kubernetes.io/name: 'ignored-testserver-name' app.kubernetes.io/part-of: 'overridden-testserver-namespace' spec: replicas: 1 diff --git a/test/integration/k8s/manifests/06-beyla-external-informer.yml b/test/integration/k8s/manifests/06-beyla-external-informer.yml index fe8f344ca..197e878a0 100644 --- a/test/integration/k8s/manifests/06-beyla-external-informer.yml +++ b/test/integration/k8s/manifests/06-beyla-external-informer.yml @@ -18,6 +18,7 @@ data: cluster_name: my-kube meta_cache_address: k8s-cache:50055 meta_naming_sources: + service_name_annotations: [ "my.custom/name" ] service_name_labels: [ "app.kubernetes.io/name" ] service_namespace_labels: [ "app.kubernetes.io/part-of" ] select: From 4aa79293e9db74a599381415c7e60ce991962fdc Mon Sep 17 00:00:00 2001 From: Mario Macias Date: Thu, 28 Nov 2024 11:59:54 +0100 Subject: [PATCH 7/8] restructure meta source configuration --- pkg/beyla/config_test.go | 8 ++++++-- pkg/internal/kube/store.go | 35 ++++++++++++++++++++--------------- pkg/transform/k8s_test.go | 12 ++++++++---- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/pkg/beyla/config_test.go b/pkg/beyla/config_test.go index 51f98bca9..c12d260ca 100644 --- a/pkg/beyla/config_test.go +++ b/pkg/beyla/config_test.go @@ -55,7 +55,10 @@ attributes: enable: true informers_sync_timeout: 30s meta_naming_sources: - service_name_labels: ["titi.com/lala"] + annotations: + service_namespace: ["huha.com/yeah"] + labels: + service_name: ["titi.com/lala"] instance_id: dns: true host_id: @@ -105,7 +108,8 @@ network: nc.CIDRs = cidr.Definitions{"10.244.0.0/16"} metaSources := kube.DefaultMetadataSources - metaSources.ServiceNameLabels = []string{"titi.com/lala"} + metaSources.Annotations.ServiceNamespace = []string{"huha.com/yeah"} + metaSources.Labels.ServiceName = []string{"titi.com/lala"} assert.Equal(t, &Config{ Exec: cfg.Exec, diff --git a/pkg/internal/kube/store.go b/pkg/internal/kube/store.go index c5d32ac72..27deaaa04 100644 --- a/pkg/internal/kube/store.go +++ b/pkg/internal/kube/store.go @@ -38,25 +38,30 @@ func qName(om *informer.ObjectMeta) qualifiedName { // MetadataSources allow overriding some metadata from kubernetes labels and annotations type MetadataSources struct { - ServiceNameAnnotations []string `yaml:"service_name_annotations" env:"BEYLA_KUBE_ANNOTATIONS_SERVICE_NAME" envSeparator:","` - ServiceNamespaceAnnotations []string `yaml:"service_namespace_annotations" env:"BEYLA_KUBE_ANNOTATIONS_SERVICE_NAMESPACE" envSeparator:","` - ServiceNameLabels []string `yaml:"service_name_labels" env:"BEYLA_KUBE_LABELS_SERVICE_NAME" envSeparator:","` - ServiceNamespaceLabels []string `yaml:"service_namespace_labels" env:"BEYLA_KUBE_LABELS_SERVICE_NAMESPACE" envSeparator:","` + Annotations AnnotationSources `yaml:"annotations"` + Labels LabelSources `yaml:"labels"` +} + +type LabelSources struct { + ServiceName []string `yaml:"service_name" env:"BEYLA_KUBE_LABELS_SERVICE_NAME" envSeparator:","` + ServiceNamespace []string `yaml:"service_namespace" env:"BEYLA_KUBE_LABELS_SERVICE_NAMESPACE" envSeparator:","` +} + +type AnnotationSources struct { + ServiceName []string `yaml:"service_name" env:"BEYLA_KUBE_ANNOTATIONS_SERVICE_NAME" envSeparator:","` + ServiceNamespace []string `yaml:"service_namespace" env:"BEYLA_KUBE_ANNOTATIONS_SERVICE_NAMESPACE" envSeparator:","` } var DefaultMetadataSources = MetadataSources{ - ServiceNameAnnotations: []string{ - "resource.opentelemetry.io/service.name", - }, - ServiceNamespaceAnnotations: []string{ - "resource.opentelemetry.io/service.namespace", + Annotations: AnnotationSources{ + ServiceName: []string{"resource.opentelemetry.io/service.name"}, + ServiceNamespace: []string{"resource.opentelemetry.io/service.namespace"}, }, // empty by default. If a user sets useLabelsForResourceAttributes: true it its OTEL operator, also // the values below should be populated so: // - `app.kubernetes.io/name` becomes `service.name` // - `app.kubernetes.io/part-of` becomes `service.namespace` - ServiceNameLabels: nil, - ServiceNamespaceLabels: nil, + Labels: LabelSources{}, } // Store aggregates Kubernetes information from multiple sources: @@ -307,14 +312,14 @@ func (s *Store) serviceNameNamespaceForMetadata(om *informer.ObjectMeta) (string name, namespace = s.serviceNameNamespaceForOwner(om) } if nameFromMeta := s.valueFromMetadata(om, - s.metadataSources.ServiceNameAnnotations, - s.metadataSources.ServiceNameLabels, + s.metadataSources.Annotations.ServiceName, + s.metadataSources.Labels.ServiceName, ); nameFromMeta != "" { name = nameFromMeta } if nsFromMeta := s.valueFromMetadata(om, - s.metadataSources.ServiceNamespaceAnnotations, - s.metadataSources.ServiceNamespaceLabels, + s.metadataSources.Annotations.ServiceNamespace, + s.metadataSources.Labels.ServiceNamespace, ); nsFromMeta != "" { namespace = nsFromMeta } diff --git a/pkg/transform/k8s_test.go b/pkg/transform/k8s_test.go index b0383a2b9..d5f254216 100644 --- a/pkg/transform/k8s_test.go +++ b/pkg/transform/k8s_test.go @@ -23,10 +23,14 @@ const timeout = 5 * time.Second func TestDecoration(t *testing.T) { inf := &fakeInformer{} store := kube.NewStore(inf, kube.MetadataSources{ - ServiceNameAnnotations: []string{"resource.opentelemetry.io/service.name"}, - ServiceNamespaceAnnotations: []string{"resource.opentelemetry.io/service.namespace"}, - ServiceNameLabels: []string{"app.kubernetes.io/name"}, - ServiceNamespaceLabels: []string{"app.kubernetes.io/part-of"}, + Annotations: kube.AnnotationSources{ + ServiceName: []string{"resource.opentelemetry.io/service.name"}, + ServiceNamespace: []string{"resource.opentelemetry.io/service.namespace"}, + }, + Labels: kube.LabelSources{ + ServiceName: []string{"app.kubernetes.io/name"}, + ServiceNamespace: []string{"app.kubernetes.io/part-of"}, + }, }) // pre-populated kubernetes metadata database inf.Notify(&informer.Event{Type: informer.EventType_CREATED, Resource: &informer.ObjectMeta{ From a56bfcd59d877c78f565f82111aaf001e2bdad6f Mon Sep 17 00:00:00 2001 From: Mario Macias Date: Thu, 28 Nov 2024 12:55:34 +0100 Subject: [PATCH 8/8] give preference to OTEL_RESOURCE_ATTRIBUTES --- pkg/internal/kube/store.go | 46 +++++++---------- pkg/transform/k8s_test.go | 51 +++++++++++++++++-- .../05-uninstrumented-service-python.yml | 2 + .../manifests/06-beyla-external-informer.yml | 8 +-- 4 files changed, 72 insertions(+), 35 deletions(-) diff --git a/pkg/internal/kube/store.go b/pkg/internal/kube/store.go index 27deaaa04..28bfa7cbe 100644 --- a/pkg/internal/kube/store.go +++ b/pkg/internal/kube/store.go @@ -307,21 +307,9 @@ func (s *Store) serviceNameNamespaceForMetadata(om *informer.ObjectMeta) (string var name string var namespace string if owner := TopOwner(om.Pod); owner != nil { - name, namespace = s.serviceNameNamespaceForPod(om, owner) + name, namespace = s.serviceNameNamespaceOwnerID(om, owner.Name) } else { - name, namespace = s.serviceNameNamespaceForOwner(om) - } - if nameFromMeta := s.valueFromMetadata(om, - s.metadataSources.Annotations.ServiceName, - s.metadataSources.Labels.ServiceName, - ); nameFromMeta != "" { - name = nameFromMeta - } - if nsFromMeta := s.valueFromMetadata(om, - s.metadataSources.Annotations.ServiceNamespace, - s.metadataSources.Labels.ServiceNamespace, - ); nsFromMeta != "" { - namespace = nsFromMeta + name, namespace = s.serviceNameNamespaceOwnerID(om, om.Name) } return name, namespace } @@ -365,25 +353,29 @@ func (s *Store) ServiceNameNamespaceForIP(ip string) (string, string) { return name, namespace } -func (s *Store) serviceNameNamespaceForOwner(om *informer.ObjectMeta) (string, string) { - ownerKey := ownerID(om.Namespace, om.Name) - return s.serviceNameNamespaceOwnerID(ownerKey, om.Name, om.Namespace) -} - -func (s *Store) serviceNameNamespaceForPod(om *informer.ObjectMeta, owner *informer.Owner) (string, string) { - ownerKey := ownerID(om.Namespace, owner.Name) - return s.serviceNameNamespaceOwnerID(ownerKey, owner.Name, om.Namespace) -} - -func (s *Store) serviceNameNamespaceOwnerID(ownerKey, name, namespace string) (string, string) { - serviceName := name - serviceNamespace := namespace +func (s *Store) serviceNameNamespaceOwnerID(om *informer.ObjectMeta, ownerName string) (string, string) { + // ownerName can be the top Owner name, or om.Name in case it's a pod without owner + serviceName := ownerName + serviceNamespace := om.Namespace + ownerKey := ownerID(serviceNamespace, serviceName) + // OTEL_SERVICE_NAME and OTEL_SERVICE_NAMESPACE variables take precedence over user-configured annotations + // and labels if envName, ok := s.serviceNameFromEnv(ownerKey); ok { serviceName = envName + } else if nameFromMeta := s.valueFromMetadata(om, + s.metadataSources.Annotations.ServiceName, + s.metadataSources.Labels.ServiceName, + ); nameFromMeta != "" { + serviceName = nameFromMeta } if envName, ok := s.serviceNamespaceFromEnv(ownerKey); ok { serviceNamespace = envName + } else if nsFromMeta := s.valueFromMetadata(om, + s.metadataSources.Annotations.ServiceNamespace, + s.metadataSources.Labels.ServiceNamespace, + ); nsFromMeta != "" { + serviceNamespace = nsFromMeta } return serviceName, serviceNamespace diff --git a/pkg/transform/k8s_test.go b/pkg/transform/k8s_test.go index d5f254216..5230eb6d1 100644 --- a/pkg/transform/k8s_test.go +++ b/pkg/transform/k8s_test.go @@ -92,17 +92,39 @@ func TestDecoration(t *testing.T) { Containers: []*informer.ContainerInfo{{Name: "a-container", Id: "container-33"}}, }, }}) + inf.Notify(&informer.Event{Type: informer.EventType_CREATED, Resource: &informer.ObjectMeta{ + Name: "env-var-takes-precedence", Namespace: "the-ns", Kind: "Pod", + Annotations: map[string]string{ + "resource.opentelemetry.io/service.name": "otel-override-name", + "resource.opentelemetry.io/service.namespace": "otel-override-ns", + }, + Labels: map[string]string{ + "app.kubernetes.io/name": "a-cool-name", + "app.kubernetes.io/part-of": "a-cool-namespace", + }, + Pod: &informer.PodInfo{ + NodeName: "the-node", + Uid: "uid-66", + StartTimeStr: "2020-01-02 12:56:56", + Containers: []*informer.ContainerInfo{{ + Name: "a-container", Id: "container-66", + Env: map[string]string{ + "OTEL_RESOURCE_ATTRIBUTES": "service.name=env-svc-name,service.namespace=env-svc-ns", + }, + }}, + }, + }}) + // we need to add PID metadata for all the pod/containers above + // by convention, the mocked pid namespace will be PID+1000 kube.InfoForPID = func(pid uint32) (container.Info, error) { return container.Info{ ContainerID: fmt.Sprintf("container-%d", pid), PIDNamespace: 1000 + pid, }, nil } - store.AddProcess(12) - store.AddProcess(34) - store.AddProcess(56) - store.AddProcess(78) - store.AddProcess(33) + for _, pid := range []uint32{12, 34, 56, 78, 33, 66} { + store.AddProcess(pid) + } dec := metadataDecorator{db: store, clusterName: "the-cluster"} inputCh, outputhCh := make(chan []request.Span, 10), make(chan []request.Span, 10) @@ -211,6 +233,25 @@ func TestDecoration(t *testing.T) { "k8s.cluster.name": "the-cluster", }, deco[0].Service.Metadata) }) + t.Run("user can override service name and ns via env vars, taking precedence over any other criteria", func(t *testing.T) { + inputCh <- []request.Span{{ + Pid: request.PidInfo{Namespace: 1066}, Service: autoNameSvc, + }} + deco := testutil.ReadChannel(t, outputhCh, timeout) + require.Len(t, deco, 1) + assert.Equal(t, "env-svc-ns", deco[0].Service.UID.Namespace) + assert.Equal(t, "env-svc-name", deco[0].Service.UID.Name) + assert.EqualValues(t, "the-ns.env-var-takes-precedence.a-container", deco[0].Service.UID.Instance) + assert.Equal(t, map[attr.Name]string{ + "k8s.node.name": "the-node", + "k8s.namespace.name": "the-ns", + "k8s.pod.name": "env-var-takes-precedence", + "k8s.container.name": "a-container", + "k8s.pod.uid": "uid-66", + "k8s.pod.start_time": "2020-01-02 12:56:56", + "k8s.cluster.name": "the-cluster", + }, deco[0].Service.Metadata) + }) t.Run("process without pod Info won't be decorated", func(t *testing.T) { svc := svc.Attrs{UID: svc.UID{Name: "exec"}} svc.SetAutoName() diff --git a/test/integration/k8s/manifests/05-uninstrumented-service-python.yml b/test/integration/k8s/manifests/05-uninstrumented-service-python.yml index 3ea743827..196a7a1c6 100644 --- a/test/integration/k8s/manifests/05-uninstrumented-service-python.yml +++ b/test/integration/k8s/manifests/05-uninstrumented-service-python.yml @@ -16,6 +16,8 @@ metadata: name: pytestserver labels: app: pytestserver + annotations: + resource.opentelemetry.io/service.name: 'this-will-be-ignored-due-to-otel-attrs-env' spec: replicas: 1 selector: diff --git a/test/integration/k8s/manifests/06-beyla-external-informer.yml b/test/integration/k8s/manifests/06-beyla-external-informer.yml index 197e878a0..99c8485f8 100644 --- a/test/integration/k8s/manifests/06-beyla-external-informer.yml +++ b/test/integration/k8s/manifests/06-beyla-external-informer.yml @@ -18,9 +18,11 @@ data: cluster_name: my-kube meta_cache_address: k8s-cache:50055 meta_naming_sources: - service_name_annotations: [ "my.custom/name" ] - service_name_labels: [ "app.kubernetes.io/name" ] - service_namespace_labels: [ "app.kubernetes.io/part-of" ] + annotations: + service_name: [ "my.custom/name" ] + labels: + service_name: [ "app.kubernetes.io/name" ] + service_namespace: [ "app.kubernetes.io/part-of" ] select: "*": include: [ "*" ]