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 27namespace libtextclassifier { 28namespace 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. 39class 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. 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. 84class NullStream { 85 public: 86 NullStream() {} 87 NullStream &stream() { return *this; } 88}; 89template <typename T> 90inline 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