C++ and writing enum values into Windows registry - c++

I am writing a function as follows:
bool abc::GetLoggingStatus() {
//true or false is returned
int value;
if (regKey->HasValue("LoggingStatus")) {
regKey->QueryValue("LoggingStatus", &value);
if (value == 1)
return true; //no logging possible
else
return false;
}
regKey->SetValue("LoggingStatus", 1);
return true;
}
Logging level is defined as:
typedef enum {
Entry,
Exit,
Debug,
Warning,
Notification,
Error
} TYPE;
What I need if I select 1 the levels for logging must be shown namely debug,error ... In regedit and if 0 nothing should be shown and logging be disabled.

You can't create dropdown menus in regedit, but what you can do is create a new entry called LoggingLevel. This entry is ignored if LoggingStatus is 0. LoggingLevel is a string defining the level.
If you want to convert this string back to an enum, the easiest way is to create a map from string to your Enum type:
std::map<std::string, TYPE> typeMap;
typeMap["Warning"] = Warning;
...
In your code you query the logging level:
char* level;
regKey->QueryValue("LoggingLevel", level);
TYPE theLevel = typeMap[level];
Of course you need to do appropriate error checking.
edit
You should add two function to get the log settings, shouldLog() and getLevel().
The log function would then look like:
void log(Logger* logger, TYPE type, string sClassName, string sMethodName, string sMessage = "") {
if (!logger || !abc::shouldLog()) {
return;
}
TYPE curLevel = abc::getLevel();
bool shouldLog = false;
if (type == Warning && (curLevel == All || curLevel == Warning) ...) {
shouldLog = true;
}
if (shouldLog) {logger->WriteEntry(sClassName, sMethodName); }
}
If you want to avoid complicated if-structures, you could also try and map the enums to a value and compare that. For example Warning = 1 and ALL = 0. Then you can check if curLevel < type to see if the logger should log.

Related

How can I use multiple filters on a single sink with boost::log

