log.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved.
  2. // 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.
  3. package common
  4. import (
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "log"
  9. "os"
  10. "strings"
  11. "sync"
  12. "time"
  13. )
  14. //sdkLogger an interface for logging in the SDK
  15. type sdkLogger interface {
  16. //LogLevel returns the log level of sdkLogger
  17. LogLevel() int
  18. //Log logs v with the provided format if the current log level is loglevel
  19. Log(logLevel int, format string, v ...interface{}) error
  20. }
  21. //noLogging no logging messages
  22. const noLogging = 0
  23. //infoLogging minimal logging messages
  24. const infoLogging = 1
  25. //debugLogging some logging messages
  26. const debugLogging = 2
  27. //verboseLogging all logging messages
  28. const verboseLogging = 3
  29. //defaultSDKLogger the default implementation of the sdkLogger
  30. type defaultSDKLogger struct {
  31. currentLoggingLevel int
  32. verboseLogger *log.Logger
  33. debugLogger *log.Logger
  34. infoLogger *log.Logger
  35. nullLogger *log.Logger
  36. }
  37. //defaultLogger is the defaultLogger in the SDK
  38. var defaultLogger sdkLogger
  39. var loggerLock sync.Mutex
  40. var file *os.File
  41. //initializes the SDK defaultLogger as a defaultLogger
  42. func init() {
  43. l, _ := newSDKLogger()
  44. setSDKLogger(l)
  45. }
  46. //setSDKLogger sets the logger used by the sdk
  47. func setSDKLogger(logger sdkLogger) {
  48. loggerLock.Lock()
  49. defaultLogger = logger
  50. loggerLock.Unlock()
  51. }
  52. // newSDKLogger creates a defaultSDKLogger
  53. // Debug logging is turned on/off by the presence of the environment variable "OCI_GO_SDK_DEBUG"
  54. // The value of the "OCI_GO_SDK_DEBUG" environment variable controls the logging level.
  55. // "null" outputs no log messages
  56. // "i" or "info" outputs minimal log messages
  57. // "d" or "debug" outputs some logs messages
  58. // "v" or "verbose" outputs all logs messages, including body of requests
  59. func newSDKLogger() (defaultSDKLogger, error) {
  60. logger := defaultSDKLogger{}
  61. logger.currentLoggingLevel = noLogging
  62. logger.verboseLogger = log.New(os.Stderr, "VERBOSE ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
  63. logger.debugLogger = log.New(os.Stderr, "DEBUG ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
  64. logger.infoLogger = log.New(os.Stderr, "INFO ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
  65. logger.nullLogger = log.New(ioutil.Discard, "", log.Ldate|log.Lmicroseconds|log.Lshortfile)
  66. configured, isLogEnabled := os.LookupEnv("OCI_GO_SDK_DEBUG")
  67. // If env variable not present turn logging of
  68. if !isLogEnabled {
  69. logger.currentLoggingLevel = noLogging
  70. } else {
  71. logOutputModeConfig(logger)
  72. switch strings.ToLower(configured) {
  73. case "null":
  74. logger.currentLoggingLevel = noLogging
  75. break
  76. case "i", "info":
  77. logger.currentLoggingLevel = infoLogging
  78. break
  79. case "d", "debug":
  80. logger.currentLoggingLevel = debugLogging
  81. break
  82. //1 here for backwards compatibility
  83. case "v", "verbose", "1":
  84. logger.currentLoggingLevel = verboseLogging
  85. break
  86. default:
  87. logger.currentLoggingLevel = infoLogging
  88. }
  89. logger.infoLogger.Println("logger level set to: ", logger.currentLoggingLevel)
  90. }
  91. return logger, nil
  92. }
  93. func (l defaultSDKLogger) getLoggerForLevel(logLevel int) *log.Logger {
  94. if logLevel > l.currentLoggingLevel {
  95. return l.nullLogger
  96. }
  97. switch logLevel {
  98. case noLogging:
  99. return l.nullLogger
  100. case infoLogging:
  101. return l.infoLogger
  102. case debugLogging:
  103. return l.debugLogger
  104. case verboseLogging:
  105. return l.verboseLogger
  106. default:
  107. return l.nullLogger
  108. }
  109. }
  110. // Set SDK Log output mode
  111. // Output mode is switched based on environment variable "OCI_GO_SDK_LOG_OUPUT_MODE"
  112. // "file" outputs log to a specific file
  113. // "combine" outputs log to both stderr and specific file
  114. // other unsupported value ouputs log to stderr
  115. // output file can be set via environment variable "OCI_GO_SDK_LOG_FILE"
  116. // if this environment variable is not set, a default log file will be created under project root path
  117. func logOutputModeConfig(logger defaultSDKLogger) {
  118. logMode, isLogOutputModeEnabled := os.LookupEnv("OCI_GO_SDK_LOG_OUTPUT_MODE")
  119. if !isLogOutputModeEnabled {
  120. return
  121. }
  122. fileName, isLogFileNameProvided := os.LookupEnv("OCI_GO_SDK_LOG_FILE")
  123. if !isLogFileNameProvided {
  124. fileName = fmt.Sprintf("logging_%v%s", time.Now().Unix(), ".log")
  125. }
  126. switch strings.ToLower(logMode) {
  127. case "file", "f":
  128. file = openLogOutputFile(logger, fileName)
  129. logger.infoLogger.SetOutput(file)
  130. logger.debugLogger.SetOutput(file)
  131. logger.verboseLogger.SetOutput(file)
  132. break
  133. case "combine", "c":
  134. file = openLogOutputFile(logger, fileName)
  135. wrt := io.MultiWriter(os.Stderr, file)
  136. logger.infoLogger.SetOutput(wrt)
  137. logger.debugLogger.SetOutput(wrt)
  138. logger.verboseLogger.SetOutput(wrt)
  139. break
  140. }
  141. }
  142. func openLogOutputFile(logger defaultSDKLogger, fileName string) *os.File {
  143. file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
  144. if err != nil {
  145. logger.verboseLogger.Fatal(err)
  146. }
  147. return file
  148. }
  149. //CloseLogFile close the logging file and return error
  150. func CloseLogFile() error {
  151. return file.Close()
  152. }
  153. //LogLevel returns the current debug level
  154. func (l defaultSDKLogger) LogLevel() int {
  155. return l.currentLoggingLevel
  156. }
  157. func (l defaultSDKLogger) Log(logLevel int, format string, v ...interface{}) error {
  158. logger := l.getLoggerForLevel(logLevel)
  159. logger.Output(4, fmt.Sprintf(format, v...))
  160. return nil
  161. }
  162. //Logln logs v appending a new line at the end
  163. //Deprecated
  164. func Logln(v ...interface{}) {
  165. defaultLogger.Log(infoLogging, "%v\n", v...)
  166. }
  167. // Logf logs v with the provided format
  168. func Logf(format string, v ...interface{}) {
  169. defaultLogger.Log(infoLogging, format, v...)
  170. }
  171. // Debugf logs v with the provided format if debug mode is set
  172. func Debugf(format string, v ...interface{}) {
  173. defaultLogger.Log(debugLogging, format, v...)
  174. }
  175. // Debug logs v if debug mode is set
  176. func Debug(v ...interface{}) {
  177. m := fmt.Sprint(v...)
  178. defaultLogger.Log(debugLogging, "%s", m)
  179. }
  180. // Debugln logs v appending a new line if debug mode is set
  181. func Debugln(v ...interface{}) {
  182. m := fmt.Sprint(v...)
  183. defaultLogger.Log(debugLogging, "%s\n", m)
  184. }
  185. // IfDebug executes closure if debug is enabled
  186. func IfDebug(fn func()) {
  187. if defaultLogger.LogLevel() >= debugLogging {
  188. fn()
  189. }
  190. }