Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[receiver/awscontainerinsightreceiver] Add option for adding container name as a metric label #21411

Closed
wants to merge 7 commits into from
Prev Previous commit
[receiver/awscontainerinsightreceiver] Add option for adding containe…
…r name as a metric label
  • Loading branch information
sky333999 committed May 2, 2023
commit c13108cef1703cc2bd6623805bc9c00a4f9850a3
7 changes: 6 additions & 1 deletion receiver/awscontainerinsightreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ receivers:
container_orchestrator: eks
add_service_as_attribute: true
prefer_full_pod_name: false
add_full_pod_name_metric_label: false
add_full_pod_name_metric_label: false
add_container_name_metric_label: false
```
There is no need to provide any parameters since they are all optional.

Expand All @@ -55,6 +56,10 @@ The "PodName" attribute is set based on the name of the relevant controllers lik

The "FullPodName" attribute is the pod name including suffix. If false FullPodName label is not added. The default value is false

**add_container_name_metric_label (optional)**

The "ContainerName" attribute is the name of the container. If false ContainerName label is not added. The default value is false

**cluster_name (optional)**

"ClusterName" can be used to explicitly provide the cluster's name for EKS/ECS NOT on EC2 since it's not possible to auto-detect it using EC2 tags.
Expand Down
5 changes: 5 additions & 0 deletions receiver/awscontainerinsightreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ type Config struct {
// The default value is false
AddFullPodNameMetricLabel bool `mapstructure:"add_full_pod_name_metric_label"`

// The "ContainerName" attribute is the name of the container
// If false ContainerName label is not added
// The default value is false
AddContainerNameMetricLabel bool `mapstructure:"add_container_name_metric_label"`

// ClusterName can be used to explicitly provide the Cluster's Name for scenarios where it's not
// possible to auto-detect it using EC2 tags.
ClusterName string `mapstructure:"cluster_name"`
Expand Down
18 changes: 11 additions & 7 deletions receiver/awscontainerinsightreceiver/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const (
// Don't tag pod full name by default
defaultAddFullPodNameMetricLabel = false

// Don't tag container name by default
defaultAddContainerNameMetricLabel = false

// Rely on EC2 tags to auto-detect cluster name by default
defaultClusterName = ""

Expand All @@ -64,13 +67,14 @@ func NewFactory() receiver.Factory {
// createDefaultConfig returns a default config for the receiver.
func createDefaultConfig() component.Config {
return &Config{
CollectionInterval: defaultCollectionInterval,
ContainerOrchestrator: defaultContainerOrchestrator,
TagService: defaultTagService,
PrefFullPodName: defaultPrefFullPodName,
AddFullPodNameMetricLabel: defaultAddFullPodNameMetricLabel,
ClusterName: defaultClusterName,
LeaderLockName: defaultLeaderLockName,
CollectionInterval: defaultCollectionInterval,
ContainerOrchestrator: defaultContainerOrchestrator,
TagService: defaultTagService,
PrefFullPodName: defaultPrefFullPodName,
AddFullPodNameMetricLabel: defaultAddFullPodNameMetricLabel,
AddContainerNameMetricLabel: defaultAddContainerNameMetricLabel,
ClusterName: defaultClusterName,
LeaderLockName: defaultLeaderLockName,
}
}

Expand Down
10 changes: 6 additions & 4 deletions receiver/awscontainerinsightreceiver/internal/stores/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,19 @@ type K8sDecorator struct {
// It would be easier to keep the ctx here than passing it as a parameter for Decorate(...) function.
// The K8sStore (e.g. podstore) does network request in Decorate function, thus needs to take a context
// object for canceling the request
ctx context.Context
ctx context.Context
addContainerNameMetricLabel bool
}

func NewK8sDecorator(ctx context.Context, tagService bool, prefFullPodName bool, addFullPodNameMetricLabel bool, logger *zap.Logger) (*K8sDecorator, error) {
func NewK8sDecorator(ctx context.Context, tagService bool, prefFullPodName bool, addFullPodNameMetricLabel bool, addContainerNameMetricLabel bool, logger *zap.Logger) (*K8sDecorator, error) {
hostIP := os.Getenv("HOST_IP")
if hostIP == "" {
return nil, errors.New("environment variable HOST_IP is not set in k8s deployment config")
}

k := &K8sDecorator{
ctx: ctx,
ctx: ctx,
addContainerNameMetricLabel: addContainerNameMetricLabel,
}

podstore, err := NewPodStore(hostIP, prefFullPodName, addFullPodNameMetricLabel, logger)
Expand Down Expand Up @@ -104,7 +106,7 @@ func (k *K8sDecorator) Decorate(metric *extractors.CAdvisorMetric) *extractors.C
}
}

AddKubernetesInfo(metric, kubernetesBlob)
AddKubernetesInfo(metric, kubernetesBlob, k.addContainerNameMetricLabel)
TagMetricSource(metric)
return metric
}
12 changes: 8 additions & 4 deletions receiver/awscontainerinsightreceiver/internal/stores/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,16 @@ func TagMetricSource(metric CIMetric) {
}
}

func AddKubernetesInfo(metric CIMetric, kubernetesBlob map[string]interface{}) {
needMoveToKubernetes := map[string]string{ci.ContainerNamekey: "container_name", ci.K8sPodNameKey: "pod_name",
ci.PodIDKey: "pod_id"}

func AddKubernetesInfo(metric CIMetric, kubernetesBlob map[string]interface{}, retainContainerNameTag bool) {
needMoveToKubernetes := map[string]string{ci.K8sPodNameKey: "pod_name", ci.PodIDKey: "pod_id"}
needCopyToKubernetes := map[string]string{ci.K8sNamespace: "namespace_name", ci.TypeService: "service_name", ci.NodeNameKey: "host"}

if retainContainerNameTag {
needCopyToKubernetes[ci.ContainerNamekey] = "container_name"
} else {
needMoveToKubernetes[ci.ContainerNamekey] = "container_name"
}

for k, v := range needMoveToKubernetes {
if attVal := metric.GetTag(k); attVal != "" {
kubernetesBlob[v] = attVal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestUtils_addKubernetesInfo(t *testing.T) {
}

kubernetesBlob := map[string]interface{}{}
AddKubernetesInfo(metric, kubernetesBlob)
AddKubernetesInfo(metric, kubernetesBlob, false)
assert.Equal(t, "", metric.GetTag(ci.ContainerNamekey))
assert.Equal(t, "", metric.GetTag(ci.K8sPodNameKey))
assert.Equal(t, "", metric.GetTag(ci.PodIDKey))
Expand All @@ -98,6 +98,36 @@ func TestUtils_addKubernetesInfo(t *testing.T) {
assert.Equal(t, expectedKubeBlob, kubernetesBlob)
}

func TestUtils_addKubernetesInfoRetainContainerNameTag(t *testing.T) {
fields := map[string]interface{}{ci.MetricName(ci.TypePod, ci.CPUTotal): float64(1)}
tags := map[string]string{
ci.ContainerNamekey: "testContainer",
ci.K8sPodNameKey: "testPod",
ci.PodIDKey: "123",
ci.K8sNamespace: "testNamespace",
ci.TypeService: "testService",
ci.NodeNameKey: "testNode",
ci.Timestamp: strconv.FormatInt(time.Now().UnixNano(), 10),
}

metric := &mockCIMetric{
tags: tags,
fields: fields,
}

kubernetesBlob := map[string]interface{}{}
AddKubernetesInfo(metric, kubernetesBlob, true)
assert.Equal(t, "testContainer", metric.GetTag(ci.ContainerNamekey))
assert.Equal(t, "", metric.GetTag(ci.K8sPodNameKey))
assert.Equal(t, "", metric.GetTag(ci.PodIDKey))
assert.Equal(t, "testNamespace", metric.GetTag(ci.K8sNamespace))
assert.Equal(t, "testService", metric.GetTag(ci.TypeService))
assert.Equal(t, "testNode", metric.GetTag(ci.NodeNameKey))

expectedKubeBlob := map[string]interface{}{"container_name": "testContainer", "host": "testNode", "namespace_name": "testNamespace", "pod_id": "123", "pod_name": "testPod", "service_name": "testService"}
assert.Equal(t, expectedKubeBlob, kubernetesBlob)
}

func TestUtils_TagMetricSource(t *testing.T) {
types := []string{
"",
Expand Down
2 changes: 1 addition & 1 deletion receiver/awscontainerinsightreceiver/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (acir *awsContainerInsightReceiver) Start(ctx context.Context, host compone
}

if acir.config.ContainerOrchestrator == ci.EKS {
k8sDecorator, err := stores.NewK8sDecorator(ctx, acir.config.TagService, acir.config.PrefFullPodName, acir.config.AddFullPodNameMetricLabel, acir.settings.Logger)
k8sDecorator, err := stores.NewK8sDecorator(ctx, acir.config.TagService, acir.config.PrefFullPodName, acir.config.AddFullPodNameMetricLabel, acir.config.AddContainerNameMetricLabel, acir.settings.Logger)
if err != nil {
return err
}
Expand Down