I'm using a sink to log information and a file with information on the different levels I want for each tag I created like so:
sink->set_filter(logging::trivial::severity >= logging::trivial::warning && expr::attr<std::string>("Tag") == tag);
[...]
sink->set_filter(logging::trivial::severity >= logging::trivial::warning && expr::attr<std::string>("Tag") == tag1);
with both tag and tag1 different tags
I also tried to apply the documentation of boost::phoenix to my problem but I can't figure out how to implement it.
Right now, I have this code, but it just overrides the filter each time I get into a leaf.
void setSinks()
{
logging::core::get()->add_global_attribute("Tag", attrs::mutable_constant<std::string>(""));
std::string path = "..../log_config.json";
[def of sink...]
pt::ptree root;
pt::read_json(path, root);
std::function<void(pt::ptree, std::string)> parse_tree;
auto setFilter = [](std::string tag, std::string logLevel) {
logging::trivial::severity_level level;
if (logLevel == "TRACE") level = logging::trivial::trace;
else if (logLevel == "DEBUG") level = logging::trivial::debug;
else if (logLevel == "INFO") level = logging::trivial::info;
else if (logLevel == "WARNING") level = logging::trivial::warning;
else if (logLevel == "ERROR") level = logging::trivial::error;
else if (logLevel == "FATAL") level = logging::trivial::fatal;
else level = logging::trivial::debug;
return logging::trivial::severity >= level && expr::attr<std::string>("Tag") == tag;
};
parse_tree = [&sink, &setFilter, &parse_tree](pt::ptree tree, std::string tag)
{
for (const auto& v : tree)
{
std::string name = v.first;
pt::ptree value = v.second;
if (value.empty())
{
sink->set_filter(setFilter(tag + "." + name, value.data()));
}
else
{
parse_tree(value, (tag.empty() ? name : tag + "." + name));
}
}
};
parse_tree(root, "");
}
If your list of tags is known and fixed at compile time, you can compose a filter using template expressions like this:
sink->set_filter
(
(expr::attr<std::string>("Tag") == tag1 && logging::trivial::severity >= severity1) ||
(expr::attr<std::string>("Tag") == tag2 && logging::trivial::severity >= severity2) ||
...
);
Here, tag1, tag2, severity1 and severity2 may be constants or dynamic values, e.g. obtained from a file.
If the list of tags is more dynamic, you could use channel_severity_filter. It is used to map severity level thresholds to different channels, and in your case your "Tag" attribute plays the role of a channel name.
// Create a threshold table. If not using keywords, you have to explicitly
// specify the value types of Tag and Severity attributes.
auto min_severity = expr::channel_severity_filter<
std::string, logging::trivial::severity_level>("Tag", "Severity");
// Populate the table. You may do this dynamically, in a loop.
min_severity[tag] = severity;
sink->set_filter(min_severity);
You may also combine this filter with other template expressions, as shown in the docs.
Lastly, you can implement whatever filtering logic you want by writing your own filtering function.
typedef std::map<std::string, logging::trivial::severity_level> severity_table_t;
bool my_filter(
severity_table_t const& table,
logging::value_ref<std::string> tag,
logging::value_ref<logging::trivial::severity_level> severity)
{
// Check if Tag and Severity attributes were present in the log record
if (!tag || !severity)
return false;
// Check if the Tag is present in the table
auto it = table.find(*tag);
if (it == table.end())
return false;
// Check if Severity satisfies the threshold
return *severity >= it->second;
}
// Populate the table, e.g. from a file
severity_table_t table;
sink->set_filter(boost::phoenix::bind(
&my_filter,
table,
expr::attr<std::string>("Tag").or_none(),
expr::attr<logging::trivial::severity_level>("Severity").or_none()));
You can also do away with Boost.Phoenix and implement attribute value extraction yourself.
typedef std::map<std::string, logging::trivial::severity_level> severity_table_t;
// Populate the table, e.g. from a file
severity_table_t table;
sink->set_filter
(
[table](logging::attribute_value_set const& record)
{
// Check if Tag and Severity attributes were present in the log record
auto tag = record["Tag"].extract<std::string>();
if (!tag)
return false;
// You can use keywords to reference attribute values
auto severity = record[logging::trivial::severity];
if (!severity)
return false;
// Check if the Tag is present in the table
auto it = table.find(*tag);
if (it == table.end())
return false;
// Check if Severity satisfies the threshold
return *severity >= it->second;
}
);

Recursive symbol checking

