blob: 9c478ce05981673fed0e1405741880379b56574b [file] [log] [blame]
Yuri Wiitalab7979032019-11-08 15:17:20 -08001// 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
Jordan Baylesa44d04a2020-05-06 16:59:39 -07005#ifndef UTIL_OSP_LOGGING_H_
6#define UTIL_OSP_LOGGING_H_
Yuri Wiitalab7979032019-11-08 15:17:20 -08007
8#include <sstream>
Yuri Wiitala75ea15d2019-12-03 16:01:48 -08009#include <utility>
Yuri Wiitalab7979032019-11-08 15:17:20 -080010
Yuri Wiitala0fda1ab2019-11-20 11:43:36 -080011#include "platform/api/logging.h"
12
Yuri Wiitalab7979032019-11-08 15:17:20 -080013namespace openscreen {
Yuri Wiitalab7979032019-11-08 15:17:20 -080014namespace internal {
15
16// The stream-based logging macros below are adapted from Chromium's
17// base/logging.h.
18class LogMessage {
19 public:
20 LogMessage(LogLevel level, const char* file, int line)
21 : level_(level), file_(file), line_(line) {}
22
23 ~LogMessage() {
Yuri Wiitala75ea15d2019-12-03 16:01:48 -080024 LogWithLevel(level_, file_, line_, std::move(stream_));
Yuri Wiitalab7979032019-11-08 15:17:20 -080025 if (level_ == LogLevel::kFatal) {
26 Break();
27 }
28 }
29
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_;
Yuri Wiitala75ea15d2019-12-03 16:01:48 -080040 std::stringstream stream_;
Yuri Wiitalab7979032019-11-08 15:17:20 -080041};
42
43// Used by the OSP_LAZY_STREAM macro to return void after evaluating an ostream
44// chain expression.
45class Voidify {
46 public:
47 void operator&(std::ostream&) {}
48};
49
50} // namespace internal
Yuri Wiitalab7979032019-11-08 15:17:20 -080051} // namespace openscreen
52
53#define OSP_LAZY_STREAM(condition, stream) \
Yuri Wiitala2b02e322019-12-03 16:59:40 -080054 !(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__) \
Yuri Wiitalab7979032019-11-08 15:17:20 -080060 .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
Yuri Wiitalab7979032019-11-08 15:17:20 -080073#define OSP_VLOG_IF(condition) !(condition) ? (void)0 : OSP_VLOG
74#define OSP_LOG_IF(level, condition) !(condition) ? (void)0 : OSP_LOG_##level
75
Yuri Wiitalab7979032019-11-08 15:17:20 -080076#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
Jordan Bayles759af7f2020-11-24 12:09:04 -0800136// 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 }
Yuri Wiitalab7979032019-11-08 15:17:20 -0800144
Jordan Baylesa44d04a2020-05-06 16:59:39 -0700145#endif // UTIL_OSP_LOGGING_H_