• 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 // TODO(b/401363381): Remove this once we have a better way to log to
43 // /dev/hvc2 in isolated storage.
44 // Indicate whether we should force logging to /dev/hvc2 for ICING_LOG.
45 void SetForceDebugLogging(bool force);
46 
47 // TODO(b/401363381): Remove this once we have a better way to log to
48 // /dev/hvc2 in isolated storage.
49 // Get whether or not we should force logging to /dev/hvc2 for ICING_LOG.
50 bool GetForceDebugLogging();
51 
52 // A tiny code footprint string stream for assembling log messages.
53 struct LoggingStringStream {
LoggingStringStreamLoggingStringStream54   explicit LoggingStringStream(bool should_log) : should_log_(should_log) {}
streamLoggingStringStream55   LoggingStringStream& stream() { return *this; }
56 
57   std::string message;
58   const bool should_log_;
59 };
60 
61 template <typename T>
62 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
63                                        const T& entry) {
64   if (stream.should_log_) {
65     stream.message.append(std::to_string(entry));
66   }
67   return stream;
68 }
69 
70 template <typename T>
71 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
72                                        T* const entry) {
73   if (stream.should_log_) {
74     stream.message.append(
75         std::to_string(reinterpret_cast<const uint64_t>(entry)));
76   }
77   return stream;
78 }
79 
80 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
81                                        const char* message) {
82   if (stream.should_log_) {
83     stream.message.append(message);
84   }
85   return stream;
86 }
87 
88 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
89                                        const std::string& message) {
90   if (stream.should_log_) {
91     stream.message.append(message);
92   }
93   return stream;
94 }
95 
96 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
97                                        std::string_view message) {
98   if (stream.should_log_) {
99     stream.message.append(message);
100   }
101   return stream;
102 }
103 
104 template <typename T1, typename T2>
105 inline LoggingStringStream& operator<<(LoggingStringStream& stream,
106                                        const std::pair<T1, T2>& entry) {
107   if (stream.should_log_) {
108     stream << "(" << entry.first << ", " << entry.second << ")";
109   }
110   return stream;
111 }
112 
113 // The class that does all the work behind our ICING_LOG(severity) macros.  Each
114 // ICING_LOG(severity) << obj1 << obj2 << ...; logging statement creates a
115 // LogMessage temporary object containing a stringstream.  Each operator<< adds
116 // info to that stringstream and the LogMessage destructor performs the actual
117 // logging.  The reason this works is that in C++, "all temporary objects are
118 // destroyed as the last step in evaluating the full-expression that (lexically)
119 // contains the point where they were created."  For more info, see
120 // http://en.cppreference.com/w/cpp/language/lifetime.  Hence, the destructor is
121 // invoked after the last << from that logging statement.
122 class LogMessage {
123  public:
124   LogMessage(LogSeverity::Code severity, uint16_t verbosity,
125              const char* file_name, int line_number) __attribute__((noinline));
126 
127   ~LogMessage() __attribute__((noinline));
128 
129   // Returns the stream associated with the logger object.
stream()130   LoggingStringStream& stream() { return stream_; }
131 
132  private:
133   const LogSeverity::Code severity_;
134   const uint16_t verbosity_;
135   const bool should_log_;
136   const bool force_debug_logs_;
137 
138   // Stream that "prints" all info into a string (not to a file).  We construct
139   // here the entire logging message and next print it in one operation.
140   LoggingStringStream stream_;
141 };
142 
143 inline constexpr char kIcingLoggingTag[] = "AppSearchIcing";
144 
145 // Define consts to make it easier to refer to log severities in code.
146 constexpr ::icing::lib::LogSeverity::Code VERBOSE =
147     ::icing::lib::LogSeverity::VERBOSE;
148 
149 constexpr ::icing::lib::LogSeverity::Code DBG = ::icing::lib::LogSeverity::DBG;
150 
151 constexpr ::icing::lib::LogSeverity::Code INFO =
152     ::icing::lib::LogSeverity::INFO;
153 
154 constexpr ::icing::lib::LogSeverity::Code WARNING =
155     ::icing::lib::LogSeverity::WARNING;
156 
157 constexpr ::icing::lib::LogSeverity::Code ERROR =
158     ::icing::lib::LogSeverity::ERROR;
159 
160 constexpr ::icing::lib::LogSeverity::Code FATAL =
161     ::icing::lib::LogSeverity::FATAL;
162 
163 #define ICING_VLOG(verbose_level) \
164   ::icing::lib::LogMessage(VERBOSE, verbose_level, __FILE__, __LINE__).stream()
165 
166 #define ICING_LOG(severity)                                               \
167   ::icing::lib::LogMessage(severity, /*verbosity=*/0, __FILE__, __LINE__) \
168       .stream()
169 
170 }  // namespace lib
171 }  // namespace icing
172 
173 #endif  // ICING_UTIL_LOGGING_H_
174