xref: /aosp_15_r20/external/icing/icing/text_classifier/lib3/utils/base/logging.h (revision 8b6cd535a057e39b3b86660c4aa06c99747c2136)
1 // Copyright (C) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ICING_TEXT_CLASSIFIER_LIB3_UTILS_BASE_LOGGING_H_
16 #define ICING_TEXT_CLASSIFIER_LIB3_UTILS_BASE_LOGGING_H_
17 
18 #include <cassert>
19 #include <cstdint>
20 #include <string>
21 
22 #include "icing/text_classifier/lib3/utils/base/logging_levels.h"
23 #include "icing/text_classifier/lib3/utils/base/port.h"
24 
25 namespace libtextclassifier3 {
26 namespace logging {
27 
28 // A tiny code footprint string stream for assembling log messages.
29 struct LoggingStringStream {
LoggingStringStreamLoggingStringStream30   LoggingStringStream() {}
streamLoggingStringStream31   LoggingStringStream& stream() { return *this; }
32   // Needed for invocation in TC3_CHECK macro.
33   explicit operator bool() const { return true; }
34 
35   std::string message;
36 };
37 
38 template <typename T>
39 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
40                                        const T& entry) {
41   stream.message.append(std::to_string(entry));
42   return stream;
43 }
44 
45 template <typename T>
46 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
47                                        T* const entry) {
48   stream.message.append(
49       std::to_string(reinterpret_cast<const uint64_t>(entry)));
50   return stream;
51 }
52 
53 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
54                                        const char* message) {
55   stream.message.append(message);
56   return stream;
57 }
58 
59 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
60                                        const std::string& message) {
61   stream.message.append(message);
62   return stream;
63 }
64 
65 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
66                                        const std::string_view message) {
67   stream.message.append(message);
68   return stream;
69 }
70 
71 template <typename T1, typename T2>
72 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
73                                        const std::pair<T1, T2>& entry) {
74   stream << "(" << entry.first << ", " << entry.second << ")";
75   return stream;
76 }
77 
78 // The class that does all the work behind our TC3_LOG(severity) macros.  Each
79 // TC3_LOG(severity) << obj1 << obj2 << ...; logging statement creates a
80 // LogMessage temporary object containing a stringstream.  Each operator<< adds
81 // info to that stringstream and the LogMessage destructor performs the actual
82 // logging.  The reason this works is that in C++, "all temporary objects are
83 // destroyed as the last step in evaluating the full-expression that (lexically)
84 // contains the point where they were created."  For more info, see
85 // http://en.cppreference.com/w/cpp/language/lifetime.  Hence, the destructor is
86 // invoked after the last << from that logging statement.
87 class LogMessage {
88  public:
89   LogMessage(LogSeverity severity, const char* file_name,
90              int line_number) TC3_ATTRIBUTE_NOINLINE;
91 
92   ~LogMessage() TC3_ATTRIBUTE_NOINLINE;
93 
94   // Returns the stream associated with the logger object.
stream()95   LoggingStringStream& stream() { return stream_; }
96 
97  private:
98   const LogSeverity severity_;
99 
100   // Stream that "prints" all info into a string (not to a file).  We construct
101   // here the entire logging message and next print it in one operation.
102   LoggingStringStream stream_;
103 };
104 
105 // Pseudo-stream that "eats" the tokens <<-pumped into it, without printing
106 // anything.
107 class NullStream {
108  public:
NullStream()109   NullStream() {}
stream()110   NullStream& stream() { return *this; }
111 };
112 template <typename T>
113 inline NullStream& operator<<(NullStream& str, const T&) {
114   return str;
115 }
116 
117 }  // namespace logging
118 }  // namespace libtextclassifier3
119 
120 #define TC3_LOG(severity)                                          \
121   ::libtextclassifier3::logging::LogMessage(                       \
122       ::libtextclassifier3::logging::severity, __FILE__, __LINE__) \
123       .stream()
124 
125 // If condition x is true, does nothing.  Otherwise, crashes the program (like
126 // LOG(FATAL)) with an informative message.  Can be continued with extra
127 // messages, via <<, like any logging macro, e.g.,
128 //
129 // TC3_CHECK(my_cond) << "I think we hit a problem";
130 #define TC3_CHECK(x)                                                           \
131   (x) || TC3_LOG(FATAL) << __FILE__ << ":" << __LINE__ << ": check failed: \"" \
132                         << #x << "\" "
133 
134 #define TC3_CHECK_EQ(x, y) TC3_CHECK((x) == (y))
135 #define TC3_CHECK_LT(x, y) TC3_CHECK((x) < (y))
136 #define TC3_CHECK_GT(x, y) TC3_CHECK((x) > (y))
137 #define TC3_CHECK_LE(x, y) TC3_CHECK((x) <= (y))
138 #define TC3_CHECK_GE(x, y) TC3_CHECK((x) >= (y))
139 #define TC3_CHECK_NE(x, y) TC3_CHECK((x) != (y))
140 
141 #define TC3_NULLSTREAM ::libtextclassifier3::logging::NullStream().stream()
142 
143 // Debug checks: a TC3_DCHECK<suffix> macro should behave like TC3_CHECK<suffix>
144 // in debug mode an don't check / don't print anything in non-debug mode.
145 #if defined(NDEBUG) && !defined(TC3_DEBUG_LOGGING) && !defined(TC3_DEBUG_CHECKS)
146 
147 #define TC3_DCHECK(x) TC3_NULLSTREAM
148 #define TC3_DCHECK_EQ(x, y) TC3_NULLSTREAM
149 #define TC3_DCHECK_LT(x, y) TC3_NULLSTREAM
150 #define TC3_DCHECK_GT(x, y) TC3_NULLSTREAM
151 #define TC3_DCHECK_LE(x, y) TC3_NULLSTREAM
152 #define TC3_DCHECK_GE(x, y) TC3_NULLSTREAM
153 #define TC3_DCHECK_NE(x, y) TC3_NULLSTREAM
154 
155 #else  // NDEBUG
156 
157 // In debug mode, each TC3_DCHECK<suffix> is equivalent to TC3_CHECK<suffix>,
158 // i.e., a real check that crashes when the condition is not true.
159 #define TC3_DCHECK(x) TC3_CHECK(x)
160 #define TC3_DCHECK_EQ(x, y) TC3_CHECK_EQ(x, y)
161 #define TC3_DCHECK_LT(x, y) TC3_CHECK_LT(x, y)
162 #define TC3_DCHECK_GT(x, y) TC3_CHECK_GT(x, y)
163 #define TC3_DCHECK_LE(x, y) TC3_CHECK_LE(x, y)
164 #define TC3_DCHECK_GE(x, y) TC3_CHECK_GE(x, y)
165 #define TC3_DCHECK_NE(x, y) TC3_CHECK_NE(x, y)
166 
167 #endif  // NDEBUG
168 
169 #ifdef TC3_ENABLE_VLOG
170 #define TC3_VLOG(severity)                                     \
171   ::libtextclassifier3::logging::LogMessage(                   \
172       ::libtextclassifier3::logging::INFO, __FILE__, __LINE__) \
173       .stream()
174 #else
175 #define TC3_VLOG(severity) TC3_NULLSTREAM
176 #endif
177 
178 #endif  // ICING_TEXT_CLASSIFIER_LIB3_UTILS_BASE_LOGGING_H_
179