From 6be4431a1138922be364d2b4cdc248d3ed26c807 Mon Sep 17 00:00:00 2001 From: Jonathan Hess Date: Tue, 12 Aug 2025 14:33:29 -0600 Subject: [PATCH 1/2] Rebased and updated dependencies. --- cmd/root.go | 2 +- go.mod | 1 - go.sum | 4 -- internal/log/log.go | 102 ++++++++++++++++++++++++++------------------ 4 files changed, 61 insertions(+), 48 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 3ab5d69d3..d30b0b9fc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -579,7 +579,7 @@ func loadConfig(c *Command, args []string, opts []Option) error { // Handle logger separately from config if c.conf.StructuredLogs { - c.logger, c.cleanup = log.NewStructuredLogger(c.conf.Quiet) + c.logger = log.NewStructuredLogger(c.conf.Quiet) } if c.conf.Quiet { diff --git a/go.mod b/go.mod index 9a04e0ecd..91e1f5433 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,6 @@ require ( github.com/spf13/pflag v1.0.6 github.com/spf13/viper v1.20.1 go.opencensus.io v0.24.0 - go.uber.org/zap v1.27.0 golang.org/x/oauth2 v0.30.0 golang.org/x/sys v0.34.0 google.golang.org/api v0.241.0 diff --git a/go.sum b/go.sum index aa818aea5..1e8b296f1 100644 --- a/go.sum +++ b/go.sum @@ -1230,16 +1230,12 @@ go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/internal/log/log.go b/internal/log/log.go index 6779ee6dd..33e5fa53f 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -15,36 +15,42 @@ package log import ( + "fmt" "io" llog "log" + "log/slog" "os" + "time" "github.com/GoogleCloudPlatform/cloud-sql-proxy/v2/cloudsql" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" +) + +const ( + googLvlKey = "severity" + googMsgKey = "message" + googSourceKey = "sourceLocation" + googTimeKey = "timestamp" ) // StdLogger is the standard logger that distinguishes between info and error // logs. type StdLogger struct { - infoLog *llog.Logger - debugLog *llog.Logger - errLog *llog.Logger + stdLog *llog.Logger + errLog *llog.Logger } // NewStdLogger create a Logger that uses out and err for informational and // error messages. func NewStdLogger(out, err io.Writer) cloudsql.Logger { return &StdLogger{ - infoLog: llog.New(out, "", llog.LstdFlags), - debugLog: llog.New(out, "", llog.LstdFlags), - errLog: llog.New(err, "", llog.LstdFlags), + stdLog: llog.New(out, "", llog.LstdFlags), + errLog: llog.New(err, "", llog.LstdFlags), } } // Infof logs informational messages func (l *StdLogger) Infof(format string, v ...interface{}) { - l.infoLog.Printf(format, v...) + l.stdLog.Printf(format, v...) } // Errorf logs error messages @@ -54,61 +60,73 @@ func (l *StdLogger) Errorf(format string, v ...interface{}) { // Debugf logs debug messages func (l *StdLogger) Debugf(format string, v ...interface{}) { - l.debugLog.Printf(format, v...) + l.stdLog.Printf(format, v...) } // StructuredLogger writes log messages in JSON. type StructuredLogger struct { - logger *zap.SugaredLogger + stdLog *slog.Logger + errLog *slog.Logger } // Infof logs informational messages func (l *StructuredLogger) Infof(format string, v ...interface{}) { - l.logger.Infof(format, v...) + l.stdLog.Info(fmt.Sprintf(format, v...)) } // Errorf logs error messages func (l *StructuredLogger) Errorf(format string, v ...interface{}) { - l.logger.Errorf(format, v...) + l.errLog.Error(fmt.Sprintf(format, v...)) } // Debugf logs debug messages func (l *StructuredLogger) Debugf(format string, v ...interface{}) { - l.logger.Debugf(format, v...) + l.stdLog.Debug(fmt.Sprintf(format, v...)) } // NewStructuredLogger creates a Logger that logs messages using JSON. -func NewStructuredLogger(quiet bool) (cloudsql.Logger, func() error) { - // Configure structured logs to adhere to LogEntry format - // https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry - c := zap.NewProductionEncoderConfig() - c.LevelKey = "severity" - c.MessageKey = "message" - c.TimeKey = "timestamp" - c.EncodeLevel = zapcore.CapitalLevelEncoder - c.EncodeTime = zapcore.ISO8601TimeEncoder - - enc := zapcore.NewJSONEncoder(c) - - var syncer zapcore.WriteSyncer - // quiet disables writing to the info log +func NewStructuredLogger(quiet bool) cloudsql.Logger { + var infoHandler, errorHandler slog.Handler if quiet { - syncer = zapcore.AddSync(io.Discard) + infoHandler = slog.DiscardHandler } else { - syncer = zapcore.Lock(os.Stdout) + infoHandler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, + ReplaceAttr: replaceAttr, + }) } - core := zapcore.NewTee( - zapcore.NewCore(enc, syncer, zap.LevelEnablerFunc(func(l zapcore.Level) bool { - // Anything below error, goes to the info log. - return l < zapcore.ErrorLevel - })), - zapcore.NewCore(enc, zapcore.Lock(os.Stderr), zap.LevelEnablerFunc(func(l zapcore.Level) bool { - // Anything at error or higher goes to the error log. - return l >= zapcore.ErrorLevel - })), - ) + errorHandler = slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ + Level: slog.LevelError, + ReplaceAttr: replaceAttr, + }) + l := &StructuredLogger{ - logger: zap.New(core).Sugar(), + stdLog: slog.New(infoHandler), + errLog: slog.New(errorHandler), + } + return l +} + +// replaceAttr remaps default Go logging keys to adhere to LogEntry format +// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry +func replaceAttr(groups []string, a slog.Attr) slog.Attr { + if groups == nil { + if a.Key == slog.LevelKey { + a.Key = googLvlKey + return a + } else if a.Key == slog.MessageKey { + a.Key = googMsgKey + return a + } else if a.Key == slog.SourceKey { + a.Key = googSourceKey + return a + } else if a.Key == slog.TimeKey { + a.Key = googTimeKey + if a.Value.Kind() == slog.KindTime { + a.Value = slog.StringValue(a.Value.Time().Format(time.RFC3339)) + } + return a + } } - return l, l.logger.Sync + return a } From b19513a463526eecc40f5bd543091fe3ceef2840 Mon Sep 17 00:00:00 2001 From: Daniel Andersson Date: Mon, 12 May 2025 23:58:01 +0200 Subject: [PATCH 2/2] refactor: early returns + inline constants --- internal/log/log.go | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/internal/log/log.go b/internal/log/log.go index 33e5fa53f..b88a968ca 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -25,13 +25,6 @@ import ( "github.com/GoogleCloudPlatform/cloud-sql-proxy/v2/cloudsql" ) -const ( - googLvlKey = "severity" - googMsgKey = "message" - googSourceKey = "sourceLocation" - googTimeKey = "timestamp" -) - // StdLogger is the standard logger that distinguishes between info and error // logs. type StdLogger struct { @@ -110,22 +103,21 @@ func NewStructuredLogger(quiet bool) cloudsql.Logger { // replaceAttr remaps default Go logging keys to adhere to LogEntry format // https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry func replaceAttr(groups []string, a slog.Attr) slog.Attr { - if groups == nil { - if a.Key == slog.LevelKey { - a.Key = googLvlKey - return a - } else if a.Key == slog.MessageKey { - a.Key = googMsgKey - return a - } else if a.Key == slog.SourceKey { - a.Key = googSourceKey - return a - } else if a.Key == slog.TimeKey { - a.Key = googTimeKey - if a.Value.Kind() == slog.KindTime { - a.Value = slog.StringValue(a.Value.Time().Format(time.RFC3339)) - } - return a + if groups != nil { + return a + } + + switch a.Key { + case slog.LevelKey: + a.Key = "severity" + case slog.MessageKey: + a.Key = "message" + case slog.SourceKey: + a.Key = "sourceLocation" + case slog.TimeKey: + a.Key = "timestamp" + if a.Value.Kind() == slog.KindTime { + a.Value = slog.StringValue(a.Value.Time().Format(time.RFC3339)) } } return a