Reputation: 4186
I was writing program when suddenly wild thought appear: What is the best way to create log system in my program? I mean how can i save logs in any place in my code (of course excluding header files)? Something like
myLogs << "Ups, somthing failed :(";
You know, earlier i just opened file and save what i want to, but now i would like do it in a pro way :D I was thinking about class which will be inherited by all other classes but it's kind of problematic. I also thought about static function, but i'm not sure how it would work.
Upvotes: 0
Views: 3236
Reputation: 153919
There is no one simple answer; it depends on the application. I've worked on some very big projects where you could configure logging differently for different subsystems; such a system would be overkill in a smaller application. It also makes a difference if the application has to remain up for long periods of times; in such cases, you'll want some provision for reconfiguring the log without stopping the application.
More or less generally, however, you'll want a log configuration file, specifying different levels of logging, and what to do with the log messages. You'll also want to ensure that you do a minimum of actions when there is no logging. One solution I've used is to maintain various streambufs for each of the available actions (write to file, send email, or send to syslog). I'll then have a table of ostream* indexed by the log level; if there is any logging for that level, I'll create a streambuf which forwards to all of the necessary action streambufs, and put the address of an ostream which uses it in the table. These special streambuf's also have functions to start and stop each logging record: the one to start the record will be called with filename and linenumber, and the one to stop the record will flush each of the managed streams. If there's no logging on a given level, the ostream pointer is null.
The basic logger is then:
class Logger
{
std::ostream* myDest;
int* myUseCount;
public:
Logger( int level, char const* filename, int lineNumber )
: myDest( ourLogTable[level] )
, myUseCount( new int( 1 ) )
{
if ( myDest != NULL ) {
myDest->rdbuf()->startLogRecord( filename, lineNumber );
}
}
Logger( Logger const& other )
: myDest( other.myDest )
, myUseCount( other.myUseCount )
{
++ *myUseCount;
}
~Logger()
{
-- *myUseCount;
if ( *myUseCount == 0 && myDest != NULL ) {
myDest->flush();
}
}
template <typename T>
Logger& operator<<( T const& obj )
{
if ( myDest != NULL ) {
*myDest << obj;
}
}
};
(With C++11, you should use move semantics rather than my reference counting. Much simpler.)
Finally, you invoke the logger through a macro:
#define LOG(level) Logger( level, __FILE__, __LINE__ )
The use of a macro is necessary if you want to automatically insert filename and line number.
Upvotes: 3
Reputation: 3401
Not sure if I understand the question exactly, but what I have done is send the log data to another application, using the WM_SETTEXT message (and then another custom message to commit the data) - you will also need to write a basic listener application which will be reading and storing the data, preferably in a control like a listbox. This is very fast, as it does not involve the file system, pipes, sockets etc. You can also use conditional compilation in a header file (controlled by #define/#ifdef directives) to turn logging on or off.
Upvotes: 0
Reputation: 29966
Make a class, and overload operator<<
to implement writing into a file, or whatever you want.
#include <fstream>
#include <iostream>
using namespace std;
class logger
{
public:
void operator<<( const std::string & input );
}MyLogger;
void logger::operator <<(const string &input)
{
std::ofstream of("filename.txt");
of << input;
of.close();
}
int main()
{
MyLogger<<"sometext";
}
Upvotes: 2