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