flush every period

This commit is contained in:
gabime 2014-03-01 14:06:58 +02:00
parent 6f4c780089
commit ddcf45d65f
11 changed files with 105 additions and 76 deletions

View File

@ -2,7 +2,7 @@
// //
#include <string> #include <string>
#include <functional> #include <functional>
#include <iomanip>
#include "c11log/logger.h" #include "c11log/logger.h"
#include "c11log/sinks/async_sink.h" #include "c11log/sinks/async_sink.h"
#include "c11log/sinks/file_sinks.h" #include "c11log/sinks/file_sinks.h"
@ -47,7 +47,32 @@ void testlog(int threads)
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
using namespace std::chrono; using namespace std::chrono;
using namespace c11log;
using namespace utils;
using std::cout;
using std::endl;
auto fsink2 = std::make_shared<sinks::rotating_file_sink>("log", "txt", 1024*1024*50 , 5, seconds(1));
auto &logger2 = c11log::get_logger("logger2");
logger2.add_sink(fsink2);
//logger2.add_sink(std::make_shared<sinks::null_sink>());
auto start = system_clock::now();
const unsigned int howmany = 10000000;
for(unsigned int i = 0; i < howmany ; i++)
logger2.info() << "Hello logger " << i;
auto delta = system_clock::now() - start;
auto delta_d = duration_cast<duration<double>> (delta);
cout << "Total " << format(howmany) << endl;
cout << "Delta " << format(delta_d.count()) << endl;
cout << "Rate: " << format(howmany/delta_d.count()) << "/sec" << endl;
return 0;
if(argc !=3) { if(argc !=3) {
std::cerr << "Usage: " << argv[0] << " qsize, threads" << std::endl; std::cerr << "Usage: " << argv[0] << " qsize, threads" << std::endl;
@ -56,16 +81,18 @@ int main(int argc, char* argv[])
int qsize = atoi(argv[1]); int qsize = atoi(argv[1]);
int threads = atoi(argv[2]); int threads = atoi(argv[2]);
using namespace c11log;
auto null_sink = std::make_shared<sinks::null_sink>(); auto null_sink = std::make_shared<sinks::null_sink>();
auto stdout_sink = std::make_shared<sinks::stdout_sink>(); auto stdout_sink = std::make_shared<sinks::stdout_sink>();
auto async = std::make_shared<sinks::async_sink>(qsize); auto async = std::make_shared<sinks::async_sink>(qsize);
auto fsink = std::make_shared<sinks::rotating_file_sink>("log", "txt", 1024*1024*50 , 5, 1000); auto fsink = std::make_shared<sinks::rotating_file_sink>("log", "txt", 1024*1024*50 , 5, std::chrono::milliseconds(1000));
async->add_sink(fsink); async->add_sink(fsink);
auto &logger = c11log::get_logger("async"); //auto &logger = c11log::get_logger("async");
logger.add_sink(fsink); //logger.add_sink(fsink);
testlog(threads); testlog(threads);
} }

View File

@ -1,4 +1,4 @@
CXX = g++ CXX = ccache g++
CXXFLAGS = -march=native -Wall -Wextra -Wshadow -pedantic -std=c++11 -pthread -I../include CXXFLAGS = -march=native -Wall -Wextra -Wshadow -pedantic -std=c++11 -pthread -I../include
CXX_RELEASE_FLAGS = -O3 -flto CXX_RELEASE_FLAGS = -O3 -flto
CXX_DEBUG_FLAGS= -g CXX_DEBUG_FLAGS= -g

View File

@ -19,6 +19,16 @@ std::string format(const T& value)
return ss.str(); return ss.str();
} }
template<>
std::string format(const double & value)
{
static std::locale loc("");
std::stringstream ss;
ss.imbue(loc);
ss << std::fixed << std::setprecision(1) << value;
return ss.str();
}
inline void bench(const std::string& fn_name, const std::chrono::milliseconds &duration, const std::function<void() >& fn) inline void bench(const std::string& fn_name, const std::chrono::milliseconds &duration, const std::function<void() >& fn)
{ {
using namespace std::chrono; using namespace std::chrono;

View File

@ -58,7 +58,7 @@ public:
// If the queue is full, block the calling thread until there is room. // If the queue is full, block the calling thread until there is room.
template<typename TT> template<typename TT>
void push(TT&& item) { void push(TT&& item) {
while (!push(std::forward<TT>(item), one_hour)); while (!push(std::forward<TT>(item), _one_hour));
} }
// Pop a copy of the front item in the queue into the given item ref. // Pop a copy of the front item in the queue into the given item ref.
@ -85,7 +85,7 @@ public:
// Pop a copy of the front item in the queue into the given item ref. // Pop a copy of the front item in the queue into the given item ref.
// If the queue is empty, block the calling thread util there is item to pop. // If the queue is empty, block the calling thread util there is item to pop.
void pop(T& item) { void pop(T& item) {
while (!pop(item, one_hour)); while (!pop(item, _one_hour));
} }
// Clear the queue // Clear the queue
@ -103,7 +103,7 @@ private:
std::mutex _mutex; std::mutex _mutex;
std::condition_variable _item_pushed_cond; std::condition_variable _item_pushed_cond;
std::condition_variable _item_popped_cond; std::condition_variable _item_popped_cond;
static constexpr auto one_hour = std::chrono::hours(1); static constexpr auto _one_hour = std::chrono::hours(1);
}; };
} }

