Skip to content
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

Open
wants to merge 75 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
7ab80fb
Implement easy logging
sfc-gh-ext-simba-nl Oct 2, 2024
836a82a
Add missing function definition
sfc-gh-ext-simba-nl Oct 2, 2024
c1878f3
Fix linux build errors
sfc-gh-ext-simba-nl Oct 2, 2024
21673d4
Fix conversion issue on linux
sfc-gh-ext-simba-nl Oct 2, 2024
806fb9c
Fix mac build error and fix logging test failure
sfc-gh-ext-simba-nl Oct 2, 2024
4a5ad67
Fix mac build error in test case
sfc-gh-ext-simba-nl Oct 3, 2024
4e05bc7
Fix setting of global log path
sfc-gh-ext-simba-nl Oct 3, 2024
a79370d
Use sf_memcpy instead
sfc-gh-ext-simba-nl Oct 4, 2024
be865c1
Remove the use of boost algorithm string for compare
sfc-gh-ext-simba-nl Oct 7, 2024
f90848d
Fix test issue
sfc-gh-ext-simba-nl Oct 8, 2024
3823568
Fix build issue with test
sfc-gh-ext-simba-nl Oct 9, 2024
a863b05
Change ifstream to FILE due to 32bit debug read issue
sfc-gh-ext-simba-nl Oct 9, 2024
994228b
Fix linux build issue
sfc-gh-ext-simba-nl Oct 10, 2024
70bdc60
Fix test issues
sfc-gh-ext-simba-nl Oct 10, 2024
309d118
Rename ifndef for headers to be more consistent
sfc-gh-ext-simba-nl Oct 11, 2024
65e29f1
Merge branch 'master' into SNOW-981602-implement-easy-logging-config-…
sfc-gh-ext-simba-nl Oct 11, 2024
21a3b11
Replace boost with std::filesystem, fix possible NULL issues, add tests
sfc-gh-ext-simba-nl Oct 16, 2024
8d97f3a
Add client_config_parser to include dir
sfc-gh-ext-simba-nl Oct 16, 2024
577925a
Fix compilation error
sfc-gh-ext-simba-nl Oct 16, 2024
6a27fe5
Fix return value error
sfc-gh-ext-simba-nl Oct 17, 2024
fdb5187
Use experimental filesystem for non-windows
sfc-gh-ext-simba-nl Oct 17, 2024
2d66b20
Add stdc++fs to link libraries for unix builds
sfc-gh-ext-simba-nl Oct 17, 2024
e480074
Fix macos filesystem error
sfc-gh-ext-simba-nl Oct 17, 2024
39d1036
SNOW-692945: multiple statements support (#727)
SimbaGithub Oct 17, 2024
1ee5015
Merge branch 'master' into master-2.0.0
sfc-gh-ext-simba-hx Oct 17, 2024
f162232
Revert from using std::filesystem, add back check file exists due to …
sfc-gh-ext-simba-nl Oct 17, 2024
04993e8
Fix boost error
sfc-gh-ext-simba-nl Oct 18, 2024
0f494ee
Fix test cases
sfc-gh-ext-simba-nl Oct 18, 2024
0aaea59
Fix logger unit tests
sfc-gh-ext-simba-nl Oct 18, 2024
6bc1b92
SNOW-692945: refactoring for resultset C wrapper (#724)
SimbaGithub Oct 18, 2024
3c4f610
Merge branch 'master' into SNOW-981602-implement-easy-logging-config-…
sfc-gh-ext-simba-nl Oct 21, 2024
e3e1b88
SNOW-1524269: support put/get for GCP (#738)
sfc-gh-ext-simba-hx Oct 22, 2024
4b2cc16
SNOW-1524269 native put get support (#745)
sfc-gh-ext-simba-hx Oct 23, 2024
81bf6fb
Merge branch 'master' into master-2.0.0
sfc-gh-ext-simba-hx Oct 24, 2024
96b9b87
Implement easy logging
sfc-gh-ext-simba-nl Oct 2, 2024
8ce9da6
Add missing function definition
sfc-gh-ext-simba-nl Oct 2, 2024
9fcc790
Fix linux build errors
sfc-gh-ext-simba-nl Oct 2, 2024
1f778c0
Fix conversion issue on linux
sfc-gh-ext-simba-nl Oct 2, 2024
17e1d10
Fix mac build error and fix logging test failure
sfc-gh-ext-simba-nl Oct 2, 2024
5c90290
Fix mac build error in test case
sfc-gh-ext-simba-nl Oct 3, 2024
ac79374
Fix setting of global log path
sfc-gh-ext-simba-nl Oct 3, 2024
99daf14
Use sf_memcpy instead
sfc-gh-ext-simba-nl Oct 4, 2024
16fd3bf
Remove the use of boost algorithm string for compare
sfc-gh-ext-simba-nl Oct 7, 2024
2a80a5e
Fix test issue
sfc-gh-ext-simba-nl Oct 8, 2024
47334d0
Fix build issue with test
sfc-gh-ext-simba-nl Oct 9, 2024
3e80253
Change ifstream to FILE due to 32bit debug read issue
sfc-gh-ext-simba-nl Oct 9, 2024
0d642b2
Fix linux build issue
sfc-gh-ext-simba-nl Oct 10, 2024
c89424a
Fix test issues
sfc-gh-ext-simba-nl Oct 10, 2024
a742893
Rename ifndef for headers to be more consistent
sfc-gh-ext-simba-nl Oct 11, 2024
e16a67c
Replace boost with std::filesystem, fix possible NULL issues, add tests
sfc-gh-ext-simba-nl Oct 16, 2024
05331fb
Add client_config_parser to include dir
sfc-gh-ext-simba-nl Oct 16, 2024
f370f9b
Fix compilation error
sfc-gh-ext-simba-nl Oct 16, 2024
d0cbc0c
Fix return value error
sfc-gh-ext-simba-nl Oct 17, 2024
e020429
Use experimental filesystem for non-windows
sfc-gh-ext-simba-nl Oct 17, 2024
d351866
Add stdc++fs to link libraries for unix builds
sfc-gh-ext-simba-nl Oct 17, 2024
5cc39ae
Fix macos filesystem error
sfc-gh-ext-simba-nl Oct 17, 2024
75eb366
Revert from using std::filesystem, add back check file exists due to …
sfc-gh-ext-simba-nl Oct 17, 2024
8651788
SNOW-1744756 add picojson to libsnowflakeclient (#755)
sfc-gh-jszczerbinski Oct 28, 2024
48d562f
Fix boost error
sfc-gh-ext-simba-nl Oct 18, 2024
79128b4
Fix test cases
sfc-gh-ext-simba-nl Oct 18, 2024
98c4924
Fix logger unit tests
sfc-gh-ext-simba-nl Oct 18, 2024
9d54bab
Merge branch 'SNOW-981602-implement-easy-logging-config-file' of http…
sfc-gh-ext-simba-nl Oct 29, 2024
a5549aa
Update log level and path precedence logic, add SF_LOG_DEFAULT
sfc-gh-ext-simba-nl Oct 29, 2024
169063c
Remove accidentally added files
sfc-gh-ext-simba-nl Oct 29, 2024
2c285bf
Fix test case
sfc-gh-ext-simba-nl Oct 30, 2024
9ede47a
Merge master
sfc-gh-ext-simba-nl Nov 13, 2024
bc61cd7
Merge branch 'master' into SNOW-981602-implement-easy-logging-config-…
sfc-gh-ext-simba-nl Nov 14, 2024
9eaadd0
Use picojson instead of cjson, refactor client config parser
sfc-gh-ext-simba-nl Nov 15, 2024
6c3aa65
Add exception to keep track of errors
sfc-gh-ext-simba-nl Nov 16, 2024
c022028
Revert accidental inclusions from master-2.0.0 branch
sfc-gh-ext-simba-nl Nov 16, 2024
b03491a
Add back missing files, fix styling change
sfc-gh-ext-simba-nl Nov 18, 2024
0d2e977
Disable test case for windows 32-bit debug
sfc-gh-ext-simba-nl Nov 18, 2024
36faf07
Ignore client config loading on win32 debug
sfc-gh-ext-simba-nl Nov 19, 2024
be2a7b3
Add comment explaining the ifdef
sfc-gh-ext-simba-nl Nov 20, 2024
d6a00fe
Fix log message
sfc-gh-ext-simba-nl Nov 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ set(SOURCE_FILES_CPP_WRAPPER
include/snowflake/SFURL.hpp
include/snowflake/CurlDesc.hpp
include/snowflake/CurlDescPool.hpp
include/snowflake/ClientConfigParser.hpp
cpp/lib/Exceptions.cpp
cpp/lib/Connection.cpp
cpp/lib/Statement.cpp
Expand All @@ -235,6 +236,7 @@ set(SOURCE_FILES_CPP_WRAPPER
cpp/lib/ResultSetJson.hpp
cpp/lib/Authenticator.cpp
cpp/lib/Authenticator.hpp
cpp/lib/ClientConfigParser.cpp
cpp/jwt/jwtWrapper.cpp
cpp/util/SnowflakeCommon.cpp
cpp/util/SFURL.cpp
Expand All @@ -245,7 +247,8 @@ set(SOURCE_FILES_CPP_WRAPPER
lib/result_set_json.h
lib/query_context_cache.h
lib/curl_desc_pool.h
lib/authenticator.h)
lib/authenticator.h
lib/client_config_parser.h)

if (UNIX)
if (LINUX)
Expand Down
315 changes: 315 additions & 0 deletions cpp/lib/ClientConfigParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
/**
* Copyright (c) 2024 Snowflake Computing
*/

#include "snowflake/ClientConfigParser.hpp"
#include "snowflake/Exceptions.hpp"
#include "../logger/SFLogger.hpp"
#include "client_config_parser.h"
#include "memory.h"

#include <fstream>
#include <sstream>
#include <set>

#undef snprintf
#include <boost/filesystem.hpp>

#ifndef _WIN32
#include <dlfcn.h>
#endif

using namespace Snowflake::Client;

namespace
{
// constants
const std::string SF_CLIENT_CONFIG_FILE_NAME("sf_client_config.json");
const std::string SF_CLIENT_CONFIG_ENV_NAME("SF_CLIENT_CONFIG_FILE");
std::set<std::string> KnownCommonEntries = {"log_level", "log_path"};
}

////////////////////////////////////////////////////////////////////////////////
void load_client_config(
Copy link
Collaborator

@sfc-gh-ext-simba-hx sfc-gh-ext-simba-hx Oct 11, 2024

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.

const char* in_configFilePath,
client_config* out_clientConfig)
{
ClientConfigParser configParser;
ClientConfig clientConfig;
configParser.loadClientConfig(in_configFilePath, clientConfig);
if (!clientConfig.logLevel.empty())
{
out_clientConfig->logLevel = (char*)SF_CALLOC(1, sizeof(clientConfig.logLevel));
sf_memcpy(out_clientConfig->logLevel, sizeof(out_clientConfig->logLevel),
clientConfig.logLevel.data(), clientConfig.logLevel.size());
}
if (!clientConfig.logPath.empty())
{
out_clientConfig->logPath = (char*)SF_CALLOC(1, sizeof(clientConfig.logPath));
sf_memcpy(out_clientConfig->logPath, MAX_PATH,
clientConfig.logPath.data(), clientConfig.logPath.size());
}
}

// Public ======================================================================
////////////////////////////////////////////////////////////////////////////////
ClientConfigParser::ClientConfigParser()
Copy link
Contributor

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

{
; // Do nothing.
}

////////////////////////////////////////////////////////////////////////////////
ClientConfigParser::~ClientConfigParser()
{
; // Do nothing.
}

////////////////////////////////////////////////////////////////////////////////
void ClientConfigParser::loadClientConfig(
const std::string& in_configFilePath,
ClientConfig& out_clientConfig)
{
char envbuf[MAX_PATH + 1];
std::string derivedConfigPath = "";
if (!in_configFilePath.empty())
sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

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

{
// 1. Try config file if it was passed in
derivedConfigPath = in_configFilePath;
CXX_LOG_INFO("sf", "ClientConfigParser", "loadClientConfig",
"Using client configuration path from a connection string: %s", in_configFilePath.c_str());
}
else if (const char* clientConfigEnv = sf_getenv_s(SF_CLIENT_CONFIG_ENV_NAME.c_str(), envbuf, sizeof(envbuf)))
{
// 2. Try environment variable SF_CLIENT_CONFIG_ENV_NAME
derivedConfigPath = clientConfigEnv;
CXX_LOG_INFO("sf", "ClientConfigParser", "loadClientConfig",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use logging pattern present throughout the project: Remove "sf", "ClientConfigParser", "loadClientConfig" parameters

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please adjust other log calls too

"Using client configuration path from an environment variable: %s", clientConfigEnv);
}
else
{
// 3. Try DLL binary dir
std::string binaryDir = getBinaryPath();
std::string binaryDirFilePath = binaryDir + SF_CLIENT_CONFIG_FILE_NAME;
if (checkFileExists(binaryDirFilePath))
{
derivedConfigPath = binaryDirFilePath;
CXX_LOG_INFO("sf", "ClientConfigParser", "loadClientConfig",
"Using client configuration path from binary directory: %s", binaryDirFilePath.c_str());
}
else
{
#if defined(WIN32) || defined(_WIN64)
Copy link
Contributor

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.

// 4. Try user home dir
std::string homeDir = sf_getenv_s("USERPROFILE", envbuf, sizeof(envbuf));
Copy link
Collaborator

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.

sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
if (homeDir.empty())
{
// USERPROFILE is empty, try HOMEDRIVE and HOMEPATH
std::string homeDriveEnv = sf_getenv_s("HOMEDRIVE", envbuf, sizeof(envbuf));
std::string homePathEnv = sf_getenv_s("HOMEPATH", envbuf, sizeof(envbuf));
if (!homeDriveEnv.empty() && !homePathEnv.empty())
{
homeDir = homeDriveEnv + homePathEnv;
}
}
std::string homeDirFilePath = homeDir + PATH_SEP + SF_CLIENT_CONFIG_FILE_NAME;
if (checkFileExists(homeDirFilePath))
{
derivedConfigPath = homeDirFilePath;
CXX_LOG_INFO("sf", "ClientConfigParser", "loadClientConfig",
"Using client configuration path from home directory: %s", homeDirFilePath.c_str());
}
#else
// 4. Try user home dir
if (const char* homeDir = sf_getenv_s("HOME", envbuf, sizeof(envbuf)))
{
std::string homeDirFilePath = std::string(homeDir) + PATH_SEP + SF_CLIENT_CONFIG_FILE_NAME;
if (checkFileExists(homeDirFilePath))
{
derivedConfigPath = homeDirFilePath;
CXX_LOG_INFO("sf", "ClientConfigParser", "loadClientConfig",
"Using client configuration path from home directory: %s", homeDirFilePath.c_str());
}
}
#endif
}
}
if (!derivedConfigPath.empty())
{
parseConfigFile(derivedConfigPath, out_clientConfig);
}
}

// Private =====================================================================
////////////////////////////////////////////////////////////////////////////////
bool ClientConfigParser::checkFileExists(const std::string& in_filePath)
Copy link
Collaborator

@sfc-gh-ext-simba-hx sfc-gh-ext-simba-hx Oct 11, 2024

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?

Copy link
Collaborator Author

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

Copy link
Contributor

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

Copy link
Collaborator Author

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

{
FILE* file = sf_fopen(&file, in_filePath.c_str(), "r");
if (file != nullptr)
{
fclose(file);
return true;
}
return false;
}

////////////////////////////////////////////////////////////////////////////////
void ClientConfigParser::parseConfigFile(
const std::string& in_filePath,
ClientConfig& out_clientConfig)
{
cJSON* jsonConfig;
FILE* configFile;
try
{
configFile = sf_fopen(&configFile, in_filePath.c_str(), "r");
Copy link
Contributor

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?

Copy link
Collaborator Author

@sfc-gh-ext-simba-nl sfc-gh-ext-simba-nl Oct 17, 2024

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

Copy link
Contributor

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?

Copy link
Collaborator Author

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

Copy link
Contributor

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

Copy link
Contributor

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

Copy link
Collaborator Author

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

if (!configFile)
{
CXX_LOG_INFO("sf", "ClientConfigParser", "parseConfigFile",
"Could not open a file. The file may not exist: %s",
in_filePath.c_str());
std::string errMsg = "Error finding client configuration file: " + in_filePath;
throw ClientConfigException(errMsg.c_str());
}
#if !defined(WIN32) && !defined(_WIN64)
checkIfValidPermissions(in_filePath);
#endif
fseek(configFile, 0, SEEK_END);
long length = ftell(configFile);
rewind(configFile);
char* buffer = (char*)malloc(length);
if (buffer)
{
size_t result = fread(buffer, 1, length, configFile);
if (result != length)
{
CXX_LOG_ERROR(
"sf",
"ClientConfigParser",
"parseConfigFile",
"Error in reading file: %s", in_filePath.c_str());
}
}
jsonConfig = snowflake_cJSON_Parse(buffer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use picojson in c++ code

const char* error_ptr = snowflake_cJSON_GetErrorPtr();
if (error_ptr)
{
CXX_LOG_ERROR(
"sf",
"ClientConfigParser",
"parseConfigFile",
"Error in parsing JSON: %s, err: %s", in_filePath.c_str(), error_ptr);
std::string errMsg = "Error parsing client configuration file: " + in_filePath;
throw ClientConfigException(errMsg.c_str());
}
}
catch (std::exception& ex)
{
fclose(configFile);
throw;
}

const cJSON* commonProps = snowflake_cJSON_GetObjectItem(jsonConfig, "common");
checkUnknownEntries(snowflake_cJSON_Print(commonProps));
const cJSON* logLevel = snowflake_cJSON_GetObjectItem(commonProps, "log_level");
if (snowflake_cJSON_IsString(logLevel))
{
out_clientConfig.logLevel = snowflake_cJSON_GetStringValue(logLevel);
}
const cJSON* logPath = snowflake_cJSON_GetObjectItem(commonProps, "log_path");
if (snowflake_cJSON_IsString(logPath))
{
out_clientConfig.logPath = snowflake_cJSON_GetStringValue(logPath);
}
fclose(configFile);
}

////////////////////////////////////////////////////////////////////////////////
void ClientConfigParser::checkIfValidPermissions(const std::string& in_filePath)
{
boost::filesystem::file_status fileStatus = boost::filesystem::status(in_filePath);
sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
boost::filesystem::perms permissions = fileStatus.permissions();
if (permissions & boost::filesystem::group_write ||
permissions & boost::filesystem::others_write)
{
CXX_LOG_ERROR(
"sf",
"ClientConfigParser",
"checkIfValidPermissions",
"Error due to other users having permission to modify the config file: %s",
in_filePath.c_str());
std::string errMsg = "Error due to other users having permission to modify the config file: " + in_filePath;
throw ClientConfigException(errMsg.c_str());
}
}

////////////////////////////////////////////////////////////////////////////////
void ClientConfigParser::checkUnknownEntries(const std::string& in_jsonString)
{
cJSON* jsonConfig = snowflake_cJSON_Parse(in_jsonString.c_str());
const char* error_ptr = snowflake_cJSON_GetErrorPtr();
if (error_ptr)
{
CXX_LOG_ERROR(
"sf",
"ClientConfigParser",
"checkUnknownEntries",
"Error in parsing JSON: %s, err: %s", in_jsonString.c_str(), error_ptr);
std::string errMsg = "Error parsing json: " + in_jsonString;
throw ClientConfigException(errMsg.c_str());
}

if (snowflake_cJSON_IsObject(jsonConfig))
{
cJSON* entry = NULL;
snowflake_cJSON_ArrayForEach(entry, jsonConfig)
{
std::string key = entry->string;
bool found = false;
for (std::string knownEntry : KnownCommonEntries)
{
if (sf_strncasecmp(key.c_str(), knownEntry.c_str(), knownEntry.length()) == 0)
{
found = true;
}
}
if (!found)
{
std::string warnMsg =
"Unknown configuration entry: " + key + " with value:" + entry->valuestring;
CXX_LOG_WARN(
"sf",
"ClientConfigParser",
"checkUnknownEntries",
warnMsg.c_str());
}
}
}
}

////////////////////////////////////////////////////////////////////////////////
std::string ClientConfigParser::getBinaryPath()
{
std::string binaryFullPath;
#if defined(WIN32) || defined(_WIN64)
std::wstring path;
HMODULE hm = NULL;
wchar_t appName[256];
GetModuleFileNameW(hm, appName, 256);
path = appName;
binaryFullPath = std::string(path.begin(), path.end());
#else
Dl_info info;
int result = dladdr((void*)load_client_config, &info);
if (result)
{
binaryFullPath = std::string(info.dli_fname);
}
#endif
size_t pos = binaryFullPath.find_last_of(PATH_SEP);
if (pos == std::string::npos)
{
return "";
}
std::string binaryPath = binaryFullPath.substr(0, pos + 1);
return binaryPath;
}
Loading
Loading