From b8dfc398bb81f9f277ef1dbe99a4fbdf27c2ec9d Mon Sep 17 00:00:00 2001 From: Jeffrey Chien Date: Tue, 27 Aug 2024 20:15:48 -0400 Subject: [PATCH 1/5] Support JMX annotations. --- .../collector/adapters/config_from.go | 4 ++ internal/manifests/collector/ports.go | 12 +++-- internal/manifests/collector/ports_test.go | 15 ++++++ .../manifests/collector/testdata/jmx.json | 8 +++ pkg/instrumentation/defaultinstrumentation.go | 54 +++++++++++++------ .../defaultinstrumentation_test.go | 4 +- pkg/instrumentation/jmx/jmx.go | 24 +++++++++ pkg/instrumentation/podmutator.go | 29 ++++++++-- pkg/instrumentation/podmutator_test.go | 54 ++++++++++++++++++- 9 files changed, 179 insertions(+), 25 deletions(-) create mode 100644 internal/manifests/collector/testdata/jmx.json create mode 100644 pkg/instrumentation/jmx/jmx.go diff --git a/internal/manifests/collector/adapters/config_from.go b/internal/manifests/collector/adapters/config_from.go index cfb6d766d..e81b69cc1 100644 --- a/internal/manifests/collector/adapters/config_from.go +++ b/internal/manifests/collector/adapters/config_from.go @@ -58,6 +58,7 @@ type Traces struct { type MetricsCollected struct { StatsD *statsD `json:"statsd,omitempty"` CollectD *collectD `json:"collectd,omitempty"` + JMX *jmx `json:"jmx,omitempty"` } type LogMetricsCollected struct { @@ -86,6 +87,9 @@ type AppSignals struct { type emf struct { } + +type jmx struct{} + type kubernetes struct { EnhancedContainerInsights bool `json:"enhanced_container_insights,omitempty"` AcceleratedComputeMetrics bool `json:"accelerated_compute_metrics,omitempty"` diff --git a/internal/manifests/collector/ports.go b/internal/manifests/collector/ports.go index 55fed0c2c..0f6a2178a 100644 --- a/internal/manifests/collector/ports.go +++ b/internal/manifests/collector/ports.go @@ -27,9 +27,9 @@ const ( XrayTraces = "aws-traces" OtlpGrpc = "otlp-grpc" OtlpHttp = "otlp-http" - AppSignalsGrpc = "appsig-grpc" - AppSignalsHttp = "appsig-http" - AppSignalsProxy = "appsig-xray" + AppSignalsGrpc = "appsignals-grpc" + AppSignalsHttp = "appsignals-http" + AppSignalsProxy = "appsignals-xray" AppSignalsGrpcSA = ":4315" AppSignalsHttpSA = ":4316" AppSignalsProxySA = ":2000" @@ -37,12 +37,14 @@ const ( EMFTcp = "emf-tcp" EMFUdp = "emf-udp" CWA = "cwa-" + JmxHttp = "jmx-http" ) var receiverDefaultPortsMap = map[string]int32{ StatsD: 8125, CollectD: 25826, XrayTraces: 2000, + JmxHttp: 4314, OtlpGrpc: 4317, OtlpHttp: 4318, EMF: 25888, @@ -83,6 +85,7 @@ func getContainerPorts(logger logr.Logger, cfg string, specPorts []corev1.Servic if err != nil { logger.Error(err, "error parsing cw agent config") } else { + logger.Info("%v", config) servicePorts = getServicePortsFromCWAgentConfig(logger, config) } @@ -143,6 +146,9 @@ func getMetricsReceiversServicePorts(logger logr.Logger, config *adapters.CwaCon if config.Metrics.MetricsCollected.CollectD != nil { getReceiverServicePort(logger, config.Metrics.MetricsCollected.CollectD.ServiceAddress, CollectD, corev1.ProtocolUDP, servicePortsMap) } + if config.Metrics.MetricsCollected.JMX != nil { + getReceiverServicePort(logger, "", JmxHttp, corev1.ProtocolTCP, servicePortsMap) + } } func getReceiverServicePort(logger logr.Logger, serviceAddress string, receiverName string, protocol corev1.Protocol, servicePortsMap map[int32][]corev1.ServicePort) { diff --git a/internal/manifests/collector/ports_test.go b/internal/manifests/collector/ports_test.go index bade37cb7..630ad9bb1 100644 --- a/internal/manifests/collector/ports_test.go +++ b/internal/manifests/collector/ports_test.go @@ -204,6 +204,21 @@ func TestInvalidConfigGetContainerPorts(t *testing.T) { } +func TestJMXGetContainerPorts(t *testing.T) { + cfg := getJSONStringFromFile("testdata/jmx.json") + containerPorts := getContainerPorts(logger, cfg, []corev1.ServicePort{}) + assert.Equal(t, 4, len(containerPorts)) + assert.Equal(t, int32(4315), containerPorts[AppSignalsGrpc].ContainerPort) + assert.Equal(t, AppSignalsGrpc, containerPorts[AppSignalsGrpc].Name) + assert.Equal(t, int32(4316), containerPorts[AppSignalsHttp].ContainerPort) + assert.Equal(t, AppSignalsHttp, containerPorts[AppSignalsHttp].Name) + assert.Equal(t, int32(2000), containerPorts[AppSignalsProxy].ContainerPort) + assert.Equal(t, AppSignalsProxy, containerPorts[AppSignalsProxy].Name) + assert.Equal(t, int32(4314), containerPorts[JmxHttp].ContainerPort) + assert.Equal(t, JmxHttp, containerPorts[JmxHttp].Name) + assert.Equal(t, corev1.ProtocolTCP, containerPorts[JmxHttp].Protocol) +} + func getJSONStringFromFile(path string) string { buf, err := os.ReadFile(path) if err != nil { diff --git a/internal/manifests/collector/testdata/jmx.json b/internal/manifests/collector/testdata/jmx.json new file mode 100644 index 000000000..70756dc00 --- /dev/null +++ b/internal/manifests/collector/testdata/jmx.json @@ -0,0 +1,8 @@ +{ + "metrics": { + "metrics_collected": { + "jmx": { + } + } + } +} \ No newline at end of file diff --git a/pkg/instrumentation/defaultinstrumentation.go b/pkg/instrumentation/defaultinstrumentation.go index a16857280..c3f3fc256 100644 --- a/pkg/instrumentation/defaultinstrumentation.go +++ b/pkg/instrumentation/defaultinstrumentation.go @@ -8,13 +8,13 @@ import ( "fmt" "os" - "k8s.io/apimachinery/pkg/api/resource" - corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/aws/amazon-cloudwatch-agent-operator/apis/v1alpha1" "github.com/aws/amazon-cloudwatch-agent-operator/internal/manifests/collector/adapters" + "github.com/aws/amazon-cloudwatch-agent-operator/pkg/instrumentation/jmx" ) const ( @@ -50,7 +50,7 @@ func getInstrumentationConfigForResource(langStr string, resourceStr string) cor return instrumentationConfigForResource } -func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, isWindowsPod bool) (*v1alpha1.Instrumentation, error) { +func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs map[Type]map[string]string, isWindowsPod bool) (*v1alpha1.Instrumentation, error) { javaInstrumentationImage, ok := os.LookupEnv("AUTO_INSTRUMENTATION_JAVA") if !ok { return nil, errors.New("unable to determine java instrumentation image") @@ -103,18 +103,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, isWindowsPod boo }, Java: v1alpha1.Java{ Image: javaInstrumentationImage, - Env: []corev1.EnvVar{ - {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe - {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, - {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", http, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, - {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, - {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, //TODO: remove in favor of new name once safe - {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, - }, + Env: getJavaEnvs(cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeJava]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(java, limit), Requests: getInstrumentationConfigForResource(java, request), @@ -182,3 +171,38 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, isWindowsPod boo }, }, nil } + +func getJavaEnvs(cloudwatchAgentServiceEndpoint, exporterPrefix string, additionalEnvs map[string]string) []corev1.EnvVar { + envs := []corev1.EnvVar{ + {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe + {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, + {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", http, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, //TODO: remove in favor of new name once safe + {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + } + var jmxEnvs []corev1.EnvVar + if targetSystems, ok := additionalEnvs[jmx.EnvTargetSystem]; ok { + jmxEnvs = []corev1.EnvVar{ + {Name: "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", Value: fmt.Sprintf("%s://%s:4314/v1/metrics", http, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_INSTRUMENTATION_RUNTIME_TELEMETRY_ENABLED", Value: "false"}, + {Name: "OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED", Value: "false"}, + {Name: "OTEL_JMX_ENABLED", Value: "true"}, + {Name: "OTEL_JMX_TARGET_SYSTEM", Value: targetSystems}, + {Name: "OTEL_EXPERIMENTAL_METRICS_VIEW_CONFIG", Value: "classpath:/jmx/view.yaml"}, + } + } + if len(jmxEnvs) == 0 { + envs = append( + envs, + corev1.EnvVar{Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + corev1.EnvVar{Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + ) + } else { + envs = append(envs, corev1.EnvVar{Name: "OTEL_LOGS_EXPORTER", Value: "none"}) + envs = append(envs, jmxEnvs...) + } + return envs +} diff --git a/pkg/instrumentation/defaultinstrumentation_test.go b/pkg/instrumentation/defaultinstrumentation_test.go index bb1d920ff..a73efe56c 100644 --- a/pkg/instrumentation/defaultinstrumentation_test.go +++ b/pkg/instrumentation/defaultinstrumentation_test.go @@ -327,7 +327,7 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := getDefaultInstrumentation(tt.args.agentConfig, false) + got, err := getDefaultInstrumentation(tt.args.agentConfig, nil, false) if (err != nil) != tt.wantErr { t.Errorf("getDefaultInstrumentation() error = %v, wantErr %v", err, tt.wantErr) return @@ -650,7 +650,7 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := getDefaultInstrumentation(tt.args.agentConfig, true) + got, err := getDefaultInstrumentation(tt.args.agentConfig, nil, true) if (err != nil) != tt.wantErr { t.Errorf("getDefaultInstrumentation() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/instrumentation/jmx/jmx.go b/pkg/instrumentation/jmx/jmx.go new file mode 100644 index 000000000..eb4b2a46a --- /dev/null +++ b/pkg/instrumentation/jmx/jmx.go @@ -0,0 +1,24 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package jmx + +const ( + annotationPrefix = "cloudwatch.aws.amazon.com/inject-jmx-" +) + +const ( + EnvTargetSystem = "OTEL_JMX_TARGET_SYSTEM" + + TargetJVM = "jvm" + TargetTomcat = "tomcat" + TargetKafka = "kafka" + TargetKafkaConsumer = "kafka-consumer" + TargetKafkaProducer = "kafka-producer" +) + +var SupportedTargets = []string{TargetJVM, TargetTomcat, TargetKafka, TargetKafkaConsumer, TargetKafkaProducer} + +func AnnotationKey(target string) string { + return annotationPrefix + target +} diff --git a/pkg/instrumentation/podmutator.go b/pkg/instrumentation/podmutator.go index 2e893a2f2..ba67a55c1 100644 --- a/pkg/instrumentation/podmutator.go +++ b/pkg/instrumentation/podmutator.go @@ -19,6 +19,7 @@ import ( "github.com/aws/amazon-cloudwatch-agent-operator/internal/manifests/collector/adapters" "github.com/aws/amazon-cloudwatch-agent-operator/internal/webhook/podmutation" "github.com/aws/amazon-cloudwatch-agent-operator/pkg/featuregate" + "github.com/aws/amazon-cloudwatch-agent-operator/pkg/instrumentation/jmx" ) const ( @@ -368,8 +369,19 @@ func (pm *instPodMutator) getInstrumentationInstance(ctx context.Context, ns cor return nil, nil } + var additionalEnvs map[Type]map[string]string + if instAnnotation == annotationInjectJava { + additionalEnvs = map[Type]map[string]string{} + targetSystems := getJmxTargetSystems(ns, pod) + if len(targetSystems) != 0 { + additionalEnvs[TypeJava] = map[string]string{ + jmx.EnvTargetSystem: strings.Join(targetSystems, ","), + } + } + } + if strings.EqualFold(instValue, "true") { - return pm.selectInstrumentationInstanceFromNamespace(ctx, ns, isWindowsPod(pod)) + return pm.selectInstrumentationInstanceFromNamespace(ctx, ns, additionalEnvs, isWindowsPod(pod)) } var instNamespacedName types.NamespacedName @@ -388,7 +400,7 @@ func (pm *instPodMutator) getInstrumentationInstance(ctx context.Context, ns cor return otelInst, nil } -func (pm *instPodMutator) selectInstrumentationInstanceFromNamespace(ctx context.Context, ns corev1.Namespace, isWindowsPod bool) (*v1alpha1.Instrumentation, error) { +func (pm *instPodMutator) selectInstrumentationInstanceFromNamespace(ctx context.Context, ns corev1.Namespace, additionalEnvs map[Type]map[string]string, isWindowsPod bool) (*v1alpha1.Instrumentation, error) { var otelInsts v1alpha1.InstrumentationList if err := pm.Client.List(ctx, &otelInsts, client.InNamespace(ns.Name)); err != nil { return nil, err @@ -403,7 +415,7 @@ func (pm *instPodMutator) selectInstrumentationInstanceFromNamespace(ctx context pm.Logger.Error(err, "unable to retrieve cloudwatch agent config for instrumentation") } - return getDefaultInstrumentation(config, isWindowsPod) + return getDefaultInstrumentation(config, additionalEnvs, isWindowsPod) case s > 1: return nil, errMultipleInstancesPossible default: @@ -425,3 +437,14 @@ func GetAmazonCloudWatchAgentResource(ctx context.Context, c client.Client, name func isWindowsPod(pod corev1.Pod) bool { return pod.Spec.NodeSelector["kubernetes.io/os"] == "windows" } + +func getJmxTargetSystems(ns corev1.Namespace, pod corev1.Pod) []string { + var targetSystems []string + for _, target := range jmx.SupportedTargets { + value := annotationValue(ns.ObjectMeta, pod.ObjectMeta, jmx.AnnotationKey(target)) + if strings.EqualFold(value, "true") { + targetSystems = append(targetSystems, target) + } + } + return targetSystems +} diff --git a/pkg/instrumentation/podmutator_test.go b/pkg/instrumentation/podmutator_test.go index cbf66bc2f..a08e17d3d 100644 --- a/pkg/instrumentation/podmutator_test.go +++ b/pkg/instrumentation/podmutator_test.go @@ -9,6 +9,8 @@ import ( "os" "testing" + "github.com/aws/amazon-cloudwatch-agent-operator/pkg/instrumentation/jmx" + "github.com/go-logr/logr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -31,7 +33,7 @@ const ( ) func TestGetInstrumentationInstanceFromNameSpaceDefault(t *testing.T) { - defaultInst, _ := getDefaultInstrumentation(&adapters.CwaConfig{}, false) + defaultInst, _ := getDefaultInstrumentation(&adapters.CwaConfig{}, nil, false) namespace := corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "default-namespace", @@ -45,12 +47,60 @@ func TestGetInstrumentationInstanceFromNameSpaceDefault(t *testing.T) { Client: fake.NewClientBuilder().Build(), Logger: logr.Logger{}, } - instrumentation, err := podMutator.selectInstrumentationInstanceFromNamespace(context.Background(), namespace, false) + instrumentation, err := podMutator.selectInstrumentationInstanceFromNamespace(context.Background(), namespace, nil, false) assert.Nil(t, err) assert.Equal(t, defaultInst, instrumentation) } +func TestGetInstrumentationInstanceJMX(t *testing.T) { + if err := v1alpha1.AddToScheme(testScheme); err != nil { + fmt.Printf("failed to register scheme: %v", err) + os.Exit(1) + } + mutator := instPodMutator{ + Client: fake.NewClientBuilder().Build(), + Logger: logr.Discard(), + } + + tests := []struct { + name string + pod corev1.Pod + ns corev1.Namespace + wantLen int + wantEnv []corev1.EnvVar + }{ + { + name: "enable jvm/tomcat", + pod: corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + annotationInjectJava: "true", + jmx.AnnotationKey(jmx.TargetJVM): "true", + jmx.AnnotationKey(jmx.TargetTomcat): "true", + }, + }, + }, + ns: corev1.Namespace{}, + wantLen: 15, + wantEnv: []corev1.EnvVar{ + {Name: "OTEL_JMX_ENABLED", Value: "true"}, + {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm,tomcat"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + inst, err := mutator.getInstrumentationInstance(context.Background(), tt.ns, tt.pod, annotationInjectJava) + assert.NoError(t, err) + assert.Len(t, inst.Spec.Java.Env, tt.wantLen) + for _, env := range tt.wantEnv { + assert.Containsf(t, inst.Spec.Java.Env, env, "java env does not contain %s:%s", env.Name, env.Value) + } + }) + } +} + func TestMutatePod(t *testing.T) { mutator := NewMutator(logr.Discard(), k8sClient, record.NewFakeRecorder(100)) require.NotNil(t, mutator) From c8e6e2f11058a06618e2395507f5b5e737aca657 Mon Sep 17 00:00:00 2001 From: Mitali Salvi Date: Thu, 3 Oct 2024 11:15:05 -0400 Subject: [PATCH 2/5] Supporting JMX annotations --- internal/manifests/collector/ports.go | 7 +- internal/manifests/collector/ports_test.go | 10 +- .../jmxAgentConfig.json} | 0 pkg/instrumentation/defaultinstrumentation.go | 153 ++++++---- .../defaultinstrumentation_test.go | 287 +++++++++++++++++- pkg/instrumentation/podmutator_test.go | 9 +- 6 files changed, 375 insertions(+), 91 deletions(-) rename internal/manifests/collector/{testdata/jmx.json => test-resources/jmxAgentConfig.json} (100%) diff --git a/internal/manifests/collector/ports.go b/internal/manifests/collector/ports.go index 0f6a2178a..291b4bb4d 100644 --- a/internal/manifests/collector/ports.go +++ b/internal/manifests/collector/ports.go @@ -27,9 +27,9 @@ const ( XrayTraces = "aws-traces" OtlpGrpc = "otlp-grpc" OtlpHttp = "otlp-http" - AppSignalsGrpc = "appsignals-grpc" - AppSignalsHttp = "appsignals-http" - AppSignalsProxy = "appsignals-xray" + AppSignalsGrpc = "appsig-grpc" + AppSignalsHttp = "appsig-http" + AppSignalsProxy = "appsig-xray" AppSignalsGrpcSA = ":4315" AppSignalsHttpSA = ":4316" AppSignalsProxySA = ":2000" @@ -85,7 +85,6 @@ func getContainerPorts(logger logr.Logger, cfg string, specPorts []corev1.Servic if err != nil { logger.Error(err, "error parsing cw agent config") } else { - logger.Info("%v", config) servicePorts = getServicePortsFromCWAgentConfig(logger, config) } diff --git a/internal/manifests/collector/ports_test.go b/internal/manifests/collector/ports_test.go index 630ad9bb1..b797e911c 100644 --- a/internal/manifests/collector/ports_test.go +++ b/internal/manifests/collector/ports_test.go @@ -205,15 +205,9 @@ func TestInvalidConfigGetContainerPorts(t *testing.T) { } func TestJMXGetContainerPorts(t *testing.T) { - cfg := getJSONStringFromFile("testdata/jmx.json") + cfg := getJSONStringFromFile("./test-resources/jmxAgentConfig.json") containerPorts := getContainerPorts(logger, cfg, []corev1.ServicePort{}) - assert.Equal(t, 4, len(containerPorts)) - assert.Equal(t, int32(4315), containerPorts[AppSignalsGrpc].ContainerPort) - assert.Equal(t, AppSignalsGrpc, containerPorts[AppSignalsGrpc].Name) - assert.Equal(t, int32(4316), containerPorts[AppSignalsHttp].ContainerPort) - assert.Equal(t, AppSignalsHttp, containerPorts[AppSignalsHttp].Name) - assert.Equal(t, int32(2000), containerPorts[AppSignalsProxy].ContainerPort) - assert.Equal(t, AppSignalsProxy, containerPorts[AppSignalsProxy].Name) + assert.Equal(t, 1, len(containerPorts)) assert.Equal(t, int32(4314), containerPorts[JmxHttp].ContainerPort) assert.Equal(t, JmxHttp, containerPorts[JmxHttp].Name) assert.Equal(t, corev1.ProtocolTCP, containerPorts[JmxHttp].Protocol) diff --git a/internal/manifests/collector/testdata/jmx.json b/internal/manifests/collector/test-resources/jmxAgentConfig.json similarity index 100% rename from internal/manifests/collector/testdata/jmx.json rename to internal/manifests/collector/test-resources/jmxAgentConfig.json diff --git a/pkg/instrumentation/defaultinstrumentation.go b/pkg/instrumentation/defaultinstrumentation.go index c3f3fc256..252087468 100644 --- a/pkg/instrumentation/defaultinstrumentation.go +++ b/pkg/instrumentation/defaultinstrumentation.go @@ -77,9 +77,8 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m // set protocol by checking cloudwatch agent config for tls setting exporterPrefix := http - if agentConfig != nil { - appSignalsConfig := agentConfig.GetApplicationSignalsConfig() - if appSignalsConfig != nil && appSignalsConfig.TLS != nil { + if isApplicationSignalsEnabled(agentConfig) { + if agentConfig.GetApplicationSignalsConfig().TLS != nil { exporterPrefix = https } } @@ -103,7 +102,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, Java: v1alpha1.Java{ Image: javaInstrumentationImage, - Env: getJavaEnvs(cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeJava]), + Env: getJavaEnvs(isApplicationSignalsEnabled(agentConfig), cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeJava]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(java, limit), Requests: getInstrumentationConfigForResource(java, request), @@ -111,20 +110,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, Python: v1alpha1.Python{ Image: pythonInstrumentationImage, - Env: []corev1.EnvVar{ - {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe - {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, - {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", http, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, - {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, - {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, //TODO: remove in favor of new name once safe - {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - {Name: "OTEL_PYTHON_DISTRO", Value: "aws_distro"}, - {Name: "OTEL_PYTHON_CONFIGURATOR", Value: "aws_configurator"}, - {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, - }, + Env: getPythonEnvs(isApplicationSignalsEnabled(agentConfig), cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypePython]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(python, limit), Requests: getInstrumentationConfigForResource(python, request), @@ -132,20 +118,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, DotNet: v1alpha1.DotNet{ Image: dotNetInstrumentationImage, - Env: []corev1.EnvVar{ - {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, - {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", http, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, - {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, - {Name: "OTEL_EXPORTER_OTLP_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - {Name: "OTEL_DOTNET_DISTRO", Value: "aws_distro"}, - {Name: "OTEL_DOTNET_CONFIGURATOR", Value: "aws_configurator"}, - {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, - {Name: "OTEL_DOTNET_AUTO_PLUGINS", Value: "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation"}, - }, + Env: getDotNetEnvs(isApplicationSignalsEnabled(agentConfig), cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeDotNet]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(dotNet, limit), Requests: getInstrumentationConfigForResource(dotNet, request), @@ -153,16 +126,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, NodeJS: v1alpha1.NodeJS{ Image: nodeJSInstrumentationImage, - Env: []corev1.EnvVar{ - {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, - {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, - {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, - {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, - }, + Env: getNodeJSEnvs(isApplicationSignalsEnabled(agentConfig), cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeDotNet]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(nodeJS, limit), Requests: getInstrumentationConfigForResource(nodeJS, request), @@ -172,37 +136,102 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, nil } -func getJavaEnvs(cloudwatchAgentServiceEndpoint, exporterPrefix string, additionalEnvs map[string]string) []corev1.EnvVar { +func getJavaEnvs(isAppSignalsEnabled bool, cloudwatchAgentServiceEndpoint, exporterPrefix string, additionalEnvs map[string]string) []corev1.EnvVar { envs := []corev1.EnvVar{ - {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe - {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, - {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", http, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, - {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, //TODO: remove in favor of new name once safe - {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + } + + if isAppSignalsEnabled { + appSignalsEnvs := []corev1.EnvVar{ + {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe + {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, + {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", http, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, + {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, //TODO: remove in favor of new name once safe + {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + } + envs = append(envs, appSignalsEnvs...) } + var jmxEnvs []corev1.EnvVar if targetSystems, ok := additionalEnvs[jmx.EnvTargetSystem]; ok { jmxEnvs = []corev1.EnvVar{ - {Name: "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", Value: fmt.Sprintf("%s://%s:4314/v1/metrics", http, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_INSTRUMENTATION_RUNTIME_TELEMETRY_ENABLED", Value: "false"}, - {Name: "OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED", Value: "false"}, + {Name: "OTEL_JMX_EXPORTER_METRICS_ENDPOINT", Value: fmt.Sprintf("%s://%s:4314/v1/metrics", http, cloudwatchAgentServiceEndpoint)}, {Name: "OTEL_JMX_ENABLED", Value: "true"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: targetSystems}, - {Name: "OTEL_EXPERIMENTAL_METRICS_VIEW_CONFIG", Value: "classpath:/jmx/view.yaml"}, } } - if len(jmxEnvs) == 0 { - envs = append( - envs, - corev1.EnvVar{Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - corev1.EnvVar{Name: "OTEL_LOGS_EXPORTER", Value: "none"}, - ) - } else { - envs = append(envs, corev1.EnvVar{Name: "OTEL_LOGS_EXPORTER", Value: "none"}) + if len(jmxEnvs) != 0 { envs = append(envs, jmxEnvs...) } return envs } + +func getPythonEnvs(isAppSignalsEnabled bool, cloudwatchAgentServiceEndpoint, exporterPrefix string, additionalEnvs map[string]string) []corev1.EnvVar { + var envs []corev1.EnvVar + if isAppSignalsEnabled { + envs = []corev1.EnvVar{ + {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe + {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, + {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", http, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, //TODO: remove in favor of new name once safe + {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_PYTHON_DISTRO", Value: "aws_distro"}, + {Name: "OTEL_PYTHON_CONFIGURATOR", Value: "aws_configurator"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + } + } + return envs +} + +func getDotNetEnvs(isAppSignalsEnabled bool, cloudwatchAgentServiceEndpoint, exporterPrefix string, additionalEnvs map[string]string) []corev1.EnvVar { + var envs []corev1.EnvVar + if isAppSignalsEnabled { + envs = []corev1.EnvVar{ + {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, + {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", http, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_EXPORTER_OTLP_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_DOTNET_DISTRO", Value: "aws_distro"}, + {Name: "OTEL_DOTNET_CONFIGURATOR", Value: "aws_configurator"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + {Name: "OTEL_DOTNET_AUTO_PLUGINS", Value: "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation"}, + } + } + return envs +} + +func getNodeJSEnvs(isAppSignalsEnabled bool, cloudwatchAgentServiceEndpoint, exporterPrefix string, additionalEnvs map[string]string) []corev1.EnvVar { + var envs []corev1.EnvVar + if isAppSignalsEnabled { + envs = []corev1.EnvVar{ + {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, + {Name: "OTEL_TRACES_SAMPLER_ARG", Value: fmt.Sprintf("endpoint=%s://%s:2000", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/traces", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + } + } + return envs +} + +func isApplicationSignalsEnabled(agentConfig *adapters.CwaConfig) bool { + if agentConfig != nil { + return agentConfig.GetApplicationSignalsConfig() != nil + } + return false +} diff --git a/pkg/instrumentation/defaultinstrumentation_test.go b/pkg/instrumentation/defaultinstrumentation_test.go index a73efe56c..86695677f 100644 --- a/pkg/instrumentation/defaultinstrumentation_test.go +++ b/pkg/instrumentation/defaultinstrumentation_test.go @@ -8,13 +8,14 @@ import ( "reflect" "testing" - "k8s.io/apimachinery/pkg/api/resource" - + "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/aws/amazon-cloudwatch-agent-operator/apis/v1alpha1" "github.com/aws/amazon-cloudwatch-agent-operator/internal/manifests/collector/adapters" + "github.com/aws/amazon-cloudwatch-agent-operator/pkg/instrumentation/jmx" ) func Test_getDefaultInstrumentationLinux(t *testing.T) { @@ -59,16 +60,16 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { Java: v1alpha1.Java{ Image: defaultJavaInstrumentationImage, Env: []corev1.EnvVar{ + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, {Name: "OTEL_TRACES_SAMPLER_ARG", Value: "endpoint=http://cloudwatch-agent.amazon-cloudwatch:2000"}, {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, - {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4316/v1/traces"}, {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4316/v1/metrics"}, //TODO: remove in favor of new name once safe {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4316/v1/metrics"}, - {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, Resources: corev1.ResourceRequirements{ Limits: corev1.ResourceList{ @@ -180,16 +181,16 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { Java: v1alpha1.Java{ Image: defaultJavaInstrumentationImage, Env: []corev1.EnvVar{ + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, {Name: "OTEL_TRACES_SAMPLER_ARG", Value: "endpoint=http://cloudwatch-agent.amazon-cloudwatch:2000"}, {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, - {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: "https://cloudwatch-agent.amazon-cloudwatch:4316/v1/traces"}, {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: "https://cloudwatch-agent.amazon-cloudwatch:4316/v1/metrics"}, //TODO: remove in favor of new name once safe {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: "https://cloudwatch-agent.amazon-cloudwatch:4316/v1/metrics"}, - {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, Resources: corev1.ResourceRequirements{ Limits: corev1.ResourceList{ @@ -382,16 +383,16 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { Java: v1alpha1.Java{ Image: defaultJavaInstrumentationImage, Env: []corev1.EnvVar{ + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, {Name: "OTEL_TRACES_SAMPLER_ARG", Value: "endpoint=http://cloudwatch-agent-windows-headless.amazon-cloudwatch.svc.cluster.local:2000"}, {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, - {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: "http://cloudwatch-agent-windows-headless.amazon-cloudwatch.svc.cluster.local:4316/v1/traces"}, {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: "http://cloudwatch-agent-windows-headless.amazon-cloudwatch.svc.cluster.local:4316/v1/metrics"}, //TODO: remove in favor of new name once safe {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: "http://cloudwatch-agent-windows-headless.amazon-cloudwatch.svc.cluster.local:4316/v1/metrics"}, - {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, Resources: corev1.ResourceRequirements{ Limits: corev1.ResourceList{ @@ -503,16 +504,16 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { Java: v1alpha1.Java{ Image: defaultJavaInstrumentationImage, Env: []corev1.EnvVar{ + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_AWS_APP_SIGNALS_ENABLED", Value: "true"}, //TODO: remove in favor of new name once safe {Name: "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", Value: "true"}, {Name: "OTEL_TRACES_SAMPLER_ARG", Value: "endpoint=http://cloudwatch-agent-windows-headless.amazon-cloudwatch.svc.cluster.local:2000"}, {Name: "OTEL_TRACES_SAMPLER", Value: "xray"}, - {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: "https://cloudwatch-agent-windows-headless.amazon-cloudwatch.svc.cluster.local:4316/v1/traces"}, {Name: "OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT", Value: "https://cloudwatch-agent-windows-headless.amazon-cloudwatch.svc.cluster.local:4316/v1/metrics"}, //TODO: remove in favor of new name once safe {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: "https://cloudwatch-agent-windows-headless.amazon-cloudwatch.svc.cluster.local:4316/v1/metrics"}, - {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, - {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, Resources: corev1.ResourceRequirements{ Limits: corev1.ResourceList{ @@ -661,3 +662,261 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { }) } } + +func Test_getDefaultInstrumentationLinuxWithApplicationSignalsDisabled(t *testing.T) { + os.Setenv("AUTO_INSTRUMENTATION_JAVA", defaultJavaInstrumentationImage) + os.Setenv("AUTO_INSTRUMENTATION_PYTHON", defaultPythonInstrumentationImage) + os.Setenv("AUTO_INSTRUMENTATION_DOTNET", defaultDotNetInstrumentationImage) + os.Setenv("AUTO_INSTRUMENTATION_NODEJS", defaultNodeJSInstrumentationImage) + os.Setenv("AUTO_INSTRUMENTATION_JAVA_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_MEM_LIMIT", "64Mi") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_MEM_REQUEST", "64Mi") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_MEM_LIMIT", "32Mi") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_MEM_REQUEST", "32Mi") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_MEM_LIMIT", "128Mi") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_MEM_REQUEST", "128Mi") + os.Setenv("AUTO_INSTRUMENTATION_NODEJS_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_NODEJS_MEM_LIMIT", "128Mi") + os.Setenv("AUTO_INSTRUMENTATION_NODEJS_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_NODEJS_MEM_REQUEST", "128Mi") + + httpInst := &v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{ + APIVersion: defaultAPIVersion, + Kind: defaultKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: defaultInstrumentation, + Namespace: defaultNamespace, + }, + Spec: v1alpha1.InstrumentationSpec{ + Propagators: []v1alpha1.Propagator{ + v1alpha1.TraceContext, + v1alpha1.Baggage, + v1alpha1.B3, + v1alpha1.XRay, + }, + Java: v1alpha1.Java{ + Image: defaultJavaInstrumentationImage, + Env: []corev1.EnvVar{ + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + }, + }, + Python: v1alpha1.Python{ + Image: defaultPythonInstrumentationImage, + Env: []corev1.EnvVar{}, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, + }, + DotNet: v1alpha1.DotNet{ + Image: defaultDotNetInstrumentationImage, + Env: []corev1.EnvVar{}, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + }, + NodeJS: v1alpha1.NodeJS{ + Image: defaultNodeJSInstrumentationImage, + Env: []corev1.EnvVar{}, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + }, + }, + } + + jmxInst := &v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{ + APIVersion: defaultAPIVersion, + Kind: defaultKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: defaultInstrumentation, + Namespace: defaultNamespace, + }, + Spec: v1alpha1.InstrumentationSpec{ + Propagators: []v1alpha1.Propagator{ + v1alpha1.TraceContext, + v1alpha1.Baggage, + v1alpha1.B3, + v1alpha1.XRay, + }, + Java: v1alpha1.Java{ + Image: defaultJavaInstrumentationImage, + Env: []corev1.EnvVar{ + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + {Name: "OTEL_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, + {Name: "OTEL_JMX_ENABLED", Value: "true"}, + {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm"}, + }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + }, + }, + Python: v1alpha1.Python{ + Image: defaultPythonInstrumentationImage, + Env: []corev1.EnvVar{}, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, + }, + DotNet: v1alpha1.DotNet{ + Image: defaultDotNetInstrumentationImage, + Env: []corev1.EnvVar{}, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + }, + NodeJS: v1alpha1.NodeJS{ + Image: defaultNodeJSInstrumentationImage, + Env: []corev1.EnvVar{}, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + }, + }, + } + + type args struct { + agentConfig *adapters.CwaConfig + additionalEnvs map[Type]map[string]string + } + tests := []struct { + name string + args args + want *v1alpha1.Instrumentation + wantErr bool + }{ + { + name: "no-application-signals", + args: args{ + agentConfig: &adapters.CwaConfig{ + Logs: &adapters.Logs{ + LogMetricsCollected: &adapters.LogMetricsCollected{}, + }, + }, + }, + want: httpInst, + wantErr: false, + }, + { + name: "no-application-signals-with-additional-vars", + args: args{ + agentConfig: &adapters.CwaConfig{ + Logs: &adapters.Logs{ + LogMetricsCollected: &adapters.LogMetricsCollected{}, + }, + }, + additionalEnvs: map[Type]map[string]string{ + TypeJava: { + jmx.EnvTargetSystem: jmx.TargetJVM, + }, + }, + }, + want: jmxInst, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := getDefaultInstrumentation(tt.args.agentConfig, tt.args.additionalEnvs, false) + if (err != nil) != tt.wantErr { + t.Errorf("getDefaultInstrumentation() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got.Spec.Java.Env, tt.want.Spec.Java.Env) { + t.Errorf("getDefaultInstrumentation() Java environment vars got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsApplicationSignalsEnabled(t *testing.T) { + applicationSignalsConfig := &adapters.CwaConfig{ + Logs: &adapters.Logs{ + LogMetricsCollected: &adapters.LogMetricsCollected{ + ApplicationSignals: &adapters.AppSignals{}, + }, + }, + } + assert.True(t, isApplicationSignalsEnabled(applicationSignalsConfig)) + applicationSignalsConfig = &adapters.CwaConfig{ + Logs: &adapters.Logs{ + LogMetricsCollected: &adapters.LogMetricsCollected{}, + }, + } + assert.False(t, isApplicationSignalsEnabled(applicationSignalsConfig)) + +} diff --git a/pkg/instrumentation/podmutator_test.go b/pkg/instrumentation/podmutator_test.go index a08e17d3d..b8402e258 100644 --- a/pkg/instrumentation/podmutator_test.go +++ b/pkg/instrumentation/podmutator_test.go @@ -9,8 +9,6 @@ import ( "os" "testing" - "github.com/aws/amazon-cloudwatch-agent-operator/pkg/instrumentation/jmx" - "github.com/go-logr/logr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -23,6 +21,7 @@ import ( "github.com/aws/amazon-cloudwatch-agent-operator/apis/v1alpha1" "github.com/aws/amazon-cloudwatch-agent-operator/internal/manifests/collector/adapters" "github.com/aws/amazon-cloudwatch-agent-operator/pkg/featuregate" + "github.com/aws/amazon-cloudwatch-agent-operator/pkg/instrumentation/jmx" ) const ( @@ -82,8 +81,12 @@ func TestGetInstrumentationInstanceJMX(t *testing.T) { }, }, ns: corev1.Namespace{}, - wantLen: 15, + wantLen: 6, wantEnv: []corev1.EnvVar{ + {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, + {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, + {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + {Name: "OTEL_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, {Name: "OTEL_JMX_ENABLED", Value: "true"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm,tomcat"}, }, From f8bb90821feab51069f88b67c6bd9e3b68874367 Mon Sep 17 00:00:00 2001 From: Mitali Salvi Date: Fri, 11 Oct 2024 15:38:57 -0400 Subject: [PATCH 3/5] add support for jmx container insights port and updating env vars for JMX --- .../manifests/collector/adapters/config_from.go | 1 + internal/manifests/collector/ports.go | 14 ++++++++++++++ internal/manifests/collector/ports_test.go | 9 +++++++++ .../test-resources/jmxContainerInsightsConfig.json | 10 ++++++++++ pkg/instrumentation/defaultinstrumentation.go | 4 ++-- pkg/instrumentation/defaultinstrumentation_test.go | 4 ++-- pkg/instrumentation/podmutator_test.go | 4 ++-- 7 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 internal/manifests/collector/test-resources/jmxContainerInsightsConfig.json diff --git a/internal/manifests/collector/adapters/config_from.go b/internal/manifests/collector/adapters/config_from.go index e81b69cc1..685fdbcab 100644 --- a/internal/manifests/collector/adapters/config_from.go +++ b/internal/manifests/collector/adapters/config_from.go @@ -93,6 +93,7 @@ type jmx struct{} type kubernetes struct { EnhancedContainerInsights bool `json:"enhanced_container_insights,omitempty"` AcceleratedComputeMetrics bool `json:"accelerated_compute_metrics,omitempty"` + JMXContainerInsights bool `json:"jmx_container_insights,omitempty"` } type xray struct { diff --git a/internal/manifests/collector/ports.go b/internal/manifests/collector/ports.go index 291b4bb4d..929b54384 100644 --- a/internal/manifests/collector/ports.go +++ b/internal/manifests/collector/ports.go @@ -200,6 +200,20 @@ func getLogsReceiversServicePorts(logger logr.Logger, config *adapters.CwaConfig servicePortsMap[receiverDefaultPortsMap[EMF]] = []corev1.ServicePort{tcp, udp} } } + + //JMX Container Insights + if config.Logs != nil && config.Logs.LogMetricsCollected != nil && config.Logs.LogMetricsCollected.Kubernetes != nil && config.Logs.LogMetricsCollected.Kubernetes.JMXContainerInsights { + if _, ok := servicePortsMap[receiverDefaultPortsMap[JmxHttp]]; ok { + logger.Info("Duplicate port has been configured in Agent Config for port", zap.Int32("port", receiverDefaultPortsMap[JmxHttp])) + } else { + tcp := corev1.ServicePort{ + Name: JmxHttp, + Port: receiverDefaultPortsMap[JmxHttp], + Protocol: corev1.ProtocolTCP, + } + servicePortsMap[receiverDefaultPortsMap[JmxHttp]] = []corev1.ServicePort{tcp} + } + } } func getTracesReceiversServicePorts(logger logr.Logger, config *adapters.CwaConfig, servicePortsMap map[int32][]corev1.ServicePort) []corev1.ServicePort { diff --git a/internal/manifests/collector/ports_test.go b/internal/manifests/collector/ports_test.go index b797e911c..b8cf41292 100644 --- a/internal/manifests/collector/ports_test.go +++ b/internal/manifests/collector/ports_test.go @@ -213,6 +213,15 @@ func TestJMXGetContainerPorts(t *testing.T) { assert.Equal(t, corev1.ProtocolTCP, containerPorts[JmxHttp].Protocol) } +func TestJMXContainerInsightsGetContainerPorts(t *testing.T) { + cfg := getJSONStringFromFile("./test-resources/jmxContainerInsightsConfig.json") + containerPorts := getContainerPorts(logger, cfg, []corev1.ServicePort{}) + assert.Equal(t, 1, len(containerPorts)) + assert.Equal(t, int32(4314), containerPorts[JmxHttp].ContainerPort) + assert.Equal(t, JmxHttp, containerPorts[JmxHttp].Name) + assert.Equal(t, corev1.ProtocolTCP, containerPorts[JmxHttp].Protocol) +} + func getJSONStringFromFile(path string) string { buf, err := os.ReadFile(path) if err != nil { diff --git a/internal/manifests/collector/test-resources/jmxContainerInsightsConfig.json b/internal/manifests/collector/test-resources/jmxContainerInsightsConfig.json new file mode 100644 index 000000000..9ee4ef445 --- /dev/null +++ b/internal/manifests/collector/test-resources/jmxContainerInsightsConfig.json @@ -0,0 +1,10 @@ +{ + "logs": { + "metrics_collected": { + "kubernetes": { + "cluster_name": "TestCluster", + "jmx_container_insights": true + } + } + } +} \ No newline at end of file diff --git a/pkg/instrumentation/defaultinstrumentation.go b/pkg/instrumentation/defaultinstrumentation.go index 252087468..72a5b4da5 100644 --- a/pkg/instrumentation/defaultinstrumentation.go +++ b/pkg/instrumentation/defaultinstrumentation.go @@ -159,8 +159,8 @@ func getJavaEnvs(isAppSignalsEnabled bool, cloudwatchAgentServiceEndpoint, expor var jmxEnvs []corev1.EnvVar if targetSystems, ok := additionalEnvs[jmx.EnvTargetSystem]; ok { jmxEnvs = []corev1.EnvVar{ - {Name: "OTEL_JMX_EXPORTER_METRICS_ENDPOINT", Value: fmt.Sprintf("%s://%s:4314/v1/metrics", http, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_JMX_ENABLED", Value: "true"}, + {Name: "OTEL_AWS_JMX_EXPORTER_METRICS_ENDPOINT", Value: fmt.Sprintf("%s://%s:4314/v1/metrics", http, cloudwatchAgentServiceEndpoint)}, + {Name: "OTEL_AWS_JMX_ENABLED", Value: "true"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: targetSystems}, } } diff --git a/pkg/instrumentation/defaultinstrumentation_test.go b/pkg/instrumentation/defaultinstrumentation_test.go index 86695677f..70524481d 100644 --- a/pkg/instrumentation/defaultinstrumentation_test.go +++ b/pkg/instrumentation/defaultinstrumentation_test.go @@ -788,8 +788,8 @@ func Test_getDefaultInstrumentationLinuxWithApplicationSignalsDisabled(t *testin {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, - {Name: "OTEL_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, - {Name: "OTEL_JMX_ENABLED", Value: "true"}, + {Name: "OTEL_AWS_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, + {Name: "OTEL_AWS_JMX_ENABLED", Value: "true"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm"}, }, Resources: corev1.ResourceRequirements{ diff --git a/pkg/instrumentation/podmutator_test.go b/pkg/instrumentation/podmutator_test.go index b8402e258..c252ac1a3 100644 --- a/pkg/instrumentation/podmutator_test.go +++ b/pkg/instrumentation/podmutator_test.go @@ -86,8 +86,8 @@ func TestGetInstrumentationInstanceJMX(t *testing.T) { {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, - {Name: "OTEL_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, - {Name: "OTEL_JMX_ENABLED", Value: "true"}, + {Name: "OTEL_AWS_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, + {Name: "OTEL_AWS_JMX_ENABLED", Value: "true"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm,tomcat"}, }, }, From 02ffe6009303d668eec521c732f18dcc504641b8 Mon Sep 17 00:00:00 2001 From: Mitali Salvi Date: Fri, 11 Oct 2024 16:03:28 -0400 Subject: [PATCH 4/5] updating env vars --- pkg/instrumentation/defaultinstrumentation.go | 1 - pkg/instrumentation/defaultinstrumentation_test.go | 1 - pkg/instrumentation/podmutator_test.go | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/instrumentation/defaultinstrumentation.go b/pkg/instrumentation/defaultinstrumentation.go index 72a5b4da5..5e408741a 100644 --- a/pkg/instrumentation/defaultinstrumentation.go +++ b/pkg/instrumentation/defaultinstrumentation.go @@ -160,7 +160,6 @@ func getJavaEnvs(isAppSignalsEnabled bool, cloudwatchAgentServiceEndpoint, expor if targetSystems, ok := additionalEnvs[jmx.EnvTargetSystem]; ok { jmxEnvs = []corev1.EnvVar{ {Name: "OTEL_AWS_JMX_EXPORTER_METRICS_ENDPOINT", Value: fmt.Sprintf("%s://%s:4314/v1/metrics", http, cloudwatchAgentServiceEndpoint)}, - {Name: "OTEL_AWS_JMX_ENABLED", Value: "true"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: targetSystems}, } } diff --git a/pkg/instrumentation/defaultinstrumentation_test.go b/pkg/instrumentation/defaultinstrumentation_test.go index 70524481d..96be8d768 100644 --- a/pkg/instrumentation/defaultinstrumentation_test.go +++ b/pkg/instrumentation/defaultinstrumentation_test.go @@ -789,7 +789,6 @@ func Test_getDefaultInstrumentationLinuxWithApplicationSignalsDisabled(t *testin {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_AWS_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, - {Name: "OTEL_AWS_JMX_ENABLED", Value: "true"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm"}, }, Resources: corev1.ResourceRequirements{ diff --git a/pkg/instrumentation/podmutator_test.go b/pkg/instrumentation/podmutator_test.go index c252ac1a3..3fab70a35 100644 --- a/pkg/instrumentation/podmutator_test.go +++ b/pkg/instrumentation/podmutator_test.go @@ -81,13 +81,12 @@ func TestGetInstrumentationInstanceJMX(t *testing.T) { }, }, ns: corev1.Namespace{}, - wantLen: 6, + wantLen: 5, wantEnv: []corev1.EnvVar{ {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_AWS_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, - {Name: "OTEL_AWS_JMX_ENABLED", Value: "true"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm,tomcat"}, }, }, From bff2e353cdc8b6ec10b2c3f61b910dca2a994eaa Mon Sep 17 00:00:00 2001 From: Mitali Salvi Date: Fri, 11 Oct 2024 20:34:31 -0400 Subject: [PATCH 5/5] addressing comments --- pkg/instrumentation/defaultinstrumentation.go | 23 +++++++++---------- .../defaultinstrumentation_test.go | 21 ++--------------- pkg/instrumentation/podmutator_test.go | 3 ++- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/pkg/instrumentation/defaultinstrumentation.go b/pkg/instrumentation/defaultinstrumentation.go index 5e408741a..b5421389b 100644 --- a/pkg/instrumentation/defaultinstrumentation.go +++ b/pkg/instrumentation/defaultinstrumentation.go @@ -77,7 +77,9 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m // set protocol by checking cloudwatch agent config for tls setting exporterPrefix := http - if isApplicationSignalsEnabled(agentConfig) { + isApplicationSignalsEnabled := agentConfig != nil && agentConfig.GetApplicationSignalsConfig() != nil + + if isApplicationSignalsEnabled { if agentConfig.GetApplicationSignalsConfig().TLS != nil { exporterPrefix = https } @@ -102,7 +104,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, Java: v1alpha1.Java{ Image: javaInstrumentationImage, - Env: getJavaEnvs(isApplicationSignalsEnabled(agentConfig), cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeJava]), + Env: getJavaEnvs(isApplicationSignalsEnabled, cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeJava]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(java, limit), Requests: getInstrumentationConfigForResource(java, request), @@ -110,7 +112,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, Python: v1alpha1.Python{ Image: pythonInstrumentationImage, - Env: getPythonEnvs(isApplicationSignalsEnabled(agentConfig), cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypePython]), + Env: getPythonEnvs(isApplicationSignalsEnabled, cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypePython]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(python, limit), Requests: getInstrumentationConfigForResource(python, request), @@ -118,7 +120,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, DotNet: v1alpha1.DotNet{ Image: dotNetInstrumentationImage, - Env: getDotNetEnvs(isApplicationSignalsEnabled(agentConfig), cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeDotNet]), + Env: getDotNetEnvs(isApplicationSignalsEnabled, cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeDotNet]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(dotNet, limit), Requests: getInstrumentationConfigForResource(dotNet, request), @@ -126,7 +128,7 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, additionalEnvs m }, NodeJS: v1alpha1.NodeJS{ Image: nodeJSInstrumentationImage, - Env: getNodeJSEnvs(isApplicationSignalsEnabled(agentConfig), cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeDotNet]), + Env: getNodeJSEnvs(isApplicationSignalsEnabled, cloudwatchAgentServiceEndpoint, exporterPrefix, additionalEnvs[TypeDotNet]), Resources: corev1.ResourceRequirements{ Limits: getInstrumentationConfigForResource(nodeJS, limit), Requests: getInstrumentationConfigForResource(nodeJS, request), @@ -154,6 +156,10 @@ func getJavaEnvs(isAppSignalsEnabled bool, cloudwatchAgentServiceEndpoint, expor {Name: "OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT", Value: fmt.Sprintf("%s://%s:4316/v1/metrics", exporterPrefix, cloudwatchAgentServiceEndpoint)}, } envs = append(envs, appSignalsEnvs...) + } else { + envs = append(envs, corev1.EnvVar{ + Name: "OTEL_TRACES_EXPORTER", Value: "none", + }) } var jmxEnvs []corev1.EnvVar @@ -227,10 +233,3 @@ func getNodeJSEnvs(isAppSignalsEnabled bool, cloudwatchAgentServiceEndpoint, exp } return envs } - -func isApplicationSignalsEnabled(agentConfig *adapters.CwaConfig) bool { - if agentConfig != nil { - return agentConfig.GetApplicationSignalsConfig() != nil - } - return false -} diff --git a/pkg/instrumentation/defaultinstrumentation_test.go b/pkg/instrumentation/defaultinstrumentation_test.go index 96be8d768..2b31e716e 100644 --- a/pkg/instrumentation/defaultinstrumentation_test.go +++ b/pkg/instrumentation/defaultinstrumentation_test.go @@ -8,7 +8,6 @@ import ( "reflect" "testing" - "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -708,6 +707,7 @@ func Test_getDefaultInstrumentationLinuxWithApplicationSignalsDisabled(t *testin {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + {Name: "OTEL_TRACES_EXPORTER", Value: "none"}, }, Resources: corev1.ResourceRequirements{ Limits: corev1.ResourceList{ @@ -788,6 +788,7 @@ func Test_getDefaultInstrumentationLinuxWithApplicationSignalsDisabled(t *testin {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + {Name: "OTEL_TRACES_EXPORTER", Value: "none"}, {Name: "OTEL_AWS_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm"}, }, @@ -901,21 +902,3 @@ func Test_getDefaultInstrumentationLinuxWithApplicationSignalsDisabled(t *testin }) } } - -func TestIsApplicationSignalsEnabled(t *testing.T) { - applicationSignalsConfig := &adapters.CwaConfig{ - Logs: &adapters.Logs{ - LogMetricsCollected: &adapters.LogMetricsCollected{ - ApplicationSignals: &adapters.AppSignals{}, - }, - }, - } - assert.True(t, isApplicationSignalsEnabled(applicationSignalsConfig)) - applicationSignalsConfig = &adapters.CwaConfig{ - Logs: &adapters.Logs{ - LogMetricsCollected: &adapters.LogMetricsCollected{}, - }, - } - assert.False(t, isApplicationSignalsEnabled(applicationSignalsConfig)) - -} diff --git a/pkg/instrumentation/podmutator_test.go b/pkg/instrumentation/podmutator_test.go index 3fab70a35..e7ad2f061 100644 --- a/pkg/instrumentation/podmutator_test.go +++ b/pkg/instrumentation/podmutator_test.go @@ -81,11 +81,12 @@ func TestGetInstrumentationInstanceJMX(t *testing.T) { }, }, ns: corev1.Namespace{}, - wantLen: 5, + wantLen: 6, wantEnv: []corev1.EnvVar{ {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, + {Name: "OTEL_TRACES_EXPORTER", Value: "none"}, {Name: "OTEL_AWS_JMX_EXPORTER_METRICS_ENDPOINT", Value: "http://cloudwatch-agent.amazon-cloudwatch:4314/v1/metrics"}, {Name: "OTEL_JMX_TARGET_SYSTEM", Value: "jvm,tomcat"}, },