1 // Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by a apache 2.0 license that can be
3 // found in the LICENSE file.
11 #define PROJECT_TAG ""
30 #define __FILENAME__ \
31 (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
43 log_priority LogLevelToPriority(LogLevel level);
45 template<LogLevel> struct LogTag;
46 template<> struct LogTag<LogLevel::LOG_ERROR> {
47 static constexpr const char* value = "\033[1;31m| ERROR |\033[0m";
49 template<> struct LogTag<LogLevel::LOG_WARNING> {
50 static constexpr const char* value = "\033[1;33m| WARNING |\033[0m";
52 template<> struct LogTag<LogLevel::LOG_INFO> {
53 static constexpr const char* value = "\033[1;32m| INFO |\033[0m";
55 template<> struct LogTag<LogLevel::LOG_DEBUG> {
56 static constexpr const char* value = "\033[0m| DEBUG |\033[0m";
59 template <class charT, class traits = std::char_traits<charT>>
60 class StringStream : private std::basic_ostringstream<charT, traits> {
62 using std::basic_ostringstream<charT, traits>::str;
65 StringStream& operator<<(const T& value) {
66 static_cast<std::basic_ostringstream<charT, traits> &>(*this) << value;
71 // Interface class for logging backends. The custom LogBackend which wants
72 // log using LOG() macro should be implement following interface.
75 virtual void WriteLog(LogLevel level, const std::string& tag,
76 const std::string& logstr) = 0;
79 class DLogBackend : public ILogBackend {
81 void WriteLog(LogLevel level, const std::string& tag,
82 const std::string& logstr) override {
83 dlog_print(LogLevelToPriority(level), tag.c_str(), "%s",
84 Escape(logstr).c_str());
86 if (level == LogLevel::LOG_ERROR)
87 std::cerr << logstr << std::endl;
91 // Since LogCatcher passes input to dlog_print(), the input which contains
92 // format string(such as %d, %n) can cause unexpected result.
93 // This is simple function to escape '%'.
94 // NOTE: Is there any gorgeous way instead of this?
95 std::string Escape(const std::string& str) const {
96 std::string escaped = std::string(str);
98 std::string from = "%";
99 std::string to = "%%";
100 while ((start_pos = escaped.find(from, start_pos)) != std::string::npos) {
101 escaped.replace(start_pos, from.length(), to);
102 start_pos += to.length();
110 // Do not call this function at destructor of global object
111 static LogCore& GetCore() {
116 void AddLogBackend(std::shared_ptr<ILogBackend> backend) {
117 backend_list_.emplace_back(backend);
120 void Log(LogLevel level, const std::string& tag, const std::string& log) {
121 for (auto backend : backend_list_)
122 backend->WriteLog(level, tag, log);
127 // add default dlog backend
128 AddLogBackend(std::shared_ptr<ILogBackend>(new DLogBackend()));
130 ~LogCore() = default;
131 LogCore(const LogCore&) = delete;
132 LogCore& operator=(const LogCore&) = delete;
134 std::vector<std::shared_ptr<ILogBackend>> backend_list_;
139 LogCatcher(LogLevel level, const char* tag)
140 : level_(level), tag_(tag) { }
142 void operator&(const StringStream<char>& str) const {
143 LogCore::GetCore().Log(level_, tag_, str.str());
154 inline static const constexpr char* __tag_for_logging() {
158 inline static const constexpr char* __tag_for_project() {
162 // To be defined in class namespace if user want different log tag for given
164 #define SCOPE_LOG_TAG(TAG) \
165 inline static const constexpr char* __tag_for_logging() { \
169 // Simple logging macro of following usage:
170 // LOG(LEVEL) << object_1 << object_2 << object_n;
172 // LEVEL = ERROR | WARNING | INFO | DEBUG
174 ::utils::LogCatcher( \
175 ::utils::LogLevel::LOG_ ## LEVEL, __tag_for_project()) \
176 & ::utils::StringStream<char>() \
177 << std::string(::utils::LogTag<::utils::LogLevel::LOG_ ## LEVEL>::value) \
178 << " " << std::setw(25) << std::left << __tag_for_logging() \
179 << " : " << std::setw(36) \
180 << (std::string(__FILENAME__) + ":" + std::to_string(__LINE__)).c_str() \
181 << std::setw(0) << " : " \
183 #endif // MANIFEST_PARSER_UTILS_LOGGING_H_