Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[exporter/awsemfexporter] add tags feature for Cloudwatch Log Group #19406

Merged
merged 29 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
52e29ba
Add set tags to config
humivo Mar 3, 2023
639d0c1
Add config to cloudwatchlogsexporter too
humivo Mar 7, 2023
e25c61f
Add unit testing to aws emf
humivo Mar 8, 2023
08215ec
Add unit testing for other code changes and update README
humivo Mar 8, 2023
fb8c6c7
Add chlog entry
humivo Mar 8, 2023
e5c93d7
Merge branch 'main' into SetTagsLogGroup
humivo Mar 8, 2023
9792497
Fix issue number
humivo Mar 8, 2023
d086990
Change naming to accountID
humivo Mar 8, 2023
a56ab0c
Add sts endpoint and fix validate func
humivo Mar 16, 2023
80c0914
Fix import
humivo Mar 16, 2023
1af294c
Merge branch 'main' into SetTagsLogGroup
humivo Mar 16, 2023
6a72fec
Add comments to client code
humivo Mar 16, 2023
0e32886
Move functions to utils.go
humivo Mar 28, 2023
2ab601c
Remove line
humivo Mar 28, 2023
37403f4
Change tags call
humivo Apr 26, 2023
aa69c3d
Merge branch 'main' into SetTagsLogGroup
humivo Apr 26, 2023
57be341
Fix code after merge
humivo Apr 26, 2023
2ac02ce
Fix spelling error
humivo Apr 26, 2023
3576ddb
gci the file
humivo Apr 26, 2023
c3acf58
gci the exporter files
humivo Apr 26, 2023
71eb45c
Add gci option prefix
humivo Apr 26, 2023
27a640a
Add comment to cwlog_client
humivo Apr 27, 2023
ed6562f
Address comments on PR
humivo Apr 27, 2023
3701061
Improve testing
humivo May 9, 2023
18dacb3
Run gci command
humivo May 9, 2023
5a64e2d
Merge branch 'main' into SetTagsLogGroup
humivo May 9, 2023
5e99c16
Fix license header
humivo May 9, 2023
71e81c3
Simplify return statement
humivo May 11, 2023
26df4c3
Run gci command on code
humivo May 11, 2023
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
16 changes: 16 additions & 0 deletions .chloggen/add-tags-log-group.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: awsemfexporter

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Added a `tags` field to the config of the exporter to set tags for a Cloudwatch Log Group

# One or more tracking issues related to the change
issues: [19406]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
2 changes: 2 additions & 0 deletions exporter/awscloudwatchlogsexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The following settings can be optionally configured:
- `region`: The AWS region where the log stream is in.
- `endpoint`: The CloudWatch Logs service endpoint which the requests are forwarded to. [See the CloudWatch Logs endpoints](https://docs.aws.amazon.com/general/latest/gr/cwl_region.html) for a list.
- `log_retention`: LogRetention is the option to set the log retention policy for only newly created CloudWatch Log Groups. Defaults to Never Expire if not specified or set to 0. Possible values for retention in days are 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 2192, 2557, 2922, 3288, or 3653.
- `tags`: Tags is the option to set tags for the CloudWatch Log Group. If specified, please add at most 50 tags. Input is a string to string map like so: { 'key': 'value' }. Keys must be between 1-128 characters and follow the regex pattern: `^([\p{L}\p{Z}\p{N}_.:/=+\-@]+)$`. Values must be between 1-256 characters and follow the regex pattern: `^([\p{L}\p{Z}\p{N}_.:/=+\-@]*)$`.
- `role_arn`: The AWS IAM role to upload segments to a same/different account
- `raw_log`: Boolean default false. If you want to export only the log message to cw logs. This is required for emf logs.

Expand All @@ -49,6 +50,7 @@ exporters:
role_arn: "arn:aws:iam::123456789:role/monitoring-application-logs"
endpoint: "logs.us-east-1.amazonaws.com"
log_retention: 365
tags: { 'sampleKey': 'sampleValue'}
sending_queue:
queue_size: 50
retry_on_failure:
Expand Down
43 changes: 11 additions & 32 deletions exporter/awscloudwatchlogsexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"go.uber.org/zap"

"github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/awsutil"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/cwlogs"
)

