// // file_logger.cxx // logging // // Created by Sam Jaffe on 4/1/19. // #include #include "expect/expect.hpp" #include "resource_factory/prototype_factory.hpp" #include "logger/detail/appender.h" #include "logger/detail/layout.h" #include "logger/log_manager.h" #include "logger/properties.h" using namespace logging; struct buffer : std::filebuf { buffer(properties const & props); buffer * setbuf(char* data, std::streamsize n); }; class file_appender : public simple_appender { public: static std::shared_ptr create(properties const & props); explicit file_appender(properties const & props); std::ostream & stream() override { return out_; } void write(logpacket const & packet, layout & withLayout) override; private: bool flush_immediately_; buffer rdbuf_; std::ostream out_; std::unique_ptr buffer_; }; using namespace logging::property; properties const DEFAULT_FILE_APPENDER{_obj({ {"immediateFlush", _v(true)}, {"threshold", _v("ERROR")}, {"filename", {}}, // Will throw if accessed {"fileAppend", _v(true)}, {"bufferedIO", _v(false)}, {"bufferSize", _v(8192)} })}; std::shared_ptr file_appender::create(properties const & props) { properties const actual = DEFAULT_FILE_APPENDER.mergedWith(props); return std::make_shared(actual); } static std::ios_base::openmode mode(bool append) { return append ? std::ios_base::app : std::ios_base::out; } buffer::buffer(properties const & props) : std::filebuf() { if (open(props["filename"], mode(props["fileAppend"])) == nullptr) { throw std::runtime_error("Cannot open file"); } } buffer * buffer::setbuf(char* data, std::streamsize n) { std::filebuf::setbuf(data, n); return this; } file_appender::file_appender(properties const & props) : simple_appender(props), flush_immediately_(props["immediateFlush"]), rdbuf_(props), out_(&rdbuf_) { if (props["bufferedIO"]) { int const size = props["bufferSize"]; buffer_.reset(new char[size]); rdbuf_.setbuf(buffer_.get(), size); } } void file_appender::write(logpacket const & packet, layout & withLayout) { withLayout.format(out_, packet); if (flush_immediately_) { flush(); } } namespace { bool _ = appenders::instance().bind("File", file_appender::create); }