//go:build unit // +build unit // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package logger import ( "os" "testing" "github.com/cihub/seelog" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" mock_seelog "github.com/aws/amazon-ecs-agent/ecs-agent/logger/mocks" ) func init() { format := os.Getenv(LOG_OUTPUT_FORMAT_ENV_VAR) if format == "" { os.Setenv(LOG_OUTPUT_FORMAT_ENV_VAR, logFmt) } reloadConfig() } func globalLoggerBackup() func() { loggerMux.RLock() seeLoggerBkp := seelog.Current structuredLoggerBkp := globalStructuredLogger loggerMux.RUnlock() return func() { loggerMux.Lock() defer loggerMux.Unlock() seelog.ReplaceLogger(seeLoggerBkp) globalStructuredLogger = structuredLoggerBkp } } func TestNewStructuredLogger(t *testing.T) { sl := newStructuredLogger(logFmt) assert.Equal(t, defaultStructuredTextFormatter, sl.formatter) sl = newStructuredLogger(jsonFmt) assert.Equal(t, defaultStructuredJsonFormatter, sl.formatter) } // note: this also tests the global structured logger functions func TestStructuredLogger(t *testing.T) { defer globalLoggerBackup()() sl := newStructuredLogger(logFmt) for _, tc := range []struct { expectedLevel seelog.LogLevel funcToTest []func(string, ...Fields) }{ { seelog.LogLevel(seelog.TraceLvl), []func(string, ...Fields){ sl.Trace, Trace, }, }, { seelog.LogLevel(seelog.DebugLvl), []func(string, ...Fields){ sl.Debug, Debug, }, }, {seelog.LogLevel(seelog.InfoLvl), []func(string, ...Fields){ sl.Info, Info, }, }, {seelog.LogLevel(seelog.WarnLvl), []func(string, ...Fields){ sl.Warn, Warn, }, }, {seelog.LogLevel(seelog.ErrorLvl), []func(string, ...Fields){ sl.Error, Error, }, }, {seelog.LogLevel(seelog.CriticalLvl), []func(string, ...Fields){ sl.Critical, Critical, }, }, } { t.Run(tc.expectedLevel.String(), func(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockReceiver := mock_seelog.NewMockCustomReceiver(ctrl) seeLog, err := seelog.LoggerFromCustomReceiver(mockReceiver) require.NoError(t, err) setGlobalLogger(seeLog, logFmt) mockReceiver.EXPECT().ReceiveMessage( `logger=structured msg="Live long and prosper 🖖🏼" f1="field value with \"quotation\" marks"`, tc.expectedLevel, gomock.Any(), ).Times(2) mockReceiver.EXPECT().Flush().AnyTimes() mockReceiver.EXPECT().Close().AnyTimes() for _, logfunc := range tc.funcToTest { logfunc("Live long and prosper 🖖🏼", Fields{ "f1": `field value with "quotation" marks`, }) } }) } } func BenchmarkStructuredLogger_Info(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { Info("Live long and prosper 🖖🏼", Fields{ "field1": "field value 1", "field2": "field value 2", "field3": "field value 3", }) } } func BenchmarkSeelog_Info(b *testing.B) { for n := 0; n < b.N; n++ { seelog.Infof("Live long and prosper 🖖🏼 %s=%s %s=%s %s=%s", "field1", "field value 1", "field2", "field value 2", "field3", "field value 3") } }