// // json_layout.cxx // logging // // Created by Sam Jaffe on 4/7/19. // #include #include #include #include "resource_factory/prototype_factory.hpp" #include "common.h" #include "logger/detail/layout.h" #include "logger/log_manager.h" #include "logger/logpacket.h" #include "logger/properties.h" using namespace logging; class json_layout : public layout { public: static std::shared_ptr create(properties const &); json_layout(properties const & props); void format(std::ostream & os, logpacket const & pkt) const override; private: Json::StreamWriterBuilder build; bool eol_, log_as_json_; }; using namespace logging::property; properties const DEFAULT_JSON_LAYOUT{_obj({ {"charset", _v("en_US.UTF-8")}, {"compact", _v(false)}, {"eventEol", _v(false)}, {"complete", _v(false)}, {"locationInfo", _v(false)}, {"includeNullDelimiter", _v(false)}, {"objectMessageAsJsonObject", _v(false)} })}; std::shared_ptr json_layout::create(properties const & props) { properties const actual = DEFAULT_JSON_LAYOUT.mergedWith(props); return std::make_shared(actual); } json_layout::json_layout(properties const & props) : eol_(props["eventEol"]), log_as_json_(props["objectMessageAsJsonObject"]) { build["indentation"] = props["compact"] ? "" : " "; } void json_layout::format(std::ostream & os, logpacket const & pkt) const { Json::Value root; root["instant"]["epochSecond"] = (Json::UInt64) pkt.time.tv_sec; root["instant"]["nanoOfSecond"] = pkt.time.tv_usec * 1000; root["level"] = level_to_string(pkt.level); root["loggerName"] = pkt.logger; if (log_as_json_) { root["message"] = pkt.message.json(); } else { root["message"] = pkt.message.str(); } std::string data = Json::writeString(build, root); // jsoncpp is dumb and writes a newline after each ':' token if // the child is an object or array. std::regex_replace(std::ostreambuf_iterator(os), data.begin(), data.end(), std::regex(": \n( )*(\\{|\\[)"), ": $2"); if (eol_) { os << NEWLINE_TOKEN; } } namespace { bool _ = layouts::instance().bind("JsonLayout", json_layout::create); }