Home | History | Annotate | Download | only in base
      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.
     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:
     86   NullStream() {}
     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