diff --git a/cmd/config-translator/translator_test.go b/cmd/config-translator/translator_test.go index b6dd36e7ef..3fb8c7fb4b 100644 --- a/cmd/config-translator/translator_test.go +++ b/cmd/config-translator/translator_test.go @@ -97,6 +97,7 @@ func TestLogWindowsEventConfig(t *testing.T) { func TestMetricsConfig(t *testing.T) { checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/validLinuxMetrics.json", true, map[string]int{}) checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/validWindowsMetrics.json", true, map[string]int{}) + checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/validMetricsWithAppSignals.json", true, map[string]int{}) expectedErrorMap := map[string]int{} expectedErrorMap["invalid_type"] = 2 checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidMetricsWithInvalidAggregationDimensions.json", false, expectedErrorMap) diff --git a/plugins/processors/awsappsignals/config.go b/plugins/processors/awsappsignals/config.go deleted file mode 100644 index 82f7283c91..0000000000 --- a/plugins/processors/awsappsignals/config.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT - -package awsappsignals - -import ( - "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/rules" -) - -type Config struct { - Resolvers []string `mapstructure:"resolvers"` - Rules []rules.Rule `mapstructure:"rules"` -} - -func (cfg *Config) Validate() error { - // TODO: validate those mandatory fields (if exist) in the config - return nil -} diff --git a/plugins/processors/awsappsignals/config/config.go b/plugins/processors/awsappsignals/config/config.go new file mode 100644 index 0000000000..a85b3e7ed4 --- /dev/null +++ b/plugins/processors/awsappsignals/config/config.go @@ -0,0 +1,33 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package config + +import ( + "errors" + + "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/rules" +) + +type Config struct { + Resolvers []Resolver `mapstructure:"resolvers"` + Rules []rules.Rule `mapstructure:"rules"` +} + +func (cfg *Config) Validate() error { + if len(cfg.Resolvers) == 0 { + return errors.New("resolvers must not be empty") + } + for _, resolver := range cfg.Resolvers { + switch resolver.Platform { + case PlatformEKS: + if resolver.Name == "" { + return errors.New("name must not be empty for eks resolver") + } + case PlatformGeneric: + default: + return errors.New("unknown resolver") + } + } + return nil +} diff --git a/plugins/processors/awsappsignals/config/config_test.go b/plugins/processors/awsappsignals/config/config_test.go new file mode 100644 index 0000000000..2c592f5885 --- /dev/null +++ b/plugins/processors/awsappsignals/config/config_test.go @@ -0,0 +1,34 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValidatePassed(t *testing.T) { + config := Config{ + Resolvers: []Resolver{NewEKSResolver("test"), NewGenericResolver("")}, + Rules: nil, + } + assert.Nil(t, config.Validate()) +} + +func TestValidateFailedOnEmptyResolver(t *testing.T) { + config := Config{ + Resolvers: []Resolver{}, + Rules: nil, + } + assert.NotNil(t, config.Validate()) +} + +func TestValidateFailedOnEmptyClusterName(t *testing.T) { + config := Config{ + Resolvers: []Resolver{NewEKSResolver("")}, + Rules: nil, + } + assert.NotNil(t, config.Validate()) +} diff --git a/plugins/processors/awsappsignals/config/resolvers.go b/plugins/processors/awsappsignals/config/resolvers.go new file mode 100644 index 0000000000..2ef9982ba9 --- /dev/null +++ b/plugins/processors/awsappsignals/config/resolvers.go @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package config + +const ( + // PlatformGeneric Platforms other than Amazon EKS + PlatformGeneric = "generic" + // PlatformEKS Amazon EKS platform + PlatformEKS = "eks" +) + +type Resolver struct { + Name string `mapstructure:"name"` + Platform string `mapstructure:"platform"` +} + +func NewEKSResolver(name string) Resolver { + return Resolver{ + Name: name, + Platform: PlatformEKS, + } +} + +func NewGenericResolver(name string) Resolver { + return Resolver{ + Name: name, + Platform: PlatformGeneric, + } +} diff --git a/plugins/processors/awsappsignals/config/resolvers_test.go b/plugins/processors/awsappsignals/config/resolvers_test.go new file mode 100644 index 0000000000..742426ee13 --- /dev/null +++ b/plugins/processors/awsappsignals/config/resolvers_test.go @@ -0,0 +1,20 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewEKSResolver(t *testing.T) { + resolver := NewEKSResolver("test") + assert.Equal(t, "eks", resolver.Platform) +} + +func TestNewGenericResolver(t *testing.T) { + resolver := NewGenericResolver("") + assert.Equal(t, "generic", resolver.Platform) +} diff --git a/plugins/processors/awsappsignals/config_test.go b/plugins/processors/awsappsignals/config_test.go deleted file mode 100644 index 4cb8f47df9..0000000000 --- a/plugins/processors/awsappsignals/config_test.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT - -package awsappsignals - -import ( - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/confmap/confmaptest" - - "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/rules" -) - -func TestLoadConfig(t *testing.T) { - t.Parallel() - - tests := []struct { - id component.ID - expected component.Config - errorMessage string - }{ - { - id: component.NewIDWithName("awsappsignals", ""), - expected: &Config{ - Resolvers: []string{"eks"}, - Rules: []rules.Rule{ - { - Selectors: []rules.Selector{ - { - Dimension: "Operation", - Match: "* /api/visits/*", - }, - { - Dimension: "RemoteOperation", - Match: "*", - }, - }, - Action: "keep", - RuleName: "keep01", - }, - { - Selectors: []rules.Selector{ - { - Dimension: "RemoteService", - Match: "UnknownRemoteService", - }, - { - Dimension: "RemoteOperation", - Match: "GetShardIterator", - }, - }, - Action: "drop", - }, - { - Selectors: []rules.Selector{ - { - Dimension: "Operation", - Match: "* /api/visits/*", - }, - { - Dimension: "RemoteOperation", - Match: "*", - }, - }, - Replacements: []rules.Replacement{ - { - TargetDimension: "RemoteOperation", - Value: "ListPetsByCustomer", - }, - { - TargetDimension: "ResourceTarget", - Value: " ", - }, - }, - Action: "replace", - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.id.String(), func(t *testing.T) { - cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) - require.NoError(t, err) - - factory := NewFactory() - cfg := factory.CreateDefaultConfig() - sub, err := cm.Sub(tt.id.String()) - require.NoError(t, err) - require.NoError(t, component.UnmarshalConfig(sub, cfg)) - - if tt.expected == nil { - assert.EqualError(t, component.ValidateConfig(cfg), tt.errorMessage) - return - } - assert.NoError(t, component.ValidateConfig(cfg)) - assert.Equal(t, tt.expected, cfg) - }) - } -} diff --git a/plugins/processors/awsappsignals/factory.go b/plugins/processors/awsappsignals/factory.go index 8cb3bc6298..83a6c764ed 100644 --- a/plugins/processors/awsappsignals/factory.go +++ b/plugins/processors/awsappsignals/factory.go @@ -11,6 +11,8 @@ import ( "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processorhelper" + + appsignalsconfig "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/config" ) const ( @@ -33,9 +35,8 @@ func NewFactory() processor.Factory { } func createDefaultConfig() component.Config { - return &Config{ - // TODO: change default config when other resolvers are supported - Resolvers: []string{"eks"}, + return &appsignalsconfig.Config{ + Resolvers: []appsignalsconfig.Resolver{}, } } @@ -87,7 +88,7 @@ func createProcessor( params processor.CreateSettings, cfg component.Config, ) (*awsappsignalsprocessor, error) { - pCfg, ok := cfg.(*Config) + pCfg, ok := cfg.(*appsignalsconfig.Config) if !ok { return nil, errors.New("could not initialize awsappsignalsprocessor") } diff --git a/plugins/processors/awsappsignals/factory_test.go b/plugins/processors/awsappsignals/factory_test.go new file mode 100644 index 0000000000..1bc2c4761f --- /dev/null +++ b/plugins/processors/awsappsignals/factory_test.go @@ -0,0 +1,152 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package awsappsignals + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/confmap/confmaptest" + + "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/config" + "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/rules" +) + +var expectedRules = []rules.Rule{ + { + Selectors: []rules.Selector{ + { + Dimension: "Operation", + Match: "* /api/visits/*", + }, + { + Dimension: "RemoteOperation", + Match: "*", + }, + }, + Action: "keep", + RuleName: "keep01", + }, + { + Selectors: []rules.Selector{ + { + Dimension: "RemoteService", + Match: "UnknownRemoteService", + }, + { + Dimension: "RemoteOperation", + Match: "GetShardIterator", + }, + }, + Action: "drop", + }, + { + Selectors: []rules.Selector{ + { + Dimension: "Operation", + Match: "* /api/visits/*", + }, + { + Dimension: "RemoteOperation", + Match: "*", + }, + }, + Replacements: []rules.Replacement{ + { + TargetDimension: "RemoteOperation", + Value: "ListPetsByCustomer", + }, + { + TargetDimension: "ResourceTarget", + Value: " ", + }, + }, + Action: "replace", + }, +} + +func TestLoadEKSConfig(t *testing.T) { + t.Parallel() + + tests := []struct { + id component.ID + expected component.Config + errorMessage string + }{ + { + id: component.NewIDWithName("awsappsignals", ""), + expected: &config.Config{ + Resolvers: []config.Resolver{config.NewEKSResolver("test")}, + Rules: expectedRules, + }, + }, + } + for _, tt := range tests { + t.Run(tt.id.String(), func(t *testing.T) { + cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config_eks.yaml")) + require.NoError(t, err) + + factory := NewFactory() + cfg := factory.CreateDefaultConfig().(*config.Config) + + sub, err := cm.Sub(tt.id.String()) + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + if tt.expected == nil { + assert.EqualError(t, component.ValidateConfig(cfg), tt.errorMessage) + return + } + assert.NoError(t, component.ValidateConfig(cfg)) + assert.Equal(t, tt.expected, cfg) + + validateErr := cfg.Validate() + assert.Nil(t, validateErr, validateErr) + }) + } +} + +func TestLoadGenericConfig(t *testing.T) { + t.Parallel() + + tests := []struct { + id component.ID + expected component.Config + errorMessage string + }{ + { + id: component.NewIDWithName("awsappsignals", ""), + expected: &config.Config{ + Resolvers: []config.Resolver{config.NewGenericResolver("")}, + Rules: expectedRules, + }, + }, + } + for _, tt := range tests { + t.Run(tt.id.String(), func(t *testing.T) { + cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config_generic.yaml")) + require.NoError(t, err) + + factory := NewFactory() + cfg := factory.CreateDefaultConfig().(*config.Config) + + sub, err := cm.Sub(tt.id.String()) + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + if tt.expected == nil { + assert.EqualError(t, component.ValidateConfig(cfg), tt.errorMessage) + return + } + assert.NoError(t, component.ValidateConfig(cfg)) + assert.Equal(t, tt.expected, cfg) + + validateErr := cfg.Validate() + assert.Nil(t, validateErr, validateErr) + }) + } +} diff --git a/plugins/processors/awsappsignals/internal/resolver/attributesresolver.go b/plugins/processors/awsappsignals/internal/resolver/attributesresolver.go index 724c43f065..5d06814554 100644 --- a/plugins/processors/awsappsignals/internal/resolver/attributesresolver.go +++ b/plugins/processors/awsappsignals/internal/resolver/attributesresolver.go @@ -10,9 +10,12 @@ import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.uber.org/zap" + appsignalsconfig "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/config" attr "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/internal/attributes" ) +const AttributePlatformGeneric = "Generic" + var DefaultHostedInAttributes = map[string]string{ attr.AWSHostedInEnvironment: attr.HostedInEnvironment, } @@ -27,13 +30,13 @@ type attributesResolver struct { } // create a new attributes resolver -func NewAttributesResolver(resolverNames []string, logger *zap.Logger) *attributesResolver { +func NewAttributesResolver(resolvers []appsignalsconfig.Resolver, logger *zap.Logger) *attributesResolver { subResolvers := []subResolver{} - for _, resolverName := range resolverNames { - if resolverName == "eks" { - subResolvers = append(subResolvers, getEksResolver(logger), newEKSHostedInAttributeResolver()) + for _, resolver := range resolvers { + if resolver.Platform == appsignalsconfig.PlatformEKS { + subResolvers = append(subResolvers, getEksResolver(logger), newEKSHostedInAttributeResolver(resolver.Name)) } else { - subResolvers = append(subResolvers, newHostedInAttributeResolver(DefaultHostedInAttributes)) + subResolvers = append(subResolvers, newHostedInAttributeResolver(resolver.Name, DefaultHostedInAttributes)) } } return &attributesResolver{ @@ -62,11 +65,16 @@ func (r *attributesResolver) Stop(ctx context.Context) error { } type hostedInAttributeResolver struct { + name string attributeMap map[string]string } -func newHostedInAttributeResolver(attributeMap map[string]string) *hostedInAttributeResolver { +func newHostedInAttributeResolver(name string, attributeMap map[string]string) *hostedInAttributeResolver { + if name == "" { + name = AttributePlatformGeneric + } return &hostedInAttributeResolver{ + name: name, attributeMap: attributeMap, } } @@ -78,8 +86,7 @@ func (h *hostedInAttributeResolver) Process(attributes, resourceAttributes pcomm } if _, ok := resourceAttributes.Get(attr.AWSHostedInEnvironment); !ok { - hostedInEnv := "Generic" - attributes.PutStr(attr.HostedInEnvironment, hostedInEnv) + attributes.PutStr(attr.HostedInEnvironment, h.name) } return nil diff --git a/plugins/processors/awsappsignals/internal/resolver/attributesresolver_test.go b/plugins/processors/awsappsignals/internal/resolver/attributesresolver_test.go index 2597c4926f..5f5d4868aa 100644 --- a/plugins/processors/awsappsignals/internal/resolver/attributesresolver_test.go +++ b/plugins/processors/awsappsignals/internal/resolver/attributesresolver_test.go @@ -11,6 +11,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "go.opentelemetry.io/collector/pdata/pcommon" + + attr "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/internal/attributes" ) type MockSubResolver struct { @@ -27,6 +29,43 @@ func (m *MockSubResolver) Stop(ctx context.Context) error { return args.Error(0) } +func TestHostedInAttributeResolverWithNoConfiguredName(t *testing.T) { + resolver := newHostedInAttributeResolver("", DefaultHostedInAttributes) + + attributes := pcommon.NewMap() + resourceAttributes := pcommon.NewMap() + + resolver.Process(attributes, resourceAttributes) + envAttr, ok := attributes.Get(attr.HostedInEnvironment) + assert.True(t, ok) + assert.Equal(t, "Generic", envAttr.AsString()) +} + +func TestHostedInAttributeResolverWithConfiguredName(t *testing.T) { + resolver := newHostedInAttributeResolver("test", DefaultHostedInAttributes) + + attributes := pcommon.NewMap() + resourceAttributes := pcommon.NewMap() + + resolver.Process(attributes, resourceAttributes) + envAttr, ok := attributes.Get(attr.HostedInEnvironment) + assert.True(t, ok) + assert.Equal(t, "test", envAttr.AsString()) +} + +func TestHostedInAttributeResolverWithConflictedName(t *testing.T) { + resolver := newHostedInAttributeResolver("test", DefaultHostedInAttributes) + + attributes := pcommon.NewMap() + resourceAttributes := pcommon.NewMap() + resourceAttributes.PutStr(attr.AWSHostedInEnvironment, "self-defined") + + resolver.Process(attributes, resourceAttributes) + envAttr, ok := attributes.Get(attr.HostedInEnvironment) + assert.True(t, ok) + assert.Equal(t, "self-defined", envAttr.AsString()) +} + func TestAttributesResolver_Process(t *testing.T) { attributes := pcommon.NewMap() resourceAttributes := pcommon.NewMap() diff --git a/plugins/processors/awsappsignals/internal/resolver/eks.go b/plugins/processors/awsappsignals/internal/resolver/eks.go index 5c2dfb65b6..290862a675 100644 --- a/plugins/processors/awsappsignals/internal/resolver/eks.go +++ b/plugins/processors/awsappsignals/internal/resolver/eks.go @@ -663,8 +663,9 @@ type eksHostedInAttributeResolver struct { attributeMap map[string]string } -func newEKSHostedInAttributeResolver() *eksHostedInAttributeResolver { +func newEKSHostedInAttributeResolver(clusterName string) *eksHostedInAttributeResolver { return &eksHostedInAttributeResolver{ + clusterName: clusterName, attributeMap: map[string]string{ semconv.AttributeK8SNamespaceName: attr.HostedInK8SNamespace, }, @@ -677,23 +678,7 @@ func (h *eksHostedInAttributeResolver) Process(attributes, resourceAttributes pc } } - if h.clusterName != "" { - attributes.PutStr(attr.HostedInClusterName, h.clusterName) - } else { - platform, _ := resourceAttributes.Get(semconv.AttributeCloudProvider) - if platform.AsString() == semconv.AttributeCloudProviderAWS { - // iterate resource attributes to find the cluster name - resourceAttributes.Range(func(key string, value pcommon.Value) bool { - if strings.HasPrefix(key, "ec2.tag.kubernetes.io/cluster/") && value.Type() == pcommon.ValueTypeStr && value.AsString() == "owned" { - h.clusterName = strings.TrimPrefix(key, "ec2.tag.kubernetes.io/cluster/") - attributes.PutStr(attr.HostedInClusterName, h.clusterName) - return false - } - return true - }) - } - } - + attributes.PutStr(attr.HostedInClusterName, h.clusterName) return nil } diff --git a/plugins/processors/awsappsignals/internal/resolver/eks_test.go b/plugins/processors/awsappsignals/internal/resolver/eks_test.go index 5f92a55f80..c33b672f59 100644 --- a/plugins/processors/awsappsignals/internal/resolver/eks_test.go +++ b/plugins/processors/awsappsignals/internal/resolver/eks_test.go @@ -825,14 +825,13 @@ func TestHostedInEksResolver(t *testing.T) { } } - resolver := newEKSHostedInAttributeResolver() + resolver := newEKSHostedInAttributeResolver("test-cluster") // Test case 1 and 2: resourceAttributes contains "k8s.namespace.name" and EKS cluster name attributes := pcommon.NewMap() resourceAttributes := pcommon.NewMap() resourceAttributes.PutStr("cloud.provider", "aws") resourceAttributes.PutStr("k8s.namespace.name", "test-namespace-3") - resourceAttributes.PutStr("ec2.tag.kubernetes.io/cluster/test-cluster", "owned") err := resolver.Process(attributes, resourceAttributes) assert.NoError(t, err) assert.Equal(t, "test-namespace-3", getStrAttr(attributes, attr.HostedInK8SNamespace, t)) diff --git a/plugins/processors/awsappsignals/processor.go b/plugins/processors/awsappsignals/processor.go index f92d50ec4d..3fe73e356e 100644 --- a/plugins/processors/awsappsignals/processor.go +++ b/plugins/processors/awsappsignals/processor.go @@ -12,6 +12,7 @@ import ( "go.opentelemetry.io/collector/pdata/ptrace" "go.uber.org/zap" + appsignalsconfig "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/config" "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/internal/normalizer" "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/internal/resolver" "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/rules" @@ -37,7 +38,7 @@ type stopper interface { type awsappsignalsprocessor struct { logger *zap.Logger - config *Config + config *appsignalsconfig.Config replaceActions *rules.ReplaceActions allowlistMutators []allowListMutator metricMutators []attributesMutator diff --git a/plugins/processors/awsappsignals/processor_test.go b/plugins/processors/awsappsignals/processor_test.go index 1793aaad33..60defaf078 100644 --- a/plugins/processors/awsappsignals/processor_test.go +++ b/plugins/processors/awsappsignals/processor_test.go @@ -12,6 +12,7 @@ import ( "go.opentelemetry.io/collector/pdata/ptrace" "go.uber.org/zap" + "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/config" "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/rules" ) @@ -59,8 +60,8 @@ func TestProcessMetrics(t *testing.T) { logger, _ := zap.NewDevelopment() ap := &awsappsignalsprocessor{ logger: logger, - config: &Config{ - Resolvers: []string{"test"}, + config: &config.Config{ + Resolvers: []config.Resolver{config.NewGenericResolver("")}, Rules: testRules, }, } @@ -103,8 +104,8 @@ func TestProcessTraces(t *testing.T) { logger, _ := zap.NewDevelopment() ap := &awsappsignalsprocessor{ logger: logger, - config: &Config{ - Resolvers: []string{"test"}, + config: &config.Config{ + Resolvers: []config.Resolver{config.NewGenericResolver("")}, Rules: testRules, }, } diff --git a/plugins/processors/awsappsignals/testdata/config_eks.yaml b/plugins/processors/awsappsignals/testdata/config_eks.yaml new file mode 100644 index 0000000000..2d00d37565 --- /dev/null +++ b/plugins/processors/awsappsignals/testdata/config_eks.yaml @@ -0,0 +1,31 @@ +awsappsignals: + resolvers: + - platform: eks + name: test + rules: + - selectors: + - dimension: Operation + match: "* /api/visits/*" + - dimension: RemoteOperation + match: "*" + action: keep + rule_name: "keep01" + + - selectors: + - dimension: RemoteService + match: "UnknownRemoteService" + - dimension: RemoteOperation + match: "GetShardIterator" + action: drop + + - selectors: + - dimension: Operation + match: "* /api/visits/*" + - dimension: RemoteOperation + match: "*" + replacements: + - target_dimension: RemoteOperation + value: ListPetsByCustomer + - target_dimension: ResourceTarget + value: ' ' + action: replace \ No newline at end of file diff --git a/plugins/processors/awsappsignals/testdata/config.yaml b/plugins/processors/awsappsignals/testdata/config_generic.yaml similarity index 95% rename from plugins/processors/awsappsignals/testdata/config.yaml rename to plugins/processors/awsappsignals/testdata/config_generic.yaml index 71c5c84e97..e875c741f4 100644 --- a/plugins/processors/awsappsignals/testdata/config.yaml +++ b/plugins/processors/awsappsignals/testdata/config_generic.yaml @@ -1,5 +1,6 @@ awsappsignals: - resolvers: [eks] + resolvers: + - platform: generic rules: - selectors: - dimension: Operation diff --git a/translator/config/sampleSchema/validMetricsWithAppSignals.json b/translator/config/sampleSchema/validMetricsWithAppSignals.json new file mode 100644 index 0000000000..c97ed1c2bb --- /dev/null +++ b/translator/config/sampleSchema/validMetricsWithAppSignals.json @@ -0,0 +1,44 @@ +{ + "agent": { + "region": "us-west-2", + "debug": true + }, + "traces": { + "traces_collected": { + "app_signals": {} + } + }, + "logs": { + "metrics_collected": { + "app_signals": { + "hosted_in": "test", + "rules": [ + { + "selectors": [ + { + "dimension": "Service", + "match": "pet-clinic-frontend" + }, + { + "dimension": "RemoteService", + "match": "customers-service" + } + ], + "action": "keep", + "rule_name": "keep01" + }, + { + "selectors": [ + { + "dimension": "Operation", + "match": "GET *" + } + ], + "action": "drop", + "rule_name": "drop01" + } + ] + } + } + } +} \ No newline at end of file diff --git a/translator/config/schema.json b/translator/config/schema.json index cdef086ac7..0ab4e1d17d 100644 --- a/translator/config/schema.json +++ b/translator/config/schema.json @@ -514,6 +514,11 @@ "app_signals": { "type": "object", "properties": { + "hosted_in": { + "type": "string", + "minLength": 1, + "maxLength": 1024 + }, "rules": { "description": "Custom rules defined by customer", "type": "array", diff --git a/translator/tocwconfig/sampleConfig/appsignals_and_kubernetes_config.json b/translator/tocwconfig/sampleConfig/appsignals_and_kubernetes_config.json index 9585df211b..b2b98310c7 100644 --- a/translator/tocwconfig/sampleConfig/appsignals_and_kubernetes_config.json +++ b/translator/tocwconfig/sampleConfig/appsignals_and_kubernetes_config.json @@ -5,6 +5,7 @@ "logs": { "metrics_collected": { "app_signals": { + "hosted_in": "TestCluster" }, "kubernetes": { "cluster_name": "TestCluster", diff --git a/translator/tocwconfig/sampleConfig/appsignals_and_kubernetes_config.yaml b/translator/tocwconfig/sampleConfig/appsignals_and_kubernetes_config.yaml index 149f15fecf..2fce71b1c4 100644 --- a/translator/tocwconfig/sampleConfig/appsignals_and_kubernetes_config.yaml +++ b/translator/tocwconfig/sampleConfig/appsignals_and_kubernetes_config.yaml @@ -294,7 +294,8 @@ extensions: processors: awsappsignals: resolvers: - - eks + - platform: eks + name: TestCluster rules: [] batch/containerinsights: metadata_cardinality_limit: 1000 diff --git a/translator/tocwconfig/sampleConfig/base_appsignals_config.yaml b/translator/tocwconfig/sampleConfig/base_appsignals_config.yaml index 0e8a662357..cf1f6a302b 100644 --- a/translator/tocwconfig/sampleConfig/base_appsignals_config.yaml +++ b/translator/tocwconfig/sampleConfig/base_appsignals_config.yaml @@ -134,7 +134,8 @@ extensions: processors: awsappsignals: resolvers: - - generic + - name: "" + platform: generic rules: [] resourcedetection: aks: diff --git a/translator/translate/otel/processor/awsappsignals/testdata/config_eks.yaml b/translator/translate/otel/processor/awsappsignals/testdata/config_eks.yaml index 06bf8b38d1..b0a89474a2 100644 --- a/translator/translate/otel/processor/awsappsignals/testdata/config_eks.yaml +++ b/translator/translate/otel/processor/awsappsignals/testdata/config_eks.yaml @@ -1 +1,3 @@ -resolvers: ["eks"] \ No newline at end of file +resolvers: + - platform: eks + name: test \ No newline at end of file diff --git a/translator/translate/otel/processor/awsappsignals/testdata/config_generic.yaml b/translator/translate/otel/processor/awsappsignals/testdata/config_generic.yaml index 7524660208..15ab5b3129 100644 --- a/translator/translate/otel/processor/awsappsignals/testdata/config_generic.yaml +++ b/translator/translate/otel/processor/awsappsignals/testdata/config_generic.yaml @@ -1 +1,2 @@ -resolvers: ["generic"] \ No newline at end of file +resolvers: + - platform: generic \ No newline at end of file diff --git a/translator/translate/otel/processor/awsappsignals/testdata/invalidRulesConfig.json b/translator/translate/otel/processor/awsappsignals/testdata/invalidRulesConfig.json index 1c8bd7e378..e1f8d8cec5 100644 --- a/translator/translate/otel/processor/awsappsignals/testdata/invalidRulesConfig.json +++ b/translator/translate/otel/processor/awsappsignals/testdata/invalidRulesConfig.json @@ -2,6 +2,7 @@ "logs": { "metrics_collected": { "app_signals": { + "hosted_in": "test", "rules": [ { "selectors": [ diff --git a/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfig.json b/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfig.json index 7d6252542d..caaae63bc8 100644 --- a/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfig.json +++ b/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfig.json @@ -2,6 +2,7 @@ "logs": { "metrics_collected": { "app_signals": { + "hosted_in": "test", "rules": [ { "selectors": [ diff --git a/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfigEKS.yaml b/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfigEKS.yaml index 0d69e235f6..4508e78ffb 100644 --- a/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfigEKS.yaml +++ b/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfigEKS.yaml @@ -1,4 +1,6 @@ -resolvers: ["eks"] +resolvers: + - platform: eks + name: test rules: - selectors: - dimension: Operation diff --git a/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfigGeneric.yaml b/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfigGeneric.yaml index d3453e91ee..fb570a879c 100644 --- a/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfigGeneric.yaml +++ b/translator/translate/otel/processor/awsappsignals/testdata/validRulesConfigGeneric.yaml @@ -1,4 +1,6 @@ -resolvers: ["generic"] +resolvers: + - platform: generic + name: test rules: - selectors: - dimension: Operation diff --git a/translator/translate/otel/processor/awsappsignals/translator.go b/translator/translate/otel/processor/awsappsignals/translator.go index de8c5f1d2a..528b90135a 100644 --- a/translator/translate/otel/processor/awsappsignals/translator.go +++ b/translator/translate/otel/processor/awsappsignals/translator.go @@ -12,7 +12,9 @@ import ( "go.opentelemetry.io/collector/processor" "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals" + appsignalsconfig "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/config" "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/rules" + "github.com/aws/amazon-cloudwatch-agent/translator/translate/logs/util" "github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/common" ) @@ -56,16 +58,27 @@ func (t *translator) ID() component.ID { func (t *translator) Translate(conf *confmap.Conf) (component.Config, error) { configKey := common.AppSignalsConfigKeys[t.dataType] - cfg := t.factory.CreateDefaultConfig().(*awsappsignals.Config) + cfg := t.factory.CreateDefaultConfig().(*appsignalsconfig.Config) + + hostedInConfigKey := common.ConfigKey(common.LogsKey, common.MetricsCollectedKey, common.AppSignals, "hosted_in") + hostedIn, hostedInConfigured := common.GetString(conf, hostedInConfigKey) if common.IsAppSignalsKubernetes() { - cfg.Resolvers = []string{"eks"} + if !hostedInConfigured { + hostedIn = util.GetClusterNameFromEc2Tagger() + } + cfg.Resolvers = []appsignalsconfig.Resolver{ + appsignalsconfig.NewEKSResolver(hostedIn), + } } else { - cfg.Resolvers = []string{"generic"} + cfg.Resolvers = []appsignalsconfig.Resolver{ + appsignalsconfig.NewGenericResolver(hostedIn), + } } + return t.translateCustomRules(conf, configKey, cfg) } -func (t *translator) translateCustomRules(conf *confmap.Conf, configKey string, cfg *awsappsignals.Config) (component.Config, error) { +func (t *translator) translateCustomRules(conf *confmap.Conf, configKey string, cfg *appsignalsconfig.Config) (component.Config, error) { var rulesList []rules.Rule rulesConfigKey := common.ConfigKey(configKey, common.AppSignalsRules) if conf.IsSet(rulesConfigKey) { diff --git a/translator/translate/otel/processor/awsappsignals/translator_test.go b/translator/translate/otel/processor/awsappsignals/translator_test.go index 217563e274..b2cf580a7b 100644 --- a/translator/translate/otel/processor/awsappsignals/translator_test.go +++ b/translator/translate/otel/processor/awsappsignals/translator_test.go @@ -15,6 +15,7 @@ import ( "go.opentelemetry.io/collector/confmap" "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals" + "github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsappsignals/config" "github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/common" ) @@ -51,7 +52,9 @@ func TestTranslate(t *testing.T) { input: map[string]interface{}{ "logs": map[string]interface{}{ "metrics_collected": map[string]interface{}{ - "app_signals": map[string]interface{}{}, + "app_signals": map[string]interface{}{ + "hosted_in": "test", + }, }, }}, want: validAppSignalsYamlEKS, @@ -93,12 +96,12 @@ func TestTranslate(t *testing.T) { assert.Equal(t, testCase.wantErr, err) if err == nil { require.NotNil(t, got) - gotCfg, ok := got.(*awsappsignals.Config) + gotCfg, ok := got.(*config.Config) require.True(t, ok) wantCfg := factory.CreateDefaultConfig() yamlConfig, err := common.GetYamlFileToYamlConfig(wantCfg, testCase.want) require.NoError(t, err) - assert.Equal(t, yamlConfig.(*awsappsignals.Config), gotCfg) + assert.Equal(t, yamlConfig.(*config.Config), gotCfg) } }) }