| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #include "log.h" | 
| 2 |  |  |  |  |  |  | #include | 
| 3 |  |  |  |  |  |  | #include | 
| 4 |  |  |  |  |  |  | #include | 
| 5 |  |  |  |  |  |  | #include | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | namespace panda { namespace log { | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | namespace details { | 
| 10 | 18 |  |  |  |  |  | std::unique_ptr ilogger; | 
| 11 |  |  |  |  |  |  |  | 
| 12 | 0 |  |  |  |  |  | static thread_local std::ostringstream os; | 
| 13 |  |  |  |  |  |  |  | 
| 14 | 0 |  |  |  |  |  | std::ostream& _get_os () { return os; } | 
| 15 |  |  |  |  |  |  |  | 
| 16 | 0 |  |  |  |  |  | bool _do_log (std::ostream& _stream, const CodePoint& cp, Level level) { | 
| 17 | 0 |  |  |  |  |  | std::ostringstream& stream = static_cast(_stream); | 
| 18 | 0 | 0 |  |  |  |  | if (!ilogger) return false; | 
| 19 | 0 | 0 |  |  |  |  | stream.flush(); | 
| 20 | 0 | 0 |  |  |  |  | std::string s(stream.str()); | 
| 21 | 0 | 0 |  |  |  |  | stream.str({}); | 
| 22 | 0 | 0 |  |  |  |  | ilogger->log(level, cp, s); | 
| 23 | 0 |  |  |  |  |  | return true; | 
| 24 |  |  |  |  |  |  | } | 
| 25 |  |  |  |  |  |  | } | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 0 |  |  |  |  |  | void set_level (Level val, const string& module) { | 
| 28 | 0 | 0 |  |  |  |  | if (module) { | 
| 29 | 0 |  |  |  |  |  | auto& modules = ::panda_log_module->children; | 
| 30 | 0 | 0 |  |  |  |  | auto iter = modules.find(module); | 
| 31 | 0 | 0 |  |  |  |  | if (iter == modules.end()) { | 
| 32 | 0 | 0 |  |  |  |  | throw std::invalid_argument("unknown module"); | 
| 33 |  |  |  |  |  |  | } | 
| 34 | 0 | 0 |  |  |  |  | iter->second->set_level(val); | 
| 35 |  |  |  |  |  |  | } else { | 
| 36 | 0 |  |  |  |  |  | panda_log_module->set_level(val); | 
| 37 |  |  |  |  |  |  | } | 
| 38 |  |  |  |  |  |  |  | 
| 39 | 0 |  |  |  |  |  | } | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 0 |  |  |  |  |  | void set_logger (ILogger* l) { | 
| 42 | 0 |  |  |  |  |  | details::ilogger.reset(l); | 
| 43 | 0 |  |  |  |  |  | } | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 0 |  |  |  |  |  | std::string CodePoint::to_string () const { | 
| 46 | 0 | 0 |  |  |  |  | std::ostringstream os; | 
| 47 | 0 | 0 |  |  |  |  | os << *this; | 
| 48 | 0 | 0 |  |  |  |  | os.flush(); | 
| 49 | 0 | 0 |  |  |  |  | return os.str(); | 
| 50 |  |  |  |  |  |  | } | 
| 51 |  |  |  |  |  |  |  | 
| 52 | 0 |  |  |  |  |  | std::ostream& operator<< (std::ostream& stream, const CodePoint& cp) { | 
| 53 | 0 |  |  |  |  |  | size_t total = cp.file.size() + log10(cp.line) + 2; | 
| 54 | 0 |  |  |  |  |  | const char* whitespaces = "                        "; // 24 spaces | 
| 55 | 0 | 0 |  |  |  |  | if (total < 24) { | 
| 56 | 0 |  |  |  |  |  | whitespaces += total; | 
| 57 |  |  |  |  |  |  | } else { | 
| 58 | 0 |  |  |  |  |  | whitespaces = ""; | 
| 59 |  |  |  |  |  |  | } | 
| 60 | 0 |  |  |  |  |  | stream << cp.file << ":" << cp.line << whitespaces; | 
| 61 | 0 |  |  |  |  |  | return stream; | 
| 62 |  |  |  |  |  |  | } | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 0 |  |  |  |  |  | std::ostream& operator<< (std::ostream& stream, const escaped& str) { | 
| 65 | 0 | 0 |  |  |  |  | for (auto c : str.src) { | 
| 66 | 0 | 0 |  |  |  |  | if (c > 31) { | 
| 67 | 0 |  |  |  |  |  | stream << c; | 
| 68 |  |  |  |  |  |  | } else { | 
| 69 | 0 |  |  |  |  |  | stream << "\\" << std::setfill('0') << std::setw(2) << uint32_t(uint8_t(c)); | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  | } | 
| 72 | 0 |  |  |  |  |  | return stream; | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 0 |  |  |  |  |  | Module::Module(const string& name, Level level) | 
| 76 | 0 |  |  |  |  |  | : Module(name, panda_log_module, level) | 
| 77 | 0 |  |  |  |  |  | {} | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 18 |  |  |  |  |  | Module::Module(const string& name, Module* parent, Level level) | 
| 80 | 18 |  |  |  |  |  | : level(level), name(name) | 
| 81 |  |  |  |  |  |  | { | 
| 82 | 18 | 50 |  |  |  |  | if (!parent) return; | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 0 |  |  |  |  |  | this->parent = parent; | 
| 85 |  |  |  |  |  |  |  | 
| 86 | 0 | 0 |  |  |  |  | if (parent->children.find(name) != parent->children.end()) { | 
|  |  | 0 |  |  |  |  |  | 
| 87 | 0 | 0 |  |  |  |  | string msg = "panda::log::Module " + name + "is already registered"; | 
|  |  | 0 |  |  |  |  |  | 
| 88 | 0 | 0 |  |  |  |  | throw std::logic_error(msg.c_str()); | 
|  |  | 0 |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | } | 
| 90 | 18 | 0 |  |  |  |  | parent->children[name] = this; | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 0 |  |  |  |  |  | void Module::set_level(Level level) { | 
| 94 | 0 |  |  |  |  |  | this->level = level; | 
| 95 | 0 | 0 |  |  |  |  | for (auto& p : children) { | 
| 96 | 0 | 0 |  |  |  |  | p.second->set_level(level); | 
| 97 |  |  |  |  |  |  | } | 
| 98 | 0 |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  |  | 
| 103 | 18 |  |  |  |  |  | static panda::log::Module* panda_log_root_module() { | 
| 104 | 18 | 50 |  |  |  |  | static panda::log::Module inst("", nullptr); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 105 | 18 |  |  |  |  |  | return &inst; | 
| 106 |  |  |  |  |  |  | } | 
| 107 | 90 | 0 |  |  |  |  | panda::log::Module* panda_log_module = panda_log_root_module(); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  |