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