C++ Pass Boost::log severity level as argument to function - c++

I want to have only one function to write logs which would parse ellipsis and send result to the Boost::log, based on severity level. In header file would be defined different macros, which would select a correct severity level. There is the code:
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#define DEBUG(msg, ...) Logger::write_log(debug, msg, ##__VA_ARGS__);
#define INFO(msg, ...) Logger::write_log(info, msg, ##__VA_ARGS__);
#define WARNING(msg, ...) Logger::write_log(warning, msg, ##__VA_ARGS__);
#define ERROR(msg, ...) Logger::write_log(error, msg, ##__VA_ARGS__);
namespace logging = boost::log;
void write_log(auto level, const char *message, ...)
{
char buffer[512];
va_list args;
// Parse ellipsis and add arguments to message
va_start (args, message);
vsnprintf (buffer, sizeof(buffer), message, args);
va_end (args);
BOOST_LOG_TRIVIAL(level) << buffer;
}
int main(int argc, char** argv)
{
DEBUG("Test string %s", "additional string");
return 0;
}
But during compilation I get the next error:
error: 'level' is not a member of 'boost::log::v2s_mt_nt5::trivial'
BOOST_LOG_TRIVIAL(level) << buffer;
Seems that my level argument have an incorrect type. I also tried to use logging::trivial::severity_level level instead of auto level, but this didn't help. How can I fix this error?
UPDATED:
there is working solution:
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#define DEBUG(msg, ...) Logger::write_log(debug, msg, ##__VA_ARGS__);
#define INFO(msg, ...) Logger::write_log(info, msg, ##__VA_ARGS__);
#define WARNING(msg, ...) Logger::write_log(warning, msg, ##__VA_ARGS__);
#define ERROR(msg, ...) Logger::write_log(error, msg, ##__VA_ARGS__);
namespace logging = boost::log;
enum severity_level
{
debug,
info,
warning,
error,
exception
};
src::severity_logger<severity_level> slg;
void write_log(severity_level level, const char *message, ...)
{
char buffer[512];
va_list args;
// Parse ellipsis and add arguments to message
va_start (args, message);
vsnprintf (buffer, sizeof(buffer), message, args);
va_end (args);
BOOST_LOG_SEV(slg, level) << buffer;
}
int main(int argc, char** argv)
{
DEBUG("Test string %s", "additional string");
return 0;
}

Follow boost log example and define:
// severity levels
enum severity_level
{
trace,
debug,
info,
warning,
error,
fatal
};
And you need to make your function to accept proper type:
void write_log(severity_level level, const char *message, ...){ ... }
Another option:
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#define DEBUG(msg, ...) Logger::write_log(logging::trivial::debug, msg, ##__VA_ARGS__);
#define INFO(msg, ...) Logger::write_log(logging::trivial::info, msg, ##__VA_ARGS__);
#define WARNING(msg, ...) Logger::write_log(logging::trivial::warning, msg, ##__VA_ARGS__);
#define ERROR(msg, ...) Logger::write_log(logging::trivial::error, msg, ##__VA_ARGS__);
namespace logging = boost::log;
#define LOG_TRIVIAL(lvl)\
BOOST_LOG_STREAM_WITH_PARAMS(::boost::log::trivial::logger::get(),\
(::boost::log::keywords::severity = lvl))
void write_log(logging::trivial::severity_level level, const char *message, ...)
{
char buffer[512];
va_list args;
// Parse ellipsis and add arguments to message
va_start(args, message);
vsnprintf(buffer, sizeof(buffer), message, args);
va_end(args);
LOG_TRIVIAL(level) << buffer;
}
int main(int argc, char** argv)
{
DEBUG("Test string %s", "additional string");
return 0;
}

My advice: create your own severity. It's just an enum! Follow the source code of that "level" (using your IDE) to see that it's a simple enum. Copy it to your implementation, and change it as necessary. This is how it looks (after changing its name):
enum my_severity_level
{
trace,
debug,
info,
warning,
error,
fatal
};
Take that to your code, and use it as necessary.
That write_log function should be like this:
void write_log(my_severity_level level, const char *message, ...) { ... }

Related

Issue with nested #define for defining a function with variadic arguments