I am getting an error that I am having problems fixing as recursion hasn't "sunk in" yet.
It is supposed to go through an array of symbols already placed by the Class OrderManager Object and check if the symbol passed in is already there or not, if it is not there it should allow the trade, otherwise it will block it (multiple orders on the same currency compounds risk)
[Error] '}' - not all control paths return a value.
I believe it is because of the retest portion not having a return value but again I'm still newish to making my own recursive functions. However it may also be because my base and test cases are wrong possibly?
P.S I added (SE) comments in places to clarify language specific things since it is so close to C++.
P.P.S Due to the compiler error, I have no clue if this meets MVRC. Sorry everyone.
bool OrderManager::Check_Risk(const string symbol, uint iter = 0) {
if((iter + 1) != ArraySize(m_symbols) &&
m_trade_restrict != LEVEL_LOW) // Index is one less than Size (SE if
// m_trade_restrict is set to LOW, it
// allows all trades so just break out)
{
if(OrderSelect(OrderManager::Get(m_orders[iter]),
SELECT_BY_TICKET)) // Check the current iterator position
// order (SE OrderSelect() sets an
// external variable in the terminal,
// sort of like an environment var)
{
string t_base = SymbolInfoString(
OrderSymbol(),
SYMBOL_CURRENCY_BASE); // Test base (SE function pulls apart
// the Symbol into two strings
// representing the currency to check
// against)
string t_profit =
SymbolInfoString(OrderSymbol(), SYMBOL_CURRENCY_PROFIT);
string c_base =
SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE); // Current base
// (SE does the same as above but for the passed variable instead):
string c_profit = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
// Uses ENUM_LEVELS from Helpers.mqh (SE ENUM of 5 levels: Strict,
// High, Normal, Low, None in that order):
switch(m_trade_restrict) {
case LEVEL_STRICT: {
if(t_base == c_base || t_profit == c_profit) {
return false; // Restrictions won't allow doubling
// orders on any currency
} else
return Check_Risk(symbol, iter++);
};
case LEVEL_NORMAL: {
if(symbol == OrderSymbol()) {
return false; // Restrictions won't allow doubling
// orders on that curr pair
} else
return Check_Risk(symbol, iter++);
};
default: {
// TODO: Logging Manager
// Hardcoded constant global (SE set to LEVEL_NORMAL):
ENB_Trade_Restrictions(default_level);
return Check_Risk(symbol, iter);
}
}
}
} else {
return true;
}
}
So, I must just have been staring at the code for too long but the problem was the if(OrderSelect(...)) on ln 7 did not have a return case if the order was not properly set in the terminal. I will need to polish this but the following code removes the error.
bool OrderManager::Check_Risk(const string symbol, uint iter=0)
{
if((iter + 1) != ArraySize(m_symbols) && m_trade_restrict != LEVEL_LOW) // Index is one less than Size
{
if(OrderSelect(OrderManager::Get(m_orders[iter]), SELECT_BY_TICKET)) //Check the current iterator position order
{
string t_base = SymbolInfoString(OrderSymbol(), SYMBOL_CURRENCY_BASE); //Test base
string t_profit = SymbolInfoString(OrderSymbol(), SYMBOL_CURRENCY_PROFIT);
string c_base = SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE); //Current base
string c_profit = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
switch(m_trade_restrict) // Uses ENUM_LEVELS from Helpers.mqh
{
case LEVEL_STRICT :
{
if(t_base == c_base || t_profit == c_profit)
{
return false;
}
else return Check_Risk(symbol, ++iter);
};
case LEVEL_NORMAL :
{
if(symbol == OrderSymbol())
{
return false;
}
else return Check_Risk(symbol, ++iter);
};
default: {
// TODO: Logging Messages
ENB_Trade_Restrictions(default_level); //Hardcoded constant global
return Check_Risk(symbol, iter);
}
}
}
else {return Check_Risk(symbol, ++iter);}
}
else {return true;}
}

per thread c++ guard to prevent re-entrant function calls

I've got function that call the registry that can fail and print the failure reason.
This function can also be called directly or indirectly from the context of a dedicated built-in printing function, and I wish to avoid printing the reason in this case to avoid endless recursion.
I can use thread_local to define per thread flag to avoid calling the print function from this function, but I guess it's rather widespread problem, so I'm looking for std implementation for this guard or any other well debugged code.
Here's an example that just made to express the problem.
Each print function comes with log level, and it's being compared with the current log level threshold that reside in registry. if lower than threshold, the function returns without print. However, in order to get the threshold, additional print can be made, so I wanted to create a guard that will prevent the print from getPrintLevelFromRegistry if it's called from print
int getPrintLevelFromRegistry() {
int value = 0;
DWORD res = RegGetValueW("//Software//...//logLevel" , &value);
if (res != ERROR_SUCCESS) {
print("couldn't find registry key");
return 0;
}
return value;
}
void print(const char * text, int printLoglevel) {
if (printLogLevel < getPrintLevelFromRegistry()) {
return;
}
// do the print itself
...
}
Thanks !
The root of the problem is that you are attempting to have your logging code log itself. Rather than some complicated guard, consider the fact that you really don't need to log a registry read. Just have it return a default value and just log the error to the console.
int getPrintLevelFromRegistry() {
int value = 0;
DWORD res = RegGetValueW("//Software//...//logLevel" , &value);
if (res != ERROR_SUCCESS) {
OutputDebugStringA("getPrintLevelFromRegistry: Can't read from registry\r\n");
}
return value;
}
Further, it's OK to read from the registry on each log statement, but it's redundant and unnecessary.
Better:
int getPrintLevelFromRegistry() {
static std::atomic<int> cachedValue(-1);
int value = cachedValue;
if (value == -1) {
DWORD res = RegGetValueW("//Software//...//logLevel" , &value);
if (res == ERROR_SUCCESS) {
cachedValue = value;
}
}
return value;
}

