Prechádzať zdrojové kódy

add additional log levels, and testing (#3138)

Signed-off-by: Alex Meijer <alexander.meijer@ibm.com>
Alex Meijer 1 rok pred
rodič
commit
e3060a9e7a
2 zmenil súbory, kde vykonal 296 pridanie a 0 odobranie
  1. 12 0
      core/pkg/log/log.go
  2. 284 0
      core/pkg/log/log_test.go

+ 12 - 0
core/pkg/log/log.go

@@ -73,6 +73,10 @@ func SetLogLevel(l string) error {
 	return nil
 	return nil
 }
 }
 
 
+func Error(msg string) {
+	log.Error().Msg(msg)
+}
+
 func Errorf(format string, a ...interface{}) {
 func Errorf(format string, a ...interface{}) {
 	log.Error().Msgf(format, a...)
 	log.Error().Msgf(format, a...)
 }
 }
@@ -88,6 +92,10 @@ func DedupedErrorf(logTypeLimit int, format string, a ...interface{}) {
 	}
 	}
 }
 }
 
 
+func Warn(msg string) {
+	log.Warn().Msg(msg)
+}
+
 func Warnf(format string, a ...interface{}) {
 func Warnf(format string, a ...interface{}) {
 	log.Warn().Msgf(format, a...)
 	log.Warn().Msgf(format, a...)
 }
 }
@@ -142,6 +150,10 @@ func Tracef(format string, a ...interface{}) {
 	log.Trace().Msgf(format, a...)
 	log.Trace().Msgf(format, a...)
 }
 }
 
 
+func Fatal(msg string) {
+	log.Fatal().Msg(msg)
+}
+
 func Fatalf(format string, a ...interface{}) {
 func Fatalf(format string, a ...interface{}) {
 	log.Fatal().Msgf(format, a...)
 	log.Fatal().Msgf(format, a...)
 }
 }

+ 284 - 0
core/pkg/log/log_test.go

@@ -3,10 +3,14 @@ package log
 import (
 import (
 	"bytes"
 	"bytes"
 	"encoding/json"
 	"encoding/json"
+	"fmt"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
+	"time"
 
 
 	"github.com/rs/zerolog"
 	"github.com/rs/zerolog"
+	"github.com/rs/zerolog/log"
+	"github.com/spf13/viper"
 )
 )
 
 
 func TestGetLogger(t *testing.T) {
 func TestGetLogger(t *testing.T) {
@@ -62,3 +66,283 @@ func parseLogMessage(t *testing.T, logMessage string) map[string]interface{} {
 	}
 	}
 	return loggedData
 	return loggedData
 }
 }
