Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions processor/awsapplicationsignalsprocessor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# AWS AppSignals Processor for Amazon Cloudwatch Agent

The AWS AppSignals processor is used to reduce the cardinality of telemetry metrics and traces before exporting them to CloudWatch Logs via [EMF](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/awsemfexporter) and [X-Ray](github.com/open-telemetry/opentelemetry-collector-contrib/exporter/awsxrayexporter) respectively.
It reduces the cardinality of metrics/traces via 3 types of actions, `keep`, `drop` and `replace`, which are configured by users. CloudWatch Agent(CWA) customers will configure these rules with their CWA configurations.

Note: Traces support only `replace` actions and are implicitly pulled from the logs section of the CWA configuration

| Status | |
| ------------------------ |---------------------------|
| Stability | [beta] |
| Supported pipeline types | metrics, traces |
| Distributions | [amazon-cloudwatch-agent] |

## Exporter Configuration

The following exporter configuration parameters are supported.

| Name | Description | Default |
|:---------------------------------------------|:------------------------------------------------------------------------------------------------------------------|---------|
| `resolvers` | Platform processor is being configured for. Currently supports EKS. EC2 platform will be supported in the future. | [eks] |
| `rules` | Custom configuration rules used for filtering metrics/traces. Can be of type `drop`, `keep`, `replace`. | [] |

### rules
The rules section defines the rules (filters) to be applied

| Name | Description | Default |
|:---------------|:-------------------------------------------------------------------------------------------------------------------------| --- |
| `selectors` | List of metrics/traces dimension matchers. | [] |
| `action` | Action being applied for the specified selector. `keep`, `drop`, `replace` | "" |
| `rule_name` | (Optional) Name of rule. | [] |
| `replacements` | (Optional) List of metrics/traces replacements to be executed. Based on specified selectors. requires `action = replace` | [] |

#### selectors
A selectors section defines a matching against the dimensions of incoming metrics/traces.

| Name | Description | Default |
|:------------|:--------------------------------------------------------------| ------ |
| `dimension` | Dimension of metrics/traces | "" |
| `match` | glob used for matching values of dimensions | "" |

### replacements
A replacements section defines a matching against the dimensions of incoming metrics/traces for which value replacements will be done. action must be `replace`

| Name | Description | Default |
|:-------------------|:----------------------------------------------| ------ |
| `target_dimension` | Dimension to replace | "" |
| `value` | Value to replace current dimension value with | "" |


## AWS AppSignals Processor Configuration Example

```yaml
awsapplicationsignals:
resolvers: ["eks"]
rules:
- selectors:
- dimension: Operation
match: "POST *"
- dimension: RemoteService
match: "*"
action: keep
rule_name: "keep01"
- selectors:
- dimension: Operation
match: "GET *"
- dimension: RemoteService
match: "*"
action: keep
rule_name: "keep02"
- selectors:
- dimension: Operation
match: "POST *"
action: drop
rule_name: "drop01"
- selectors:
- dimension: Operation
match: "*"
replacements:
- target_dimension: RemoteOperation
value: "This is a test string"
action: replace
rule_name: "replace01"
```

## Amazon CloudWatch Agent Configuration Example
Comment thread
jefchien marked this conversation as resolved.
Outdated

```json
{
"agent": {
"region": "us-west-2",
"debug": true
},
"traces": {
"traces_collected": {
"app_signals": {}
}
},
"logs": {
"metrics_collected": {
"app_signals": {
"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"
}
}
}
}
}
```
65 changes: 65 additions & 0 deletions processor/awsapplicationsignalsprocessor/common/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT

package common

// Metric attribute used as CloudWatch metric dimension.
const (
CWMetricAttributeLocalService = "Service"
CWMetricAttributeLocalOperation = "Operation"
CWMetricAttributeEnvironment = "Environment"
CWMetricAttributeRemoteService = "RemoteService"
CWMetricAttributeRemoteEnvironment = "RemoteEnvironment"
CWMetricAttributeRemoteOperation = "RemoteOperation"
CWMetricAttributeRemoteResourceIdentifier = "RemoteResourceIdentifier"
CWMetricAttributeRemoteResourceType = "RemoteResourceType"
)

// Platform attribute used as CloudWatch EMF log field and X-Ray trace annotation.
const (
AttributePlatformType = "PlatformType"
AttributeEKSClusterName = "EKS.Cluster"
AttributeK8SClusterName = "K8s.Cluster"
AttributeK8SNamespace = "K8s.Namespace"
AttributeK8SWorkload = "K8s.Workload"
AttributeK8SPod = "K8s.Pod"
AttributeEC2AutoScalingGroup = "EC2.AutoScalingGroup"
AttributeEC2InstanceId = "EC2.InstanceId"
AttributeHost = "Host"
)

