|
|
@@ -20,17 +20,24 @@ namespace logging {
|
|
|
level level_from_string(std::string const & value);
|
|
|
}
|
|
|
|
|
|
+struct buffer : std::filebuf {
|
|
|
+ buffer(properties const & props);
|
|
|
+ buffer * setbuf(char* data, std::streamsize n);
|
|
|
+};
|
|
|
+
|
|
|
class file_appender : public appender {
|
|
|
public:
|
|
|
- static std::shared_ptr<appender> create(properties const&);
|
|
|
+ static std::shared_ptr<appender> create(properties const & props);
|
|
|
|
|
|
- explicit file_appender(const std::string& fname, bool append);
|
|
|
+ explicit file_appender(properties const & props);
|
|
|
|
|
|
void write(std::string const & msg) override;
|
|
|
void flush() override;
|
|
|
private:
|
|
|
bool flush_immediately_{false};
|
|
|
- std::ofstream out_;
|
|
|
+ buffer rdbuf_;
|
|
|
+ std::ostream out_;
|
|
|
+ std::unique_ptr<char[]> buffer_;
|
|
|
};
|
|
|
|
|
|
using namespace logging::property;
|
|
|
@@ -38,25 +45,41 @@ properties const DEFAULT_FILE_APPENDER{_obj({
|
|
|
{"immediateFlush", _v(true)},
|
|
|
{"threshold", _v("ERROR")},
|
|
|
{"filename", {}}, // Will throw if accessed
|
|
|
- {"fileAppend", _v(true)}/*,
|
|
|
+ {"fileAppend", _v(true)},
|
|
|
{"bufferedIO", _v(false)},
|
|
|
- {"bufferSize", _v(8192)}*/
|
|
|
+ {"bufferSize", _v(8192)}
|
|
|
})};
|
|
|
|
|
|
std::shared_ptr<appender> file_appender::create(properties const & props) {
|
|
|
properties const actual = DEFAULT_FILE_APPENDER.mergedWith(props);
|
|
|
- file_appender app(actual["filename"], actual["fileAppend"]);
|
|
|
- app.flush_immediately_ = actual["immediateFlush"];
|
|
|
- app.min_log_level = level_from_string(actual["threshold"]);
|
|
|
- return std::make_shared<file_appender>(std::move(app));
|
|
|
+ return std::make_shared<file_appender>(actual);
|
|
|
}
|
|
|
|
|
|
static std::ios_base::openmode mode(bool append) {
|
|
|
- return (append ? std::ios_base::app : 0) | std::ios_base::out;
|
|
|
+ return append ? std::ios_base::app : 0;
|
|
|
+}
|
|
|
+
|
|
|
+buffer::buffer(properties const & props) : std::filebuf() {
|
|
|
+ if (open(props["filename"], mode(props["fileAppend"])) == nullptr) {
|
|
|
+ // TODO: throw
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-file_appender::file_appender(const std::string& fname, bool append)
|
|
|
-: out_(fname, mode(append)) {}
|
|
|
+buffer * buffer::setbuf(char* data, std::streamsize n) {
|
|
|
+ std::filebuf::setbuf(data, n);
|
|
|
+ return this;
|
|
|
+}
|
|
|
+
|
|
|
+file_appender::file_appender(properties const & props)
|
|
|
+: appender(level_from_string(props["threshold"])),
|
|
|
+ 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(std::string const & msg) {
|
|
|
out_ << msg;
|