I have different parts of my application calling a logger function to log details.
Logger class
std::string filename = "blahblah"; // variable to store the location of the properties file
log4cpp::PropertyConfigurator::configure(filename);
void Logger::logging(const std::string& msg)
{
Log4cpp::Category& myLogger = log4cpp::Category::getRoot();
myLogger.log(log4cpp::Priority::INFO, msg);//only takes in string as input
}
Calling class
Logger logMe;
int a = 5;
double b = 6;
logMe.logging("log this msg" + a + "," + b);
I realised that the above will give me error, as a
and b
are of different types. One way to solve it is to use std::to_string
logMe.logging("log this msg" + std::to_string(a) + "," + std::to_string(b));
However, I have hundreds of calls to the logging function, and it will be time consuming to edit each and every call to std::to_string
. Is/are there any easier way(s) to do it?
Oh and to clarify, the code works before as the previous way was by defining a #define function.
#Define logging(FLAG, X)\
do {\
...
clog << x; \
}while(0)
logging(LogFlag::Warning, "log this msg" << a << "," << b << endl);
But i am now rewriting parts of the code to comply to static testing.
Thanks in advance.
You can concatenate two C-style strings in C++ using strcat() function.
(String Concatenation) In the C Programming Language, the strcat function appends a copy of the string pointed to by s2 to the end of the string pointed to by s1. It returns a pointer to s1 where the resulting concatenated string resides.
You can think of string concatenation as gluing strings together. And, you can think of string interpolation without strings as injecting strings inside of other strings.
This example demonstrates the difference between strcat() and strncat() . The strcat() function appends the entire second string to the first, whereas strncat() appends only the specified number of characters in the second string to the first.
You can add an overload of logging
that takes a parameter pack and joins it up into a string, using std::stringstream
In c++17, we can use a fold expression, e.g.
template <typename Args ...>
void Logger::logging(Args ... args)
{
std::stringstream ss;
(ss << ... << args);
Log4cpp::Category& myLogger = log4cpp::Category::getRoot();
myLogger.log(log4cpp::Priority::INFO, ss.str());
}
In c++11 or 14, we have to be slightly more tricky
template <typename ... Args >
void Logger::logging(Args ... args)
{
std::stringstream ss;
std::initializer_list<int> unused{ (ss << args, 0)... };
Log4cpp::Category& myLogger = log4cpp::Category::getRoot();
myLogger.log(log4cpp::Priority::INFO, ss.str());
}
Then you call either as e.g.
logMe.logging("log this msg", a, ",", b);
I suggest adding an operator<<()
to the class
class Logger
{
public:
Logger &operator<<(const std::string &s)
{
logging(s)
return *this;
};
Logger &operator<<(const char *s)
{
return operator<<(std::string(s));
}
template <class T>
Logger &operator<<(const T &v)
{
std::ostringstream s;
s << v;
return operator<<(logging(ss.str()));
};
// other stuff you have in your class, including the logging() function
};
// to use
logMe << "log this msg" << a << b;
Not quite the same syntax to use this as you have described, but it works more generally.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With