OLD | NEW |
| (Empty) |
1 // Copyright 2006-2009 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 | |
16 #ifndef OMAHA_COMMON_LOGGING_LOGGING_H__ | |
17 #define OMAHA_COMMON_LOGGING_LOGGING_H__ | |
18 | |
19 #include <string> | |
20 #include <cstring> | |
21 #include <strstream> | |
22 #include <tchar.h> | |
23 | |
24 #include "base/basictypes.h" | |
25 #include "base/scoped_ptr.h" | |
26 | |
27 // This file provides logging facility for Windows client apps. | |
28 // | |
29 // Optional message capabilities | |
30 // ----------------------------- | |
31 // Assertion failed messages and fatal errors are displayed in a dialog box | |
32 // before the application exits. However, running this UI creates a message | |
33 // loop, which causes application messages to be processed and potentially | |
34 // dispatched to existing application windows. Since the application is in a | |
35 // bad state when this assertion dialog is displayed, these messages may not | |
36 // get processed and hang the dialog, or the application might go crazy. | |
37 // | |
38 // Therefore, it can be beneficial to display the error dialog in a separate | |
39 // process from the main application. When the logging system needs to display | |
40 // a fatal error dialog box, it will look for a program called | |
41 // "DebugMessage.exe" in the same directory as the application executable. It | |
42 // will run this application with the message as the command line, and will | |
43 // not include the name of the application as is traditional for easier | |
44 // parsing. | |
45 // | |
46 // The code for DebugMessage.exe is only one line. In WinMain, do: | |
47 // MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0); | |
48 // | |
49 // If DebugMessage.exe is not found, the logging code will use a normal | |
50 // MessageBox, potentially causing the problems discussed above. | |
51 | |
52 | |
53 // Instructions | |
54 // ------------ | |
55 // | |
56 // Make a bunch of macros for logging. The way to log things is to stream | |
57 // things to LOG(<a particular severity level>). E.g., | |
58 // | |
59 // LOG(INFO) << "Found " << num_cookies << " cookies"; | |
60 // | |
61 // You can also do conditional logging: | |
62 // | |
63 // LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; | |
64 // | |
65 // The above will cause log messages to be output on the 1st, 11th, 21st, ... | |
66 // times it is executed. Note that the special COUNTER value is used to | |
67 // identify which repetition is happening. | |
68 // | |
69 // The CHECK(condition) macro is active in both debug and release builds and | |
70 // effectively performs a LOG(FATAL) which terminates the process and | |
71 // generates a crashdump unless a debugger is attached. | |
72 // | |
73 // There are also "debug mode" logging macros like the ones above: | |
74 // | |
75 // DLOG(INFO) << "Found cookies"; | |
76 // | |
77 // DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; | |
78 // | |
79 // All "debug mode" logging is compiled away to nothing for non-debug mode | |
80 // compiles. LOG_IF and development flags also work well together | |
81 // because the code can be compiled away sometimes. | |
82 // | |
83 // We also have | |
84 // | |
85 // LOG_ASSERT(assertion); | |
86 // DLOG_ASSERT(assertion); | |
87 // | |
88 // which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; | |
89 // | |
90 // We also override the standard 'assert' to use 'DLOG_ASSERT'. | |
91 // | |
92 // The supported severity levels for macros that allow you to specify one | |
93 // are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. | |
94 // | |
95 // There is also the special severity of DFATAL, which logs FATAL in | |
96 // debug mode, ERROR in normal mode. | |
97 // | |
98 // Very important: logging a message at the FATAL severity level causes | |
99 // the program to terminate (after the message is logged). | |
100 | |
101 namespace logging { | |
102 | |
103 // Where to record logging output? A flat file and/or system debug log via | |
104 // OutputDebugString. Defaults to LOG_ONLY_TO_FILE. | |
105 enum LoggingDestination { LOG_ONLY_TO_FILE, | |
106 LOG_ONLY_TO_SYSTEM_DEBUG_LOG, | |
107 LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG }; | |
108 | |
109 // Indicates that the log file should be locked when being written to. | |
110 // Often, there is no locking, which is fine for a single threaded program. | |
111 // If logging is being done from multiple threads or there can be more than | |
112 // one process doing the logging, the file should be locked during writes to | |
113 // make each log outut atomic. Other writers will block. | |
114 // | |
115 // All processes writing to the log file must have their locking set for it to | |
116 // work properly. Defaults to DONT_LOCK_LOG_FILE. | |
117 enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE }; | |
118 | |
119 // On startup, should we delete or append to an existing log file (if any)? | |
120 // Defaults to APPEND_TO_OLD_LOG_FILE. | |
121 enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE }; | |
122 | |
123 // Sets the log file name and other global logging state. Calling this function | |
124 // is recommended, and is normally done at the beginning of application init. | |
125 // If you don't call it, all the flags will be initialized to their default | |
126 // values, and there is a race condition that may leak a critical section | |
127 // object if two threads try to do the first log at the same time. | |
128 // See the definition of the enums above for descriptions and default values. | |
129 // | |
130 // The default log file is initialized to "debug.log" in the application | |
131 // directory. You probably don't want this, especially since the program | |
132 // directory may not be writable on an enduser's system. | |
133 void InitLogging(const TCHAR* log_file, LoggingDestination logging_dest, | |
134 LogLockingState lock_log, OldFileDeletionState delete_old); | |
135 | |
136 // Sets the log level. Anything at or above this level will be written to the | |
137 // log file/displayed to the user (if applicable). Anything below this level | |
138 // will be silently ignored. The log level defaults to 0 (everything is logged) | |
139 // if this function is not called. | |
140 void SetMinLogLevel(int level); | |
141 | |
142 // Sets the common items you want to be prepended to each log message. | |
143 // process and thread IDs default to off, the timestamp defaults to on. | |
144 // If this function is not called, logging defaults to writing the timestamp | |
145 // only. | |
146 void SetLogItems(bool enable_process_id, bool enable_thread_id, | |
147 bool enable_timestamp, bool enable_tickcount); | |
148 | |
149 // Sets the Log Assert Handler that will be used to notify of check failures. | |
150 // The default handler shows a dialog box, however clients can use this | |
151 // function to override with their own handling (e.g. a silent one for Unit | |
152 // Tests) | |
153 typedef void (*LogAssertHandlerFunction)(const std::string& str); | |
154 void SetLogAssertHandler(LogAssertHandlerFunction handler); | |
155 | |
156 typedef int LogSeverity; | |
157 const LogSeverity LOG_INFO = 0; | |
158 const LogSeverity LOG_WARNING = 1; | |
159 const LogSeverity LOG_ERROR = 2; | |
160 const LogSeverity LOG_FATAL = 3; | |
161 const LogSeverity LOG_NUM_SEVERITIES = 4; | |
162 | |
163 // LOG_DFATAL_LEVEL is LOG_FATAL in debug mode, ERROR in normal mode | |
164 #ifdef NDEBUG | |
165 const LogSeverity LOG_DFATAL_LEVEL = LOG_ERROR; | |
166 #else | |
167 const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL; | |
168 #endif | |
169 | |
170 // A few definitions of macros that don't generate much code. These are used | |
171 // by LOG() and LOG_IF, etc. Since these are used all over our code, it's | |
172 // better to have compact code for these operations. | |
173 #define COMPACT_GOOGLE_LOG_INFO \ | |
174 logging::LogMessage(__FILE__, __LINE__) | |
175 #define COMPACT_GOOGLE_LOG_WARNING \ | |
176 logging::LogMessage(__FILE__, __LINE__, logging::LOG_WARNING) | |
177 #define COMPACT_GOOGLE_LOG_ERROR \ | |
178 logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR) | |
179 #define COMPACT_GOOGLE_LOG_FATAL \ | |
180 logging::LogMessage(__FILE__, __LINE__, logging::LOG_FATAL) | |
181 #define COMPACT_GOOGLE_LOG_DFATAL \ | |
182 logging::LogMessage(__FILE__, __LINE__, logging::LOG_DFATAL_LEVEL) | |
183 | |
184 // wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets | |
185 // substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us | |
186 // to keep using this syntax, we define this macro to do the same thing | |
187 // as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that | |
188 // the Windows SDK does for consistency. | |
189 #define ERROR 0 | |
190 #define COMPACT_GOOGLE_LOG_0 \ | |
191 logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR) | |
192 | |
193 // We use the preprocessor's merging operator, "##", so that, e.g., | |
194 // LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny | |
195 // subtle difference between ostream member streaming functions (e.g., | |
196 // ostream::operator<<(int) and ostream non-member streaming functions | |
197 // (e.g., ::operator<<(ostream&, string&): it turns out that it's | |
198 // impossible to stream something like a string directly to an unnamed | |
199 // ostream. We employ a neat hack by calling the stream() member | |
200 // function of LogMessage which seems to avoid the problem. | |
201 | |
202 #define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() | |
203 #define SYSLOG(severity) LOG(severity) | |
204 | |
205 #define LOG_IF(severity, condition) \ | |
206 !(condition) ? (void) 0 : logging::LogMessageVoidify() & LOG(severity) | |
207 #define SYSLOG_IF(severity, condition) LOG_IF(severity, condition) | |
208 | |
209 #define LOG_ASSERT(condition) \ | |
210 LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " | |
211 #define SYSLOG_ASSERT(condition) \ | |
212 SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " | |
213 | |
214 // CHECK dies with a fatal error if condition is not true. It is *not* | |
215 // controlled by NDEBUG, so the check will be executed regardless of | |
216 // compilation mode. | |
217 #define CHECK(condition) \ | |
218 LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". " | |
219 | |
220 // A container for a string pointer which can be evaluated to a bool - | |
221 // true iff the pointer is NULL. | |
222 struct CheckOpString { | |
223 CheckOpString(std::string* str) : str_(str) { } | |
224 // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), | |
225 // so there's no point in cleaning up str_. | |
226 operator bool() const { return str_ != NULL; } | |
227 std::string* str_; | |
228 }; | |
229 | |
230 // Build the error message string. This is separate from the "Impl" | |
231 // function template because it is not performance critical and so can | |
232 // be out of line, while the "Impl" code should be inline. | |
233 template<class t1, class t2> | |
234 std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) { | |
235 std::ostrstream ss; | |
236 ss << names << " (" << v1 << " vs. " << v2 << ")"; | |
237 return new std::string(ss.str(), ss.pcount()); | |
238 } | |
239 | |
240 extern std::string* MakeCheckOpStringIntInt(int v1, int v2, const char* names); | |
241 | |
242 template<int, int> | |
243 std::string* MakeCheckOpString(const int& v1, const int& v2, const char* names)
{ | |
244 return MakeCheckOpStringIntInt(v1, v2, names); | |
245 } | |
246 | |
247 // Plus some debug-logging macros that get compiled to nothing for production | |
248 // | |
249 // DEBUG_MODE is for uses like | |
250 // if (DEBUG_MODE) foo.CheckThatFoo(); | |
251 // instead of | |
252 // #ifndef NDEBUG | |
253 // foo.CheckThatFoo(); | |
254 // #endif | |
255 | |
256 #ifndef NDEBUG | |
257 | |
258 #define DLOG(severity) LOG(severity) | |
259 #define DLOG_IF(severity, condition) LOG_IF(severity, condition) | |
260 #define DLOG_ASSERT(condition) LOG_ASSERT(condition) | |
261 | |
262 // debug-only checking. not executed in NDEBUG mode. | |
263 enum { DEBUG_MODE = 1 }; | |
264 #define DCHECK(condition) \ | |
265 LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". " | |
266 | |
267 // Helper functions for DCHECK_OP macro. | |
268 // The (int, int) specialization works around the issue that the compiler | |
269 // will not instantiate the template version of the function on values of | |
270 // unnamed enum type - see comment below. | |
271 #define DEFINE_DCHECK_OP_IMPL(name, op) \ | |
272 template <class t1, class t2> \ | |
273 inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ | |
274 const char* names) { \ | |
275 if (v1 op v2) return NULL; \ | |
276 else return MakeCheckOpString(v1, v2, names); \ | |
277 } \ | |
278 inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ | |
279 if (v1 op v2) return NULL; \ | |
280 else return MakeCheckOpString(v1, v2, names); \ | |
281 } | |
282 DEFINE_DCHECK_OP_IMPL(EQ, ==) | |
283 DEFINE_DCHECK_OP_IMPL(NE, !=) | |
284 DEFINE_DCHECK_OP_IMPL(LE, <=) | |
285 DEFINE_DCHECK_OP_IMPL(LT, < ) | |
286 DEFINE_DCHECK_OP_IMPL(GE, >=) | |
287 DEFINE_DCHECK_OP_IMPL(GT, > ) | |
288 #undef DEFINE_DCHECK_OP_IMPL | |
289 | |
290 // Helper macro for binary operators. | |
291 // Don't use this macro directly in your code, use CHECK_EQ et al below. | |
292 #define DCHECK_OP(name, op, val1, val2) \ | |
293 while (logging::CheckOpString _result = \ | |
294 logging::Check##name##Impl((val1), (val2), #val1 " " #op " " #val2)) \ | |
295 logging::LogMessage(__FILE__, __LINE__, _result).stream() | |
296 | |
297 // Equality/Inequality checks - compare two values, and log a LOG_FATAL message | |
298 // including the two values when the result is not as expected. The values | |
299 // must have operator<<(ostream, ...) defined. | |
300 // | |
301 // You may append to the error message like so: | |
302 // CHECK_NE(1, 2) << ": The world must be ending!"; | |
303 // | |
304 // We are very careful to ensure that each argument is evaluated exactly | |
305 // once, and that anything which is legal to pass as a function argument is | |
306 // legal here. In particular, the arguments may be temporary expressions | |
307 // which will end up being destroyed at the end of the apparent statement, | |
308 // for example: | |
309 // CHECK_EQ(string("abc")[1], 'b'); | |
310 // | |
311 // WARNING: These don't compile correctly if one of the arguments is a pointer | |
312 // and the other is NULL. To work around this, simply static_cast NULL to the | |
313 // type of the desired pointer. | |
314 | |
315 #define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2) | |
316 #define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2) | |
317 #define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2) | |
318 #define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2) | |
319 #define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2) | |
320 #define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2) | |
321 | |
322 // Helper functions for string comparisons. | |
323 // To avoid bloat, the definitions are in logging.cc. | |
324 #define DECLARE_DCHECK_STROP_IMPL(func, expected) \ | |
325 std::string* Check##func##expected##Impl(const char* s1, \ | |
326 const char* s2, \ | |
327 const char* names); | |
328 DECLARE_DCHECK_STROP_IMPL(strcmp, true) | |
329 DECLARE_DCHECK_STROP_IMPL(strcmp, false) | |
330 DECLARE_DCHECK_STROP_IMPL(_stricmp, true) | |
331 DECLARE_DCHECK_STROP_IMPL(_stricmp, false) | |
332 #undef DECLARE_DCHECK_STROP_IMPL | |
333 | |
334 // Helper macro for string comparisons. | |
335 // Don't use this macro directly in your code, use CHECK_STREQ et al below. | |
336 #define DCHECK_STROP(func, op, expected, s1, s2) \ | |
337 while (CheckOpString _result = \ | |
338 logging::Check##func##expected##Impl((s1), (s2), \ | |
339 #s1 " " #op " " #s2)) \ | |
340 LOG(FATAL) << *_result.str_ | |
341 | |
342 // String (char*) equality/inequality checks. | |
343 // CASE versions are case-insensitive. | |
344 // | |
345 // Note that "s1" and "s2" may be temporary strings which are destroyed | |
346 // by the compiler at the end of the current "full expression" | |
347 // (e.g. DCHECK_STREQ(Foo().c_str(), Bar().c_str())). | |
348 | |
349 #define DCHECK_STREQ(s1, s2) DCHECK_STROP(strcmp, ==, true, s1, s2) | |
350 #define DCHECK_STRNE(s1, s2) DCHECK_STROP(strcmp, !=, false, s1, s2) | |
351 #define DCHECK_STRCASEEQ(s1, s2) DCHECK_STROP(_stricmp, ==, true, s1, s2) | |
352 #define DCHECK_STRCASENE(s1, s2) DCHECK_STROP(_stricmp, !=, false, s1, s2) | |
353 | |
354 #define DCHECK_INDEX(I,A) DCHECK(I < (sizeof(A)/sizeof(A[0]))) | |
355 #define DCHECK_BOUND(B,A) DCHECK(B <= (sizeof(A)/sizeof(A[0]))) | |
356 | |
357 #else // NDEBUG | |
358 | |
359 #define DLOG(severity) \ | |
360 true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity) | |
361 | |
362 #define DLOG_IF(severity, condition) \ | |
363 true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity) | |
364 | |
365 #define DLOG_ASSERT(condition) \ | |
366 true ? (void) 0 : LOG_ASSERT(condition) | |
367 | |
368 enum { DEBUG_MODE = 0 }; | |
369 | |
370 // This macro can be followed by a sequence of stream parameters in | |
371 // non-debug mode. The DCHECK and friends macros use this so that | |
372 // the expanded expression DCHECK(foo) << "asdf" is still syntactically | |
373 // valid, even though the expression will get optimized away. | |
374 #define NDEBUG_EAT_STREAM_PARAMETERS \ | |
375 logging::LogMessage(__FILE__, __LINE__).stream() | |
376 | |
377 #define DCHECK(condition) \ | |
378 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
379 | |
380 #define DCHECK_EQ(val1, val2) \ | |
381 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
382 | |
383 #define DCHECK_NE(val1, val2) \ | |
384 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
385 | |
386 #define DCHECK_LE(val1, val2) \ | |
387 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
388 | |
389 #define DCHECK_LT(val1, val2) \ | |
390 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
391 | |
392 #define DCHECK_GE(val1, val2) \ | |
393 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
394 | |
395 #define DCHECK_GT(val1, val2) \ | |
396 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
397 | |
398 #define DCHECK_STREQ(str1, str2) \ | |
399 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
400 | |
401 #define DCHECK_STRCASEEQ(str1, str2) \ | |
402 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
403 | |
404 #define DCHECK_STRNE(str1, str2) \ | |
405 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
406 | |
407 #define DCHECK_STRCASENE(str1, str2) \ | |
408 while (false) NDEBUG_EAT_STREAM_PARAMETERS | |
409 | |
410 #endif // NDEBUG | |
411 | |
412 #define NOTREACHED() DCHECK(false) | |
413 | |
414 // Redefine the standard assert to use our nice log files | |
415 #undef assert | |
416 #define assert(x) DLOG_ASSERT(x) | |
417 | |
418 // This class more or less represents a particular log message. You | |
419 // create an instance of LogMessage and then stream stuff to it. | |
420 // When you finish streaming to it, ~LogMessage is called and the | |
421 // full message gets streamed to the appropriate destination. | |
422 // | |
423 // You shouldn't actually use LogMessage's constructor to log things, | |
424 // though. You should use the LOG() macro (and variants thereof) | |
425 // above. | |
426 class LogMessage { | |
427 public: | |
428 LogMessage(const char* file, int line, LogSeverity severity, int ctr); | |
429 | |
430 // Two special constructors that generate reduced amounts of code at | |
431 // LOG call sites for common cases. | |
432 // | |
433 // Used for LOG(INFO): Implied are: | |
434 // severity = LOG_INFO, ctr = 0 | |
435 // | |
436 // Using this constructor instead of the more complex constructor above | |
437 // saves a couple of bytes per call site. | |
438 LogMessage(const char* file, int line); | |
439 | |
440 // Used for LOG(severity) where severity != INFO. Implied | |
441 // are: ctr = 0 | |
442 // | |
443 // Using this constructor instead of the more complex constructor above | |
444 // saves a couple of bytes per call site. | |
445 LogMessage(const char* file, int line, LogSeverity severity); | |
446 | |
447 // A special constructor used for check failures. | |
448 // Implied severity = LOG_FATAL | |
449 LogMessage(const char* file, int line, const CheckOpString& result); | |
450 | |
451 ~LogMessage(); | |
452 | |
453 std::ostream& stream() { return stream_; } | |
454 | |
455 private: | |
456 void Init(const char* file, int line); | |
457 | |
458 LogSeverity severity_; | |
459 std::ostrstream stream_; | |
460 | |
461 DISALLOW_EVIL_CONSTRUCTORS(LogMessage); | |
462 }; | |
463 | |
464 // A non-macro interface to the log facility; (useful | |
465 // when the logging level is not a compile-time constant). | |
466 inline void LogAtLevel(int const log_level, std::string const &msg) { | |
467 LogMessage(__FILE__, __LINE__, log_level).stream() << msg; | |
468 } | |
469 | |
470 // This class is used to explicitly ignore values in the conditional | |
471 // logging macros. This avoids compiler warnings like "value computed | |
472 // is not used" and "statement has no effect". | |
473 class LogMessageVoidify { | |
474 public: | |
475 LogMessageVoidify() { } | |
476 // This has to be an operator with a precedence lower than << but | |
477 // higher than ?: | |
478 void operator&(std::ostream&) { } | |
479 }; | |
480 | |
481 // Closes the log file explicitly if open. | |
482 // NOTE: Since the log file is opened as necessary by the action of logging | |
483 // statements, there's no guarantee that it will stay closed | |
484 // after this call. | |
485 void CloseLogFile(); | |
486 | |
487 } // namespace Logging | |
488 | |
489 // These functions are provided as a convenience for logging, which is where we | |
490 // use streams (it is against Google style to use streams in other places). It | |
491 // is designed to allow you to emit non-ASCII Unicode strings to the log file, | |
492 // which is normally ASCII. It is relatively slow, so try not to use it for | |
493 // common cases. Non-ASCII characters will be converted to UTF-8 by these operat
ors. | |
494 std::ostream& operator<<(std::ostream& out, const wchar_t* wstr); | |
495 inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) { | |
496 return out << wstr.c_str(); | |
497 } | |
498 | |
499 #endif // OMAHA_COMMON_LOGGING_LOGGING_H__ | |
OLD | NEW |