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