is there a better way to make this software flow

I have several functions that try and evaluate some data. Each function returns a 1 if it can successfully evaluate the data or 0 if it can not. The functions are called one after the other but execution should stop if one returns a value of 1.
Example functions look like so:
int function1(std::string &data)
{
// do something
if (success)
{
return 1;
}
return 0;
}
int function2(std::string &data)
{
// do something
if (success)
{
return 1;
}
return 0;
}
... more functions ...
How would be the clearest way to organise this flow? I know I can use if statements as such:
void doSomething(void)
{
if (function1(data))
{
return;
}
if (function2(data))
{
return;
}
... more if's ...
}
But this seems long winded and has a huge number of if's that need typing. Another choice I thought of is to call the next function from the return 0 of the function like so
int function1(std::string &data)
{
// do something
if (success)
{
return 1;
}
return function2(data);
}
int function2(std::string &data)
{
// do something
if (success)
{
return 1;
}
return function3(data);
}
... more functions ...
Making calling cleaner because you only need to call function1() to evaluate as far as you need to but seems to make the code harder to maintain. If another check need to be inserted into the middle of the flow, or the order of the calls changes, then all of the functions after the new one will need to be changed to account for it.
Am I missing some smart clear c++ way of achieving this kind of program flow or is one of these methods best. I am leaning towards the if method at the moment but I feel like I am missing something.
void doSomething() {
function1(data) || function2(data) /* || ... more function calls ... */;
}
Logical-or || operator happens to have the properties you need - evaluated left to right and stops as soon as one operand is true.
I think you can make a vector of lambdas where each lambdas contains specific process on how you evaluate your data. Something like this.
std::vector<std::function<bool(std::string&)> listCheckers;
listCheckers.push_back([](std::string& p_data) -> bool { return function1(p_data); });
listCheckers.push_back([](std::string& p_data) -> bool { return function2(p_data); });
listCheckers.push_back([](std::string& p_data) -> bool { return function3(p_data); });
//...and so on...
//-----------------------------
std::string theData = "Hello I'm a Data";
//evaluate all data
bool bSuccess = false;
for(fnChecker : listCheckers){
if(fnChecker(theData)) {
bSuccess = true;
break;
}
}
if(bSuccess ) { cout << "A function has evaluated the data successfully." << endl; }
You can modify the list however you like at runtime by: external objects, config settings from file, etc...

Convert CefRefPtr<CefV8Value> into int in Chromium Embedded Framework

I'm trying to extend the cefsimple app that comes with the Chromium Embedded Framework to include a V8 handler. The code I've written looks like this so far;
bool SimpleHandler::Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) {
int argn = arguments.size();
if (name == "serial_connect" && (argn == 4 || argn == 1))
{
if (connection.isOpen())
connection.~Serial();
connection = NULL;
if (argn == 1)
{
int port = (arguments[0]); // convert to int?
}
else
{
}
}
else if (name == "serial_send" && argn >= 1)
{
}
else if (name == "serial_recieve")
{
}
else
return false;
return true;
}
I'm having trouble converting the generic value object returned given by the handler into a cpp int that I can use in calculations. I've found the function CefV8Value::GetIntValue();, but I can't figure out how to use it.
try calling object->GetIntValue()
The reason is that CefRefPtr is an object that holds a reference to CefV8Value, so you need the arrow operator to access the underlying CefV8Value object it points to