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 "PKGMGR_INFO"
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());
88 // Since LogCatcher passes input to dlog_print(), the input which contains
89 // format string(such as %d, %n) can cause unexpected result.
90 // This is simple function to escape '%'.
91 // NOTE: Is there any gorgeous way instead of this?
92 std::string Escape(const std::string& str) const {
93 std::string escaped = std::string(str);
95 std::string from = "%";
96 std::string to = "%%";
97 while ((start_pos = escaped.find(from, start_pos)) != std::string::npos) {
98 escaped.replace(start_pos, from.length(), to);
99 start_pos += to.length();
107 // Do not call this function at destructor of global object
108 static LogCore& GetCore() {
113 void AddLogBackend(std::shared_ptr<ILogBackend> backend) {
114 backend_list_.emplace_back(backend);
117 void Log(LogLevel level, const std::string& tag, const std::string& log) {
118 for (auto backend : backend_list_)
119 backend->WriteLog(level, tag, log);
124 // add default dlog backend
125 AddLogBackend(std::shared_ptr<ILogBackend>(new DLogBackend()));
127 ~LogCore() = default;
128 LogCore(const LogCore&) = delete;
129 LogCore& operator=(const LogCore&) = delete;
131 std::vector<std::shared_ptr<ILogBackend>> backend_list_;
136 LogCatcher(LogLevel level, const char* tag)
137 : level_(level), tag_(tag) { }
139 void operator&(const StringStream<char>& str) const {
140 LogCore::GetCore().Log(level_, tag_, str.str());
151 inline static const constexpr char* __tag_for_logging() {
155 inline static const constexpr char* __tag_for_project() {
159 // To be defined in class namespace if user want different log tag for given
161 #define SCOPE_LOG_TAG(TAG) \
162 inline static const constexpr char* __tag_for_logging() { \
166 // Simple logging macro of following usage:
167 // LOG(LEVEL) << object_1 << object_2 << object_n;
169 // LEVEL = ERROR | WARNING | INFO | DEBUG
171 ::utils::LogCatcher( \
172 ::utils::LogLevel::LOG_ ## LEVEL, __tag_for_project()) \
173 & ::utils::StringStream<char>() \
174 << std::string(::utils::LogTag<::utils::LogLevel::LOG_ ## LEVEL>::value) \
175 << " " << std::setw(25) << std::left << __tag_for_logging() \
176 << " : " << std::setw(36) \
177 << (std::string(__FILENAME__) + ":" + std::to_string(__LINE__)).c_str() \
178 << std::setw(0) << " : " \
180 #endif // LOGGING_HH_