1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef UTIL_LOGGING_H_
6 #define UTIL_LOGGING_H_
7 
8 #include <sstream>
9 #include <utility>
10 
11 #include "platform/api/logging.h"
12 
13 namespace openscreen {
14 namespace internal {
15 
16 // The stream-based logging macros below are adapted from Chromium's
17 // base/logging.h.
18 class LogMessage {
19  public:
LogMessage(LogLevel level,const char * file,int line)20   LogMessage(LogLevel level, const char* file, int line)
21       : level_(level), file_(file), line_(line) {}
22 
~LogMessage()23   ~LogMessage() {
24     LogWithLevel(level_, file_, line_, std::move(stream_));
25     if (level_ == LogLevel::kFatal) {
26       Break();
27     }
28   }
29 
stream()30   std::ostream& stream() { return stream_; }
31 
32  protected:
33   const LogLevel level_;
34 
35   // The file here comes from the __FILE__ macro, which should persist while
36   // we are doing the logging. Hence, keeping it unmanaged here and not
37   // creating a copy should be safe.
38   const char* const file_;
39   const int line_;
40   std::stringstream stream_;
41 };
42 
43 // Used by the OSP_LAZY_STREAM macro to return void after evaluating an ostream
44 // chain expression.
45 class Voidify {
46  public:
47   void operator&(std::ostream&) {}
48 };
49 
50 }  // namespace internal
51 }  // namespace openscreen
52 
53 #define OSP_LAZY_STREAM(condition, stream) \
54   !(condition) ? (void)0 : openscreen::internal::Voidify() & (stream)
55 #define OSP_LOG_IS_ON(level_enum) \
56   openscreen::IsLoggingOn(openscreen::LogLevel::level_enum, __FILE__)
57 #define OSP_LOG_STREAM(level_enum)                                             \
58   openscreen::internal::LogMessage(openscreen::LogLevel::level_enum, __FILE__, \
59                                    __LINE__)                                   \
60       .stream()
61 
62 #define OSP_VLOG \
63   OSP_LAZY_STREAM(OSP_LOG_IS_ON(kVerbose), OSP_LOG_STREAM(kVerbose))
64 #define OSP_LOG_INFO \
65   OSP_LAZY_STREAM(OSP_LOG_IS_ON(kInfo), OSP_LOG_STREAM(kInfo))
66 #define OSP_LOG_WARN \
67   OSP_LAZY_STREAM(OSP_LOG_IS_ON(kWarning), OSP_LOG_STREAM(kWarning))
68 #define OSP_LOG_ERROR \
69   OSP_LAZY_STREAM(OSP_LOG_IS_ON(kError), OSP_LOG_STREAM(kError))
70 #define OSP_LOG_FATAL \
71   OSP_LAZY_STREAM(OSP_LOG_IS_ON(kFatal), OSP_LOG_STREAM(kFatal))
72 
73 // TODO(miu): Remove this legacy alias.
74 #define OSP_LOG OSP_LOG_INFO
75 
76 #define OSP_VLOG_IF(condition) !(condition) ? (void)0 : OSP_VLOG
77 #define OSP_LOG_IF(level, condition) !(condition) ? (void)0 : OSP_LOG_##level
78 
79 // TODO(btolsch): Add tests for (D)OSP_CHECK and possibly logging.
80 #define OSP_CHECK(condition) \
81   OSP_LOG_IF(FATAL, !(condition)) << "OSP_CHECK(" << #condition << ") failed: "
82 
83 #define OSP_CHECK_EQ(a, b) \
84   OSP_CHECK((a) == (b)) << (a) << " vs. " << (b) << ": "
85 #define OSP_CHECK_NE(a, b) \
86   OSP_CHECK((a) != (b)) << (a) << " vs. " << (b) << ": "
87 #define OSP_CHECK_LT(a, b) OSP_CHECK((a) < (b)) << (a) << " vs. " << (b) << ": "
88 #define OSP_CHECK_LE(a, b) \
89   OSP_CHECK((a) <= (b)) << (a) << " vs. " << (b) << ": "
90 #define OSP_CHECK_GT(a, b) OSP_CHECK((a) > (b)) << (a) << " vs. " << (b) << ": "
91 #define OSP_CHECK_GE(a, b) \
92   OSP_CHECK((a) >= (b)) << (a) << " vs. " << (b) << ": "
93 
94 #if defined(_DEBUG) || defined(DCHECK_ALWAYS_ON)
95 #define OSP_DCHECK_IS_ON() 1
96 #define OSP_DCHECK(condition) OSP_CHECK(condition)
97 #define OSP_DCHECK_EQ(a, b) OSP_CHECK_EQ(a, b)
98 #define OSP_DCHECK_NE(a, b) OSP_CHECK_NE(a, b)
99 #define OSP_DCHECK_LT(a, b) OSP_CHECK_LT(a, b)
100 #define OSP_DCHECK_LE(a, b) OSP_CHECK_LE(a, b)
101 #define OSP_DCHECK_GT(a, b) OSP_CHECK_GT(a, b)
102 #define OSP_DCHECK_GE(a, b) OSP_CHECK_GE(a, b)
103 #else
104 #define OSP_DCHECK_IS_ON() 0
105 // When DCHECKs are off, nothing will be logged. Use that fact to make
106 // references to the |condition| expression (or |a| and |b|) so the compiler
107 // won't emit unused variable warnings/errors when DCHECKs are turned off.
108 #define OSP_EAT_STREAM OSP_LOG_IF(FATAL, false)
109 #define OSP_DCHECK(condition) OSP_EAT_STREAM << !(condition)
110 #define OSP_DCHECK_EQ(a, b) OSP_EAT_STREAM << !((a) == (b))
111 #define OSP_DCHECK_NE(a, b) OSP_EAT_STREAM << !((a) != (b))
112 #define OSP_DCHECK_LT(a, b) OSP_EAT_STREAM << !((a) < (b))
113 #define OSP_DCHECK_LE(a, b) OSP_EAT_STREAM << !((a) <= (b))
114 #define OSP_DCHECK_GT(a, b) OSP_EAT_STREAM << !((a) > (b))
115 #define OSP_DCHECK_GE(a, b) OSP_EAT_STREAM << !((a) >= (b))
116 #endif
117 
118 #define OSP_DVLOG OSP_VLOG_IF(OSP_DCHECK_IS_ON())
119 #define OSP_DLOG_INFO OSP_LOG_IF(INFO, OSP_DCHECK_IS_ON())
120 #define OSP_DLOG_WARN OSP_LOG_IF(WARN, OSP_DCHECK_IS_ON())
121 #define OSP_DLOG_ERROR OSP_LOG_IF(ERROR, OSP_DCHECK_IS_ON())
122 #define OSP_DLOG_FATAL OSP_LOG_IF(FATAL, OSP_DCHECK_IS_ON())
123 #define OSP_DVLOG_IF(condition) OSP_VLOG_IF(OSP_DCHECK_IS_ON() && (condition))
124 #define OSP_DLOG_IF(level, condition) \
125   OSP_LOG_IF(level, OSP_DCHECK_IS_ON() && (condition))
126 
127 // Log when unimplemented code points are reached: If verbose logging is turned
128 // on, log always. Otherwise, just attempt to log once.
129 #define OSP_UNIMPLEMENTED()                                           \
130   if (OSP_LOG_IS_ON(kVerbose)) {                                      \
131     OSP_LOG_STREAM(kVerbose) << __func__ << ": UNIMPLEMENTED() hit."; \
132   } else {                                                            \
133     static bool needs_warning = true;                                 \
134     if (needs_warning) {                                              \
135       OSP_LOG_WARN << __func__ << ": UNIMPLEMENTED() hit.";           \
136       needs_warning = false;                                          \
137     }                                                                 \
138   }
139 
140 #define OSP_NOTREACHED() OSP_LOG_FATAL << __func__ << ": NOTREACHED() hit."
141 
142 #endif  // UTIL_LOGGING_H_
143