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 NLP_SAFT_COMPONENTS_COMMON_MOBILE_LITE_BASE_COMPACT_LOGGING_H_ 18 #define NLP_SAFT_COMPONENTS_COMMON_MOBILE_LITE_BASE_COMPACT_LOGGING_H_ 19 20 #include <cassert> 21 #include <string> 22 23 #include "lang_id/common/lite_base/attributes.h" 24 #include "lang_id/common/lite_base/compact-logging-levels.h" 25 #include "lang_id/common/lite_strings/stringpiece.h" 26 27 namespace libtextclassifier3 { 28 namespace mobile { 29 namespace internal_logging { 30 31 // A tiny code footprint string stream for assembling log messages. 32 struct LoggingStringStream { LoggingStringStreamLoggingStringStream33 LoggingStringStream() {} streamLoggingStringStream34 LoggingStringStream &stream() { return *this; } 35 36 // Needed for invocation in SAFTM_CHECK macro. 37 explicit operator bool() const { return true; } 38 39 std::string message; 40 }; 41 42 template <typename T> 43 inline LoggingStringStream &operator<<(LoggingStringStream &stream, 44 const T &entry) { 45 stream.message.append(std::to_string(entry)); 46 return stream; 47 } 48 49 inline LoggingStringStream &operator<<(LoggingStringStream &stream, 50 const char *message) { 51 stream.message.append(message); 52 return stream; 53 } 54 55 inline LoggingStringStream &operator<<(LoggingStringStream &stream, 56 const std::string &message) { 57 stream.message.append(message); 58 return stream; 59 } 60 61 inline LoggingStringStream &operator<<(LoggingStringStream &stream, 62 StringPiece sp) { 63 stream.message.append(sp.data(), sp.size()); 64 return stream; 65 } 66 67 // The class that does all the work behind our SAFTM_LOG(severity) macros. Each 68 // SAFTM_LOG(severity) << obj1 << obj2 << ...; logging statement creates a 69 // LogMessage temporary object containing a stringstream. Each operator<< adds 70 // info to that stringstream and the LogMessage destructor performs the actual 71 // logging. The reason this works is that in C++, "all temporary objects are 72 // destroyed as the last step in evaluating the full-expression that (lexically) 73 // contains the point where they were created." For more info, see 74 // http://en.cppreference.com/w/cpp/language/lifetime. Hence, the destructor is 75 // invoked after the last << from that logging statement. 76 class LogMessage { 77 public: 78 LogMessage(LogSeverity severity, const char *file_name, 79 int line_number) SAFTM_ATTRIBUTE_NOINLINE; 80 81 ~LogMessage() SAFTM_ATTRIBUTE_NOINLINE; 82 83 // Returns the stream associated with the logger object. stream()84 LoggingStringStream &stream() { return stream_; } 85 86 private: 87 const LogSeverity severity_; 88 89 // Stream that "prints" all info into a string (not to a file). We construct 90 // here the entire logging message and next print it in one operation. 91 LoggingStringStream stream_; 92 }; 93 94 // Pseudo-stream that "eats" the tokens <<-pumped into it, without printing 95 // anything. 96 class NullStream { 97 public: NullStream()98 NullStream() {} stream()99 NullStream &stream() { return *this; } 100 }; 101 template <typename T> 102 inline NullStream &operator<<(NullStream &str, const T &) { 103 return str; 104 } 105 106 } // namespace internal_logging 107 } // namespace mobile 108 } // namespace nlp_saft 109 110 #define SAFTM_LOG(severity) \ 111 ::libtextclassifier3::mobile::internal_logging::LogMessage( \ 112 ::libtextclassifier3::mobile::internal_logging::severity, __FILE__, __LINE__) \ 113 .stream() 114 115 // If condition x is true, does nothing. Otherwise, crashes the program (liek 116 // LOG(FATAL)) with an informative message. Can be continued with extra 117 // messages, via <<, like any logging macro, e.g., 118 // 119 // SAFTM_CHECK(my_cond) << "I think we hit a problem"; 120 #define SAFTM_CHECK(x) \ 121 (x) || SAFTM_LOG(FATAL) << __FILE__ << ":" << __LINE__ \ 122 << ": check failed: \"" << #x 123 124 #define SAFTM_CHECK_EQ(x, y) SAFTM_CHECK((x) == (y)) 125 #define SAFTM_CHECK_LT(x, y) SAFTM_CHECK((x) < (y)) 126 #define SAFTM_CHECK_GT(x, y) SAFTM_CHECK((x) > (y)) 127 #define SAFTM_CHECK_LE(x, y) SAFTM_CHECK((x) <= (y)) 128 #define SAFTM_CHECK_GE(x, y) SAFTM_CHECK((x) >= (y)) 129 #define SAFTM_CHECK_NE(x, y) SAFTM_CHECK((x) != (y)) 130 131 #define SAFTM_NULLSTREAM \ 132 ::libtextclassifier3::mobile::internal_logging::NullStream().stream() 133 134 // Debug checks: a SAFTM_DCHECK<suffix> macro should behave like 135 // SAFTM_CHECK<suffix> in debug mode an don't check / don't print anything in 136 // non-debug mode. 137 #ifdef NDEBUG 138 139 #define SAFTM_DCHECK(x) SAFTM_NULLSTREAM 140 #define SAFTM_DCHECK_EQ(x, y) SAFTM_NULLSTREAM 141 #define SAFTM_DCHECK_LT(x, y) SAFTM_NULLSTREAM 142 #define SAFTM_DCHECK_GT(x, y) SAFTM_NULLSTREAM 143 #define SAFTM_DCHECK_LE(x, y) SAFTM_NULLSTREAM 144 #define SAFTM_DCHECK_GE(x, y) SAFTM_NULLSTREAM 145 #define SAFTM_DCHECK_NE(x, y) SAFTM_NULLSTREAM 146 147 // In non-debug mode, SAFT_DLOG statements do not generate any logging. 148 #define SAFTM_DLOG(severity) SAFTM_NULLSTREAM 149 150 #else // NDEBUG 151 152 // In debug mode, each SAFTM_DCHECK<suffix> is equivalent to 153 // SAFTM_CHECK<suffix>, i.e., a real check that crashes when the condition is 154 // not true. 155 #define SAFTM_DCHECK(x) SAFTM_CHECK(x) 156 #define SAFTM_DCHECK_EQ(x, y) SAFTM_CHECK_EQ(x, y) 157 #define SAFTM_DCHECK_LT(x, y) SAFTM_CHECK_LT(x, y) 158 #define SAFTM_DCHECK_GT(x, y) SAFTM_CHECK_GT(x, y) 159 #define SAFTM_DCHECK_LE(x, y) SAFTM_CHECK_LE(x, y) 160 #define SAFTM_DCHECK_GE(x, y) SAFTM_CHECK_GE(x, y) 161 #define SAFTM_DCHECK_NE(x, y) SAFTM_CHECK_NE(x, y) 162 163 // In debug mode, SAFT_DLOG statements are like SAFT_LOG. 164 #define SAFTM_DLOG SAFTM_LOG 165 166 #endif // NDEBUG 167 168 #ifdef LIBTEXTCLASSIFIER_VLOG 169 #define SAFTM_VLOG(severity) \ 170 ::libtextclassifier3::mobile::internal_logging::LogMessage( \ 171 ::libtextclassifier3::mobile::internal_logging::INFO, __FILE__, __LINE__) \ 172 .stream() 173 #else 174 #define SAFTM_VLOG(severity) SAFTM_NULLSTREAM 175 #endif 176 177 #endif // NLP_SAFT_COMPONENTS_COMMON_MOBILE_LITE_BASE_COMPACT_LOGGING_H_ 178