// Platform attribute used as CloudWatch EMF log field.
const (
MetricAttributeECSCluster = "ECS.Cluster"
MetricAttributeECSTaskId = "ECS.TaskId"
MetricAttributeECSTaskDefinitionFamily = "ECS.TaskDefinitionFamily"
MetricAttributeECSTaskDefinitionRevision = "ECS.TaskDefinitionRevision"
)

// Telemetry attributes used as CloudWatch EMF log fields.
const (
MetricAttributeTelemetrySDK = "Telemetry.SDK"
MetricAttributeTelemetryAgent = "Telemetry.Agent"
MetricAttributeTelemetrySource = "Telemetry.Source"
)

// Resource attributes used as CloudWatch EMF log fields.
const (
MetricAttributeRemoteDbUser = "RemoteDbUser"
MetricAttributeRemoteResourceCfnPrimaryIdentifier = "RemoteResourceCfnPrimaryIdentifier"
)

const (
AttributeTmpReserved = "aws.tmp.reserved"
)

var CWMetricAttributes = []string{
CWMetricAttributeLocalService,
CWMetricAttributeLocalOperation,
CWMetricAttributeEnvironment,
CWMetricAttributeRemoteService,
CWMetricAttributeRemoteEnvironment,
CWMetricAttributeRemoteOperation,
CWMetricAttributeRemoteResourceIdentifier,
CWMetricAttributeRemoteResourceType,
}
75 changes: 75 additions & 0 deletions processor/awsapplicationsignalsprocessor/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT

package config

import (
"context"
"errors"
"time"

"github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsapplicationsignals/rules"
)

type Config struct {
Resolvers []Resolver `mapstructure:"resolvers"`
Rules []rules.Rule `mapstructure:"rules"`
Limiter *LimiterConfig `mapstructure:"limiter"`
}

type LimiterConfig struct {
Threshold int `mapstructure:"drop_threshold"`
Disabled bool `mapstructure:"disabled"`
LogDroppedMetrics bool `mapstructure:"log_dropped_metrics"`
RotationInterval time.Duration `mapstructure:"rotation_interval"`
GarbageCollectionInterval time.Duration `mapstructure:"garbage_collection_interval"`
ParentContext context.Context `mapstructure:"-"`
}

const (
DefaultThreshold = 500
DefaultRotationInterval = 1 * time.Hour
DefaultGCInterval = 10 * time.Minute
)

func NewDefaultLimiterConfig() *LimiterConfig {
return &LimiterConfig{
Threshold: DefaultThreshold,
Disabled: false,
LogDroppedMetrics: false,
RotationInterval: DefaultRotationInterval,
GarbageCollectionInterval: DefaultGCInterval,
}
}

func (lc *LimiterConfig) Validate() {
if lc.GarbageCollectionInterval == 0 {
lc.GarbageCollectionInterval = DefaultGCInterval
}
}

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 PlatformK8s:
if resolver.Name == "" {
return errors.New("name must not be empty for k8s resolver")
}
case PlatformEC2, PlatformECS, PlatformGeneric:
default:
return errors.New("unknown resolver")
}
}

if cfg.Limiter != nil {
cfg.Limiter.Validate()
}
return nil
}
82 changes: 82 additions & 0 deletions processor/awsapplicationsignalsprocessor/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// 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) {
tests := []struct {
name string
resolver Resolver
}{
{
"testEKS",
NewEKSResolver("test"),
},
{
"testK8S",
NewK8sResolver("test"),
},
{
"testEC2",
NewEC2Resolver("test"),
},
{
"testECS",
NewECSResolver("test"),
},
{
"testGeneric",
NewGenericResolver("test"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := Config{
Resolvers: []Resolver{tt.resolver},
Rules: nil,
}
assert.Nil(t, config.Validate())

})
}
}

func TestValidateFailedOnEmptyResolver(t *testing.T) {
config := Config{
Resolvers: []Resolver{},
Rules: nil,
}
assert.NotNil(t, config.Validate())
}

func TestValidateFailedOnEmptyResolverName(t *testing.T) {
tests := []struct {
name string
resolver Resolver
}{
{
"testEKS",
NewEKSResolver(""),
},
{
"testK8S",
NewK8sResolver(""),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := Config{
Resolvers: []Resolver{tt.resolver},
Rules: nil,
}
assert.NotNil(t, config.Validate())

})
}
}
Loading