• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ICING_UTIL_LOGGING_H_
16 #define ICING_UTIL_LOGGING_H_
17 
18 #include <atomic>
19 #include <cstdint>
20 #include <string>
21 
22 #include "icing/proto/debug.pb.h"
23 
24 // This header provides base/logging.h style macros, ICING_LOG and ICING_VLOG,
25 // for logging in various platforms. The macros use __android_log_write on
26 // Android, and log to stdout/stderr on others. It also provides a function
27 // SetLoggingLevel to control the log severity level for ICING_LOG and verbosity
28 // for ICING_VLOG.
29 namespace icing {
30 namespace lib {
31 
32 // Whether we should log according to the current logging level.
33 // The function will always return false when verbosity is negative.
34 bool ShouldLog(LogSeverity::Code severity, int16_t verbosity = 0);
35 
36 // Set the minimal logging severity to be enabled, and the verbose level to see
37 // from the logs.
38 // Return false if severity is set higher than VERBOSE but verbosity is not 0.
39 // The function will always return false when verbosity is negative.
40 bool SetLoggingLevel(LogSeverity::Code severity, int16_t verbosity = 0);
41 
42 // A tiny code footprint string stream for assembling log messages.
43 struct LoggingStringStream {
LoggingStringStreamLoggingStringStream44   explicit LoggingStringStream(bool should_log) : should_log_(should_log) {}
streamLoggingStringStream45   LoggingStringStream& stream() { return *this; }
46 
47   std::string message;
48   const bool should_log_;
49 };
50 
51 template <typename T>
52 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
53                                        const T& entry) {
54   if (stream.should_log_) {
55     stream.message.append(std::to_string(entry));
56   }
57   return stream;
58 }
59 
60 template <typename T>
61 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
62                                        T* const entry) {
63   if (stream.should_log_) {
64     stream.message.append(
65         std::to_string(reinterpret_cast<const uint64_t>(entry)));
66   }
67   return stream;
68 }
69 
70 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
71                                        const char* message) {
72   if (stream.should_log_) {
73     stream.message.append(message);
74   }
75   return stream;
76 }
77 
78 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
79                                        const std::string& message) {
80   if (stream.should_log_) {
81     stream.message.append(message);
82   }
83   return stream;
84 }
85 
86 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
87                                        std::string_view message) {
88   if (stream.should_log_) {
89     stream.message.append(message);
90   }
91   return stream;
92 }
93 
94 template <typename T1, typename T2>
95 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
96                                        const std::pair<T1, T2>& entry) {
97   if (stream.should_log_) {
98     stream << "(" << entry.first << ", " << entry.second << ")";
99   }
100   return stream;
101 }
102 
103 // The class that does all the work behind our ICING_LOG(severity) macros.  Each
104 // ICING_LOG(severity) << obj1 << obj2 << ...; logging statement creates a
105 // LogMessage temporary object containing a stringstream.  Each operator<< adds
106 // info to that stringstream and the LogMessage destructor performs the actual
107 // logging.  The reason this works is that in C++, "all temporary objects are
108 // destroyed as the last step in evaluating the full-expression that (lexically)
109 // contains the point where they were created."  For more info, see
110 // http://en.cppreference.com/w/cpp/language/lifetime.  Hence, the destructor is
111 // invoked after the last << from that logging statement.
112 class LogMessage {
113  public:
114   LogMessage(LogSeverity::Code severity, uint16_t verbosity,
115              const char* file_name, int line_number) __attribute__((noinline));
116 
117   ~LogMessage() __attribute__((noinline));
118 
119   // Returns the stream associated with the logger object.
stream()120   LoggingStringStream& stream() { return stream_; }
121 
122  private:
123   const LogSeverity::Code severity_;
124   const uint16_t verbosity_;
125   const bool should_log_;
126 
127   // Stream that "prints" all info into a string (not to a file).  We construct
128   // here the entire logging message and next print it in one operation.
129   LoggingStringStream stream_;
130 };
131 
132 inline constexpr char kIcingLoggingTag[] = "AppSearchIcing";
133 
134 // Define consts to make it easier to refer to log severities in code.
135 constexpr ::icing::lib::LogSeverity::Code VERBOSE =
136     ::icing::lib::LogSeverity::VERBOSE;
137 
138 constexpr ::icing::lib::LogSeverity::Code DBG = ::icing::lib::LogSeverity::DBG;
139 
140 constexpr ::icing::lib::LogSeverity::Code INFO =
141     ::icing::lib::LogSeverity::INFO;
142 
143 constexpr ::icing::lib::LogSeverity::Code WARNING =
144     ::icing::lib::LogSeverity::WARNING;
145 
146 constexpr ::icing::lib::LogSeverity::Code ERROR =
147     ::icing::lib::LogSeverity::ERROR;
148 
149 constexpr ::icing::lib::LogSeverity::Code FATAL =
150     ::icing::lib::LogSeverity::FATAL;
151 
152 #define ICING_VLOG(verbose_level) \
153   ::icing::lib::LogMessage(VERBOSE, verbose_level, __FILE__, __LINE__).stream()
154 
155 #define ICING_LOG(severity)                                               \
156   ::icing::lib::LogMessage(severity, /*verbosity=*/0, __FILE__, __LINE__) \
157       .stream()
158 
159 }  // namespace lib
160 }  // namespace icing
161 
162 #endif  // ICING_UTIL_LOGGING_H_
163