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