C++ style Logger that supports __LINE__ macro and others - c++

I want to make a Logger that can be used like std::cout, but I want to log some extra data like date, time, __LINE__, __func__, and __FILE__ which should be saved to the file automatically.
Example
ToolLogger log;
log << "some data" << std::endl;
Expected output
[14.11.2015 21:10:12.344 (main.cpp) (main,14): some data
Inadequate solution
To do this I have to put macros like __LINE__ direct in the line where I call my logger, otherwise the macros won't work correct. I found that I can replace std::endl with my macro that will do this black magic like this:
#define __FILENAME__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/') + 1 : __FILE__)
#define logendl \
((ToolLogger::fileName = __FILENAME__).empty() ? "" : "") \
<< ((ToolLogger::line = __LINE__) ? "" : "") \
<< ((ToolLogger::function = __func__).empty() ? "" : "") \
<< std::endl
The macro logendl uses static variables from my ToolLogger class to save the values of __LINE__, __func__ and __FILE__ needed later. So actually using the logger will looks like this:
ToolLogger log;
log << "some data" << logendl;
In the class i have to overload the operator<< to get this to work, and I need two of them. One for taking the normal values like std::string or int, and the other to take the std::endl manipulator. Here is the most important things from my class:
class ToolLogger
{
public:
// standard operator<< //
template<typename T>
ToolLogger& operator<< (const T& str)
{
out << str;
return *this;
}
// operator<< for taking the std::endl manipulator //
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
typedef CoutType& (*StandardEndLine)(CoutType&);
ToolLogger& operator<<(StandardEndLine manip)
{
// save fileName, line and function to the file //
// and all what is already in stringstream //
// clear stringstream //
return *this;
}
static string fileName;
static int line;
static string function;
private:
ofstream file;
std::stringstream out;
};
string ToolLogger::fileName;
int ToolLogger::line;
string ToolLogger::function;
Problem
The problem in this solution is that I can use my logger in two ways:
log << "some data" << logendl; // correct //
log << "some data" << std::endl; // compiles -> wrong /
So actually I need to remove the operator<< from my class that takes std::endl manipulator, and solve it other way, but how to do it? I was thinking about changing std::endl in logendl macro to other custom manipulator, and then this custom manipulator will do the work that is actually doing the operator<<, but I have no idea how to do it. I'm looking for other solution, any suggestions?

Here's what I do. It kind of skirts your question. That is, is does away with having to define an endl. What I do is separate out a Logger class (which just takes strings and outputs then to wherever you need them to go) from a LogMessage class which builds a message.
The benefits are:
Each class, on it's own, is pretty simple.
Very simple macros. I don't define the macro below but it's easy enough to do.
No need to define an endl. The message ends at the semicolon when the LogMessage class destructs
Let me know what you think:
#include <iostream>
#include <sstream>
#include <string>
// logger class
// this is not complete, it exists just to illustrate the LogIt function
class Logger
{
public:
void LogIt(const std::string & s)
{
std::cout << s << std::endl;
}
};
// builds a logging message; outputs it in the destructor
class LogMessage
{
public:
// constructor
// takes identifying info of message. You can add log level if needed
LogMessage(const char * file, const char * function, int line)
{
os << file << ": " << function << '(' << line << ") ";
}
// output operator
template<typename T>
LogMessage & operator<<(const T & t)
{
os << t;
return *this;
}
// output message to Logger
~LogMessage()
{
Logger logger; // get logger here (perhaps it's a singleton?)
logger.LogIt(os.str());
}
private:
std::ostringstream os;
};
int main()
{
// example usage
// typically this is invoked via a simple macro to reduce typing of the LogMessage constructor
LogMessage(__FILE__, __func__, __LINE__) << "this is an int " << 5;
}

You might have a LoggerAt class with a LoggerAt(const char*filename, int lineno) constructor (perhaps a subclass of std::ostringstream, etc...), then define
#define LOG(Out) do {LoggerAt(__FILE__,__LINE__) \
<< Out << std::endl; }while(0)
In some of my C++ projects I have coded:
void mom_inform_at(const char*fil, int lin, std::ostringstream& out)
{ out.flush();
std::clog << fil << ":" << lin
<< " INFORM: " << out.str() << std::endl ;
}
#define MOM_INFORM_AT(Fil,Lin,Output) do { \
std::ostringstream out_##Lin; \
out_##Lin << mom_outlog << Output ; \
mom_inform_at(Fil,Lin,out_##Lin); \
} while(0)
#define MOM_INFORM_AT_BIS(Fil,Lin,Output) \
MOM_INFORM_AT(Fil,Lin,Output)
#define MOM_INFORM(Out) \
MOM_INFORM_AT_BIS(__FILE__,__LINE__,Out)
And using something like MOM_INFORM("x=" << " point:" << pt); where you could imagine the usual Point pt; example with appropriate std::ostream& operator << (std::ostream&out, const Point&point) function.
Notice that to use conveniently __FILE__ and __LINE__ you'll better use macros.

