-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Easy Logging using a config file #747
base: master
Are you sure you want to change the base?
Implement Easy Logging using a config file #747
Conversation
tests/test_unit_logger.c
Outdated
@@ -25,6 +28,47 @@ void test_log_str_to_level(void **unused) { | |||
} | |||
|
|||
#ifndef _WIN32 | |||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test case to cover the behavior in log_init(), e.g. having a config file in place, after calling snowflake_global_init() check the log settings are as expected.
cpp/lib/ClientConfigParser.cpp
Outdated
{ | ||
#if defined(WIN32) || defined(_WIN64) | ||
// 4. Try user home dir | ||
std::string homeDir = sf_getenv_s("USERPROFILE", envbuf, sizeof(envbuf)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sf_getenv_s could return NULL and cause runtime exception thrown.
cpp/lib/ClientConfigParser.cpp
Outdated
|
||
// Private ===================================================================== | ||
//////////////////////////////////////////////////////////////////////////////// | ||
bool ClientConfigParser::checkFileExists(const std::string& in_filePath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are on c++17 already maybe we could use std::filesystem::is_regular_file() directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::filesystem isn't available on osx10.14 and boost has a debug assertion on 32-bit windows with MT build
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we resolve debug assertion issue with 32-bit windows build and use boost filesystem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using boost filesystem was able to fix the issue
lib/client.c
Outdated
char client_config_file[MAX_PATH] = {0}; | ||
snowflake_global_get_attribute( | ||
SF_GLOBAL_CLIENT_CONFIG_FILE, client_config_file, sizeof(client_config_file)); | ||
client_config clientConfig = { .logLevel = "", .logPath = "" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memory leak currently with the buffer allocated in load_client_config().
When you try to free the buffer, initialize with const string could be a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if client config is not initialized .logLevel and .logPath should be null
cpp/lib/ClientConfigParser.cpp
Outdated
} | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
void load_client_config( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems we are throwing exception from loadClientConfig(). We need to catch that and return error. C interface doesn't expect exception.
Please add error test cases as well this will be caught if we have error test cases.
lib/client.c
Outdated
@@ -36,6 +37,8 @@ sf_bool DEBUG; | |||
sf_bool SF_OCSP_CHECK; | |||
char *SF_HEADER_USER_AGENT = NULL; | |||
|
|||
static char *CLIENT_CONFIG_FILE = NULL; | |||
static char* LOG_LEVEL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not to set NULL as others? Better not to add LOG_LEVEL as we've had number loglevel maintained with log_set_level() and log_get_level() already. Having another one could cause mismatch.
lib/client.c
Outdated
case SF_GLOBAL_CLIENT_CONFIG_FILE: | ||
alloc_buffer_and_copy(&CLIENT_CONFIG_FILE, value); | ||
break; | ||
case SF_GLOBAL_LOG_LEVEL: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer SF_GLOBAL_LOG_PATH and SF_GLOBAL_LOG_LEVEL to be read only attributes since application already have enough ways to do log settings.
SF_GLOBAL_OCSP_CHECK | ||
SF_GLOBAL_OCSP_CHECK, | ||
SF_GLOBAL_CLIENT_CONFIG_FILE, | ||
SF_GLOBAL_LOG_LEVEL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remind me why we need SF_GLOBAL_LOG_LEVEL and SF_GLOBAL_LOG_PATH?
Please having a brief note of the interface and usage in either the ticket or the PR description. That could help understanding the implementation and later for documentation as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated description
cpp/lib/ClientConfigParser.cpp
Outdated
FILE* configFile; | ||
try | ||
{ | ||
configFile = sf_fopen(&configFile, in_filePath.c_str(), "r"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use std::fstream and std::filesystem APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately std::filesystem isn't in osx10.14 yet so it can't be used and there seems to be a 32-bit windows debug assertion issue with reading file with fstream when built with MT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That means we cannot use std::fstream at all? Can you show me the assertion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not exactly, it only happens for Windows 32-bit built with MT. All other configurations seem to work fine. If you prefer, I can ifdef it to not run when it's windows debug and it should work fine. The assertion says something like this:
Debug Assertion Failed!
File: minkernel\crts\ucrt\src\appcrt\lowio\read.cpp
Expression: _osfile(fh) & FOPEN
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this local issue? Does it appear on CI? I think you might be building the project incorrectly. See: https://stackoverflow.com/questions/5984144/assertion-error-in-crt-calling-osfile-in-vs-2008/6010756#6010756
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am using fstream and boost filesystem on my PR without issues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still running into this issue with the tests run on jenkins. Basically the test run just hangs after it hits the assertion error. In the mean time, I've added an ifdef to to run easy logging when in 32-bit debug. I've locally tested running on /MDd and it runs fine, but currently I think we build with dynamic runtime set to OFF
…boost 32-bit windows debug issues
…s://github.com/snowflakedb/libsnowflakeclient into SNOW-981602-implement-easy-logging-config-file
cpp/lib/ClientConfigParser.cpp
Outdated
ClientConfigParser configParser; | ||
configParser.loadClientConfig(in_configFilePath, *out_clientConfig); | ||
} catch (std::exception e) { | ||
sf_fprintf(stderr, e.what()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use logger here?
{ | ||
char envbuf[MAX_PATH + 1]; | ||
std::string derivedConfigPath = ""; | ||
if (!in_configFilePath.empty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use ealy return instead of else nesting
cpp/lib/ClientConfigParser.cpp
Outdated
// USERPROFILE is empty, try HOMEDRIVE and HOMEPATH | ||
char* homeDriveEnv; | ||
char* homePathEnv; | ||
if ((homeDriveEnv = sf_getenv_s("HOMEDRIVE", envbuf, sizeof(envbuf))) && (strlen(homeDriveEnv) != 0) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can write it like this?
char* homeDriveEnv = sf_getenv_s("HOMEDRIVE", envbuf, sizeof(envbuf)
if (homeDriveEnv && strlen(homeDriveEnv) != 0)
cpp/lib/ClientConfigParser.cpp
Outdated
} | ||
else | ||
{ | ||
#if defined(WIN32) || defined(_WIN64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move finding home directory to another function.
cpp/lib/ClientConfigParser.cpp
Outdated
FILE* configFile; | ||
try | ||
{ | ||
configFile = sf_fopen(&configFile, in_filePath.c_str(), "r"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this local issue? Does it appear on CI? I think you might be building the project incorrectly. See: https://stackoverflow.com/questions/5984144/assertion-error-in-crt-calling-osfile-in-vs-2008/6010756#6010756
cpp/lib/ClientConfigParser.cpp
Outdated
|
||
// Private ===================================================================== | ||
//////////////////////////////////////////////////////////////////////////////// | ||
bool ClientConfigParser::checkFileExists(const std::string& in_filePath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we resolve debug assertion issue with 32-bit windows build and use boost filesystem
cpp/lib/ClientConfigParser.cpp
Outdated
|
||
// Public ====================================================================== | ||
//////////////////////////////////////////////////////////////////////////////// | ||
ClientConfigParser::ClientConfigParser() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we change the name? Maybe EasyLoggingConfigParser
snowflake_global_get_attribute( | ||
SF_GLOBAL_CLIENT_CONFIG_FILE, client_config_file, sizeof(client_config_file)); | ||
client_config clientConfig = { .logLevel = "", .logPath = "" }; | ||
load_client_config(client_config_file, &clientConfig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C strings are allocated by this function, we should have corresponding fuction to deallocate the string free_client_config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now we are leaking memory
lib/client.c
Outdated
char client_config_file[MAX_PATH] = {0}; | ||
snowflake_global_get_attribute( | ||
SF_GLOBAL_CLIENT_CONFIG_FILE, client_config_file, sizeof(client_config_file)); | ||
client_config clientConfig = { .logLevel = "", .logPath = "" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if client config is not initialized .logLevel and .logPath should be null
{ | ||
namespace Client | ||
{ | ||
struct ClientConfigException : public std::exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need a class if it has no member variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just using it as a wrapper for exception to pass along the error message. I saw other classes having a similar exception struct, but I can just make the function return false instead of throwing an exception if you prefer.
For SNOW-981602: Implement Easy Logging using a config file
Add several new global attributes:
SF_GLOBAL_CLIENT_CONFIG_FILE: To set the client config file so libsnowflakeclient knows where to look for the config file
SF_GLOBAL_LOG_LEVEL: To allow the user to get the log level since libsnowflakeclient handles log setup
SF_GLOBAL_LOG_PATH: To allow the user to get the log path