View File

@ -1,24 +1,33 @@
#pragma once #pragma once
#include <chrono>
#include <iostream>
// Flush to file every X writes.. // Flush to file every X writes..
namespace c11log { namespace c11log {
namespace details { namespace details {
class file_flush_helper { class file_flush_helper {
public: public:
explicit file_flush_helper(std::size_t flush_every): _flush_every(flush_every), _write_counter(0) {}; explicit file_flush_helper(const std::chrono::milliseconds &flush_every): _flush_every(flush_every), _last_flush() {};
void write(std::ofstream& ofs, const std::string& msg) { void write(std::ofstream& ofs, const std::string& msg) {
ofs << msg; ofs << msg;
if(++_write_counter >= _flush_every) { //If zero - flush every time
if(_flush_every == std::chrono::milliseconds::min()) {
ofs.flush(); ofs.flush();
_write_counter = 0; } else {
auto now = std::chrono::system_clock::now();
if(now - _last_flush >= _flush_every) {
ofs.flush();
_last_flush = now;
}
} }
} }
private: private:
std::size_t _flush_every; std::chrono::milliseconds _flush_every;
std::size_t _write_counter; std::chrono::system_clock::time_point _last_flush;
}; };
} }
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "../level.h" #include "../common_types.h"
#include "../logger.h" #include "../logger.h"
#include "fast_oss.h" #include "fast_oss.h"
@ -16,7 +16,7 @@ public:
_level(msg_level) { _level(msg_level) {
callback_logger->_formatter->format_header(callback_logger->_logger_name, callback_logger->_formatter->format_header(callback_logger->_logger_name,
msg_level, msg_level,
c11log::formatters::clock::now(), log_clock::now(),
_oss); _oss);
} }
line_logger(logger*):_callback_logger(nullptr) {}; line_logger(logger*):_callback_logger(nullptr) {};

View File

@ -1,18 +1,18 @@
#pragma once #pragma once
#include<string> #include <string>
#include<chrono> #include <chrono>
#include<functional> #include <functional>
#include <sstream> #include <sstream>
#include <iomanip>
#include "level.h" #include "common_types.h"
#include "details/os.h" #include "details/os.h"
namespace c11log { namespace c11log {
namespace formatters { namespace formatters {
typedef std::chrono::system_clock clock;
typedef clock::time_point time_point; typedef std::function<std::string(const std::string& logger_name, const std::string&, level::level_enum, const c11log::log_clock::time_point&)> format_fn;
typedef std::function<std::string(const std::string& logger_name, const std::string&, level::level_enum, const time_point&)> format_fn;
std::string to_hex(const unsigned char* buf, std::size_t size); std::string to_hex(const unsigned char* buf, std::size_t size);
@ -21,19 +21,19 @@ class formatter {
public: public:
formatter() {} formatter() {}
virtual ~formatter() {} virtual ~formatter() {}
virtual void format_header(const std::string& logger_name, level::level_enum level, const time_point& tp, std::ostream& dest) = 0; virtual void format_header(const std::string& logger_name, level::level_enum level, const log_clock::time_point& tp, std::ostream& dest) = 0;
}; };
class default_formatter: public formatter { class default_formatter: public formatter {
public: public:
// Format: [2013-12-29 01:04:42.900] [logger_name:Info] Message body // Format: [2013-12-29 01:04:42.900] [logger_name:Info] Message body
void format_header(const std::string& logger_name, level::level_enum level, const time_point& tp, std::ostream& dest) override { void format_header(const std::string& logger_name, level::level_enum level, const log_clock::time_point& tp, std::ostream& dest) override {
_format_time(tp, dest); _format_time(tp, dest);
dest << " [" << logger_name << ":" << c11log::level::to_str(level) << "] "; dest << " [" << logger_name << ":" << c11log::level::to_str(level) << "] ";
} }
private: private:
void _format_time(const time_point& tp, std::ostream &dest); void _format_time(const log_clock::time_point& tp, std::ostream &dest);
}; };
} //namespace formatter } //namespace formatter
@ -41,23 +41,19 @@ private:
inline void c11log::formatters::default_formatter::_format_time(const time_point& tp, std::ostream &dest) inline void c11log::formatters::default_formatter::_format_time(const log_clock::time_point& tp, std::ostream &dest)
{ {
using namespace std::chrono; using namespace std::chrono;
static thread_local c11log::formatters::time_point last_tp; auto tm = details::os::localtime(log_clock::to_time_t(tp));
static thread_local char timestamp_cache[64]; char buff[64];
int size = snprintf(buff, sizeof(buff), "[%d-%02d-%02d %02d:%02d:%02d]",
tm.tm_year + 1900,
tm.tm_mon + 1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec);
dest.write(buff, size);
if(duration_cast<milliseconds>(tp-last_tp).count() > 950) {
auto tm = details::os::localtime(clock::to_time_t(tp));
sprintf(timestamp_cache, "[%d-%02d-%02d %02d:%02d:%02d]", tm.tm_year + 1900,
tm.tm_mon + 1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec);
last_tp = tp;
}
dest << timestamp_cache;
} }

View File

@ -1,21 +0,0 @@
#pragma once
namespace c11log {
namespace level {
typedef enum {
DEBUG,
INFO,
WARNING,
ERROR,
FATAL,
NONE = 99
} level_enum;
const char* to_str(level_enum l);
}
}
static const char* level_names[] { "Debug", "Info", "Warning", "Error", "Fatal" };
inline const char* c11log::level::to_str(c11log::level::level_enum l)
{
return level_names[l];
}

View File

@ -8,15 +8,18 @@
#include<atomic> #include<atomic>
#include <algorithm> #include <algorithm>
#include "level.h" #include "common_types.h"
#include "sinks/base_sink.h" #include "sinks/base_sink.h"
#include "details/factory.h" #include "details/factory.h"
namespace c11log { namespace c11log {
namespace details { namespace details {
class line_logger; class line_logger;
} }
class logger { class logger {
public: public:

View File

@ -4,7 +4,7 @@
#include<atomic> #include<atomic>
#include "../formatter.h" #include "../formatter.h"
#include "../level.h" #include "../common_types.h"
namespace c11log { namespace c11log {
namespace sinks { namespace sinks {

View File

@ -14,10 +14,12 @@ namespace sinks {
*/ */
class simple_file_sink : public base_sink { class simple_file_sink : public base_sink {
public: public:
explicit simple_file_sink(const std::string &filename, const std::string& extension, size_t flush_after=1) explicit simple_file_sink(const std::string &filename,
const std::string& extension,
const std::chrono::milliseconds &flush_every=std::chrono::milliseconds::zero())
: _mutex(), : _mutex(),
_ofstream(filename + "." + extension, std::ofstream::app), _ofstream(filename + "." + extension, std::ofstream::binary|std::ofstream::app),
_flush_helper(flush_after) { _flush_helper(flush_every) {
} }
protected: protected:
void _sink_it(const std::string& msg) override { void _sink_it(const std::string& msg) override {
@ -36,15 +38,17 @@ private:
*/ */
class rotating_file_sink : public base_sink { class rotating_file_sink : public base_sink {
public: public:
rotating_file_sink(const std::string &base_filename, const std::string &extension, size_t max_size, size_t max_files, size_t flush_after=1): rotating_file_sink(const std::string &base_filename, const std::string &extension,
size_t max_size, size_t max_files,
const std::chrono::milliseconds &flush_every = std::chrono::milliseconds::zero()):
_base_filename(base_filename), _base_filename(base_filename),
_extension(extension), _extension(extension),
_max_size(max_size), _max_size(max_size),
_max_files(max_files), _max_files(max_files),
_current_size(0), _current_size(0),
_mutex(), _mutex(),
_ofstream(_calc_filename(_base_filename, 0, _extension)), _ofstream(_calc_filename(_base_filename, 0, _extension), std::ofstream::binary),
_flush_helper(flush_after) { _flush_helper(flush_every) {
} }
protected: protected:
@ -102,14 +106,15 @@ private:
*/ */
class daily_file_sink:public base_sink { class daily_file_sink:public base_sink {
public: public:
explicit daily_file_sink(const std::string& base_filename, const std::string& extension, size_t flush_after=1): explicit daily_file_sink(const std::string& base_filename,
const std::string& extension,
const std::chrono::milliseconds &flush_every = std::chrono::milliseconds::zero()):
_base_filename(base_filename), _base_filename(base_filename),
_extension(extension), _extension(extension),
_midnight_tp (_calc_midnight_tp() ), _midnight_tp (_calc_midnight_tp() ),
_mutex(), _mutex(),
_ofstream(_calc_filename(_base_filename, _extension), std::ofstream::app), _ofstream(_calc_filename(_base_filename, _extension), std::ofstream::binary|std::ofstream::app),
_flush_helper(flush_after) _flush_helper(flush_every) {
{
} }
protected: protected:
@ -147,7 +152,7 @@ private:
std::chrono::system_clock::time_point _midnight_tp; std::chrono::system_clock::time_point _midnight_tp;
std::mutex _mutex; std::mutex _mutex;
std::ofstream _ofstream; std::ofstream _ofstream;
details::file_flush_helper _flush_helper; details::file_flush_helper _flush_helper;
}; };
} }