+
+func TestInitLogging(t *testing.T) {
+	// Save original logger and restore it after tests
+	originalLogger := log.Logger
+	defer func() {
+		log.Logger = originalLogger
+	}()
+
+	// Test cases
+	tests := []struct {
+		name                   string
+		format                 string
+		level                  string
+		disableColor           bool
+		showLogLevelSetMessage bool
+		expectedLevel          zerolog.Level
+	}{
+		{
+			name:                   "default settings",
+			format:                 "pretty",
+			level:                  "info",
+			disableColor:           false,
+			showLogLevelSetMessage: true,
+			expectedLevel:          zerolog.InfoLevel,
+		},
+		{
+			name:                   "json format",
+			format:                 "json",
+			level:                  "debug",
+			disableColor:           false,
+			showLogLevelSetMessage: false,
+			expectedLevel:          zerolog.DebugLevel,
+		},
+		{
+			name:                   "invalid level",
+			format:                 "pretty",
+			level:                  "invalid",
+			disableColor:           false,
+			showLogLevelSetMessage: false,
+			expectedLevel:          zerolog.InfoLevel,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			viper.Set(flagFormat, tt.format)
+			viper.Set(flagLevel, tt.level)
+			viper.Set(flagDisableColor, tt.disableColor)
+
+			InitLogging(tt.showLogLevelSetMessage)
+
+			if zerolog.GlobalLevel() != tt.expectedLevel {
+				t.Errorf("expected level %v, got %v", tt.expectedLevel, zerolog.GlobalLevel())
+			}
+		})
+	}
+}
+
+func TestLogLevelManagement(t *testing.T) {
+	// Save original logger and restore it after tests
+	originalLogger := log.Logger
+	defer func() {
+		log.Logger = originalLogger
+	}()
+
+	tests := []struct {
+		name        string
+		level       string
+		expectError bool
+	}{
+		{"valid level - debug", "debug", false},
+		{"valid level - info", "info", false},
+		{"valid level - warn", "warn", false},
+		{"valid level - error", "error", false},
+		{"invalid level", "invalid", true},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			err := SetLogLevel(tt.level)
+			if (err != nil) != tt.expectError {
+				t.Errorf("SetLogLevel() error = %v, expectError %v", err, tt.expectError)
+			}
+
+			if !tt.expectError {
+				currentLevel := GetLogLevel()
+				if currentLevel != tt.level {
+					t.Errorf("GetLogLevel() = %v, want %v", currentLevel, tt.level)
+				}
+			}
+		})
+	}
+}
+
+func TestLoggingFunctions(t *testing.T) {
+	// Create a buffer to capture log output
+	var buf bytes.Buffer
+	logger := zerolog.New(&buf)
+	SetLogger(&logger)
+
+	// Set log level to trace to ensure all messages are captured
+	zerolog.SetGlobalLevel(zerolog.TraceLevel)
+
+	tests := []struct {
+		name     string
+		logFunc  func(string)
+		logMsg   string
+		expected string
+	}{
+		{"Error", Error, "test error", "error"},
+		{"Warn", Warn, "test warning", "warn"},
+		{"Info", Info, "test info", "info"},
+		{"Debug", Debug, "test debug", "debug"},
+		{"Trace", Trace, "test trace", "trace"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			buf.Reset()
+			tt.logFunc(tt.logMsg)
+			output := buf.String()
+			if !strings.Contains(output, tt.expected) {
+				t.Errorf("expected log level %s in output, got: %s", tt.expected, output)
+			}
+		})
+	}
+
+	// Test Fatal separately since it calls os.Exit
+	t.Run("Fatal", func(t *testing.T) {
+		// Create a new buffer for Fatal test
+		var fatalBuf bytes.Buffer
+		fatalLogger := zerolog.New(&fatalBuf)
+		SetLogger(&fatalLogger)
+
+		// We can't actually test the Fatal function since it calls os.Exit
+		// Instead, we'll verify that the Fatal function exists by checking its type
+		// and that it can be assigned to a variable of the correct type
+		var fatalFunc func(string) = Fatal
+		if fatalFunc == nil {
+			t.Error("Fatal function is nil")
+		}
+	})
+}
+
+func TestDedupedLogging(t *testing.T) {
+	// Create a buffer to capture log output
+	var buf bytes.Buffer
+	logger := zerolog.New(&buf)
+	SetLogger(&logger)
+
+	tests := []struct {
+		name         string
+		logFunc      func(int, string, ...interface{})
+		logTypeLimit int
+		format       string
+		args         []interface{}
+	}{
+		{
+			name:         "DedupedErrorf",
+			logFunc:      DedupedErrorf,
+			logTypeLimit: 3,
+			format:       "test error %d",
+			args:         []interface{}{1},
+		},
+		{
+			name:         "DedupedWarningf",
+			logFunc:      DedupedWarningf,
+			logTypeLimit: 2,
+			format:       "test warning %d",
+			args:         []interface{}{1},
+		},
+		{
+			name:         "DedupedInfof",
+			logFunc:      DedupedInfof,
+			logTypeLimit: 4,
+			format:       "test info %d",
+			args:         []interface{}{1},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			buf.Reset()
+			// Log up to the limit
+			for i := 0; i < tt.logTypeLimit+1; i++ {
+				tt.logFunc(tt.logTypeLimit, tt.format, tt.args...)
+			}
+
+			output := buf.String()
+			// Count occurrences of the exact log message (excluding the suppression message)
+			exactMsg := fmt.Sprintf(tt.format, tt.args...)
+			count := strings.Count(output, exactMsg) - 1 // Subtract 1 for the suppression message
+
+			if count != tt.logTypeLimit {
+				t.Errorf("expected %d occurrences of log message, got %d", tt.logTypeLimit, count)
+			}
+
+			// Verify suppression message
+			suppressionMsg := fmt.Sprintf("%s logged %d times: suppressing future logs", exactMsg, tt.logTypeLimit)
+			if !strings.Contains(output, suppressionMsg) {
+				t.Error("expected suppression message in output")
+			}
+		})
+	}
+}
+
+func TestProfiling(t *testing.T) {
+	// Create a buffer to capture log output
+	var buf bytes.Buffer
+	logger := zerolog.New(&buf)
+	SetLogger(&logger)
+
+	t.Run("Profilef", func(t *testing.T) {
+		buf.Reset()
+		Profilef("test profile %d", 1)
+		output := buf.String()
+		if !strings.Contains(output, "[Profiler]") {
+			t.Error("expected [Profiler] in output")
+		}
+	})
+
+	t.Run("Profile", func(t *testing.T) {
+		buf.Reset()
+		start := time.Now()
+		time.Sleep(10 * time.Millisecond) // Ensure some time has passed
+		Profile(start, "test operation")
+		output := buf.String()
+		if !strings.Contains(output, "test operation") {
+			t.Error("expected operation name in output")
+		}
+	})
+
+	t.Run("ProfileWithThreshold", func(t *testing.T) {
+		buf.Reset()
+		start := time.Now()
+		time.Sleep(10 * time.Millisecond)
+		ProfileWithThreshold(start, 5*time.Millisecond, "test operation")
+		output := buf.String()
+		if !strings.Contains(output, "test operation") {
+			t.Error("expected operation name in output")
+		}
+
+		// Test with threshold not exceeded
+		buf.Reset()
+		start = time.Now()
+		ProfileWithThreshold(start, 100*time.Millisecond, "test operation")
+		output = buf.String()
+		if output != "" {
+			t.Error("expected no output when threshold not exceeded")
+		}
+	})
+}
+
+func TestLoggerManagement(t *testing.T) {
+	// Save original logger and restore it after tests
+	originalLogger := log.Logger
+	defer func() {
+		log.Logger = originalLogger
+	}()
+
+	// Create a new logger with a unique field to identify it
+	var buf bytes.Buffer
+	newLogger := zerolog.New(&buf).With().Str("test_id", "unique_logger").Logger()
+
+	// Test GetLogger
+	currentLogger := GetLogger()
+	if currentLogger == nil {
+		t.Error("GetLogger() returned nil")
+	}
+
+	// Test SetLogger
+	SetLogger(&newLogger)
+
+	// Log a message and verify it contains our unique identifier
+	Info("test message")
+	output := buf.String()
+	if !strings.Contains(output, "unique_logger") {
+		t.Error("SetLogger() did not set the logger correctly")
+	}
+}