| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- // Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved.
- // This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
- package common
- import (
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "os"
- "strings"
- "sync"
- "time"
- )
- //sdkLogger an interface for logging in the SDK
- type sdkLogger interface {
- //LogLevel returns the log level of sdkLogger
- LogLevel() int
- //Log logs v with the provided format if the current log level is loglevel
- Log(logLevel int, format string, v ...interface{}) error
- }
- //noLogging no logging messages
- const noLogging = 0
- //infoLogging minimal logging messages
- const infoLogging = 1
- //debugLogging some logging messages
- const debugLogging = 2
- //verboseLogging all logging messages
- const verboseLogging = 3
- //defaultSDKLogger the default implementation of the sdkLogger
- type defaultSDKLogger struct {
- currentLoggingLevel int
- verboseLogger *log.Logger
- debugLogger *log.Logger
- infoLogger *log.Logger
- nullLogger *log.Logger
- }
- //defaultLogger is the defaultLogger in the SDK
- var defaultLogger sdkLogger
- var loggerLock sync.Mutex
- var file *os.File
- //initializes the SDK defaultLogger as a defaultLogger
- func init() {
- l, _ := newSDKLogger()
- setSDKLogger(l)
- }
- //setSDKLogger sets the logger used by the sdk
- func setSDKLogger(logger sdkLogger) {
- loggerLock.Lock()
- defaultLogger = logger
- loggerLock.Unlock()
- }
- // newSDKLogger creates a defaultSDKLogger
- // Debug logging is turned on/off by the presence of the environment variable "OCI_GO_SDK_DEBUG"
- // The value of the "OCI_GO_SDK_DEBUG" environment variable controls the logging level.
- // "null" outputs no log messages
- // "i" or "info" outputs minimal log messages
- // "d" or "debug" outputs some logs messages
- // "v" or "verbose" outputs all logs messages, including body of requests
- func newSDKLogger() (defaultSDKLogger, error) {
- logger := defaultSDKLogger{}
- logger.currentLoggingLevel = noLogging
- logger.verboseLogger = log.New(os.Stderr, "VERBOSE ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
- logger.debugLogger = log.New(os.Stderr, "DEBUG ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
- logger.infoLogger = log.New(os.Stderr, "INFO ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
- logger.nullLogger = log.New(ioutil.Discard, "", log.Ldate|log.Lmicroseconds|log.Lshortfile)
- configured, isLogEnabled := os.LookupEnv("OCI_GO_SDK_DEBUG")
- // If env variable not present turn logging of
- if !isLogEnabled {
- logger.currentLoggingLevel = noLogging
- } else {
- logOutputModeConfig(logger)
- switch strings.ToLower(configured) {
- case "null":
- logger.currentLoggingLevel = noLogging
- break
- case "i", "info":
- logger.currentLoggingLevel = infoLogging
- break
- case "d", "debug":
- logger.currentLoggingLevel = debugLogging
- break
- //1 here for backwards compatibility
- case "v", "verbose", "1":
- logger.currentLoggingLevel = verboseLogging
- break
- default:
- logger.currentLoggingLevel = infoLogging
- }
- logger.infoLogger.Println("logger level set to: ", logger.currentLoggingLevel)
- }
- return logger, nil
- }
- func (l defaultSDKLogger) getLoggerForLevel(logLevel int) *log.Logger {
- if logLevel > l.currentLoggingLevel {
- return l.nullLogger
- }
- switch logLevel {
- case noLogging:
- return l.nullLogger
- case infoLogging:
- return l.infoLogger
- case debugLogging:
- return l.debugLogger
- case verboseLogging:
- return l.verboseLogger
- default:
- return l.nullLogger
- }
- }
- // Set SDK Log output mode
- // Output mode is switched based on environment variable "OCI_GO_SDK_LOG_OUPUT_MODE"
- // "file" outputs log to a specific file
- // "combine" outputs log to both stderr and specific file
- // other unsupported value ouputs log to stderr
- // output file can be set via environment variable "OCI_GO_SDK_LOG_FILE"
- // if this environment variable is not set, a default log file will be created under project root path
- func logOutputModeConfig(logger defaultSDKLogger) {
- logMode, isLogOutputModeEnabled := os.LookupEnv("OCI_GO_SDK_LOG_OUTPUT_MODE")
- if !isLogOutputModeEnabled {
- return
- }
- fileName, isLogFileNameProvided := os.LookupEnv("OCI_GO_SDK_LOG_FILE")
- if !isLogFileNameProvided {
- fileName = fmt.Sprintf("logging_%v%s", time.Now().Unix(), ".log")
- }
- switch strings.ToLower(logMode) {
- case "file", "f":
- file = openLogOutputFile(logger, fileName)
- logger.infoLogger.SetOutput(file)
- logger.debugLogger.SetOutput(file)
- logger.verboseLogger.SetOutput(file)
- break
- case "combine", "c":
- file = openLogOutputFile(logger, fileName)
- wrt := io.MultiWriter(os.Stderr, file)
- logger.infoLogger.SetOutput(wrt)
- logger.debugLogger.SetOutput(wrt)
- logger.verboseLogger.SetOutput(wrt)
- break
- }
- }
- func openLogOutputFile(logger defaultSDKLogger, fileName string) *os.File {
- file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
- if err != nil {
- logger.verboseLogger.Fatal(err)
- }
- return file
- }
- //CloseLogFile close the logging file and return error
- func CloseLogFile() error {
- return file.Close()
- }
- //LogLevel returns the current debug level
- func (l defaultSDKLogger) LogLevel() int {
- return l.currentLoggingLevel
- }
- func (l defaultSDKLogger) Log(logLevel int, format string, v ...interface{}) error {
- logger := l.getLoggerForLevel(logLevel)
- logger.Output(4, fmt.Sprintf(format, v...))
- return nil
- }
- //Logln logs v appending a new line at the end
- //Deprecated
- func Logln(v ...interface{}) {
- defaultLogger.Log(infoLogging, "%v\n", v...)
- }
- // Logf logs v with the provided format
- func Logf(format string, v ...interface{}) {
- defaultLogger.Log(infoLogging, format, v...)
- }
- // Debugf logs v with the provided format if debug mode is set
- func Debugf(format string, v ...interface{}) {
- defaultLogger.Log(debugLogging, format, v...)
- }
- // Debug logs v if debug mode is set
- func Debug(v ...interface{}) {
- m := fmt.Sprint(v...)
- defaultLogger.Log(debugLogging, "%s", m)
- }
- // Debugln logs v appending a new line if debug mode is set
- func Debugln(v ...interface{}) {
- m := fmt.Sprint(v...)
- defaultLogger.Log(debugLogging, "%s\n", m)
- }
- // IfDebug executes closure if debug is enabled
- func IfDebug(fn func()) {
- if defaultLogger.LogLevel() >= debugLogging {
- fn()
- }
- }
|