file_appender.cxx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. //
  2. // file_logger.cxx
  3. // logging
  4. //
  5. // Created by Sam Jaffe on 4/1/19.
  6. //
  7. #include <fstream>
  8. #include "expect/expect.hpp"
  9. #include "resource_factory/prototype_factory.hpp"
  10. #include "logger/detail/appender.h"
  11. #include "logger/detail/layout.h"
  12. #include "logger/log_manager.h"
  13. #include "logger/properties.h"
  14. using namespace logging;
  15. struct buffer : std::filebuf {
  16. buffer(properties const & props);
  17. buffer * setbuf(char* data, std::streamsize n);
  18. };
  19. class file_appender : public simple_appender {
  20. public:
  21. static std::shared_ptr<appender> create(properties const & props);
  22. explicit file_appender(properties const & props);
  23. std::ostream & stream() override { return out_; }
  24. void write(logpacket const & packet, layout & withLayout) override;
  25. private:
  26. bool flush_immediately_;
  27. buffer rdbuf_;
  28. std::ostream out_;
  29. std::unique_ptr<char[]> buffer_;
  30. };
  31. using namespace logging::property;
  32. properties const DEFAULT_FILE_APPENDER{_obj({
  33. {"immediateFlush", _v(true)},
  34. {"threshold", _v("ERROR")},
  35. {"filename", {}}, // Will throw if accessed
  36. {"fileAppend", _v(true)},
  37. {"bufferedIO", _v(false)},
  38. {"bufferSize", _v(8192)}
  39. })};
  40. std::shared_ptr<appender> file_appender::create(properties const & props) {
  41. properties const actual = DEFAULT_FILE_APPENDER.mergedWith(props);
  42. return std::make_shared<file_appender>(actual);
  43. }
  44. static std::ios_base::openmode mode(bool append) {
  45. return append ? std::ios_base::app : std::ios_base::out;
  46. }
  47. buffer::buffer(properties const & props) : std::filebuf() {
  48. if (open(props["filename"], mode(props["fileAppend"])) == nullptr) {
  49. throw std::runtime_error("Cannot open file");
  50. }
  51. }
  52. buffer * buffer::setbuf(char* data, std::streamsize n) {
  53. std::filebuf::setbuf(data, n);
  54. return this;
  55. }
  56. file_appender::file_appender(properties const & props)
  57. : simple_appender(props),
  58. flush_immediately_(props["immediateFlush"]),
  59. rdbuf_(props), out_(&rdbuf_) {
  60. if (props["bufferedIO"]) {
  61. int const size = props["bufferSize"];
  62. buffer_.reset(new char[size]);
  63. rdbuf_.setbuf(buffer_.get(), size);
  64. }
  65. }
  66. void file_appender::write(logpacket const & packet, layout & withLayout) {
  67. withLayout.format(out_, packet);
  68. if (flush_immediately_) { flush(); }
  69. }
  70. namespace {
  71. bool _ = appenders::instance().bind("File", file_appender::create);
  72. }