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