How can I define a nested #define into a macro with variadic arguments
#ifndef MY_PRINTF
#define MY_PRINTF(f_, ...) { \
#ifdef USE_WRITE_DEBUG_INFO \
char buff[200]; \
sprintf(buff, (f_), __VA_ARGS__); \
WriteDebugInfo(buff); \
#else \
printf((f_), __VA_ARGS__); \
#endif \
}
#endif
Visual studio complains about missing directives. I'd appreciate for any hint.
You can't use preprocessor directives while defining a #define. This means that your #ifdef USE_WRITE_DEBUG_INFO won't work.
For this case, use a function rather than a macro:
#include <cstdarg>
void my_printf(const char* format, ...) {
#ifdef USE_WRITE_DEBUG_INFO
char buff[200];
va_list args;
va_start(args, format);
// Note: uses the snprintf variant rather than sprintf variant,
// avoiding buffer overlows.
vsnprintf(buff, 200, format, args);
va_end(args);
WriteDebugInfo(buff);
#else
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
#endif
}
In general, you'd have to bring the preprocessor directives outside of the #define:
#ifndef MY_PRINTF
#ifdef USE_WRITE_DEBUG_INFO
// do { ... } while (false) makes the macro behave mostly like a regular function call.
#define MY_PRINTF(f_, ...) do { \
char buff[200]; \
sprintf(buff, (f_), __VA_ARGS__); \
WriteDebugInfo(buff); \
} while (false)
#else
#define MY_PRINTF(f_, ...) printf((f_), __VA_ARGS__)
#endif
#endif

mex script and how to show output from another function which is using vprintf()

I am implementing a mex script, where at some point I need to call a function from an external library. This function is as simple as printing the provided input, which is though collected as arguments and passed to vprintf(). See below:
void PrintInfo(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
The issue now is that once I call the PrintInfo() function inside my mex script for example:
PrintInfo("Give me %i apples.\n", 3);
I am not able to get any output in the matlab's console prompt, like I do when I used printf() or cout instead. I was trying to figure it out myself but no chance so far, thus I would appreciate if someone could explain me what is the issue and how I can bypass it.
Altering the library's files is not possible, thus I am looking for a solution that can be done on mex script from my side.
Update: For example in the following mex script from the printing functions only the PrintInfo() does not show anything:
#include "mex.h"
// cpp system headers
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdarg>
using namespace std;
void PrintInfo(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
void foo()
{
printf("Vector size is: %i \n", 5);
}
void foo1(const char *format, int sz)
{
printf(format, sz);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
PrintInfo("Vector size is: \n", 10);
foo();
foo1("Vector size is: %i \n", 2);
cout << "Vector size is:" << 4 << endl;
}

how to avoid using ifdef to make code more testable

I am creating a log file for logging information. It has a switch to turn it on or off.
#define LOG_FILE
#ifdef LOG_FILE
#define LOG(MESSAGE1, MESSAGE2) log(MESSAGE1, MESSAGE2);
#else
#define LOG(MESSAGE1, MESSAGE2)
#endif
Now I can control logging using LOG_FILE switch. I was wondering there are any other way achieve similar feature which is more testable?
You can use templates like this:
#include <string>
#include <iostream>
#define USE_LOGGING true
template<bool>
inline void log(const std::string& message, const std::string& verbosity) {}
template<>
inline void log<true>(const std::string& message, const std::string& verbosity) {
std::cout << verbosity << ": " << message << "\n";
}
constexpr auto logMessage = log<USE_LOGGING>;
int main(int argc, char** argv) {
logMessage("Test", "Warning");
}
By this you will have both versions available, using logMessage gives you the global settings, alternatively you can use log directly which is a local definition of how to use logging.

Conflicting error in using c++ macro in Xcode

We having problems regarding the usage of macro in project.
Below showing three files, debug.cpp and Utils.cpp are both using debug.h's macro function AA(arg1, ...).
Three files have conflicts due to that macro definition.
When i comment out the line void AaFun(const char *arg1, const char *arg2, ...); in debug.h, debug.cpp can run but the Utils.cpp will show the error message of
Use of undeclared identifier 'AaFun'.
But if we don't comment the line in debug.h, then we received the error message from debug.cpp
Conflicting types for 'AaFun'
Three files should be able to run together, can anyone help me to understand the problem and a possible solution.
class debug.h:
#ifndef __DEBUG_H__
#define __DEBUG_H__
#define DEBUG 1
#ifdef DEBUG
#define AA(arg1, ...) AaFun(arg1, ARG2, ## __VA_ARGS__)
#endif
.....
void AaFun(const char *arg1, const char *arg2, ...);
class debug.cpp:
#include "debug.h"
...
void AaFun(const char *arg1, ...)
{
...function content...
}
class Utils.cpp
#include "debug.h"
string Utils::dupName(string origName, int num)
{
AA("Making a dupName from %s and %d\n", origName.c_str(), num);
return xxx;
}

Why following code doesn't produce any output?

Why the code below doesn't produce any output? I expected it to be 42 s. How to fix it?
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
void foo(const char* format, ...)
{
va_list args;
va_start(args, format);
printf(format, args);
va_end(args);
}
int main()
{
foo("%d %s\n", 42, "s");
return 0;
}
http://ideone.com/EsHsRO
Actually, it produces http://codepad.org/k7ld231E.
Why the foo is wrong?
You need to use vprintf instead: int vprintf( const char* format, va_list vlist );
vprintf(format, args);
printf() and friends are for normal use. vprintf() and friends are for when you want to write your own printf()-like functions.