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_OSP_LOGGING_H_ 6 #define UTIL_OSP_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 #define OSP_VLOG_IF(condition) !(condition) ? (void)0 : OSP_VLOG 74 #define OSP_LOG_IF(level, condition) !(condition) ? (void)0 : OSP_LOG_##level 75 76 #define OSP_CHECK(condition) \ 77 OSP_LOG_IF(FATAL, !(condition)) << "OSP_CHECK(" << #condition << ") failed: " 78 79 #define OSP_CHECK_EQ(a, b) \ 80 OSP_CHECK((a) == (b)) << (a) << " vs. " << (b) << ": " 81 #define OSP_CHECK_NE(a, b) \ 82 OSP_CHECK((a) != (b)) << (a) << " vs. " << (b) << ": " 83 #define OSP_CHECK_LT(a, b) OSP_CHECK((a) < (b)) << (a) << " vs. " << (b) << ": " 84 #define OSP_CHECK_LE(a, b) \ 85 OSP_CHECK((a) <= (b)) << (a) << " vs. " << (b) << ": " 86 #define OSP_CHECK_GT(a, b) OSP_CHECK((a) > (b)) << (a) << " vs. " << (b) << ": " 87 #define OSP_CHECK_GE(a, b) \ 88 OSP_CHECK((a) >= (b)) << (a) << " vs. " << (b) << ": " 89 90 #if defined(_DEBUG) || defined(DCHECK_ALWAYS_ON) 91 #define OSP_DCHECK_IS_ON() 1 92 #define OSP_DCHECK(condition) OSP_CHECK(condition) 93 #define OSP_DCHECK_EQ(a, b) OSP_CHECK_EQ(a, b) 94 #define OSP_DCHECK_NE(a, b) OSP_CHECK_NE(a, b) 95 #define OSP_DCHECK_LT(a, b) OSP_CHECK_LT(a, b) 96 #define OSP_DCHECK_LE(a, b) OSP_CHECK_LE(a, b) 97 #define OSP_DCHECK_GT(a, b) OSP_CHECK_GT(a, b) 98 #define OSP_DCHECK_GE(a, b) OSP_CHECK_GE(a, b) 99 #else 100 #define OSP_DCHECK_IS_ON() 0 101 // When DCHECKs are off, nothing will be logged. Use that fact to make 102 // references to the |condition| expression (or |a| and |b|) so the compiler 103 // won't emit unused variable warnings/errors when DCHECKs are turned off. 104 #define OSP_EAT_STREAM OSP_LOG_IF(FATAL, false) 105 #define OSP_DCHECK(condition) OSP_EAT_STREAM << !(condition) 106 #define OSP_DCHECK_EQ(a, b) OSP_EAT_STREAM << !((a) == (b)) 107 #define OSP_DCHECK_NE(a, b) OSP_EAT_STREAM << !((a) != (b)) 108 #define OSP_DCHECK_LT(a, b) OSP_EAT_STREAM << !((a) < (b)) 109 #define OSP_DCHECK_LE(a, b) OSP_EAT_STREAM << !((a) <= (b)) 110 #define OSP_DCHECK_GT(a, b) OSP_EAT_STREAM << !((a) > (b)) 111 #define OSP_DCHECK_GE(a, b) OSP_EAT_STREAM << !((a) >= (b)) 112 #endif 113 114 #define OSP_DVLOG OSP_VLOG_IF(OSP_DCHECK_IS_ON()) 115 #define OSP_DLOG_INFO OSP_LOG_IF(INFO, OSP_DCHECK_IS_ON()) 116 #define OSP_DLOG_WARN OSP_LOG_IF(WARN, OSP_DCHECK_IS_ON()) 117 #define OSP_DLOG_ERROR OSP_LOG_IF(ERROR, OSP_DCHECK_IS_ON()) 118 #define OSP_DLOG_FATAL OSP_LOG_IF(FATAL, OSP_DCHECK_IS_ON()) 119 #define OSP_DVLOG_IF(condition) OSP_VLOG_IF(OSP_DCHECK_IS_ON() && (condition)) 120 #define OSP_DLOG_IF(level, condition) \ 121 OSP_LOG_IF(level, OSP_DCHECK_IS_ON() && (condition)) 122 123 // Log when unimplemented code points are reached: If verbose logging is turned 124 // on, log always. Otherwise, just attempt to log once. 125 #define OSP_UNIMPLEMENTED() \ 126 if (OSP_LOG_IS_ON(kVerbose)) { \ 127 OSP_LOG_STREAM(kVerbose) << __func__ << ": UNIMPLEMENTED() hit."; \ 128 } else { \ 129 static bool needs_warning = true; \ 130 if (needs_warning) { \ 131 OSP_LOG_WARN << __func__ << ": UNIMPLEMENTED() hit."; \ 132 needs_warning = false; \ 133 } \ 134 } 135 136 // Since Break() is annotated as noreturn, this will properly signal to the 137 // compiler that this code is truly not reached (and thus doesn't need a return 138 // statement for non-void returning functions/methods). 139 #define OSP_NOTREACHED() \ 140 { \ 141 OSP_LOG_FATAL << __func__ << ": NOTREACHED() hit."; \ 142 Break(); \ 143 } 144 145 #endif // UTIL_OSP_LOGGING_H_ 146