// Config represent a configuration for the CloudWatch logs exporter.
Expand All @@ -46,6 +47,11 @@ type Config struct {
// Possible values are 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 2192, 2557, 2922, 3288, or 3653
LogRetention int64 `mapstructure:"log_retention"`

// Tags is the option to set tags for the CloudWatch Log Group. If specified, please add add at least 1 and at most 50 tags. Input is a string to string map like so: { 'key': 'value' }
// Keys must be between 1-128 characters and follow the regex pattern: ^([\p{L}\p{Z}\p{N}_.:/=+\-@]+)$
// Values must be between 1-256 characters and follow the regex pattern: ^([\p{L}\p{Z}\p{N}_.:/=+\-@]*)$
Tags map[string]*string `mapstructure:"tags"`

// QueueSettings is a subset of exporterhelper.QueueSettings,
// because only QueueSize is user-settable due to how AWS CloudWatch API works
QueueSettings QueueSettings `mapstructure:"sending_queue"`
Expand Down Expand Up @@ -77,41 +83,14 @@ func (config *Config) Validate() error {
if config.QueueSettings.QueueSize < 1 {
return errors.New("'sending_queue.queue_size' must be 1 or greater")
}
if !isValidRetentionValue(config.LogRetention) {
if !cwlogs.IsValidRetentionValue(config.LogRetention) {
return errors.New("invalid value for retention policy. Please make sure to use the following values: 0 (Never Expire), 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 2192, 2557, 2922, 3288, or 3653")
}
Aneurysm9 marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

// Added function to check if value is an accepted number of log retention days
func isValidRetentionValue(input int64) bool {
switch input {
case
0,
1,
3,
5,
7,
14,
30,
60,
90,
120,
150,
180,
365,
400,
545,
731,
1827,
2192,
2557,
2922,
3288,
3653:
return true
tagInputErr := cwlogs.ValidateTagsInput(config.Tags)
if tagInputErr != nil {
return errors.New(tagInputErr.Error())
Aneurysm9 marked this conversation as resolved.
Show resolved Hide resolved
}
return false
return nil
}

func (config *Config) enforcedQueueSettings() exporterhelper.QueueSettings {
Expand Down
151 changes: 150 additions & 1 deletion exporter/awscloudwatchlogsexporter/config_test.go
Aneurysm9 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package awscloudwatchlogsexporter

import (
"path/filepath"
"strconv"
"testing"

"github.com/cenkalti/backoff/v4"
Expand Down Expand Up @@ -142,6 +143,154 @@ func TestRetentionValidateWrong(t *testing.T) {
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.Error(t, wrongcfg.Validate())
assert.Error(t, component.ValidateConfig(wrongcfg))

}

func TestTagsValidateCorrect(t *testing.T) {
defaultRetrySettings := exporterhelper.NewDefaultRetrySettings()
avalue := "avalue"
cfg := &Config{
RetrySettings: defaultRetrySettings,
LogGroupName: "test-1",
LogStreamName: "testing",
Endpoint: "",
Tags: map[string]*string{"akey": &avalue},
AWSSessionSettings: awsutil.CreateDefaultSessionConfig(),
QueueSettings: QueueSettings{
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.NoError(t, component.ValidateConfig(cfg))

}

func TestTagsValidateTooManyTags(t *testing.T) {
m := make(map[string]*string)
avalue := "avalue"
for i := 0; i < 51; i++ {
m[strconv.Itoa(i)] = &avalue
}
defaultRetrySettings := exporterhelper.NewDefaultRetrySettings()
wrongcfg := &Config{
RetrySettings: defaultRetrySettings,
LogGroupName: "test-1",
LogStreamName: "testing",
Endpoint: "",
Tags: m,
AWSSessionSettings: awsutil.CreateDefaultSessionConfig(),
QueueSettings: QueueSettings{
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.EqualError(t, component.ValidateConfig(wrongcfg), "invalid amount of items. Please input at most 50 tags")
}

func TestTagsValidateWrongKeyRegex(t *testing.T) {
avalue := "avalue"
defaultRetrySettings := exporterhelper.NewDefaultRetrySettings()
wrongcfg := &Config{
RetrySettings: defaultRetrySettings,
LogGroupName: "test-1",
LogStreamName: "testing",
Endpoint: "",
Tags: map[string]*string{"***": &avalue},
AWSSessionSettings: awsutil.CreateDefaultSessionConfig(),
QueueSettings: QueueSettings{
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.EqualError(t, component.ValidateConfig(wrongcfg), "key - *** does not follow the regex pattern"+`^([\p{L}\p{Z}\p{N}_.:/=+\-@]+)$`)
}

func TestTagsValidateWrongValueRegex(t *testing.T) {
avalue := "***"
defaultRetrySettings := exporterhelper.NewDefaultRetrySettings()
wrongcfg := &Config{
RetrySettings: defaultRetrySettings,
LogGroupName: "test-1",
LogStreamName: "testing",
Endpoint: "",
Tags: map[string]*string{"akey": &avalue},
AWSSessionSettings: awsutil.CreateDefaultSessionConfig(),
QueueSettings: QueueSettings{
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.EqualError(t, component.ValidateConfig(wrongcfg), "value - "+avalue+" does not follow the regex pattern"+`^([\p{L}\p{Z}\p{N}_.:/=+\-@]*)$`)
}

func TestTagsValidateKeyTooShort(t *testing.T) {
avalue := "avalue"
defaultRetrySettings := exporterhelper.NewDefaultRetrySettings()
wrongcfg := &Config{
RetrySettings: defaultRetrySettings,
LogGroupName: "test-1",
LogStreamName: "testing",
Endpoint: "",
Tags: map[string]*string{"": &avalue},
AWSSessionSettings: awsutil.CreateDefaultSessionConfig(),
QueueSettings: QueueSettings{
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.EqualError(t, component.ValidateConfig(wrongcfg), "key - has an invalid length. Please use keys with a length of 1 to 128 characters")
}

func TestTagsValidateKeyTooLong(t *testing.T) {
avalue := "avalue"
akey := ""
for i := 0; i < 129; i++ {
akey += "a"
}
Aneurysm9 marked this conversation as resolved.
Show resolved Hide resolved
defaultRetrySettings := exporterhelper.NewDefaultRetrySettings()
wrongcfg := &Config{
RetrySettings: defaultRetrySettings,
LogGroupName: "test-1",
LogStreamName: "testing",
Endpoint: "",
Tags: map[string]*string{"": &avalue},
Aneurysm9 marked this conversation as resolved.
Show resolved Hide resolved
AWSSessionSettings: awsutil.CreateDefaultSessionConfig(),
QueueSettings: QueueSettings{
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.Error(t, component.ValidateConfig(wrongcfg), "key - "+akey+" has an invalid length. Please use keys with a length of 1 to 128 characters")
}

func TestTagsValidateValueTooShort(t *testing.T) {
avalue := ""
defaultRetrySettings := exporterhelper.NewDefaultRetrySettings()
wrongcfg := &Config{
RetrySettings: defaultRetrySettings,
LogGroupName: "test-1",
LogStreamName: "testing",
Endpoint: "",
Tags: map[string]*string{"akey": &avalue},
AWSSessionSettings: awsutil.CreateDefaultSessionConfig(),
QueueSettings: QueueSettings{
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.Error(t, component.ValidateConfig(wrongcfg), "value - "+avalue+" has an invalid length. Please use keys with a length of 1 to 256 characters")
}

func TestTagsValidateValueTooLong(t *testing.T) {
avalue := ""
for i := 0; i < 257; i++ {
avalue += "a"
}
Aneurysm9 marked this conversation as resolved.
Show resolved Hide resolved
defaultRetrySettings := exporterhelper.NewDefaultRetrySettings()
wrongcfg := &Config{
RetrySettings: defaultRetrySettings,
LogGroupName: "test-1",
LogStreamName: "testing",
Endpoint: "",
Tags: map[string]*string{"akey": &avalue},
AWSSessionSettings: awsutil.CreateDefaultSessionConfig(),
QueueSettings: QueueSettings{
QueueSize: exporterhelper.NewDefaultQueueSettings().QueueSize,
},
}
assert.Error(t, component.ValidateConfig(wrongcfg), "value - "+avalue+" has an invalid length. Please use keys with a length of 1 to 256 characters")
}
2 changes: 1 addition & 1 deletion exporter/awscloudwatchlogsexporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func newCwLogsPusher(expConfig *Config, params exp.CreateSettings) (*exporter, e
}

// create CWLogs client with aws session config
svcStructuredLog := cwlogs.NewClient(params.Logger, awsConfig, params.BuildInfo, expConfig.LogGroupName, expConfig.LogRetention, session)
svcStructuredLog := cwlogs.NewClient(params.Logger, awsConfig, params.BuildInfo, expConfig.LogGroupName, expConfig.LogRetention, expConfig.Tags, session)
collectorIdentifier, err := uuid.NewRandom()

if err != nil {
Expand Down
Loading