• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
20 
21 #include "icing/text_classifier/lib3/utils/base/integral_types.h"
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(std::to_string(reinterpret_cast<const uint64>(entry)));
49   return stream;
50 }
51 
52 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
53                                        const char* message) {
54   stream.message.append(message);
55   return stream;
56 }
57 
58 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
59                                        const std::string& message) {
60   stream.message.append(message);
61   return stream;
62 }
63 
64 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
65                                        const std::string_view message) {
66   stream.message.append(message);
67   return stream;
68 }
69 
70 template <typename T1, typename T2>
71 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
72                                        const std::pair<T1, T2>& entry) {
73   stream << "(" << entry.first << ", " << entry.second << ")";
74   return stream;
75 }
76 
77 // The class that does all the work behind our TC3_LOG(severity) macros.  Each
78 // TC3_LOG(severity) << obj1 << obj2 << ...; logging statement creates a
79 // LogMessage temporary object containing a stringstream.  Each operator<< adds
80 // info to that stringstream and the LogMessage destructor performs the actual
81 // logging.  The reason this works is that in C++, "all temporary objects are
82 // destroyed as the last step in evaluating the full-expression that (lexically)
83 // contains the point where they were created."  For more info, see
84 // http://en.cppreference.com/w/cpp/language/lifetime.  Hence, the destructor is
85 // invoked after the last << from that logging statement.
86 class LogMessage {
87  public:
88   LogMessage(LogSeverity severity, const char* file_name,
89              int line_number) TC3_ATTRIBUTE_NOINLINE;
90 
91   ~LogMessage() TC3_ATTRIBUTE_NOINLINE;
92 
93   // Returns the stream associated with the logger object.
stream()94   LoggingStringStream& stream() { return stream_; }
95 
96  private:
97   const LogSeverity severity_;
98 
99   // Stream that "prints" all info into a string (not to a file).  We construct
100   // here the entire logging message and next print it in one operation.
101   LoggingStringStream stream_;
102 };
103 
104 // Pseudo-stream that "eats" the tokens <<-pumped into it, without printing
105 // anything.
106 class NullStream {
107  public:
NullStream()108   NullStream() {}
stream()109   NullStream& stream() { return *this; }
110 };
111 template <typename T>
112 inline NullStream& operator<<(NullStream& str, const T&) {
113   return str;
114 }
115 
116 }  // namespace logging
117 }  // namespace libtextclassifier3
118 
119 #define TC3_LOG(severity)                                          \
120   ::libtextclassifier3::logging::LogMessage(                       \
121       ::libtextclassifier3::logging::severity, __FILE__, __LINE__) \
122       .stream()
123 
124 // If condition x is true, does nothing.  Otherwise, crashes the program (like
125 // LOG(FATAL)) with an informative message.  Can be continued with extra
126 // messages, via <<, like any logging macro, e.g.,
127 //
128 // TC3_CHECK(my_cond) << "I think we hit a problem";
129 #define TC3_CHECK(x)                                                           \
130   (x) || TC3_LOG(FATAL) << __FILE__ << ":" << __LINE__ << ": check failed: \"" \
131                         << #x << "\" "
132 
133 #define TC3_CHECK_EQ(x, y) TC3_CHECK((x) == (y))
134 #define TC3_CHECK_LT(x, y) TC3_CHECK((x) < (y))
135 #define TC3_CHECK_GT(x, y) TC3_CHECK((x) > (y))
136 #define TC3_CHECK_LE(x, y) TC3_CHECK((x) <= (y))
137 #define TC3_CHECK_GE(x, y) TC3_CHECK((x) >= (y))
138 #define TC3_CHECK_NE(x, y) TC3_CHECK((x) != (y))
139 
140 #define TC3_NULLSTREAM ::libtextclassifier3::logging::NullStream().stream()
141 
142 // Debug checks: a TC3_DCHECK<suffix> macro should behave like TC3_CHECK<suffix>
143 // in debug mode an don't check / don't print anything in non-debug mode.
144 #if defined(NDEBUG) && !defined(TC3_DEBUG_LOGGING) && !defined(TC3_DEBUG_CHECKS)
145 
146 #define TC3_DCHECK(x) TC3_NULLSTREAM
147 #define TC3_DCHECK_EQ(x, y) TC3_NULLSTREAM
148 #define TC3_DCHECK_LT(x, y) TC3_NULLSTREAM
149 #define TC3_DCHECK_GT(x, y) TC3_NULLSTREAM
150 #define TC3_DCHECK_LE(x, y) TC3_NULLSTREAM
151 #define TC3_DCHECK_GE(x, y) TC3_NULLSTREAM
152 #define TC3_DCHECK_NE(x, y) TC3_NULLSTREAM
153 
154 #else  // NDEBUG
155 
156 // In debug mode, each TC3_DCHECK<suffix> is equivalent to TC3_CHECK<suffix>,
157 // i.e., a real check that crashes when the condition is not true.
158 #define TC3_DCHECK(x) TC3_CHECK(x)
159 #define TC3_DCHECK_EQ(x, y) TC3_CHECK_EQ(x, y)
160 #define TC3_DCHECK_LT(x, y) TC3_CHECK_LT(x, y)
161 #define TC3_DCHECK_GT(x, y) TC3_CHECK_GT(x, y)
162 #define TC3_DCHECK_LE(x, y) TC3_CHECK_LE(x, y)
163 #define TC3_DCHECK_GE(x, y) TC3_CHECK_GE(x, y)
164 #define TC3_DCHECK_NE(x, y) TC3_CHECK_NE(x, y)
165 
166 #endif  // NDEBUG
167 
168 #ifdef TC3_ENABLE_VLOG
169 #define TC3_VLOG(severity)                                     \
170   ::libtextclassifier3::logging::LogMessage(                   \
171       ::libtextclassifier3::logging::INFO, __FILE__, __LINE__) \
172       .stream()
173 #else
174 #define TC3_VLOG(severity) TC3_NULLSTREAM
175 #endif
176 
177 #endif  // ICING_TEXT_CLASSIFIER_LIB3_UTILS_BASE_LOGGING_H_
178