I have to extend the ofstream class to write a logging stream service.
The goal is to intercept each line, adding at the head of each one a customized text (date/time, severity, and so on).
Now, it's clear that I'm not a C++ guru, so I read a lot of documentation about this task, e.g.
http://www.angelikalanger.com/Articles/Topics.html#CPP
http://asmodehn.wordpress.com/2010/06/20/busy-c-coding-and-testing
http://gabisoft.free.fr/articles-en.html
The above articles suggest to write a custom stream buffer, but during porting of this concept on file streams I encountered a lot of difficulties.
Is there a simpler method to achieve this goal?
You don't need to write a custom stream buffer; the simplest and most straightforward way is to make a class you can send output to by giving it a templatized single argument operator<<():
template <typename T>
std::ostream& operator<<(const T& data_)
{
m_outstream << m_severity << "\t" << getTimeStamp() << "\t" << data_;
return m_outstream;
}
Where m_outstream is some type of std::ostream (std::ofstream, etc). m_severity and getTimeStamp() are examples of what you can insert (and you can create a bog standard two argument operator<<() to format and output the severity type to an ostream).
This then allows you to do things like:
myLogger << "failingFunction(" << argument <<
"): Could not do something." << std::endl;
and you will get output on m_outstream that looks like:
WARNING 2012-01-03 19:32 failingFunction("argument value"): Could not do something.
Beyond this, you will want a way to set the severity, which can be as simple as a method called on the logger class you added the templatized operator<<() to. If you want to get really fancy, you can write your own manipulator that acts much like setw() would on a std::ostream. See http://www.math.hkbu.edu.hk/parallel/pgi/doc/pgC++_lib/stdlibug/man_6665.htm for a primer on writing manipulators.
Related
I am looking for a way to use an ostream with my custom string class and overload the operator << to stream to the buffer which i can then flush to anywhere i want (in my case its just gonna be printed in a window)
I'm reasonably new to the inner workings of iostream's but from my understanding the method i've seen of making std::stringbuf a base of my custom stringstream would not work because the stringbuf deals with the std::string.
in essence i want to able to do this (or similar):
MyStringClass string
MyOutput << "hello" << string << "World" << std::endl;
Where MyOutput can be changed to print to anywhere i want.
Thank you.
Not a problem. Define your class, and within it's definition add an ostream& operator<<(const String&);.
Inside that operator, you can code whatever handling you want (look at std::string for inspiration)
When you stream variables to an output stream such as cout, type conversion is automatic. What I'm trying to figure out is how to do this via a function call, for example:
inline void DEBUG(ostream& s) // Don't know if this prototype is appropriate
{
cout << s;
}
main()
{
int i = 5;
DEBUG("The value is: " << i << endl); // This doesn't compile
DEBUG("The value is: " + i + endl); // Neither does this
}
I found similar questions on here, but they all involve passing the stream object as a parameter, whereas I'm trying to pass the "streamed data" to a function that already has the stream object, so it's the other way round. Is this even possible? I don't want to resort to explicit type conversions. I also found this question, but I really don't want to write a whole logger class if I can avoid it.
At the moment I'm implementing it as a macro, which works, but I'd rather use an inline function if possible.
#define DEBUG(s) (cout << s)
Of course it does not compile. There are many reasons for that.
First, Operator << is not defined for standard streams, and you are trying to do exactly that: stream stream into stream in your DEBUG(). (Pun intended).
Second, operator << is not defined for string literals, and you are trying to invoke it here:
"The value is: " << i
+ is not defined for literals either, by the way.
To achieve the semantic you want to see, you will have to start with the stream. String literal need to be converted to stream first, and than you can apply << to it. This is ONLY way to achieve what you want.
Edit:
Now since I understand the rationale, I can give a better answer. There are many ways how people are trying to segregate different levels of debugging uniformely, and there are several libraries aiming for that (log4cpp, boost.log to name just few). Before you start implementing your own logging, I would definitely suggest looking into those. There is much more to the good logging than just debug levels.
If, for any reason, you want to use your own homebrew, here are the couple of recepies you might explore:
Use your own logger class (one of the very rare examples, close to
the single one! where Singleton is appropriate). You can than set the
logging level in the beggining of your application, and than just
call Logger::debug() << ...
Enrich above solution with macros. The problem with functions is that, unlike macros, they loose context. So if you want to log file and line number of the logging invocation (and you usually do!), you might want to do LOG_DEBUG << ...; here LOG_DEBUG would expand into something like Logger::debug() << __FILE__ << ":" << __LINE__ << ....
Once you've done this, you will see that sometimes you call other functions inside the << chain. At this point you might realize that those functions would be called regardless of your debug level, and might think you do not want to call them when debugging is not enabled (something along the lines LOG_DEBUG << " Object now is " << object.serialize(); So you will want to enrich the LOG_DEBUG macro to not execute anything when debug level does not match.
And the saga continues... Ready to use the library?
Well, what (at least some) logging libraries would do is create a temporary proxy object that would act as a stream:
#include <iostream>
struct LoggerProxy {
LoggerProxy(const char* file, int line)
{
std::cout << "File " << file << ", line " << line << ": ";
}
template<typename T>
LoggerProxy& operator<<(T&& t)
{
std::cout << t;
return *this;
}
};
#define LOG_DEBUG LoggerProxy{__FILE__, __LINE__}
int main()
{
LOG_DEBUG << "Value is: " << 4;
}
You can do a lot of fancy stuff with this, such as debug level checks, output to different streams or multiple backends (such as simultaneous output to std::cout/cerr and log file) and many more.
I'm working on a C++ beginner level project (not absolute beginner like "what's a loop" but I wouldn't say it's intermediate level either).
In this project I need to save into a file some data stored in memory in struct variables (this is plain imperative programming, with no OOP involved).
I've read a bit about options like serialization, using some non-standard libraries and such. But I need to keep it as simple and clean as possible.
So far I have 2 structs, pretty much like these:
struct client {
string name;
string address;
double phone;
};
struct invoice {
string client_name;
double total;
};
I'm looking for something like this example provided at http://www.cplusplus.com/doc/tutorial/files:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}
Is there a way to do something like that, but to write (and then be able to read) struct variables to a file, keeping it simple?
Some years ago I remember handling this in a very simple way in Pascal, when writing records to files. It was something like: open file, write record field 1, write field separador, write record field 2, write field separator, write record separator. Then when reading I would search for separators. Is this not recommended in C++?
Thanks.
You could check serialization for C++, eg. Boost::serialization in the Boost library.
Is it possible to serialize and deserialize a class in C++?
You have to associate 2 functions to this class : inputStruct and OutputStruct. Input should be able to read what Output generate. The easy way consist in writing each struct element in the same order that they are implemented.
The clear way to do that is implementing a serialize and deserialize function for every structure or class that you want to write to a file. You give the serialize function the reference of the output stream, and it writes each of the fields that you want to write. The deserialize do the opposite: it reads all the properties in the same order, and sets them in the current class or structure. If you use the stream operators for serialization, the output file will be a text file.
With c++ you can overload stream operator, so it will look pretty in your code, but in other languages you must use functions for that.
You can also use binary serialization, but it is more problematic, because you need to check the endianness of the platform that you use currently. If you will just use it on one platform, you can try write, and read functions. They need the pointer of the variable, and the size, and they copy them into/from the file. Use these for every property separate, never copy whole structures, because it can lead to errors easily.
UPDATE:
I made serialize and deserialize functions. I haven't tested them, so im not 100% sure they will work.
Static functions:
void serialize_client( ofstream& out, client& cl )
{
out << cl.name << endl;
out << cl.address << endl;
out << cl.phone << endl;
}
void deserialize_client( ifstream& in, client& cl )
{
getline( in, cl.name );
getline( in, cl.address );
in >> cl.phone;
}
Usage:
client client_instance;
deserialize_client( cin, client_instance );
serialize_client( cout, client_instance );
With operator overload:
ostream& operator<<( ostream& os, const client& cl )
{
os << cl.name << endl;
os << cl.address << endl;
os << cl.phone << endl;
return os;
}
istream& operator>>( istream& is, client& cl )
{
getlise( is, cl.name );
getlise( is, cl.address );
is >> cl.phone;
return is;
}
client client_instance;
cin >> client_instance;
cout << client_instance;
We have a log implementation that's based on std::ostream with a custom stream buffer. We implement our application's instance of the log class via a Schwarz counter.
To avoid coupling our lower level classes to our log implementation, we can pass a reference to a std::ostream. In this way our lower level classes can log to std::cout, std::cerr or to the instance created via the Schwarz counter.
I have one problem with this. The log implementation sets its severity via an overload of the stream operator:
// Overload the << operator to set the log message severity
inline CLogStream& operator << (CLogStream& myLogStream, eMsgType::type msgTypeCurrent)
{
myLogStream.SetMsgTypeCurrent(msgTypeCurrent);
return ( myLogStream ) ;
}
This allows us to use the logger like this:
CLog::Main << CLog::MSG_FATAL << "Fatal error" << std::endl;
I'd like to create a reference to our app's instance of the log which is locked to a particular severity. That way, I can pass our utility classes two std::ostream references. One of these would be used for normal reporting and the other for error reporting. These could be set to std::cout and std::cerr, or to some kind of object referring to our log object instance.
Unfortunately the std::ostream operator << aren't virtual as far as I'm aware, so I'm not sure how to design such an object.
Any thoughts?
iostream has virtual member functions (specifically, ~ios_base) so you can perform a dynamic_cast in the operator<<:
inline std::ostream &operator<<(std::ostream &os, eMsgType::type msgTypeCurrent) {
if (CLogStream *myLogStream = dynamic_cast<CLogStream *>(&os)) {
myLogStream->SetMsgTypeCurrent(msgTypeCurrent);
} else {
os << "TYPE: " << static_cast<typename std::underlying_type<eMsgType::type>
::type>(msgTypeCurrent) << ": ";
}
return os;
}
If the setting of the severity is persistent, such that both tese lines result in a log entry with fatal severity
CLog::Main << CLog::MSG_FATAL << "Log entry 1: " << some_data << std::endl;
CLog::Main << "Log entry 2: " << some_other_data << std::endl;
then your logging class is already correctly designed to be passed along as a generic ostream&. You just need separate logger instances for the different log-levels that are supported by the utility classes.
This is written under the assumption that the logger class has been inherited from ostream to take advantage of the existing operator<< overloads.
In that case, the operator<< for some_data and some_other_data are already completely unaware that the output goes to a log stream.
Read about ios_base::iword(). It gives you access to an array of long values in the stream object that you can use to store things like flags and special values.
I am looking for a portable way to implement lazy evaluation in C++ for logging class.
Let's say that I have a simple logging function like
void syslog(int priority, const char *format, ...);
then in syslog() function we can do:
if (priority < current_priority)
return;
so we never actually call the formatting function (sprintf).
On the other hand, if we use logging stream like
log << LOG_NOTICE << "test " << 123;
all the formating is always executed, which may take a lot of time.
Is there any possibility to actually use all the goodies of ostream (like custom << operator for classes, type safety, elegant syntax...) in a way that the formating is executed AFTER the logging level is checked ?
This looks like something that could be handled with expression templates. Beware, however, that expression templates can be decidedly non-trivial to implement.
The general idea of how they work is that the operators just build up a temporary object, and you pass that temporary object to your logging object. The logging object would look at the logging level and decide whether to carry out the actions embodied in the temporary object, or just discard it.
What I've done in our apps is to return a boost::iostreams::null_stream in the case where the logging level filters that statement. That works reasonably well, but will still call all << operators.
If the log level is set at compile time, you could switch to an object with a null << operator.
Otherwise, it's expression templates as Jerry said.
The easiest and most straight-forward way is to simply move the check outside of the formatting:
MyLogger log; // Probably a global variable or similar.
if (log.notice())
log << "notified!\n" << some_function("which takes forever to compute"
" and which it is impossible to elide if the check is inside log's"
" op<< or similar");
if (log.warn()) {
log << "warned!\n";
T x;
longer_code_computing(value_for, x); // easily separate out this logic
log << x;
}
If you really wanted to shorten the common case, you could use a macro:
#define LOG_NOTICE(logger) if (logger.notice()) logger <<
LOG_NOTICE(log) << "foo\n";
// instead of:
if (log.notice()) log << "foo\n";
But the savings is marginal.
One possible MyLogger:
struct MyLogger {
int priority_threshold;
bool notice() const { return notice_priority < current_priority; }
bool warn() const { return warn_priority < current_priority; }
bool etc() const { return etc_priority < current_priority; }
template<class T>
MyLogger& operator<<(T const &x) {
do_something_with(x);
return *this;
}
};
The problem here is mixing iostream-style operator overloading with a printf-like logging function – specifically translating manipulators and formatting flags/fields from iostreams into a format string. You could write to a stringstream and then chunk that to your syslog function, or try something fancier. The above MyLogger works easiest if it also contains an ostream reference to which it can forward, but you'll need a few more op<< overloads for iomanips (e.g. endl) if you do that.
For mine I made a debug_ostream class which has templated << operators. These operators check the debug level before calling the real operator.
You will need to define non-template overrides for const char* and std::ostream& (*x)(std::ostream&) because otherwise those don't work. I'm not sure why.
With inlining and high enough optimization levels the compiler will turn the whole output line into a single check of the debug level instead of one per output item.
I should add to this that this doesn't solve the original problem. For example if part of the debug line is to call an expensive function to get a value for output, that function will still be called. My solution only skips the formatting overhead.