github.com/snowflakedb/gosnowflake@v1.9.0/easy_logging.go (about) 1 package gosnowflake 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "os" 8 "path" 9 "runtime" 10 "strings" 11 "sync" 12 ) 13 14 type initTrials struct { 15 everTriedToInitialize bool 16 clientConfigFileInput string 17 configureCounter int 18 mu sync.Mutex 19 } 20 21 var easyLoggingInitTrials = initTrials{ 22 everTriedToInitialize: false, 23 clientConfigFileInput: "", 24 configureCounter: 0, 25 mu: sync.Mutex{}, 26 } 27 28 func (i *initTrials) setInitTrial(clientConfigFileInput string) { 29 i.everTriedToInitialize = true 30 i.clientConfigFileInput = clientConfigFileInput 31 } 32 33 func (i *initTrials) increaseReconfigureCounter() { 34 i.configureCounter++ 35 } 36 37 func (i *initTrials) reset() { 38 i.mu.Lock() 39 defer i.mu.Unlock() 40 41 i.everTriedToInitialize = false 42 i.clientConfigFileInput = "" 43 i.configureCounter = 0 44 } 45 46 func initEasyLogging(clientConfigFileInput string) error { 47 easyLoggingInitTrials.mu.Lock() 48 defer easyLoggingInitTrials.mu.Unlock() 49 50 if !allowedToInitialize(clientConfigFileInput) { 51 logger.Info("Skipping Easy Logging initialization as it is not allowed to initialize") 52 return nil 53 } 54 logger.Infof("Trying to initialize Easy Logging") 55 config, configPath, err := getClientConfig(clientConfigFileInput) 56 if err != nil { 57 logger.Errorf("Failed to initialize Easy Logging, err: %s", err) 58 return easyLoggingInitError(err) 59 } 60 if config == nil { 61 logger.Info("Easy Logging is disabled as no config has been found") 62 easyLoggingInitTrials.setInitTrial(clientConfigFileInput) 63 return nil 64 } 65 var logLevel string 66 logLevel, err = getLogLevel(config.Common.LogLevel) 67 if err != nil { 68 logger.Errorf("Failed to initialize Easy Logging, err: %s", err) 69 return easyLoggingInitError(err) 70 } 71 var logPath string 72 logPath, err = getLogPath(config.Common.LogPath) 73 if err != nil { 74 logger.Errorf("Failed to initialize Easy Logging, err: %s", err) 75 return easyLoggingInitError(err) 76 } 77 logger.Infof("Initializing Easy Logging with logPath=%s and logLevel=%s from file: %s", logPath, logLevel, configPath) 78 err = reconfigureEasyLogging(logLevel, logPath) 79 if err != nil { 80 logger.Errorf("Failed to initialize Easy Logging, err: %s", err) 81 } 82 easyLoggingInitTrials.setInitTrial(clientConfigFileInput) 83 easyLoggingInitTrials.increaseReconfigureCounter() 84 return err 85 } 86 87 func easyLoggingInitError(err error) error { 88 return &SnowflakeError{ 89 Number: ErrCodeClientConfigFailed, 90 Message: errMsgClientConfigFailed, 91 MessageArgs: []interface{}{err.Error()}, 92 } 93 } 94 95 func reconfigureEasyLogging(logLevel string, logPath string) error { 96 newLogger := CreateDefaultLogger() 97 err := newLogger.SetLogLevel(logLevel) 98 if err != nil { 99 return err 100 } 101 var output io.Writer 102 var file *os.File 103 output, file, err = createLogWriter(logPath) 104 if err != nil { 105 return err 106 } 107 newLogger.SetOutput(output) 108 err = newLogger.CloseFileOnLoggerReplace(file) 109 if err != nil { 110 logger.Errorf("%s", err) 111 } 112 logger.Replace(&newLogger) 113 return nil 114 } 115 116 func createLogWriter(logPath string) (io.Writer, *os.File, error) { 117 if strings.EqualFold(logPath, "STDOUT") { 118 return os.Stdout, nil, nil 119 } 120 logFileName := path.Join(logPath, "snowflake.log") 121 file, err := os.OpenFile(logFileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640) 122 if err != nil { 123 return nil, nil, err 124 } 125 return file, file, nil 126 } 127 128 func allowedToInitialize(clientConfigFileInput string) bool { 129 triedToInitializeWithoutConfigFile := easyLoggingInitTrials.everTriedToInitialize && easyLoggingInitTrials.clientConfigFileInput == "" 130 isAllowedToInitialize := !easyLoggingInitTrials.everTriedToInitialize || (triedToInitializeWithoutConfigFile && clientConfigFileInput != "") 131 if !isAllowedToInitialize && easyLoggingInitTrials.clientConfigFileInput != clientConfigFileInput { 132 logger.Warnf("Easy logging will not be configured for CLIENT_CONFIG_FILE=%s because it was previously configured for a different client config", clientConfigFileInput) 133 } 134 return isAllowedToInitialize 135 } 136 137 func getLogLevel(logLevel string) (string, error) { 138 if logLevel == "" { 139 logger.Warn("LogLevel in client config not found. Using default value: OFF") 140 return levelOff, nil 141 } 142 return toLogLevel(logLevel) 143 } 144 145 func getLogPath(logPath string) (string, error) { 146 logPathOrDefault := logPath 147 if logPath == "" { 148 homeDir, err := os.UserHomeDir() 149 if err != nil { 150 return "", fmt.Errorf("user home directory is not accessible, err: %w", err) 151 } 152 logPathOrDefault = homeDir 153 logger.Warnf("LogPath in client config not found. Using user home directory as a default value: %s", logPathOrDefault) 154 } 155 pathWithGoSubdir := path.Join(logPathOrDefault, "go") 156 exists, err := dirExists(pathWithGoSubdir) 157 if err != nil { 158 return "", err 159 } 160 if !exists { 161 err = os.MkdirAll(pathWithGoSubdir, 0700) 162 if err != nil { 163 return "", err 164 } 165 } 166 logDirPermValid, perm, err := isDirAccessCorrect(pathWithGoSubdir) 167 if err != nil { 168 return "", err 169 } 170 if !logDirPermValid { 171 logger.Warnf("Log directory: %s could potentially be accessed by others. Directory chmod: 0%o", pathWithGoSubdir, *perm) 172 } 173 return pathWithGoSubdir, nil 174 } 175 176 func isDirAccessCorrect(dirPath string) (bool, *os.FileMode, error) { 177 if runtime.GOOS == "windows" { 178 return true, nil, nil 179 } 180 dirStat, err := os.Stat(dirPath) 181 if err != nil { 182 return false, nil, err 183 } 184 perm := dirStat.Mode().Perm() 185 if perm != 0700 { 186 return false, &perm, nil 187 } 188 return true, &perm, nil 189 } 190 191 func dirExists(dirPath string) (bool, error) { 192 stat, err := os.Stat(dirPath) 193 if err == nil { 194 return stat.IsDir(), nil 195 } 196 if errors.Is(err, os.ErrNotExist) { 197 return false, nil 198 } 199 return false, err 200 }