1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #ifndef MOZC_BASE_LOGGING_H_
31 #define MOZC_BASE_LOGGING_H_
32 
33 
34 #include <iostream>
35 #include <string>
36 
37 #include "base/flags.h"
38 #include "base/port.h"
39 
40 namespace mozc {
41 
42 enum LogSeverity {
43 #ifdef OS_ANDROID
44   // Defined in <android/log.h>
45   LOG_UNKNOWN = 0,  // ANDROID_LOG_UNKNOWN
46   LOG_DEFAULT = 1,  // ANDROID_LOG_DEFAULT
47   LOG_VERBOSE = 2,  // ANDROID_LOG_VERBOSE
48   LOG_DEBUG   = 3,  // ANDROID_LOG_DEBUG
49   LOG_INFO    = 4,  // ANDROID_LOG_INFO
50   LOG_WARNING = 5,  // ANDROID_LOG_WARN
51   LOG_ERROR   = 6,  // ANDROID_LOG_ERROR
52   LOG_FATAL   = 7,  // ANDROID_LOG_FATAL
53   LOG_SILENT  = 8,  // ANDROID_LOG_SILENT
54   LOG_SEVERITY_SIZE = 9,
55 #else
56   LOG_INFO    = 0,
57   LOG_WARNING = 1,
58   LOG_ERROR   = 2,
59   // Special hack for Windows build, where ERROR is defined as 0 in wingdi.h.
60 #ifdef OS_WIN
61   LOG_0       = LOG_ERROR,
62 #endif  // OS_WIN
63   LOG_FATAL   = 3,
64   LOG_SEVERITY_SIZE = 4,
65 #endif
66 };
67 
68 // DFATAL is FATAL in debug mode, ERROR in normal mode
69 #ifdef DEBUG
70 #define LOG_DFATAL LOG_FATAL
71 #else
72 #define LOG_DFATAL LOG_ERROR
73 #endif  // DEBUG
74 
75 class NullLogStream;
76 
77 class Logging {
78  public:
79   // Initializes log stream with the output file path and --logtostderr.
80   static void InitLogStream(const string &log_file_path);
81 
82   // Closes the logging stream
83   static void CloseLogStream();
84 
85   // Gets working log stream. The log message can be written to the stream.
86   // The stream must be finalized by FinalizeWorkingLogStream().
87   static std::ostream &GetWorkingLogStream();
88 
89   // Finalizes the working stream.
90   // - Appends std::endl to working stream.
91   // - Writes the content to real backing logging stream, which is initialized
92   //     by InitLogStream().
93   // - Deletes the working stream object.
94   static void FinalizeWorkingLogStream(LogSeverity, std::ostream*);
95 
96   // Gets NullLogStream for NO_LOGGING mode
97   static NullLogStream &GetNullLogStream();
98 
99   // Converts LogSeverity to the string name
100   static const char *GetLogSeverityName(LogSeverity severity);
101 
102   // Returns "YYYY-MM-DD HH:MM:SS PID TID", e.g. "2008 11-16 19:40:21 100 20"
103   static string GetLogMessageHeader();
104 
105   // Returns FLAGS_v
106   static int GetVerboseLevel();
107 
108   // Sets FLAGS_v
109   static void SetVerboseLevel(int verboselevel);
110 
111   // Sets Verbose Level for Config.
112   // Since Config dialog will overwrite -v option, we separate
113   // config_verbose_level and FLAGS_v.
114   // real_config_level = max(FLAGS_v, config_verbose_level);
115   static void SetConfigVerboseLevel(int verboselevel);
116 
117   // Gets an escape sequence to colorize log messages on tty devices.
118   static const char *GetBeginColorEscapeSequence(LogSeverity severity);
119   static const char *GetEndColorEscapeSequence();
120 
121  private:
122   DISALLOW_IMPLICIT_CONSTRUCTORS(Logging);
123 };
124 
125 // Finalizer to flush/delete working log stream.
126 // Finalizer takes woking log stream instance through operator&()
127 // and finalizes it in destructor.
128 class LogFinalizer {
129  public:
130   explicit LogFinalizer(LogSeverity severity);
131   ~LogFinalizer();
132 
133   // Google's C++ style guide requires reference argument to be const.
134   // Here we need non-const reference in order to delete working stream object.
135   void operator&(std::ostream&);
136 
137  private:
138   const LogSeverity severity_;
139   std::ostream *working_stream_;
140 };
141 
142 // When using NullLogStream, all debug message will be stripped
143 class NullLogStream {
144  public:
145   template <typename T>
146   NullLogStream& operator<<(const T &value) {
147     return *this;
148   }
149   NullLogStream& operator<<(std::ostream& (*pfunc)(std::ostream&) ) {
150     return *this;
151   }
152 };
153 
154 class NullLogFinalizer {
155  public:
NullLogFinalizer(LogSeverity severity)156   explicit NullLogFinalizer(LogSeverity severity)
157       : severity_(severity) {}
158 
~NullLogFinalizer()159   ~NullLogFinalizer() {
160     if (severity_ >= LOG_FATAL) {
161       OnFatal();
162     }
163   }
164 
165   void operator&(NullLogStream&) {}
166 
167  private:
168   static void OnFatal();
169 
170   const LogSeverity severity_;
171 };
172 
173 }  // namespace mozc
174 
175 // ad-hoc porting of google-glog
176 #ifdef NO_LOGGING   // don't use logging feature.
177 
178 // in release binary, we don't want to evaluate the outputs for logging.
179 // LOG(FATAL) is an exception.
180 #define LOG(severity) \
181   (mozc::LOG_##severity < mozc::LOG_FATAL) ? (void) 0 : \
182   mozc::NullLogFinalizer(mozc::LOG_##severity) & \
183   mozc::Logging::GetNullLogStream()
184 
185 // To suppress the "statement has no effect" waring, (void) is
186 // inserted.  This technique is suggested by the gcc manual
187 // -Wunused-variable section.
188 #define LOG_IF(severity, condition) \
189   (mozc::LOG_##severity < mozc::LOG_FATAL || !(condition)) ? (void) 0 : \
190   mozc::NullLogFinalizer(mozc::LOG_##severity) & \
191   mozc::Logging::GetNullLogStream()
192 
193 #define CHECK(condition) \
194   (condition) ? (void) 0 : \
195   mozc::NullLogFinalizer(mozc::LOG_FATAL) & mozc::Logging::GetNullLogStream()
196 
197 #else   // NO_LOGGING
198 
199 #define LOG(severity) \
200   mozc::LogFinalizer(mozc::LOG_##severity) & \
201   mozc::Logging::GetWorkingLogStream() \
202   << mozc::Logging::GetLogMessageHeader() << " " \
203   << __FILE__ << "(" << __LINE__ << ") " \
204   << mozc::Logging::GetBeginColorEscapeSequence(mozc::LOG_##severity) \
205   << "LOG(" << mozc::Logging::GetLogSeverityName(mozc::LOG_##severity) << ")" \
206   << mozc::Logging::GetEndColorEscapeSequence() << " " \
207 
208 #define LOG_IF(severity, condition) \
209   (!(condition)) ? (void) 0 : \
210   mozc::LogFinalizer(mozc::LOG_##severity) & \
211   mozc::Logging::GetWorkingLogStream() \
212   << mozc::Logging::GetLogMessageHeader() << " " \
213   << __FILE__ << "(" << __LINE__ << ") " \
214   << mozc::Logging::GetBeginColorEscapeSequence(mozc::LOG_##severity) \
215   << "LOG(" << mozc::Logging::GetLogSeverityName(mozc::LOG_##severity) << ")" \
216   << mozc::Logging::GetEndColorEscapeSequence() \
217   << " [" << #condition << "] "
218 
219 #define CHECK(condition) \
220   (condition) ? (void) 0 : \
221   mozc::LogFinalizer(mozc::LOG_FATAL) & \
222   mozc::Logging::GetWorkingLogStream() \
223   << mozc::Logging::GetLogMessageHeader() << " " \
224   << __FILE__ << "(" << __LINE__ << ") " \
225   << mozc::Logging::GetBeginColorEscapeSequence(mozc::LOG_FATAL) \
226   << "CHECK" \
227   << mozc::Logging::GetEndColorEscapeSequence() \
228   << " [" << #condition << "] "
229 #endif  // end NO_LOGGING
230 
231 #define VLOG_IS_ON(verboselevel) \
232 (mozc::Logging::GetVerboseLevel() >= verboselevel)
233 
234 #define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
235 
236 #define VLOG_IF(verboselevel, condition) \
237   LOG_IF(INFO, ((condition) && VLOG_IS_ON(verboselevel)))
238 
239 #define CHECK_EQ(a, b) CHECK((a) == (b))
240 #define CHECK_NE(a, b) CHECK((a) != (b))
241 #define CHECK_GE(a, b) CHECK((a) >= (b))
242 #define CHECK_LE(a, b) CHECK((a) <= (b))
243 #define CHECK_GT(a, b) CHECK((a) > (b))
244 #define CHECK_LT(a, b) CHECK((a) < (b))
245 
246 // Debug build
247 #if defined(DEBUG) || defined(_DEBUG)
248 
249 #define DLOG(severity) LOG(severity)
250 #define DLOG_IF(severity, condition) LOG_IF(severity, condition)
251 #define DCHECK(condition) CHECK(condition)
252 #define DCHECK_EQ(a, b) CHECK_EQ(a, b)
253 #define DCHECK_NE(a, b) CHECK_NE(a, b)
254 #define DCHECK_GE(a, b) CHECK_GE(a, b)
255 #define DCHECK_LE(a, b) CHECK_LE(a, b)
256 #define DCHECK_GT(a, b) CHECK_GT(a, b)
257 #define DCHECK_LT(a, b) CHECK_LT(a, b)
258 
259 #else   // opt build
260 
261 #define DLOG(severity) \
262   mozc::NullLogFinalizer(mozc::LOG_##severity) & \
263   mozc::Logging::GetNullLogStream()
264 
265 #define DLOG_IF(severity, condition) \
266   (true || !(condition)) ? (void) 0 : \
267   mozc::NullLogFinalizer(mozc::LOG_##severity)  \
268   & mozc::Logging::GetNullLogStream()
269 
270 #define DCHECK(condition) while (false) CHECK(condition)
271 #define DCHECK_EQ(a, b) while (false) CHECK_EQ(a, b)
272 #define DCHECK_NE(a, b) while (false) CHECK_NE(a, b)
273 #define DCHECK_GE(a, b) while (false) CHECK_GE(a, b)
274 #define DCHECK_LE(a, b) while (false) CHECK_LE(a, b)
275 #define DCHECK_GT(a, b) while (false) CHECK_GT(a, b)
276 #define DCHECK_LT(a, b) while (false) CHECK_LT(a, b)
277 
278 #endif  // DEBUG
279 
280 #define DVLOG(verboselevel) DLOG_IF(INFO, VLOG_IS_ON(verboselevel))
281 
282 DECLARE_bool(logtostderr);
283 
284 
285 #ifndef DVLOG_IF
286 #define DVLOG_IF(verboselevel, condition) \
287   DLOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))
288 #endif
289 
290 #endif  // MOZC_BASE_LOGGING_H_
291