Fix build error
[platform/core/appfw/pkgmgr-info.git] / src / logging.hh
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.
4
5 #ifndef LOGGING_H_
6 #define LOGGING_H_
7
8 #include <dlog.h>
9
10 #ifndef PROJECT_TAG
11 #define PROJECT_TAG ""
12 #endif
13
14 #ifdef LOG
15 #undef LOG
16 #endif
17
18 #include <cassert>
19 #include <climits>
20 #include <cstdio>
21 #include <cstring>
22 #include <iomanip>
23 #include <iostream>
24 #include <memory>
25 #include <sstream>
26 #include <string>
27 #include <vector>
28
29 #ifndef __FILENAME__
30 #define __FILENAME__                                                           \
31     (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
32 #endif
33
34 namespace utils {
35
36 enum class LogLevel {
37   LOG_ERROR,
38   LOG_WARNING,
39   LOG_INFO,
40   LOG_DEBUG,
41 };
42
43 log_priority LogLevelToPriority(LogLevel level);
44
45 template<LogLevel> struct LogTag;
46 template<> struct LogTag<LogLevel::LOG_ERROR> {
47   static constexpr const char* value = "\033[1;31m| ERROR   |\033[0m";
48 };
49 template<> struct LogTag<LogLevel::LOG_WARNING> {
50   static constexpr const char* value = "\033[1;33m| WARNING |\033[0m";
51 };
52 template<> struct LogTag<LogLevel::LOG_INFO>  {
53   static constexpr const char* value = "\033[1;32m| INFO    |\033[0m";
54 };
55 template<> struct LogTag<LogLevel::LOG_DEBUG> {
56   static constexpr const char* value = "\033[0m| DEBUG   |\033[0m";
57 };
58
59 template <class charT, class traits = std::char_traits<charT>>
60 class StringStream : private std::basic_ostringstream<charT, traits> {
61  public:
62   using std::basic_ostringstream<charT, traits>::str;
63
64   template <class T>
65   StringStream&  operator<<(const T& value) {
66     static_cast<std::basic_ostringstream<charT, traits> &>(*this) << value;
67     return *this;
68   }
69 };
70
71 // Interface class for logging backends. The custom LogBackend which wants
72 // log using LOG() macro should be implement following interface.
73 class ILogBackend {
74  public:
75   virtual void WriteLog(LogLevel level, const std::string& tag,
76       const std::string& logstr) = 0;
77 };
78
79 class DLogBackend : public ILogBackend {
80  public:
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());
85
86     if (level == LogLevel::LOG_ERROR)
87       std::cerr << logstr << std::endl;
88   }
89
90  private:
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);
97     size_t start_pos = 0;
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();
103     }
104     return escaped;
105   }
106 };
107
108 class LogCore {
109  public:
110   // Do not call this function at destructor of global object
111   static LogCore& GetCore() {
112     static LogCore core;
113     return core;
114   }
115
116   void AddLogBackend(std::shared_ptr<ILogBackend> backend) {
117     backend_list_.emplace_back(backend);
118   }
119
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);
123   }
124
125  private:
126   LogCore() {
127     // add default dlog backend
128     AddLogBackend(std::shared_ptr<ILogBackend>(new DLogBackend()));
129   }
130   ~LogCore() = default;
131   LogCore(const LogCore&) = delete;
132   LogCore& operator=(const LogCore&) = delete;
133
134   std::vector<std::shared_ptr<ILogBackend>> backend_list_;
135 };
136
137 class LogCatcher {
138  public:
139   LogCatcher(LogLevel level, const char* tag)
140     : level_(level), tag_(tag) { }
141
142   void operator&(const StringStream<char>& str) const {
143     LogCore::GetCore().Log(level_, tag_, str.str());
144   }
145
146  private:
147   LogLevel level_;
148   std::string tag_;
149 };
150
151 }  // namespace utils
152
153
154 inline static const constexpr char* __tag_for_logging() {
155   return "";
156 }
157
158 inline static const constexpr char* __tag_for_project() {
159   return PROJECT_TAG;
160 }
161
162 // To be defined in class namespace if user want different log tag for given
163 // scope
164 #define SCOPE_LOG_TAG(TAG)                                                     \
165   inline static const constexpr char* __tag_for_logging() {                    \
166     return #TAG;                                                               \
167   }                                                                            \
168
169 // Simple logging macro of following usage:
170 //   LOG(LEVEL) << object_1 << object_2 << object_n;
171 //     where:
172 //       LEVEL = ERROR | WARNING | INFO | DEBUG
173 #define LOG(LEVEL)                                                             \
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) << " : "                                                 \
182
183 #endif  // MANIFEST_PARSER_UTILS_LOGGING_H_