Release version 0.28.2
[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 <class charT, class traits = std::char_traits<charT>>
42 class StringStream : private std::basic_ostringstream<charT, traits> {
43  public:
44   using std::basic_ostringstream<charT, traits>::str;
45
46   template <class T>
47   StringStream&  operator<<(const T& value) {
48     static_cast<std::basic_ostringstream<charT, traits> &>(*this) << value;
49     return *this;
50   }
51 };
52
53 class LogCatcher {
54  public:
55   LogCatcher(LogLevel level, const char* tag)
56     : level_(level), tag_(tag) { }
57
58   void operator&(const StringStream<char>& str) const {
59     dlog_print(LogLevelToPriority(level_), tag_.c_str(), "%s",
60         Escape(str.str()).c_str());
61   }
62
63  private:
64   // Since LogCatcher passes input to dlog_print(), the input which contains
65   // format string(such as %d, %n) can cause unexpected result.
66   // This is simple function to escape '%'.
67   // NOTE: Is there any gorgeous way instead of this?
68   std::string Escape(const std::string& str) const {
69     std::string escaped = std::string(str);
70     size_t start_pos = 0;
71     std::string from = "%";
72     std::string to = "%%";
73     while ((start_pos = escaped.find(from, start_pos)) != std::string::npos) {
74       escaped.replace(start_pos, from.length(), to);
75       start_pos += to.length();
76     }
77     return escaped;
78   }
79   LogLevel level_;
80   std::string tag_;
81 };
82
83 }  // namespace utils
84
85 inline static const constexpr char* __tag_for_project() {
86   return PROJECT_TAG;
87 }
88
89 // Simple logging macro of following usage:
90 //   LOG(LEVEL) << object_1 << object_2 << object_n;
91 //     where:
92 //       LEVEL = ERROR | WARNING | INFO | DEBUG
93 #define LOG(LEVEL)                                                             \
94     ::utils::LogCatcher(                                                       \
95       ::utils::LogLevel::LOG_ ## LEVEL, __tag_for_project())                   \
96       & ::utils::StringStream<char>()                                          \
97       << std::setw(50) << std::right                                           \
98       << (std::string(__FILENAME__) + ": " + std::string(__FUNCTION__) + "(" + \
99           std::to_string(__LINE__) + ")").c_str()                              \
100       << std::setw(0) << " : "                                                 \
101
102 #endif  // LOGGING_HH_