json_layout.cxx 2.5 KB

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