I created my own std::cout-like object that writes both to std::cout and to a log file.
I'm currently defining it like this in a header file, but I'm getting unused variable warnings.
Header file <MyLib/Log.h>
static LOut { };
static LOut lo;
template<typename T> inline LOut& operator<<(LOut& mLOut, const T& mValue)
{
std::string str{toStr(mValue)};
std::cout << str;
getLogStream() << str;
return mLOut;
}
Usage:
#include <MyLib/Log.h>
...
lo << "hello!" << std::endl;
Should lo be static? Should lo be extern?
Kudos for explaining the correct way of declaring a cout-like object and showing how the main standard library implementations do it.
Edit: by cout-like object, I mean a global variable that is always available after including the corresponding header.
std::cout is simply declared as follows:
namespace std {
extern ostream cout;
}
It is a regular global variable; you can do the same thing yourself. Put an extern declaration of your variable in a header; then define the same variable in a source file and link it to your application:
// mylog.h
extern MyLog mylog;
// mylog.cpp
MyLog mylog(someparams);
First, I'm not too sure what you mean be a cout-like object?
Perhaps an std::ostream.
Anyway, the usual way of doing this is to use a filtering
streambuf. Just write a streambuf which forwards to a log file,
in addition to the usual place, and insert it where ever you
want:
class LoggingOutputStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ofstreambuf myLogFile;
std::ostream* myOwner;
protected:
int overflow( int ch )
{
myLogFile.sputc( ch ); // ignores errors...
return myDest->sputc( ch );
}
public:
LoggingOutputStreambuf(
std::streambuf* dest,
std::string const& logfileName )
: myDest( dest )
, myLogFile( logfileName.c_str(), std::ios_base::out )
, myOwner( nullptr )
{
if ( !myLogFile.is_open() ) {
// Some error handling...
}
}
LoggingOutputStreambuf(
std::ostream& dest,
std::string const& logfileName )
: LoggingOutputStreambuf( dest.rdbuf(), logfileName )
{
dest.rdbuf( this );
myOwner = &dest;
}
~LoggingOutputStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
};
(This is C++11, but it shouldn't be hard to modify it for
C++03.)
To use, you could use something like:
LoggingOutputStreambuf logger( std::cout );
// ...
All output to std::cout will be logged until logger goes out
of scope.
In practice, you'll likely use something more complicated than a
filebuf for logging, since you may want to insert time stamps
at the start of each line, or systematically flush at the end of
each line. (Filtering streambufs can take care of those issues
as well.)
std::cout-like object that writes both to std::cout and to a log file
Maybe boost.iostreams would be sufficient?
#include <iostream>
#include <fstream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>
namespace io = boost::iostreams;
int main()
{
typedef io::tee_device<std::ostream, std::ofstream> teedev;
typedef io::stream<teedev> LOut;
std::ofstream outfile("test.txt");
teedev logtee(std::cout, outfile);
LOut mLOut(logtee);
mLOut << "hello!" << std::endl;
}
Simply sending the input value right out to cout didn't work for me, because I wanted to add headers and info to the log output.
Also, I had my static Debug class in which to wrap the Log stream.
This is the way I managed to do this, I hope it's useful. I'm somehow a newbye to c++, so feel free to tell me if something is wrong :)
#include <iostream>
#include <sstream>
#include <ostream>
enum class DebugLevel {
INFO,
WARNING,
ERROR
};
class Debug {
public:
/* other Debug class methods/properties
...
*/
// out stream object
static struct OutStream {
std::ostringstream stream;
DebugLevel level = DebugLevel::INFO;
public:
// here you can add parameters to the object, every line log
OutStream& operator()(DebugLevel l) {
level = l;
return *this;
}
// this overload receive the single values to append via <<
template<typename T>
OutStream& operator<<(T&& value) {
stream << value;
return *this;
}
// this overload intercept std::endl, to flush the stream and send all to std::cout
OutStream& operator<<(std::ostream& (*os)(std::ostream&)) {
// here you can build the real console log line, add colors and infos, or even write out to a log file
std::cout << __TIME__ << " [" << (int)level << "] " << stream.str() << os;
stream.str(""); // reset the string stream
level = DebugLevel::INFO; // reset the level to info
return *this;
}
} Log;
};
Debug::OutStream Debug::Log; // need to be instantiaded only because I use a static Debug class
int main() {
Debug::Log(DebugLevel::ERROR) << "Hello Log! " << 2 << " " << __FUNCTION__ << std::endl;
Debug::Log << "Hello Log! " << 0xFA << std::endl; // NB: this way the debugLevel is default
return 0;
}
In one of my projects, I wrote wrapper for std::cout.
It looks something like this:
struct out_t {
template<typename T>
out_t&
operator << (T&& x) {
std::cout << x;
// log << x;
return *this;
};
};
out_t out;
out << 1;
For complete code look for struct out in io.h
Related
I have a class that has a filestream of type ofstream. The constructor opens the file in append mode and all the messages always get written at the end of the file.
I need to write into outputFile up to some fixed size say 1Mb, then I need to close, rename, and compress it, and then open a new file of the same name.
This needs to be done when a certain size of file is reached.
I tried using tellg() but after reading stuffs (and this) on internet, I understood that this is not the right approach.
As I'm new to C++, I'm trying to find out the most optimized and correct way to get the accurate current size of file opened by ofstream?
class Logger {
std::ofstream outputFile;
int curr_size;
Logger (const std::string logfile) : outputFile(FILENAME,
std::ios::app)
{
curr_size = 0;
}
};
Somewhere in the program, I'm writing data into it:
// ??? Determine the size of current file ???
if (curr_size >= MAX_FILE_SIZE) {
outputFile.close();
//Code to rename and compress file
// ...
outputFile.open(FILENAME, std::ios::app);
curr_size = 0;
}
outputFile << message << std::endl;
outputFile.flush();
fstreams can be both input and output streams. tellg() will return the input position and tellp() will tell you of the output position. tellp() will after appending to a file tell you its size.
Consider initializing your Logger like this (edit: added example for output stream operator):
#include <iostream>
#include <fstream>
class Logger {
std::string m_filename;
std::ofstream m_os;
std::ofstream::pos_type m_curr_size;
std::ofstream::pos_type m_max_size;
public:
Logger(const std::string& logfile, std::ofstream::pos_type max_size) :
m_filename(logfile),
m_os(m_filename, std::ios::app),
m_curr_size(m_os.tellp()),
m_max_size(max_size)
{}
template<typename T>
friend Logger& operator<<(Logger&, const T&);
};
template<typename T>
Logger& operator<<(Logger& log, const T& msg) {
log.m_curr_size = (log.m_os << msg << std::flush).tellp();
if(log.m_curr_size>log.m_max_size) {
log.m_os.close();
//rename & compress
log.m_os = std::ofstream(log.m_filename, std::ios::app);
log.m_curr_size = log.m_os.tellp();
}
return log;
}
int main()
{
Logger test("log", 4LL*1024*1024*1024*1024);
test << "hello " << 10 << "\n";
return 0;
}
If you use C++17 or have an experimental version of <filesystem> available, you could also use that to get the absolute file size, like this:
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
class Logger {
fs::directory_entry m_logfile;
std::ofstream m_os;
std::uintmax_t m_max_size;
void rotate_if_needed() {
if(max_size_reached()) {
m_os.close();
//rename & compress
m_os = std::ofstream(m_logfile.path(), std::ios::app);
}
}
public:
Logger(const std::string& logfile, std::uintmax_t max_size) :
m_logfile(logfile),
m_os(m_logfile.path(), std::ios::app),
m_max_size(max_size)
{
// make sure the path is absolute in case the process
// have changed current directory when we need to rotate the log
if(m_logfile.path().is_relative())
m_logfile = fs::directory_entry(fs::absolute(m_logfile.path()));
}
std::uintmax_t size() const { return m_logfile.file_size(); }
bool max_size_reached() const { return size()>m_max_size; }
template<typename T>
friend Logger& operator<<(Logger&, const T&);
};
template<typename T>
Logger& operator<<(Logger& log, const T& msg) {
log.m_os << msg << std::flush;
log.rotate_if_needed();
return log;
}
int main()
{
Logger test("log", 4LL*1024*1024*1024*1024);
std::cout << test.size() << "\n";
test << "hello " << 10 << "\n";
std::cout << test.size() << "\n";
test << "some more " << 3.14159 << "\n";
std::cout << test.size() << "\n";
return 0;
}
I gave it a try with tellp() and it works fine for me:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream myFile("data.txt", ios_base::app);
myFile << "Hello World!" << endl;
cout << myFile.tellp() << endl;
return 0;
}
This is the output, when calling this program:
$ ./program
13
$ ./program
26
$ ./program
39
I have a macro that does exactly what I want it to do:
#define LOG(x)\
do { if (!cpp::app::g_app) {\
ASSERT("CANNOT LOG IF THERE IS NO CPP APP OBJECT" == 0);\
}\
else \
{ \
std::stringstream s; s << cpp::timing::currentDateTime(); s << '\t'; s << x << std::endl; \
*cpp::app::g_app << s.str(); \
cpp::app::g_app->flush(true);\
} \
} while(0)
#endif
Its really nice, because I can:
LOG("On first log line " << 0 << "Still on first log line")
..and a newline is inserted once the LOG macro is done.
Output looks like:
<date / time> On First log line 0 Still on first log line
... subsequent lines here
My question is how to overload << operator on my logging class to do the same?
If I simply overload << operator and return *this (where my logging case can be converted to ostream) then if I do:
mylogger << "First line " << "Still on first line";
then the output is something like:
<date and time> First line
<date and time> Still on first line.
So, I want to emulate the macro behaviour with the << operator. I want a newline automatically when the whole chain of << operations is complete, just like in the macro. But, since macros are evil, I'd rather convert it to a proper function.
Is this achievable?
Edit: Matt's idea about a helper class is quite nice. Based on his suggestion, I made the following disposable helper class:
class log
{
public:
log() :
m_stream(cpp::app::g_app->stream()){
}
template <typename T>
log& operator << (const T& t)
{
m_ss << t;
return *this;
}
virtual ~log(){
m_stream << cpp::timing::currentDateTime() << "\t" << m_ss.str() << "\r\n";
m_stream.flush();
}
private:
std::ostream& m_stream;
std::stringstream m_ss;
};
Use it like:
log() << "All this text" << " will be on one line in the logfile, with date and time prepended ";
log() << "And this lot falls on line 2, with date and time prepended";
I hope that helps Galik and others who may be wanting the same thing.
A small improvement to the solution offered in the question, that creates fewer temporary objects:
class log
{
public:
log() :
m_stream(cpp::app::g_app->stream()){
}
template <typename T>
std::ostream& operator<< (const T& t)
{
return m_stream << cpp::timing::currentDateTime() << "\t" << t;
}
virtual ~log(){
m_stream << "\r\n";
m_stream.flush();
}
private:
std::ostream& m_stream;
};
The temporary instance of log() will be destroyed at the end of the full-expression even if it isn't returned from operator<<. Might as well get rid of the middle-man and the extra stringstream buffer (which btw, doesn't respect the existing formatting options on the main stream -- this could be good or bad)
I have some code that you may find useful.
Its not heavily tested. I am hoping to expand on this to supply a producer/consumer queue which is why I am not using it at the moment. I am still using a macro like you :)
#include <sstream>
#include <memory>
#include <fstream>
#include <iostream>
#include <ctime>
namespace log {
typedef std::stringstream sss; // <3 brevity
class writer
{
private:
std::ostream& sink;
std::string endl = "\n";
std::string get_stamp()
{
time_t rawtime = std::time(0);
tm* timeinfo = std::localtime(&rawtime);
char buffer[32];
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", timeinfo);
return std::string(buffer);
}
public:
writer(std::ostream& sink): sink(sink) {}
void add_line(sss* ss)
{
sink << get_stamp() << " " << ss->rdbuf() << endl;
}
};
// this is used to build the log string in an sts::ostringstream
// which gets std::moved to each new temporary buffer when <<
// is invoked
struct buffer
{
writer& lw;
sss* ss;
buffer(writer& lw): lw(lw), ss(new sss) {}
buffer(const buffer& buf) = delete;
buffer(buffer&& buf): lw(buf.lw), ss(buf.ss) { buf.ss = nullptr; }
~buffer() { if(ss) lw.add_line(ss); delete ss; }
};
// each << creates a new temporary buffer that std::moves
// the std::ostringstream on to the next
template<typename Type>
buffer operator<<(buffer&& buf, const Type& t)
{
(*buf.ss) << t;
return std::move(buf);
}
// A write to a writer creates a temporary buffer and passes
// the << on to that
template<typename Type>
buffer operator<<(writer& lw, const Type& t)
{
return std::move(buffer(lw) << t);
}
} // log
int main()
{
std::ofstream ofs("output.log");
log::writer fout(ofs); // write to file
log::writer lout(std::cout); // write to std output
lout << "A " << 0.7 << " B";
fout << "wibble: " << 2;
}
The way this works is that writing to a log::writer via << causes a temporary log::buffer to be created. Subsequent writes << to the log::buffer create new temporary log::buffer objects which std::move an internal std::ostringstream between them. Because only the final log::buffer object has a non-null std::ostringstream* (because it was std::moved down when it collapsed) it writes the entire line to the log::writer.
My rather simple take on the situation:
class logger{
private:
unsigned int support_count;
std::ostream& output_stream;
public:
logger(std::ostream& str)
:support_count(0),
output_stream(str)
{}
class support_buffer{
private:
logger& l;
support_buffer(logger& l)
:l(l)
{
l.support_count++;
}
public:
support_buffer(const support_buffer& buf)
:l(buf.l)
{
l.support_count++;
}
~support_buffer(){
l.support_count--;
if (l.support_count==0){
l.output_stream << std::endl;
}
}
template <typename T>
support_buffer& operator<<(const T& t){
l.output_stream << t;
return *this;
}
friend class logger;
};
template <typename T>
support_buffer operator<<(const T& t){
output_stream << "<date/time> " << t;
return support_buffer(*this);
}
friend class support_buffer;
};
int main()
{
logger l(std::cout);
l << "Line 1: " << 0 << "Still on line 1";
l << "Line 2";
return 0;
}
Just create a wrapper class that passes all printed elements to our logger and on destruction of the last one send a new line. If you are sure that your output buffer is only being used by your logger class you could even resign of counting support objects. Just print new line character before a line instead of after it.
I have the following code which is redirecting my std::cout output to a log file.
std::ofstream out("out.txt");
std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!
Now what I want is that whenever a newline is occurring, then the current time stamp will be written to the file.
I know I can achive this with:
std::cout << getTime() << "printing data" << std::endl;
But what I want is that of std::cout taking care of it automatically somehow. Is that possible?
I assume, that You want print the TimeStamp, if the first character of the next line appears in the output.
Take a new class and inherit it from std::streambuf and connect it in the same way You do with the filebuf. If a newline-charater appears store this event in the object. Appears another character add the timestamp to the stream.
I wrote an example which use the RAII idiom for connecting the streambuf.
class AddTimeStamp : public std::streambuf
{
public:
AddTimeStamp( std::basic_ios< char >& out )
: out_( out )
, sink_()
, newline_( true )
{
sink_ = out_.rdbuf( this );
assert( sink_ );
}
~AddTimeStamp()
{
out_.rdbuf( sink_ );
}
protected:
int_type overflow( int_type m = traits_type::eof() )
{
if( traits_type::eq_int_type( m, traits_type::eof() ) )
return sink_->pubsync() == -1 ? m: traits_type::not_eof(m);
if( newline_ )
{ // -- add timestamp here
std::ostream str( sink_ );
if( !(str << getTime()) ) // add perhaps a seperator " "
return traits_type::eof(); // Error
}
newline_ = traits_type::to_char_type( m ) == '\n';
return sink_->sputc( m );
}
private:
AddTimeStamp( const AddTimeStamp& );
AddTimeStamp& operator=( const AddTimeStamp& ); // not copyable
// -- Members
std::basic_ios< char >& out_;
std::streambuf* sink_;
bool newline_;
};
call an object of this class in following way:
// some initialisation ..
{
AddTimeStamp ats( cout ); // timestamp is active
// every output to 'cout' will start with a 'getTime()' now
// ...
} // restore the old streambuf in the destructor of AddTimeStamp
That's a hack from a different point.
When you run the program, pipe the output into awk, and add there the time stamp. The command:
<program> | awk '{print strftime()" "$0}' > logfile
If you are using windows, you can download gawk from this website.
You can format the time printed by strftime. More data on that can be found in the manual
You want something like:
ostream & addTime() {
std::cout << getTime();
return std::cout;
and use it like this:
addTime() << "printing data" << std::endl;
try something like the following (it's just an abstract, I didn't test it):
class logger : ostream
{
bool line = true;
public:
template<typename T> ostream& operator<< (T somedata)
{
if (line)
ostream << getTime();
ostream << somedata;
line = somedata == std::endl;
}
}
I'm searching the best way to add a custom, initial message to all the messages that std::cout (or std::cerr) prints to console/file output.
For example, if I setup that this custom prompt message will be the string "[Log]", then a classic
std::cerr << "This is a log message" << std::endl;
will be printed in this way:
> [Log] This is a log message
Clearly I can obtain this behavior using
std::string PROMPT_MSG = "[Log]";
std::cerr << PROMPT_MSG << "This is a log message" << std::endl;
but I'd like a less invasive way.
Thanks in advance
You could write your own class:
#include <iostream>
#include <string>
class MyLogger
{
std::ostream & out;
std::string const msg;
public:
MyLogger(std::ostream & o, std::string s)
: out(o)
, msg(std::move(s))
{ }
template <typename T>
std::ostream & operator<<(T const & x)
{
return out << msg << x;
}
};
MyLogger MyErr(std::cerr, "[LOG] ");
Usage:
MyErr << "Hello" << std::endl;
As Joachim Pileborg suggested you can use a logging framework. YOu can use an existing one or start with your own that will contain just one class:
class MyLogger{}
template <typename T>
MyLogger& operator << (MyLogger& logger, const T& logStuff)
{
std::cerr << PROMPT_MSG << logStuff << std::endl;
return logger;
}
then define a global variable of class MyLogger:
MyLogger mylogger;
then when you want to write a log record, write:
mylogger << "This is a log message";
overloaded operator << of class MyLogger will do what you want;
I had the same problem in a recent project. I solved it with this little class:
class DebugOut
{
public:
static const int COLUMN_WIDTH = 15;
DebugOut(const std::wstring &type)
{
std::wcout << type;
for(int i=type.length();i<COLUMN_WIDTH;i++)
std::wcout << " ";
std::wcout << ": ";
}
~DebugOut()
{
std::wcout << std::endl;
}
template <typename T>
friend DebugOut& operator<<(DebugOut& out,T i)
{
std::wcout << i;
return out;
}
};
Sample usage: DebugOut(L"Log") << "Something";
I guess you could just define a function log and a function error, and then just call them when you want to print a log or error method. That way you don't have to add the PROMPT_MSG every time.
I'm using the cerr stream for my error output, but I also wanted to save any of this error output in a stringstream in memory.
I'm looking to turn this:
stringstream errorString;
cerr << " Something went wrong ";
errorString << " Something went wrong ";
Into
myErr << " Something went wrong ";
Where myErr is an instance of a class that stores this in a stringstream and also outputs to cerr.
Thanks for any help.
You could create the type of your myErr class like this:
class stream_fork
{
std::ostream& _a;
std::ostream& _b;
public:
stream_fork( std::ostream& a, std::ostream& b)
: _a( a ),
_b( b )
{
}
template<typename T>
stream_fork& operator<<( const T& obj )
{
_a << obj;
_b << obj;
return *this;
}
// This lets std::endl work, too!
stream_fork& operator<<( std::ostream& manip_func( std::ostream& ) )
{
_a << manip_func;
_b << manip_func;
return *this;
}
};
Usage:
stream_fork myErr( std::cerr, errorString );
myErr << "Error Message" << std::endl;
You can use Boost.IOStreams.
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
#include <sstream>
namespace io = boost::iostreams;
int main() {
std::stringstream ss;
io::tee_device<decltype(ss), decltype(std::cerr)> sink(ss, std::cerr);
io::stream<decltype(sink)> stream(sink);
stream << "foo" << std::endl;
std::cout << ss.str().length() << std::endl;
return 0;
}
Override operator<< in your MyErr class
MyErr& operator<< ( MyErr& myErr, std::string message)
{
cerr << message;
errorString << message; //Where errorString is a member of the MyErr class
return myErr;
}
Then where you want to log the error:
int main()
{
MyErr myErr;
myErr << " Something went wrong. ";
return 0;
}
You might want to make MyErr a singleton class so that everything written to errorString is in one place.
Use Boost tee.
You need to subclass streambuf and declare myErr as an ostream that uses your subclass. Make the input functions do nothing and then have the output functions copy out to whatever streams you need.
I had a class that did something similar 12 years ago, but have lost track of it. I haven't been able to find a good example, but the docs for streambuf could be a starting point. Focus on the protected output functions.