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;
}