| // Copyright 2015 Google Inc. 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. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License 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 logging contains helpers to support log messages. If you are using | |
| // the Cloud SQL Auth proxy as a Go library, you can override these variables to | |
| // control where log messages end up. | |
| package logging | |
| import ( | |
| "log" | |
| "os" | |
| "go.uber.org/zap" | |
| "go.uber.org/zap/zapcore" | |
| ) | |
| // Verbosef is called to write verbose logs, such as when a new connection is | |
| // established correctly. | |
| var Verbosef = log.Printf | |
| // Infof is called to write informational logs, such as when startup has | |
| var Infof = log.Printf | |
| // Errorf is called to write an error log, such as when a new connection fails. | |
| var Errorf = log.Printf | |
| // LogDebugToStdout updates Verbosef and Info logging to use stdout instead of stderr. | |
| func LogDebugToStdout() { | |
| logger := log.New(os.Stdout, "", log.LstdFlags) | |
| Verbosef = logger.Printf | |
| Infof = logger.Printf | |
| } | |
| func noop(string, ...interface{}) {} | |
| // LogVerboseToNowhere updates Verbosef so verbose log messages are discarded | |
| func LogVerboseToNowhere() { | |
| Verbosef = noop | |
| } | |
| // DisableLogging sets all logging levels to no-op's. | |
| func DisableLogging() { | |
| Verbosef = noop | |
| Infof = noop | |
| Errorf = noop | |
| } | |
| // EnableStructuredLogs replaces all logging functions with structured logging | |
| // variants. | |
| func EnableStructuredLogs(logDebugStdout, verbose bool) (func(), error) { | |
| // Configuration of zap is based on its Advanced Configuration example. | |
| // See: https://pkg.go.dev/go.uber.org/zap#example-package-AdvancedConfiguration | |
| // Define level-handling logic. | |
| highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { | |
| return lvl >= zapcore.ErrorLevel | |
| }) | |
| lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { | |
| return lvl < zapcore.ErrorLevel | |
| }) | |
| // Lock wraps a WriteSyncer in a mutex to make it safe for concurrent use. In | |
| // particular, *os.File types must be locked before use. | |
| consoleErrors := zapcore.Lock(os.Stderr) | |
| consoleDebugging := consoleErrors | |
| if logDebugStdout { | |
| consoleDebugging = zapcore.Lock(os.Stdout) | |
| } | |
| config := zap.NewProductionEncoderConfig() | |
| config.LevelKey = "severity" | |
| config.MessageKey = "message" | |
| config.TimeKey = "timestamp" | |
| config.EncodeLevel = zapcore.CapitalLevelEncoder | |
| config.EncodeTime = zapcore.ISO8601TimeEncoder | |
| consoleEncoder := zapcore.NewJSONEncoder(config) | |
| core := zapcore.NewTee( | |
| zapcore.NewCore(consoleEncoder, consoleErrors, highPriority), | |
| zapcore.NewCore(consoleEncoder, consoleDebugging, lowPriority), | |
| ) | |
| // By default, caller and stacktrace are not included, so add them here | |
| logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel)) | |
| sugar := logger.Sugar() | |
| Verbosef = sugar.Infof | |
| if !verbose { | |
| Verbosef = noop | |
| } | |
| Infof = sugar.Infof | |
| Errorf = sugar.Errorf | |
| return func() { | |
| logger.Sync() | |
| }, nil | |
| } |