diff --git a/plugins/outputs/cloudwatchlogs/pusher.go b/plugins/outputs/cloudwatchlogs/pusher.go index 19f717f124..2ac9e46ad5 100644 --- a/plugins/outputs/cloudwatchlogs/pusher.go +++ b/plugins/outputs/cloudwatchlogs/pusher.go @@ -340,10 +340,7 @@ func (p *pusher) createLogGroupAndStream() error { p.Log.Debugf("creating stream fail due to : %v", err) if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == cloudwatchlogs.ErrCodeResourceNotFoundException { - _, err = p.Service.CreateLogGroup(&cloudwatchlogs.CreateLogGroupInput{ - LogGroupName: &p.Group, - LogGroupClass: &p.Class, - }) + err = p.createLogGroup() // attempt to create stream again if group created successfully. if err == nil { @@ -370,6 +367,21 @@ func (p *pusher) createLogGroupAndStream() error { return err } +func (p *pusher) createLogGroup() error { + var err error + if p.Class != "" { + _, err = p.Service.CreateLogGroup(&cloudwatchlogs.CreateLogGroupInput{ + LogGroupName: &p.Group, + LogGroupClass: &p.Class, + }) + } else { + _, err = p.Service.CreateLogGroup(&cloudwatchlogs.CreateLogGroupInput{ + LogGroupName: &p.Group, + }) + } + return err +} + func (p *pusher) putRetentionPolicy() { if p.Retention > 0 { i := aws.Int64(int64(p.Retention)) diff --git a/translator/defaultKeyCase.go b/translator/defaultKeyCase.go index 42488a542c..87f358a816 100644 --- a/translator/defaultKeyCase.go +++ b/translator/defaultKeyCase.go @@ -6,8 +6,6 @@ package translator import ( "fmt" "strings" - - "github.com/aws/amazon-cloudwatch-agent/tool/util" ) // DefaultCase check if current input overrides the default value for the given config entry key. @@ -95,10 +93,10 @@ func DefaultLogGroupClassCase(key string, defaultVal, input interface{}) (return //CreateLogGroup API only accepts values STANDARD or INFREQUENT_ACCESS returnVal = strings.ToUpper(classVal) } else { - returnVal = util.StandardLogGroupClass - AddErrorMessages( + AddInfoMessages( fmt.Sprintf("LogGroupClass key: %s", key), - fmt.Sprintf("%s value (%v) in is not a valid Log Group Class field. Defaulting to standard.", key, returnVal)) + fmt.Sprintf("%s value (%v) in is not a valid Log Group Class field. Agent will not set the LogGroupClass parameter.", key, returnVal)) + returnVal = "" } return diff --git a/translator/isValid.go b/translator/isValid.go index 54cfaf3cc9..47b52a2ece 100644 --- a/translator/isValid.go +++ b/translator/isValid.go @@ -94,5 +94,5 @@ func IsValidRetentionDays(days int) bool { } func IsValidLogGroupClass(class string) bool { - return slices.Contains(ValidLogGroupClasses, class) + return slices.Contains(ValidLogGroupClasses, class) || class == "" } diff --git a/translator/translate/logs/logs_collected/files/collect_list/collect_list_test.go b/translator/translate/logs/logs_collected/files/collect_list/collect_list_test.go index b6e6197c6a..5d023296e5 100644 --- a/translator/translate/logs/logs_collected/files/collect_list/collect_list_test.go +++ b/translator/translate/logs/logs_collected/files/collect_list/collect_list_test.go @@ -23,7 +23,7 @@ func TestFileConfig(t *testing.T) { f := new(FileConfig) var input interface{} e := json.Unmarshal([]byte(`{"collect_list":[{"file_path":"path1", - "log_group_name":"group1","log_stream_name":"LOG_STREAM_NAME"}]}`), &input) + "log_group_name":"group1","log_stream_name":"LOG_STREAM_NAME", "log_group_class":"STANDARD"}]}`), &input) if e != nil { assert.Fail(t, e.Error()) } @@ -56,7 +56,7 @@ func TestFileConfigOverride(t *testing.T) { "log_group_name": "group1", "pipe": false, "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) } @@ -85,7 +85,7 @@ func TestTimestampFormat(t *testing.T) { "timestamp_regex": "(\\d{2}:\\d{2}:\\d{2} \\d{2} \\w{3} \\s{0,1}\\d{1,2})", "timezone": "UTC", "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) } @@ -111,7 +111,7 @@ func TestTimestampFormatAll(t *testing.T) { "retention_in_days": -1, "timestamp_layout": []string{"15:04:05 06 Jan _2"}, "timestamp_regex": "(\\d{2}:\\d{2}:\\d{2} \\d{2} \\w{3} \\s{0,1}\\d{1,2})", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }}, }, { @@ -130,7 +130,7 @@ func TestTimestampFormatAll(t *testing.T) { "retention_in_days": -1, "timestamp_layout": []string{"1 _2 15:04:05", "01 _2 15:04:05"}, "timestamp_regex": "(\\d{1,2} \\s{0,1}\\d{1,2} \\d{2}:\\d{2}:\\d{2})", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }}, }, { @@ -149,7 +149,7 @@ func TestTimestampFormatAll(t *testing.T) { "retention_in_days": -1, "timestamp_layout": []string{"_2 1 15:04:05", "_2 01 15:04:05"}, "timestamp_regex": "(\\d{1,2} \\s{0,1}\\d{1,2} \\d{2}:\\d{2}:\\d{2})", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }}, }, { @@ -168,7 +168,7 @@ func TestTimestampFormatAll(t *testing.T) { "retention_in_days": -1, "timestamp_layout": []string{"Jan _2 15:04:05"}, "timestamp_regex": "(\\w{3} \\s{0,1}\\d{1,2} \\d{2}:\\d{2}:\\d{2})", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }}, }, { @@ -187,7 +187,7 @@ func TestTimestampFormatAll(t *testing.T) { "retention_in_days": -1, "timestamp_layout": []string{"Jan _2 15:04:05"}, "timestamp_regex": "(\\w{3} \\s{0,1}\\d{1,2} \\d{2}:\\d{2}:\\d{2})", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }}, }, { @@ -206,7 +206,7 @@ func TestTimestampFormatAll(t *testing.T) { "retention_in_days": -1, "timestamp_layout": []string{"5 _2 1 15:04:05", "5 _2 01 15:04:05"}, "timestamp_regex": "(\\d{1,2} \\s{0,1}\\d{1,2} \\s{0,1}\\d{1,2} \\d{2}:\\d{2}:\\d{2})", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }}, }, { @@ -225,7 +225,7 @@ func TestTimestampFormatAll(t *testing.T) { "retention_in_days": -1, "timestamp_layout": []string{"5 _2 01 15:04:05", "5 _2 1 15:04:05"}, "timestamp_regex": "(\\d{1,2} \\s{0,1}\\d{1,2} \\s{0,1}\\d{1,2} \\d{2}:\\d{2}:\\d{2})", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }}, }, } @@ -268,7 +268,7 @@ func TestTimestampFormat_NonZeroPadding(t *testing.T) { expectedRegex := "(\\d{1,2}:\\d{1,2}:\\d{1,2} \\d{2} \\s{0,1}\\d{1,2} \\s{0,1}\\d{1,2})" expectVal := []interface{}{map[string]interface{}{ "file_path": "path1", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "from_beginning": true, "pipe": false, "retention_in_days": -1, @@ -314,7 +314,7 @@ func TestTimestampFormat_SpecialCharacters(t *testing.T) { expectedRegex := "(\\^\\.\\*\\?\\|\\[\\(\\{\\d{2}:\\d{2}:\\d{2} \\d{2} \\w{3} \\s{0,1}\\d{1,2}\\}\\)\\]\\$)" expectVal := []interface{}{map[string]interface{}{ "file_path": "path1", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "from_beginning": true, "pipe": false, "retention_in_days": -1, @@ -354,7 +354,7 @@ func TestTimestampFormat_Template(t *testing.T) { expectedRegex := "(\\w{3} \\s{0,1}\\d{1,2} \\d{2}:\\d{2}:\\d{2})" expectVal := []interface{}{map[string]interface{}{ "file_path": "path1", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "from_beginning": true, "pipe": false, "retention_in_days": -1, @@ -412,7 +412,7 @@ func TestMultiLineStartPattern(t *testing.T) { "from_beginning": true, "pipe": false, "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "timestamp_layout": []string{"15:04:05 06 Jan _2"}, "timestamp_regex": "(\\d{2}:\\d{2}:\\d{2} \\d{2} \\w{3} \\s{0,1}\\d{1,2})", "timezone": "UTC", @@ -443,7 +443,7 @@ func TestEncoding(t *testing.T) { "from_beginning": true, "pipe": false, "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "timestamp_layout": []string{"15:04:05 06 Jan _2"}, "timestamp_regex": "(\\d{2}:\\d{2}:\\d{2} \\d{2} \\w{3} \\s{0,1}\\d{1,2})", "timezone": "UTC", @@ -472,7 +472,7 @@ func TestEncoding_Invalid(t *testing.T) { "file_path": "path1", "from_beginning": true, "pipe": false, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "retention_in_days": -1, }} assert.Equal(t, expectVal, val) @@ -501,7 +501,7 @@ func TestAutoRemoval(t *testing.T) { "from_beginning": true, "pipe": false, "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "auto_removal": true, }} assert.Equal(t, expectVal, val) @@ -524,7 +524,7 @@ func TestAutoRemoval(t *testing.T) { "pipe": false, "retention_in_days": -1, "auto_removal": false, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) @@ -544,7 +544,7 @@ func TestAutoRemoval(t *testing.T) { "from_beginning": true, "pipe": false, "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) } @@ -617,7 +617,7 @@ func TestPublishMultiLogs_WithBlackList(t *testing.T) { "from_beginning": true, "pipe": false, "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "blacklist": "^agent.log", "publish_multi_logs": true, "timezone": "UTC", @@ -644,7 +644,7 @@ func TestPublishMultiLogs_WithBlackList(t *testing.T) { "retention_in_days": -1, "publish_multi_logs": false, "timezone": "UTC", - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) @@ -664,7 +664,7 @@ func TestPublishMultiLogs_WithBlackList(t *testing.T) { "from_beginning": true, "pipe": false, "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) } @@ -688,7 +688,7 @@ func TestLogFilters(t *testing.T) { "from_beginning": true, "pipe": false, "retention_in_days": -1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", "filters": []interface{}{ map[string]interface{}{ "type": "include", @@ -730,14 +730,14 @@ func TestRetentionDifferentLogGroups(t *testing.T) { "pipe": false, "retention_in_days": 3, "from_beginning": true, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }, map[string]interface{}{ "file_path": "path1", "log_group_name": "test1", "pipe": false, "retention_in_days": 3, "from_beginning": true, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) } @@ -769,14 +769,14 @@ func TestDuplicateRetention(t *testing.T) { "pipe": false, "retention_in_days": 3, "from_beginning": true, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }, map[string]interface{}{ "file_path": "path1", "log_group_name": "test1", "pipe": false, "retention_in_days": 3, "from_beginning": true, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) } @@ -809,14 +809,14 @@ func TestConflictingRetention(t *testing.T) { "pipe": false, "retention_in_days": 3, "from_beginning": true, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }, map[string]interface{}{ "file_path": "path1", "log_group_name": "test1", "pipe": false, "retention_in_days": 5, "from_beginning": true, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, "Under path : /logs/logs_collected/files/collect_list/ | Error : Different retention_in_days values can't be set for the same log group: test1", translator.ErrorMessages[len(translator.ErrorMessages)-1]) assert.Equal(t, expectVal, val) @@ -849,14 +849,14 @@ func TestDifferentLogGroupClasses(t *testing.T) { "pipe": false, "retention_in_days": 3, "from_beginning": true, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }, map[string]interface{}{ "file_path": "path1", "log_group_name": "test1", "pipe": false, "retention_in_days": 3, "from_beginning": true, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }} assert.Equal(t, expectVal, val) } diff --git a/translator/translate/logs/logs_collected/files/collect_list/ruleLogGroupClass.go b/translator/translate/logs/logs_collected/files/collect_list/ruleLogGroupClass.go index b7839631f1..98484e36fa 100644 --- a/translator/translate/logs/logs_collected/files/collect_list/ruleLogGroupClass.go +++ b/translator/translate/logs/logs_collected/files/collect_list/ruleLogGroupClass.go @@ -1,10 +1,8 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT - package collect_list import ( - "github.com/aws/amazon-cloudwatch-agent/tool/util" "github.com/aws/amazon-cloudwatch-agent/translator" ) @@ -14,7 +12,7 @@ type LogGroupClass struct { } func (f *LogGroupClass) ApplyRule(input interface{}) (returnKey string, returnVal interface{}) { - _, returnVal = translator.DefaultLogGroupClassCase(LogGroupClassSectionKey, util.StandardLogGroupClass, input) + _, returnVal = translator.DefaultLogGroupClassCase(LogGroupClassSectionKey, "", input) returnKey = LogGroupClassSectionKey return } diff --git a/translator/translate/logs/logs_collected/files/collect_list/ruleLogGroupClass_test.go b/translator/translate/logs/logs_collected/files/collect_list/ruleLogGroupClass_test.go index 5358ea43d8..250e57faeb 100644 --- a/translator/translate/logs/logs_collected/files/collect_list/ruleLogGroupClass_test.go +++ b/translator/translate/logs/logs_collected/files/collect_list/ruleLogGroupClass_test.go @@ -1,6 +1,5 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT - package collect_list import ( @@ -38,7 +37,7 @@ func TestInvalidLogGroupClass(t *testing.T) { if e == nil { actualReturnKey, actualReturnValue := r.ApplyRule(input) assert.Equal(t, "log_group_class", actualReturnKey) - assert.Equal(t, util.StandardLogGroupClass, actualReturnValue) + assert.Equal(t, "", actualReturnValue) } else { panic(e) } @@ -53,7 +52,22 @@ func TestInvalidTypeLogGroupClass(t *testing.T) { if e == nil { actualReturnKey, actualReturnValue := r.ApplyRule(input) assert.Equal(t, "log_group_class", actualReturnKey) - assert.Equal(t, util.StandardLogGroupClass, actualReturnValue) + assert.Equal(t, "", actualReturnValue) + } else { + panic(e) + } +} + +func TestEmptyLogGroupClass(t *testing.T) { + r := new(LogGroupClass) + var input interface{} + e := json.Unmarshal([]byte(`{ + "log_group_class": "" + }`), &input) + if e == nil { + actualReturnKey, actualReturnValue := r.ApplyRule(input) + assert.Equal(t, "log_group_class", actualReturnKey) + assert.Equal(t, "", actualReturnValue) } else { panic(e) } diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go index 848920cdd4..0c7409dfe3 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go @@ -24,7 +24,8 @@ func TestApplyRule(t *testing.T) { "INFORMATION", "CRITICAL" ], - "log_group_name": "System" + "log_group_name": "System", + "log_group_class": "STANDARD" }, { "event_name": "Application", @@ -58,7 +59,7 @@ func TestApplyRule(t *testing.T) { "log_group_name": "Application", "batch_read_size": BatchReadSizeValue, "retention_in_days": 1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }, } @@ -85,7 +86,8 @@ func TestDuplicateRetention(t *testing.T) { "CRITICAL" ], "log_group_name": "System", - "retention_in_days": 3 + "retention_in_days": 3, + "log_group_class": "INFREQUENT_ACCESS" }, { "event_name": "Application", @@ -96,7 +98,8 @@ func TestDuplicateRetention(t *testing.T) { ], "event_format": "xml", "log_group_name": "System", - "retention_in_days": 3 + "retention_in_days": 3, + "log_group_class": "INFREQUENT_ACCESS" }, { "event_name": "Application", @@ -107,7 +110,8 @@ func TestDuplicateRetention(t *testing.T) { ], "event_format": "xml", "log_group_name": "System", - "retention_in_days": 3 + "retention_in_days": 3, + "log_group_class": "INFREQUENT_ACCESS" } ] } @@ -121,7 +125,7 @@ func TestDuplicateRetention(t *testing.T) { "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": 3, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": util.InfrequentAccessLogGroupClass, }, map[string]interface{}{ "event_name": "Application", @@ -130,7 +134,7 @@ func TestDuplicateRetention(t *testing.T) { "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": 3, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": util.InfrequentAccessLogGroupClass, }, map[string]interface{}{ "event_name": "Application", @@ -139,7 +143,7 @@ func TestDuplicateRetention(t *testing.T) { "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": 3, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": util.InfrequentAccessLogGroupClass, }, } @@ -192,7 +196,7 @@ func TestConflictingRetention(t *testing.T) { "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": 3, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }, map[string]interface{}{ "event_name": "Application", @@ -201,7 +205,7 @@ func TestConflictingRetention(t *testing.T) { "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": 1, - "log_group_class": util.StandardLogGroupClass, + "log_group_class": "", }, } diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/ruleLogGroupClass.go b/translator/translate/logs/logs_collected/windows_events/collect_list/ruleLogGroupClass.go index 71784e1a61..812935cedb 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/ruleLogGroupClass.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/ruleLogGroupClass.go @@ -4,7 +4,6 @@ package collectlist import ( - "github.com/aws/amazon-cloudwatch-agent/tool/util" "github.com/aws/amazon-cloudwatch-agent/translator" ) @@ -14,7 +13,7 @@ type LogGroupClass struct { } func (f *LogGroupClass) ApplyRule(input interface{}) (returnKey string, returnVal interface{}) { - _, returnVal = translator.DefaultLogGroupClassCase(LogGroupClassSectionKey, util.StandardLogGroupClass, input) + _, returnVal = translator.DefaultLogGroupClassCase(LogGroupClassSectionKey, "", input) returnKey = LogGroupClassSectionKey return }