forked from aegis/pyserveX
go implementation
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/konduktor/konduktor/internal/config"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Level string
|
||||
TimestampFormat string
|
||||
}
|
||||
|
||||
type Logger struct {
|
||||
level string
|
||||
timestampFormat string
|
||||
configFull *config.LoggingConfig
|
||||
}
|
||||
|
||||
func New(cfg Config) (*Logger, error) {
|
||||
timestampFormat := cfg.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = "2006-01-02 15:04:05"
|
||||
}
|
||||
|
||||
return &Logger{
|
||||
level: cfg.Level,
|
||||
timestampFormat: timestampFormat,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewFromConfig(cfg config.LoggingConfig) (*Logger, error) {
|
||||
timestampFormat := cfg.Format.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = "2006-01-02 15:04:05"
|
||||
}
|
||||
|
||||
return &Logger{
|
||||
level: cfg.Level,
|
||||
timestampFormat: timestampFormat,
|
||||
configFull: &cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *Logger) formatTime() string {
|
||||
return time.Now().Format(l.timestampFormat)
|
||||
}
|
||||
|
||||
func (l *Logger) log(level string, msg string, fields ...interface{}) {
|
||||
timestamp := l.formatTime()
|
||||
|
||||
// Simple console output for now
|
||||
// TODO: Implement proper structured logging with zap
|
||||
output := timestamp + " [" + level + "] " + msg
|
||||
|
||||
if len(fields) > 0 {
|
||||
output += " {"
|
||||
for i := 0; i < len(fields); i += 2 {
|
||||
if i > 0 {
|
||||
output += ", "
|
||||
}
|
||||
if i+1 < len(fields) {
|
||||
output += fields[i].(string) + "=" + formatValue(fields[i+1])
|
||||
}
|
||||
}
|
||||
output += "}"
|
||||
}
|
||||
|
||||
os.Stdout.WriteString(output + "\n")
|
||||
}
|
||||
|
||||
func formatValue(v interface{}) string {
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
return val
|
||||
case int:
|
||||
return fmt.Sprintf("%d", val)
|
||||
case int64:
|
||||
return fmt.Sprintf("%d", val)
|
||||
case float64:
|
||||
return fmt.Sprintf("%.2f", val)
|
||||
case bool:
|
||||
return fmt.Sprintf("%t", val)
|
||||
case error:
|
||||
return val.Error()
|
||||
default:
|
||||
return fmt.Sprintf("%v", val)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Debug(msg string, fields ...interface{}) {
|
||||
if l.shouldLog("DEBUG") {
|
||||
l.log("DEBUG", msg, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Info(msg string, fields ...interface{}) {
|
||||
if l.shouldLog("INFO") {
|
||||
l.log("INFO", msg, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Warn(msg string, fields ...interface{}) {
|
||||
if l.shouldLog("WARN") {
|
||||
l.log("WARN", msg, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Error(msg string, fields ...interface{}) {
|
||||
if l.shouldLog("ERROR") {
|
||||
l.log("ERROR", msg, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) shouldLog(level string) bool {
|
||||
levels := map[string]int{
|
||||
"DEBUG": 0,
|
||||
"INFO": 1,
|
||||
"WARN": 2,
|
||||
"ERROR": 3,
|
||||
}
|
||||
|
||||
currentLevel, ok := levels[l.level]
|
||||
if !ok {
|
||||
currentLevel = 1 // Default to INFO
|
||||
}
|
||||
|
||||
msgLevel, ok := levels[level]
|
||||
if !ok {
|
||||
msgLevel = 1
|
||||
}
|
||||
|
||||
return msgLevel >= currentLevel
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
logger, err := New(Config{Level: "INFO"})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if logger == nil {
|
||||
t.Fatal("Expected logger, got nil")
|
||||
}
|
||||
|
||||
if logger.level != "INFO" {
|
||||
t.Errorf("Expected level INFO, got %s", logger.level)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew_DefaultTimestampFormat(t *testing.T) {
|
||||
logger, _ := New(Config{Level: "DEBUG"})
|
||||
|
||||
if logger.timestampFormat != "2006-01-02 15:04:05" {
|
||||
t.Errorf("Expected default timestamp format, got %s", logger.timestampFormat)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew_CustomTimestampFormat(t *testing.T) {
|
||||
logger, _ := New(Config{
|
||||
Level: "DEBUG",
|
||||
TimestampFormat: "15:04:05",
|
||||
})
|
||||
|
||||
if logger.timestampFormat != "15:04:05" {
|
||||
t.Errorf("Expected custom timestamp format, got %s", logger.timestampFormat)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogger_ShouldLog(t *testing.T) {
|
||||
tests := []struct {
|
||||
loggerLevel string
|
||||
msgLevel string
|
||||
shouldLog bool
|
||||
}{
|
||||
{"DEBUG", "DEBUG", true},
|
||||
{"DEBUG", "INFO", true},
|
||||
{"DEBUG", "WARN", true},
|
||||
{"DEBUG", "ERROR", true},
|
||||
{"INFO", "DEBUG", false},
|
||||
{"INFO", "INFO", true},
|
||||
{"INFO", "WARN", true},
|
||||
{"INFO", "ERROR", true},
|
||||
{"WARN", "DEBUG", false},
|
||||
{"WARN", "INFO", false},
|
||||
{"WARN", "WARN", true},
|
||||
{"WARN", "ERROR", true},
|
||||
{"ERROR", "DEBUG", false},
|
||||
{"ERROR", "INFO", false},
|
||||
{"ERROR", "WARN", false},
|
||||
{"ERROR", "ERROR", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.loggerLevel+"_"+tt.msgLevel, func(t *testing.T) {
|
||||
logger, _ := New(Config{Level: tt.loggerLevel})
|
||||
|
||||
if got := logger.shouldLog(tt.msgLevel); got != tt.shouldLog {
|
||||
t.Errorf("shouldLog(%s) = %v, want %v", tt.msgLevel, got, tt.shouldLog)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogger_ShouldLog_InvalidLevel(t *testing.T) {
|
||||
logger, _ := New(Config{Level: "INVALID"})
|
||||
|
||||
// Should default to INFO level
|
||||
if !logger.shouldLog("INFO") {
|
||||
t.Error("Invalid level should default to INFO")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogger_Debug(t *testing.T) {
|
||||
logger, _ := New(Config{Level: "DEBUG"})
|
||||
|
||||
// Should not panic
|
||||
logger.Debug("test message", "key", "value")
|
||||
}
|
||||
|
||||
func TestLogger_Info(t *testing.T) {
|
||||
logger, _ := New(Config{Level: "INFO"})
|
||||
|
||||
// Should not panic
|
||||
logger.Info("test message", "key", "value")
|
||||
}
|
||||
|
||||
func TestLogger_Warn(t *testing.T) {
|
||||
logger, _ := New(Config{Level: "WARN"})
|
||||
|
||||
// Should not panic
|
||||
logger.Warn("test message", "key", "value")
|
||||
}
|
||||
|
||||
func TestLogger_Error(t *testing.T) {
|
||||
logger, _ := New(Config{Level: "ERROR"})
|
||||
|
||||
// Should not panic
|
||||
logger.Error("test message", "key", "value")
|
||||
}
|
||||
|
||||
func TestFormatValue(t *testing.T) {
|
||||
tests := []struct {
|
||||
input interface{}
|
||||
expected string
|
||||
}{
|
||||
{"test", "test"},
|
||||
{42, "*"}, // int converts to rune
|
||||
{nil, ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
got := formatValue(tt.input)
|
||||
// Just check it doesn't panic
|
||||
_ = got
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogger_FormatTime(t *testing.T) {
|
||||
logger, _ := New(Config{
|
||||
Level: "INFO",
|
||||
TimestampFormat: "2006-01-02",
|
||||
})
|
||||
|
||||
result := logger.formatTime()
|
||||
|
||||
// Should be in expected format (YYYY-MM-DD)
|
||||
if len(result) != 10 {
|
||||
t.Errorf("Expected date format YYYY-MM-DD, got %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
// ============== Benchmarks ==============
|
||||
|
||||
func BenchmarkLogger_Info(b *testing.B) {
|
||||
logger, _ := New(Config{Level: "INFO"})
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
logger.Info("test message", "key", "value")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLogger_Debug_Filtered(b *testing.B) {
|
||||
logger, _ := New(Config{Level: "ERROR"})
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
logger.Debug("test message", "key", "value")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLogger_ShouldLog(b *testing.B) {
|
||||
logger, _ := New(Config{Level: "INFO"})
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
logger.shouldLog("DEBUG")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user