json_layout.cxx 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. //
  2. // json_layout.cxx
  3. // logging
  4. //
  5. // Created by Sam Jaffe on 4/7/19.
  6. //
  7. #include <iterator>
  8. #include <regex>
  9. #include <json/json.h>
  10. #include "resource_factory/prototype_factory.hpp"
  11. #include "common.h"
  12. #include "logger/detail/layout.h"
  13. #include "logger/log_manager.h"
  14. #include "logger/logpacket.h"
  15. #include "logger/properties.h"
  16. using namespace logging;
  17. class json_layout : public layout {
  18. public:
  19. static std::shared_ptr<layout> create(properties const &);
  20. json_layout(properties const & props);
  21. void format(std::ostream & os, logpacket const & pkt) const override;
  22. private:
  23. Json::StreamWriterBuilder build;
  24. bool eol_, log_as_json_;
  25. };
  26. using namespace logging::property;
  27. properties const DEFAULT_JSON_LAYOUT{_obj({
  28. {"charset", _v("en_US.UTF-8")},
  29. {"compact", _v(false)},
  30. {"eventEol", _v(false)},
  31. {"complete", _v(false)},
  32. {"locationInfo", _v(false)},
  33. {"includeNullDelimiter", _v(false)},
  34. {"objectMessageAsJsonObject", _v(false)}
  35. })};
  36. std::shared_ptr<layout> json_layout::create(properties const & props) {
  37. properties const actual = DEFAULT_JSON_LAYOUT.mergedWith(props);
  38. return std::make_shared<json_layout>(actual);
  39. }
  40. json_layout::json_layout(properties const & props)
  41. : eol_(props["eventEol"]),
  42. log_as_json_(props["objectMessageAsJsonObject"])
  43. {
  44. build["indentation"] = props["compact"] ? "" : " ";
  45. }
  46. void json_layout::format(std::ostream & os, logpacket const & pkt) const {
  47. Json::Value root;
  48. root["instant"]["epochSecond"] = (Json::UInt64) pkt.time.tv_sec;
  49. root["instant"]["nanoOfSecond"] = pkt.time.tv_usec * 1000;
  50. root["level"] = level_to_string(pkt.level);
  51. root["loggerName"] = pkt.logger;
  52. if (log_as_json_) {
  53. root["message"] = pkt.message.json();
  54. } else {
  55. root["message"] = pkt.message.str();
  56. }
  57. std::string data = Json::writeString(build, root);
  58. // jsoncpp is dumb and writes a newline after each ':' token if
  59. // the child is an object or array.
  60. std::regex_replace(std::ostreambuf_iterator<char>(os),
  61. data.begin(), data.end(),
  62. std::regex(": \n( )*(\\{|\\[)"), ": $2");
  63. if (eol_) {
  64. os << NEWLINE_TOKEN;
  65. }
  66. }
  67. namespace {
  68. bool _ = layouts::instance().bind("JsonLayout", json_layout::create);
  69. }