From f6c2da65f8de2c24d95ab1756da746425896a802 Mon Sep 17 00:00:00 2001 From: Krzysztof Nozderko Date: Mon, 30 Oct 2023 13:28:00 +0100 Subject: [PATCH 1/2] SNOW-856228 easy logging documentation (#949) SNOW-856228 easy logging documentation --- doc.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/doc.go b/doc.go index df4a61042..68b831920 100644 --- a/doc.go +++ b/doc.go @@ -123,6 +123,9 @@ The following connection parameters are supported: - disableQueryContextCache: disables parsing of query context returned from server and resending it to server as well. Default value is false. + - clientConfigFile: specifies the location of the client configuration json file. + In this file you can configure Easy Logging feature. + All other parameters are interpreted as session parameters (https://docs.snowflake.com/en/sql-reference/parameters.html). For example, the TIMESTAMP_OUTPUT_FORMAT session parameter can be set by adding: @@ -164,6 +167,46 @@ Users can use SetLogger in driver.go to set a customized logger for gosnowflake In order to enable debug logging for the driver, user could use SetLogLevel("debug") in SFLogger interface as shown in demo code at cmd/logger.go. To redirect the logs SFlogger.SetOutput method could do the work. +## Easy Logging + +The Easy Logging feature allows you to change log level and the location of a log file for the driver. +This feature was introduced to make tracing of driver's logs easier. +The feature is activated by a config file which can be: + +1. provided as clientConfigFile parameter. +Remember to URL-encode all special characters on file path if you use DSN string e. g. +`user:pass@account/db?clientConfigFile=%2Fsome-path%2Fclient_config.json` encodes clientConfigFile `/some-path/client_config.json` + +2. provided as environmental variable called `SF_CLIENT_CONFIG_FILE` (e. g. `export SF_CLIENT_CONFIG_FILE=/some-path/client_config.json`) + +3. found in the driver location by searching for sf_client_config.json file + +4. found in the home location by searching for sf_client_config.json file + +5. found in temp directory location by searching for sf_client_config.json file + +The search for a config file is executed in the order listed above. + +To minimize the number of searches for a configuration file it is executed only: +- for the first connection +- for the first connection with clientConfigFile parameter. + +The example of the configuration file is: +``` + + { + "common": { + "log_level": "INFO", + "log_path": "/some-path/some-directory" + } + } + +``` + +Available log levels are: OFF, ERROR, WARN, INFO, DEBUG, TRACE. The log levels are case insensitive. + +The logs land into `go` subfolder of given directory `/some-path/some-directory` so in this example: /some-path/some-directory/go. + # Query request ID A specific query request ID can be set in the context and will be passed through From ea5774330b14ec68b8d4ec93f4f043c75ae9d0b8 Mon Sep 17 00:00:00 2001 From: Krzysztof Nozderko Date: Mon, 30 Oct 2023 15:49:07 +0100 Subject: [PATCH 2/2] SNOW-856228 easy logging - not fail on directory serch error (#951) --- client_configuration.go | 24 +++++++++--------------- client_configuration_test.go | 15 +++++---------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/client_configuration.go b/client_configuration.go index c3b3573d9..a72718128 100644 --- a/client_configuration.go +++ b/client_configuration.go @@ -28,43 +28,37 @@ const ( func getClientConfig(filePathFromConnectionString string) (*ClientConfig, error) { configPredefinedFilePaths := clientConfigPredefinedDirs() - filePath, err := findClientConfigFilePath(filePathFromConnectionString, configPredefinedFilePaths) - if err != nil { - return nil, findClientConfigError(err) - } + filePath := findClientConfigFilePath(filePathFromConnectionString, configPredefinedFilePaths) if filePath == "" { // we did not find a config file return nil, nil } return parseClientConfiguration(filePath) } -func findClientConfigFilePath(filePathFromConnectionString string, configPredefinedDirs []string) (string, error) { +func findClientConfigFilePath(filePathFromConnectionString string, configPredefinedDirs []string) string { if filePathFromConnectionString != "" { - return filePathFromConnectionString, nil + return filePathFromConnectionString } envConfigFilePath := os.Getenv(clientConfEnvName) if envConfigFilePath != "" { - return envConfigFilePath, nil + return envConfigFilePath } return searchForConfigFile(configPredefinedDirs) } -func searchForConfigFile(directories []string) (string, error) { +func searchForConfigFile(directories []string) string { for _, dir := range directories { filePath := path.Join(dir, defaultConfigName) exists, err := existsFile(filePath) if err != nil { - return "", err + logger.Errorf("Error while searching for the client config in %s directory: %s", dir, err) + continue } if exists { - return filePath, nil + return filePath } } - return "", nil -} - -func findClientConfigError(err error) error { - return fmt.Errorf("finding client config failed: %w", err) + return "" } func existsFile(filePath string) (bool, error) { diff --git a/client_configuration_test.go b/client_configuration_test.go index 14292cc8a..9e73f7208 100644 --- a/client_configuration_test.go +++ b/client_configuration_test.go @@ -18,9 +18,8 @@ func TestFindConfigFileFromConnectionParameters(t *testing.T) { createFile(t, defaultConfigName, "random content", dirs.predefinedDir1) createFile(t, defaultConfigName, "random content", dirs.predefinedDir2) - clientConfigFilePath, err := findClientConfigFilePath(connParameterConfigPath, predefinedTestDirs(dirs)) + clientConfigFilePath := findClientConfigFilePath(connParameterConfigPath, predefinedTestDirs(dirs)) - assertNilF(t, err, "get client config error") assertEqualE(t, clientConfigFilePath, connParameterConfigPath, "config file path") } @@ -31,9 +30,8 @@ func TestFindConfigFileFromEnvVariable(t *testing.T) { createFile(t, defaultConfigName, "random content", dirs.predefinedDir1) createFile(t, defaultConfigName, "random content", dirs.predefinedDir2) - clientConfigFilePath, err := findClientConfigFilePath("", predefinedTestDirs(dirs)) + clientConfigFilePath := findClientConfigFilePath("", predefinedTestDirs(dirs)) - assertNilF(t, err, "get client config error") assertEqualE(t, clientConfigFilePath, envConfigPath, "config file path") } @@ -42,9 +40,8 @@ func TestFindConfigFileFromFirstPredefinedDir(t *testing.T) { configPath := createFile(t, defaultConfigName, "random content", dirs.predefinedDir1) createFile(t, defaultConfigName, "random content", dirs.predefinedDir2) - clientConfigFilePath, err := findClientConfigFilePath("", predefinedTestDirs(dirs)) + clientConfigFilePath := findClientConfigFilePath("", predefinedTestDirs(dirs)) - assertNilF(t, err, "get client config error") assertEqualE(t, clientConfigFilePath, configPath, "config file path") } @@ -53,9 +50,8 @@ func TestFindConfigFileFromSubsequentDirectoryIfNotFoundInPreviousOne(t *testing createFile(t, "wrong_file_name.json", "random content", dirs.predefinedDir1) configPath := createFile(t, defaultConfigName, "random content", dirs.predefinedDir2) - clientConfigFilePath, err := findClientConfigFilePath("", predefinedTestDirs(dirs)) + clientConfigFilePath := findClientConfigFilePath("", predefinedTestDirs(dirs)) - assertNilF(t, err, "get client config error") assertEqualE(t, clientConfigFilePath, configPath, "config file path") } @@ -64,9 +60,8 @@ func TestNotFindConfigFileWhenNotDefined(t *testing.T) { createFile(t, "wrong_file_name.json", "random content", dirs.predefinedDir1) createFile(t, "wrong_file_name.json", "random content", dirs.predefinedDir2) - clientConfigFilePath, err := findClientConfigFilePath("", predefinedTestDirs(dirs)) + clientConfigFilePath := findClientConfigFilePath("", predefinedTestDirs(dirs)) - assertNilF(t, err, "get client config error") assertEqualE(t, clientConfigFilePath, "", "config file path") }