Fix to return errno
[platform/core/appfw/pkgmgr-info.git] / src / utils / 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_HH_
6 #define LOGGING_HH_
7
8 #include <dlog.h>
9
10 #ifndef PROJECT_TAG
11 #define PROJECT_TAG "PKGMGR_INFO"
12 #endif
13
14 #ifdef LOG
15 #undef LOG
16 #endif
17
18 #include <cassert>
19 #include <cstring>
20 #include <iomanip>
21 #include <iostream>
22 #include <sstream>
23 #include <string>
24
25 #ifndef __FILENAME__
26 #define __FILENAME__                                                           \
27     (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
28 #endif
29
30 namespace utils {
31
32 enum class LogLevel {
33   LOG_ERROR,
34   LOG_WARNING,
35   LOG_INFO,
36   LOG_DEBUG,
37 };
38
39 log_priority LogLevelToPriority(LogLevel level);
40
41 template<LogLevel> struct LogTag;
42 template<> struct LogTag<LogLevel::LOG_ERROR> {
43   static constexpr const char* value = "\033[1;31m| ERROR   |\033[0m";
44 };
45 template<> struct LogTag<LogLevel::LOG_WARNING> {
46   static constexpr const char* value = "\033[1;33m| WARNING |\033[0m";
47 };
48 template<> struct LogTag<LogLevel::LOG_INFO>  {
49   static constexpr const char* value = "\033[1;32m| INFO    |\033[0m";
50 };
51 template<> struct LogTag<LogLevel::LOG_DEBUG> {
52   static constexpr const char* value = "\033[0m| DEBUG   |\033[0m";
53 };
54
55 template <class charT, class traits = std::char_traits<charT>>
56 class StringStream : private std::basic_ostringstream<charT, traits> {
57  public:
58   using std::basic_ostringstream<charT, traits>::str;
59
60   template <class T>
61   StringStream&  operator<<(const T& value) {
62     static_cast<std::basic_ostringstream<charT, traits> &>(*this) << value;
63     return *this;
64   }
65 };
66
67 class LogCatcher {
68  public:
69   LogCatcher(LogLevel level, const char* tag)
70     : level_(level), tag_(tag) { }
71
72   void operator&(const StringStream<char>& str) const {
73     dlog_print(LogLevelToPriority(level_), tag_.c_str(), "%s",
74         Escape(str.str()).c_str());
75   }
76
77  private:
78   // Since LogCatcher passes input to dlog_print(), the input which contains
79   // format string(such as %d, %n) can cause unexpected result.
80   // This is simple function to escape '%'.
81   // NOTE: Is there any gorgeous way instead of this?
82   std::string Escape(const std::string& str) const {
83     std::string escaped = std::string(str);
84     size_t start_pos = 0;
85     std::string from = "%";
86     std::string to = "%%";
87     while ((start_pos = escaped.find(from, start_pos)) != std::string::npos) {
88       escaped.replace(start_pos, from.length(), to);
89       start_pos += to.length();
90     }
91     return escaped;
92   }
93   LogLevel level_;
94   std::string tag_;
95 };
96
97 }  // namespace utils
98
99 inline static const constexpr char* __tag_for_project() {
100   return PROJECT_TAG;
101 }
102
103 // Simple logging macro of following usage:
104 //   LOG(LEVEL) << object_1 << object_2 << object_n;
105 //     where:
106 //       LEVEL = ERROR | WARNING | INFO | DEBUG
107 #define LOG(LEVEL)                                                             \
108     ::utils::LogCatcher(                                                       \
109       ::utils::LogLevel::LOG_ ## LEVEL, __tag_for_project())                   \
110       & ::utils::StringStream<char>()                                          \
111       << std::string(::utils::LogTag<::utils::LogLevel::LOG_ ## LEVEL>::value) \
112       << " : " << std::setw(36)                                                \
113       << (std::string(__FILENAME__) + ":" + std::to_string(__LINE__)).c_str()  \
114       << std::setw(0) << " : "                                                 \
115
116 #endif  // LOGGING_HH_