C++ style Logger that supports __LINE__ macro and others

≯℡__Kan透↙ 提交于 2019-12-04 17:14:59

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 //
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!