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