1 /* 2 * Copyright (C) 2017 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_UTIL_BASE_LOGGING_H_ 18 #define LIBTEXTCLASSIFIER_UTIL_BASE_LOGGING_H_ 19 20 #include <cassert> 21 #include <sstream> 22 #include <string> 23 24 #include "util/base/logging_levels.h" 25 #include "util/base/port.h" 26 27 namespace libtextclassifier { 28 namespace logging { 29 30 // The class that does all the work behind our TC_LOG(severity) macros. Each 31 // TC_LOG(severity) << obj1 << obj2 << ...; logging statement creates a 32 // LogMessage temporary object containing a stringstream. Each operator<< adds 33 // info to that stringstream and the LogMessage destructor performs the actual 34 // logging. The reason this works is that in C++, "all temporary objects are 35 // destroyed as the last step in evaluating the full-expression that (lexically) 36 // contains the point where they were created." For more info, see 37 // http://en.cppreference.com/w/cpp/language/lifetime. Hence, the destructor is 38 // invoked after the last << from that logging statement. 39 class LogMessage { 40 public: 41 LogMessage(LogSeverity severity, const char *file_name, 42 int line_number) TC_ATTRIBUTE_NOINLINE; 43 44 ~LogMessage() TC_ATTRIBUTE_NOINLINE; 45 46 // Returns the stream associated with the logger object. stream()47 std::stringstream &stream() { return stream_; } 48 49 private: 50 const LogSeverity severity_; 51 52 // Stream that "prints" all info into a string (not to a file). We construct 53 // here the entire logging message and next print it in one operation. 54 std::stringstream stream_; 55 }; 56 57 #define TC_LOG(severity) \ 58 ::libtextclassifier::logging::LogMessage( \ 59 ::libtextclassifier::logging::severity, __FILE__, __LINE__) \ 60 .stream() 61 62 // If condition x is true, does nothing. Otherwise, crashes the program (liek 63 // LOG(FATAL)) with an informative message. Can be continued with extra 64 // messages, via <<, like any logging macro, e.g., 65 // 66 // TC_CHECK(my_cond) << "I think we hit a problem"; 67 #define TC_CHECK(x) \ 68 (x) || TC_LOG(FATAL) << __FILE__ << ":" << __LINE__ << ": check failed: \"" \ 69 << #x 70 71 #define TC_CHECK_EQ(x, y) TC_CHECK((x) == (y)) 72 #define TC_CHECK_LT(x, y) TC_CHECK((x) < (y)) 73 #define TC_CHECK_GT(x, y) TC_CHECK((x) > (y)) 74 #define TC_CHECK_LE(x, y) TC_CHECK((x) <= (y)) 75 #define TC_CHECK_GE(x, y) TC_CHECK((x) >= (y)) 76 #define TC_CHECK_NE(x, y) TC_CHECK((x) != (y)) 77 78 // Debug checks: a TC_DCHECK<suffix> macro should behave like TC_CHECK<suffix> 79 // in debug mode an don't check / don't print anything in non-debug mode. 80 #ifdef NDEBUG 81 82 // Pseudo-stream that "eats" the tokens <<-pumped into it, without printing 83 // anything. 84 class NullStream { 85 public: NullStream()86 NullStream() {} stream()87 NullStream &stream() { return *this; } 88 }; 89 template <typename T> 90 inline NullStream &operator<<(NullStream &str, const T &) { 91 return str; 92 } 93 94 #define TC_NULLSTREAM ::libtextclassifier::logging::NullStream().stream() 95 #define TC_DCHECK(x) TC_NULLSTREAM 96 #define TC_DCHECK_EQ(x, y) TC_NULLSTREAM 97 #define TC_DCHECK_LT(x, y) TC_NULLSTREAM 98 #define TC_DCHECK_GT(x, y) TC_NULLSTREAM 99 #define TC_DCHECK_LE(x, y) TC_NULLSTREAM 100 #define TC_DCHECK_GE(x, y) TC_NULLSTREAM 101 #define TC_DCHECK_NE(x, y) TC_NULLSTREAM 102 103 #else // NDEBUG 104 105 // In debug mode, each TC_DCHECK<suffix> is equivalent to TC_CHECK<suffix>, 106 // i.e., a real check that crashes when the condition is not true. 107 #define TC_DCHECK(x) TC_CHECK(x) 108 #define TC_DCHECK_EQ(x, y) TC_CHECK_EQ(x, y) 109 #define TC_DCHECK_LT(x, y) TC_CHECK_LT(x, y) 110 #define TC_DCHECK_GT(x, y) TC_CHECK_GT(x, y) 111 #define TC_DCHECK_LE(x, y) TC_CHECK_LE(x, y) 112 #define TC_DCHECK_GE(x, y) TC_CHECK_GE(x, y) 113 #define TC_DCHECK_NE(x, y) TC_CHECK_NE(x, y) 114 115 #endif // NDEBUG 116 } // namespace logging 117 } // namespace libtextclassifier 118 119 #endif // LIBTEXTCLASSIFIER_UTIL_BASE_LOGGING_H_ 120