I have solved my own problem. Other answers posted here may be better than main, but I wanted to use logger in a simple way just like in C++ std::cout is used. Also my solution may not be optimal and may lead to other problems, but it meets my requirements.
I have added a custom std::ostream
class CustomOstream : public std::ostream
{
public:
static CustomOstream& endl( CustomOstream& out )
{
return out;
}
};
and changed macro to use the endl function from CustomOstream
#define __FILENAME__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/') + 1 : __FILE__)
#define logendl \
((ToolLogger::fileName = __FILENAME__).empty() ? "" : "") \
<< ((ToolLogger::line = __LINE__) ? "" : "") \
<< ((ToolLogger::function = __func__).empty() ? "" : "") \
<< ToolLogger::CustomOstream::endl
Also the operator<< from the main class has been changed
ToolLogger& operator<< (CustomOstream& (*f)(CustomOstream&))
{
// do something //
return *this;
}
Now the logger can be used just like I wanted
log << "some data" << logendl; // correct //
log << "some data" << std::endl; // won't compile -> correct //

Related

Variable enum 'class' in c++

I use something like in the following code fairly often:
// myclass.h
class MyClass {
public:
enum MyEnum { E1, E2, NUMMYENUM };
const char* kMyEnum[NUMMYENUM] = {"e1", "e2"};
const char* MyEnum2Char(MyEnum me) { return kMyEnum[me]; }
enum MySEnum { SE1, SE2, NUMMYSENUM };
static const char* kMySEnum[NUMMYSENUM];
static const char* MySEnum2Char(MySEnum se) { return kMySEnum[se]; }
void foo(MyEnum me) {
//do something, e.g. print
std::cout << MyEnum2Char(me) << "maps to " << emap[me] << "\n";
}
void bar(MySEnum se) {
//do something, e.g. print
std::cout << MySEnum2Char(se) << "maps to " << semap[se] << "\n";
}
private:
std::map<MyEnum, int> emap;
std::map<MySEnum, int> semap;
};
// myclass.cc
#include "myclass.h"
const char* MyClass::kMySEnum[MyClass::MySEnum::NUMMYSENUM] = {"se1", "se2"};
The way of generating an enum, a char* array and a function converting enum to char seems to add avoidable clutter and I am wondering if there isn't another way to achieve this? Something like the following isn't possible for multiple reasons, but might give you an idea of what I'd like to have:
// myclass.h
class MyClass {
public:
MyVariableEnumClass MyEnum(E1, "e1", E2, "e2");
static MyVariableEnumClass MySEnum;
void foo(MyEnum me) {
//do something, e.g. print
std::cout << me.string() << "maps to " << emap[me] << "\n";
}
void bar(MySEnum se) {
//do something, e.g. print
std::cout << se.string() << "maps to " << semap[se] << "\n";
}
private:
std::map<MyEnum, int> emap;
std::map<MySEnum, int> semap;
};
// myclass.cc
#include "myclass.h"
MyVariableEnumClass MyClass::MySEnum = MyVariableEnumClass(SE1, "se1", SE2, "se2");
Is there a way to achieve something 'clutter-free' like this? Maybe using macros?
A technique called XMacro can be used in C++ 11 as well as older versions of C++ and C to easily define consistent look-up tables for translating enums to strings.
First, you write an external file (let's call it my_class.xmacro) which includes the following:
#define SE_ENUM_TABLE \
ENTRY(SE1) \
ENTRY(SE2)
Next in your H file you include my_class.xmacro define the following:
#include "my_class.xmacro"
enum SeEnum{
#define ENTRY(a) a,
SE_ENUM_TABLE
#undef ENTRY
};
const std::string seEnumString[] = {
#define str_macro(a) #a
#define ENTRY(a) str_macro(a),
SE_ENUM_TABLE
#undef ENTRY
};
The macros inside seEnumStringId take ENTRY(a) and transform it to "a". So after pre-processor is finished with this file, it actually looks to the compiler as follows:
enum SeEnum{
SE1,
SE2
};
const std::string seEnumString[] = {
"SE1",
"SE2"
};
Using this technique you ensure that adding an enum will automatically create string id in the RIGHT order, and this technique can be used to generate additional types of look-up tables as well.

Where to put function declaration?

Let's say I'm developing a logging functionality. Inside logging.h I declare the function to be used by the application later on.
// logging.h
#include <string>
namespace logging {
void LogThis(const std::string& text);
}; // namespace logging
Its definition is obviously inside logging.cpp:
// logging.cpp
void logging::LogThis(const std::string& text) {
std::cout << "Log: " << text << '\n';
}
Now lets pretent that my LogThis function's work is split up into some smaller helper functions. They're not part of the logging interface. Let's take a Prettify function as an example.
// logging.cpp
void logging::LogThis(const std::string& text) {
Prettify(text);
std::cout << "Log: " << text << '\n';
}
My question is: Where do I put the function declaration of Prettify? I shouldn't include it in the logging.h header file, because then it can be called by other compilation units and its not part of the interface. So just put it inside logging.cpp instead like this?
// logging.cpp
namespace logging {
void Prettify(std::string& ugly_text);
void LogThis(const std::string& text) {
Prettify(text);
std::cout << "Log: " << text << '\n';
}
void Prettify(std::string& ugly_text) {
// making it pretty...
}
}
I'm looking for some best practices / rules of thumb / opinions on this :) Thanks in advance!
For things that are only needed within the file, I would just place it in an anonymous namespace within the C++ file itself, sort of the modern equivalent of the legacy C static keyword on functions(a):
namespace {
void WeaveMagic(std::string& ugly_text) {
WeaveMoreMagic(ugly_text);
}
void Prettify(std::string& ugly_text) {
WeaveMagic(ugly_text);
}
}
If you place this before any use of the functions, and ensure a strict hierarchy of calls, you can skip the declarations since the definitions provides the required information, as shown above.
Of course, if there are any circular dependencies between multiple anonymous functions (i.e., circular recursion), you will still need to provide declarations:
#include <iostream>
namespace {
int DivThree(int val); // needed to implement AddOne()
int AddOne(int val) {
std::cout << "AddOne " << val << " -> " << (val + 1) << '\n';
if (val > 0) return DivThree(val + 1);
return val;
}
int DivThree(int val) {
std::cout << "DivThree " << val << " -> " << (val / 3) << '\n';
return AddOne(val / 3);
}
}
int main(){
int final = AddOne(18);
std::cout << "Final " << final << '\n';
return 0;
}
And, yes, that's very contrived, but good examples of circular recursion are few and far between :-) The output is:
AddOne 18 -> 19
DivThree 19 -> 6
AddOne 6 -> 7
DivThree 7 -> 2
AddOne 2 -> 3
DivThree 3 -> 1
AddOne 1 -> 2
DivThree 2 -> 0
AddOne 0 -> 1
Final 0
(a) CPP Core Guidline SF.22 actually covers this:
Use an unnamed (anonymous) namespace for all internal/non-exported entities.
Reason: Nothing external can depend on an entity in a nested unnamed namespace. Consider putting every definition in an implementation source file in an unnamed namespace unless that is defining an "external/exported" entity.
An API class and its members can't live in an unnamed namespace; but any "helper" class or function that is defined in an implementation source file should be at an unnamed namespace scope.
If you are operating on functions only, as #paxdiablo have written, you can use anonymous namespace (look at his answer).
I have some C-based habits, so personally I would also see it as static function. But I'm not sure how C++ fanatics will look at it :). static (in this context) makes functions local for compilation unit (logging.cpp), so it cannot be linked from outside.
//logging.cpp
static void Prettify(std::string& ugly);
void LogThis(const std::string& text) {
Prettify(text);
std::cout << "Log: " << text << '\n';
}
static void Prettify(std::string& ugly) { }
However if your logging utility would be object-oriented. I suggest you to use D-pointer and Q-Pointer design pattern (known also as PImpl idiom) - https://en.cppreference.com/w/cpp/language/pimpl .
//logging.h
#include <string>
class loggingImpl;
class logging {
public :
logging();
virtual ~logging();
void LogThis(const std::string& text);
protected :
loggingImpl *impl;
};
//logging.cpp
class loggingImpl
{
public :
loggingImpl(logging *p) : qptr(p) { }
void Prettify(std::string& ugly) { }
//anything what you need and should be hided
// access parent through qptr
protected :
logging *qptr;
};
logging::logging() : impl(new loggingImpl) { }
logging::~logging() { delete impl; }
void logging::LogThis(const std::string& text) {
impl->Prettify(text);
std::cout << "Log: " << text << '\n';
}
As you have written, putting declaration in header file is not proper due to limiting visibility of unused symbols.

ostringstream is empty after inserting output to it

I have a strange issue where ostringstream is empty even though I insert an output to it.
Here is my code:
//logger.h
#include <string>
#include <iostream>
#include <sstream>
using std::string;
class BasicLogger {
public:
BasicLogger(const string name);
BasicLogger(const BasicLogger& basicLogger);
~BasicLogger();
template<class T>
BasicLogger& operator<<(const T &msg){
std::cout << "msg is: " << msg << std::endl;
mBuf << msg;
std::cout << "mBuf is: " << mBuf.str() << std::endl;
return *this;
}
private:
string mName;
std::ostringstream mBuf;
};
class Logger {
public:
Logger();
~Logger();
BasicLogger info();
BasicLogger error();
private:
BasicLogger mInfoLogger;
BasicLogger mErrorLogger;
};
//logger.cpp
#include "logger.h"
BasicLogger::BasicLogger(const string name):
mName(name) { }
BasicLogger::BasicLogger(const BasicLogger& otherLogger) {
this->mName = otherLogger.mName;
this->mBuf << otherLogger.mBuf.rdbuf();
}
BasicLogger::~BasicLogger() { }
Logger::Logger():
mInfoLogger("[INFO]"),
mErrorLogger("[ERROR]") {}
Logger::~Logger() {};
BasicLogger Logger::info() {
return mInfoLogger;
}
BasicLogger Logger::error() {
return mErrorLogger;
}
//main.cpp
#include "logger.h"
int main() {
Logger logger;
logger.info() << "Hellooo";
}
The output is
msg is: Hellooo
mBuf is:
While #BoPersson already gave you the solution, I would like to explain what happened here, and why your output is empty, even though you are adding to ostringstream on the line just before you display its content.
I think when you attempted to return mInfoLogger by value, the compiler complained about not being able to return it because copy constructor was deleted. The reason it was deleted because ostringstream member you have is non-copyable.
So you provided custom copy constructor and attempted to copy the stream this way:
this->mBuf << otherLogger.mBuf.rdbuf();
Only this does not copy anything as your rdbuf is empty and instead sets failbit on
The failbit
The streambuf overload of basic_ostream::operator<< if the function
inserts no characters.
http://en.cppreference.com/w/cpp/io/ios_base/iostate
If you were to check your message insertion like this:
if (!(mBuf << msg))
std::cout << "Not Inserted" << std::endl;
You would see Not Inserted message printed. There are many ways to make it print the desired message. For example making sure your rdbuf buffer is not empty or by resetting the failbit before you reuse the mBuf, something like mBuf.clear(); or simply by returning the reference to mInfoLogger (and mErrorLogger). Then you can safely get rid of your copy constructor.

input to stringstream and convert to string in single statement. Possible without helper class?

I would like to write code like this:
std::string s = ??? << "asdf" << 123;
I am not sure what to place for the ??? to make it work. I can write a helper class:
#include <string>
#include <sstream>
#include <iostream>
struct Stringify {
std::stringstream o;
template <typename T>
Stringify& operator<<(const T& t){
o << t;
return *this;
}
operator std::string(){ return o.str(); }
};
int main(){
std::string s;
s = Stringify() << " test " << 123 << " asd";
std::cout << s << std::endl;
}
...but I am not able to do it wihtout the helper class. I tried different things, the nicest error message i got from this:
s = (std::stringstream() << "test" << 123 << " asd").str();
-> error: ‘class std::basic_ostream<char>’ has no member named ‘str’
I also tried more, but it just resulted in more complicated error messages.
Is it possible to do what I want without having to write a helper class? If not, is there any good reason why it isnt possible only with std stuff?
Something like this:
std::string s = static_cast<std::ostringstream&>(std::ostringstream() << 7 << 10 << 12).str();

How to use my logging class like a std C++ stream?

I've a working logger class, which outputs some text into a richtextbox (Win32, C++).
Problem is, i always end up using it like this:
stringstream ss;
ss << someInt << someString;
debugLogger.log(ss.str());
instead, it would be much more convenient to use it like a stream as in:
debugLogger << someInt << someString;
Is there a better way than forwarding everything to an internal stringstream instance? If'd do this, when would i need to flush?
You need to implement operator << appropriately for your class. The general pattern looks like this:
template <typename T>
logger& operator <<(logger& log, T const& value) {
log.your_stringstream << value;
return log;
}
Notice that this deals with (non-const) references since the operation modifies your logger. Also notice that you need to return the log parameter in order for chaining to work:
log << 1 << 2 << endl;
// is the same as:
((log << 1) << 2) << endl;
If the innermost operation didn't return the current log instance, all other operations would either fail at compile-time (wrong method signature) or would be swallowed at run-time.
Overloading the insertion operator<< is not the way to go. You will have to add overloads for all the endl or any other user defined functions.
The way to go is to define your own streambuf, and to bind it into a stream. Then, you just have to use the stream.
Here are a few simple examples:
Logging In C++ by Petru Marginean, DDJ Sept 05th 2007
Rutger E.W. van Beusekom's logstream class, check also the .hpp alongside with this file
As Luc Hermitte noted, there is "Logging In C++" article which describes very neat approach to solve this problem. In a nutshell, given you have a function like the following:
void LogFunction(const std::string& str) {
// write to socket, file, console, e.t.c
std::cout << str << std::endl;
}
it is possible to write a wrapper to use it in std::cout like way:
#include <sstream>
#include <functional>
#define LOG(loggingFuntion) \
Log(loggingFuntion).GetStream()
class Log {
using LogFunctionType = std::function<void(const std::string&)>;
public:
explicit Log(LogFunctionType logFunction) : m_logFunction(std::move(logFunction)) { }
std::ostringstream& GetStream() { return m_stringStream; }
~Log() { m_logFunction(m_stringStream.str()); }
private:
std::ostringstream m_stringStream;
LogFunctionType m_logFunction;
};
int main() {
LOG(LogFunction) << "some string " << 5 << " smth";
}
(online demo)
Also, there is very nice solution provided by Stewart.
An elegant solution that also solves the flushing issues is the following:
#include <string>
#include <memory>
#include <sstream>
#include <iostream>
class Logger
{
using Stream = std::ostringstream;
using Buffer_p = std::unique_ptr<Stream, std::function<void(Stream*)>>;
public:
void log(const std::string& cmd) {
std::cout << "INFO: " << cmd << std::endl;
}
Buffer_p log() {
return Buffer_p(new Stream, [&](Stream* st) {
log(st->str());
});
}
};
#define LOG(instance) *(instance.log())
int main()
{
Logger logger;
LOG(logger) << "e.g. Log a number: " << 3;
return 0;
}
In the Logger class, override the << operator.
Click Here to know how to implement the << operator.
You can also avoid the logging statements inside the code
using Aspect Oriented programming.