1 /* 2 * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com> 3 * 4 * SPDX-License-Identifier: LGPL-2.1-or-later 5 * 6 */ 7 #ifndef _FCITX_UTILS_LOG_H_ 8 #define _FCITX_UTILS_LOG_H_ 9 10 /// \addtogroup FcitxUtils 11 /// \{ 12 /// \file 13 /// \brief Log utilities. 14 15 #include <cstdlib> 16 #include <iostream> 17 #include <list> 18 #include <map> 19 #include <memory> 20 #include <set> 21 #include <string> 22 #include <tuple> 23 #include <type_traits> 24 #include <unordered_map> 25 #include <unordered_set> 26 #include <fcitx-utils/fs.h> 27 #include <fcitx-utils/key.h> 28 #include <fcitx-utils/metastring.h> 29 #include <fcitx-utils/misc.h> 30 #include <fcitx-utils/tuplehelpers.h> 31 #include "fcitxutils_export.h" 32 33 namespace fcitx { 34 35 /// \brief LogLevel from high to low. 36 enum LogLevel : int { 37 NoLog = 0, 38 /// Fatal will always abort regardless of log or not. 39 Fatal = 1, 40 Error = 2, 41 Warn = 3, 42 Info = 4, 43 Debug = 5, 44 LastLogLevel = Debug 45 }; 46 47 #define FCITX_SIMPLE_LOG(TYPE) \ 48 inline LogMessageBuilder &operator<<(TYPE v) { \ 49 out_ << v; \ 50 return *this; \ 51 } 52 53 class LogCategoryPrivate; 54 class FCITXUTILS_EXPORT LogCategory { 55 public: 56 LogCategory(const char *name, LogLevel level = LogLevel::Info); 57 ~LogCategory(); 58 59 LogLevel logLevel() const; 60 bool checkLogLevel(LogLevel l) const; 61 void setLogLevel(LogLevel l); 62 void setLogLevel(std::underlying_type_t<LogLevel> l); 63 void resetLogLevel(); 64 const std::string &name() const; 65 66 // Helper function 67 bool fatalWrapper(LogLevel l) const; 68 static bool fatalWrapper2(LogLevel l); 69 70 private: 71 FCITX_DECLARE_PRIVATE(LogCategory); 72 std::unique_ptr<LogCategoryPrivate> d_ptr; 73 }; 74 75 class FCITXUTILS_EXPORT Log { 76 public: 77 static const LogCategory &defaultCategory(); 78 static void setLogRule(const std::string &rule); 79 /** 80 * @brief set the global log stream to be used by default. 81 * 82 * This function is not thread safe. 83 * Please ensure there is no other thread using it at the same time. 84 * By default is std::cerr. When you pass a stream into it, you need to 85 * ensure it out-live the last call to the function. You may reset it to 86 * std::cerr when you don't want to keep the old stream anymore. 87 * 88 * @param stream 89 * @since 5.0.6 90 */ 91 static void setLogStream(std::ostream &stream); 92 /** 93 * @brief Return the default log stream to be used. 94 * 95 * @return std::ostream& 96 * @since 5.0.6 97 */ 98 static std::ostream &logStream(); 99 }; 100 101 class FCITXUTILS_EXPORT LogMessageBuilder { 102 public: 103 LogMessageBuilder(std::ostream &out, LogLevel l, const char *filename, 104 int lineNumber); 105 ~LogMessageBuilder(); 106 self()107 LogMessageBuilder &self() { return *this; } 108 109 inline LogMessageBuilder &operator<<(const std::string &s) { 110 *this << s.c_str(); 111 return *this; 112 } 113 114 inline LogMessageBuilder &operator<<(const Key &key) { 115 out_ << "Key(" << key.toString() 116 << " states=" << key.states().toInteger() << ")"; 117 return *this; 118 } 119 120 FCITX_SIMPLE_LOG(char) 121 FCITX_SIMPLE_LOG(bool) 122 FCITX_SIMPLE_LOG(signed short) 123 FCITX_SIMPLE_LOG(unsigned short) 124 FCITX_SIMPLE_LOG(signed int) 125 FCITX_SIMPLE_LOG(unsigned int) 126 FCITX_SIMPLE_LOG(signed long) 127 FCITX_SIMPLE_LOG(unsigned long) 128 FCITX_SIMPLE_LOG(float) 129 FCITX_SIMPLE_LOG(double) 130 FCITX_SIMPLE_LOG(char *) 131 FCITX_SIMPLE_LOG(const char *) 132 FCITX_SIMPLE_LOG(const void *) 133 FCITX_SIMPLE_LOG(long double) 134 FCITX_SIMPLE_LOG(signed long long) 135 FCITX_SIMPLE_LOG(unsigned long long) 136 137 // For some random type, use ostream. 138 template <typename T> 139 FCITX_SIMPLE_LOG(T) 140 141 template <typename T> 142 inline LogMessageBuilder &operator<<(const std::unique_ptr<T> &ptr) { 143 *this << "unique_ptr(" << ptr.get() << ")"; 144 return *this; 145 } 146 147 template <typename T> 148 inline LogMessageBuilder &operator<<(const std::vector<T> &vec) { 149 *this << "["; 150 printRange(vec.begin(), vec.end()); 151 *this << "]"; 152 return *this; 153 } 154 155 template <typename T> 156 inline LogMessageBuilder &operator<<(const std::list<T> &lst) { 157 *this << "list["; 158 printRange(lst.begin(), lst.end()); 159 *this << "]"; 160 return *this; 161 } 162 163 template <typename K, typename V> 164 inline LogMessageBuilder &operator<<(const std::pair<K, V> &pair) { 165 *this << "(" << pair.first << ", " << pair.second << ")"; 166 return *this; 167 } 168 169 template <typename... Args> 170 inline LogMessageBuilder &operator<<(const std::tuple<Args...> &tuple) { 171 typename MakeSequence<sizeof...(Args)>::type a; 172 *this << "("; 173 printWithIndices(a, tuple); 174 *this << ")"; 175 return *this; 176 } 177 178 template <typename K, typename V> 179 inline LogMessageBuilder &operator<<(const std::unordered_map<K, V> &vec) { 180 *this << "{"; 181 printRange(vec.begin(), vec.end()); 182 *this << "}"; 183 return *this; 184 } 185 186 template <typename V> 187 inline LogMessageBuilder &operator<<(const std::unordered_set<V> &vec) { 188 *this << "{"; 189 printRange(vec.begin(), vec.end()); 190 *this << "}"; 191 return *this; 192 } 193 194 template <typename K, typename V> 195 inline LogMessageBuilder &operator<<(const std::map<K, V> &vec) { 196 *this << "{"; 197 printRange(vec.begin(), vec.end()); 198 *this << "}"; 199 return *this; 200 } 201 202 template <typename V> 203 inline LogMessageBuilder &operator<<(const std::set<V> &vec) { 204 *this << "{"; 205 printRange(vec.begin(), vec.end()); 206 *this << "}"; 207 return *this; 208 } 209 210 template <typename K, typename V> 211 inline LogMessageBuilder &operator<<(const std::multimap<K, V> &vec) { 212 *this << "{"; 213 printRange(vec.begin(), vec.end()); 214 *this << "}"; 215 return *this; 216 } 217 218 template <typename V> 219 inline LogMessageBuilder &operator<<(const std::multiset<V> &vec) { 220 *this << "{"; 221 printRange(vec.begin(), vec.end()); 222 *this << "}"; 223 return *this; 224 } 225 226 template <typename K, typename V> 227 inline LogMessageBuilder & 228 operator<<(const std::unordered_multimap<K, V> &vec) { 229 *this << "{"; 230 printRange(vec.begin(), vec.end()); 231 *this << "}"; 232 return *this; 233 } 234 235 template <typename V> 236 inline LogMessageBuilder & 237 operator<<(const std::unordered_multiset<V> &vec) { 238 *this << "{"; 239 printRange(vec.begin(), vec.end()); 240 *this << "}"; 241 return *this; 242 } 243 244 private: 245 template <typename Iterator> printRange(Iterator begin,Iterator end)246 void printRange(Iterator begin, Iterator end) { 247 bool first = true; 248 for (auto &item : MakeIterRange(begin, end)) { 249 if (first) { 250 first = false; 251 } else { 252 *this << ", "; 253 } 254 *this << item; 255 } 256 } 257 258 template <typename... Args, int... S> printWithIndices(Sequence<S...>,const std::tuple<Args...> & tuple)259 void printWithIndices(Sequence<S...>, const std::tuple<Args...> &tuple) { 260 using swallow = int[]; 261 (void)swallow{ 262 0, 263 (void(*this << (S == 0 ? "" : ", ") << std::get<S>(tuple)), 0)...}; 264 } 265 266 std::ostream &out_; 267 }; 268 } // namespace fcitx 269 270 #ifdef FCITX_USE_NO_METASTRING_FILENAME 271 #define FCITX_LOG_FILENAME_WRAP ::fcitx::fs::baseName(__FILE__).data() 272 #else 273 #define FCITX_LOG_FILENAME_WRAP \ 274 fcitx::MetaStringBasenameType<fcitxMakeMetaString(__FILE__)>::data() 275 #endif 276 277 #define FCITX_LOGC_IF(CATEGORY, LEVEL, CONDITION) \ 278 for (bool fcitxLogEnabled = \ 279 (CONDITION) && CATEGORY().fatalWrapper(::fcitx::LogLevel::LEVEL); \ 280 fcitxLogEnabled; \ 281 fcitxLogEnabled = CATEGORY().fatalWrapper2(::fcitx::LogLevel::LEVEL)) \ 282 ::fcitx::LogMessageBuilder(::fcitx::Log::logStream(), \ 283 ::fcitx::LogLevel::LEVEL, \ 284 FCITX_LOG_FILENAME_WRAP, __LINE__) \ 285 .self() 286 287 #define FCITX_LOGC(CATEGORY, LEVEL) \ 288 for (bool fcitxLogEnabled = \ 289 CATEGORY().fatalWrapper(::fcitx::LogLevel::LEVEL); \ 290 fcitxLogEnabled; \ 291 fcitxLogEnabled = CATEGORY().fatalWrapper2(::fcitx::LogLevel::LEVEL)) \ 292 ::fcitx::LogMessageBuilder(::fcitx::Log::logStream(), \ 293 ::fcitx::LogLevel::LEVEL, \ 294 FCITX_LOG_FILENAME_WRAP, __LINE__) \ 295 .self() 296 297 #define FCITX_LOG(LEVEL) FCITX_LOGC(::fcitx::Log::defaultCategory, LEVEL) 298 299 #define FCITX_DEBUG() FCITX_LOG(Debug) 300 #define FCITX_WARN() FCITX_LOG(Warn) 301 #define FCITX_INFO() FCITX_LOG(Info) 302 #define FCITX_ERROR() FCITX_LOG(Error) 303 #define FCITX_FATAL() FCITX_LOG(Fatal) 304 305 #define FCITX_LOG_IF(LEVEL, CONDITION) \ 306 FCITX_LOGC_IF(::fcitx::Log::defaultCategory, LEVEL, CONDITION) 307 308 #define FCITX_ASSERT(...) \ 309 FCITX_LOG_IF(Fatal, !(__VA_ARGS__)) << #__VA_ARGS__ << " failed." 310 311 #define FCITX_DEFINE_LOG_CATEGORY(name, ...) \ 312 const ::fcitx::LogCategory &name() { \ 313 static const ::fcitx::LogCategory category(__VA_ARGS__); \ 314 return category; \ 315 } 316 317 #define FCITX_DECLARE_LOG_CATEGORY(name) const ::fcitx::LogCategory &name() 318 319 #endif // _FCITX_UTILS_LOG_H_ 320