• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2022 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 #include "icing/util/logging.h"
16 
17 #include <atomic>
18 #include <exception>
19 #include <string_view>
20 
21 #include "icing/proto/debug.pb.h"
22 #include "icing/util/logging_raw.h"
23 
24 namespace icing {
25 namespace lib {
26 namespace {
27 // Returns pointer to beginning of last /-separated token from file_name.
28 // file_name should be a pointer to a zero-terminated array of chars.
29 // E.g., "foo/bar.cc" -> "bar.cc", "foo/" -> "", "foo" -> "foo".
JumpToBasename(const char * file_name)30 const char *JumpToBasename(const char *file_name) {
31   if (file_name == nullptr) {
32     return nullptr;
33   }
34 
35   // Points to the beginning of the last encountered token.
36   size_t last_token_start = std::string_view(file_name).find_last_of('/');
37   if (last_token_start == std::string_view::npos) {
38     return file_name;
39   }
40   return file_name + last_token_start + 1;
41 }
42 
43 // Calculate the logging level value based on severity and verbosity.
CalculateLoggingLevel(LogSeverity::Code severity,uint16_t verbosity)44 constexpr uint32_t CalculateLoggingLevel(LogSeverity::Code severity,
45                                          uint16_t verbosity) {
46   uint32_t logging_level = static_cast<uint16_t>(severity);
47   logging_level = (logging_level << 16) | verbosity;
48   return logging_level;
49 }
50 
51 #if defined(ICING_DEBUG_LOGGING)
52 #define DEFAULT_LOGGING_LEVEL CalculateLoggingLevel(LogSeverity::VERBOSE, 1)
53 #else
54 #define DEFAULT_LOGGING_LEVEL CalculateLoggingLevel(LogSeverity::INFO, 0)
55 #endif
56 
57 // The current global logging level for Icing, which controls which logs are
58 // printed based on severity and verbosity.
59 //
60 // This needs to be global so that it can be easily accessed from ICING_LOG and
61 // ICING_VLOG macros spread throughout the entire code base.
62 //
63 // The first 16 bits represent the minimal log severity.
64 // The last 16 bits represent the current verbosity.
65 std::atomic<uint32_t> global_logging_level = DEFAULT_LOGGING_LEVEL;
66 
67 // TODO(b/401363381): Remove this once we have a better way to log to
68 // /dev/hvc2 in isolated storage.
69 // Indicate whether we should force logging to /dev/hvc2 for ICING_LOG.
70 std::atomic<bool> global_force_debug_logs = false;
71 
72 }  // namespace
73 
74 // Whether we should log according to the current logging level.
ShouldLog(LogSeverity::Code severity,int16_t verbosity)75 bool ShouldLog(LogSeverity::Code severity, int16_t verbosity) {
76   if (verbosity < 0) {
77     return false;
78   }
79   // Using the relaxed order for better performance because we only need to
80   // guarantee the atomicity for this specific statement, without the need to
81   // worry about reordering.
82   uint32_t curr_logging_level =
83       global_logging_level.load(std::memory_order_relaxed);
84   // If severity is less than the the threshold set.
85   if (static_cast<uint16_t>(severity) < (curr_logging_level >> 16)) {
86     return false;
87   }
88   if (severity == LogSeverity::VERBOSE) {
89     // return whether the verbosity is within the current verbose level set.
90     return verbosity <= (curr_logging_level & 0xffff);
91   }
92   return true;
93 }
94 
SetLoggingLevel(LogSeverity::Code severity,int16_t verbosity)95 bool SetLoggingLevel(LogSeverity::Code severity, int16_t verbosity) {
96   if (verbosity < 0) {
97     return false;
98   }
99   if (severity > LogSeverity::VERBOSE && verbosity > 0) {
100     return false;
101   }
102   // Using the relaxed order for better performance because we only need to
103   // guarantee the atomicity for this specific statement, without the need to
104   // worry about reordering.
105   global_logging_level.store(CalculateLoggingLevel(severity, verbosity),
106                              std::memory_order_relaxed);
107   return true;
108 }
109 
110 // TODO(b/401363381): Remove this once we have a better way to log to
111 // /dev/hvc2 in isolated storage.
SetForceDebugLogging(bool force)112 void SetForceDebugLogging(bool force) {
113   // Using the relaxed order for better performance because we only need to
114   // guarantee the atomicity for this specific statement, without the need to
115   // worry about reordering.
116   global_force_debug_logs.store(force, std::memory_order_relaxed);
117 }
118 
119 // TODO(b/401363381): Remove this once we have a better way to log to
120 // /dev/hvc2 in isolated storage.
GetForceDebugLogging()121 bool GetForceDebugLogging() {
122   // Using the relaxed order for better performance because we only need to
123   // guarantee the atomicity for this specific statement, without the need to
124   // worry about reordering.
125   return global_force_debug_logs.load(std::memory_order_relaxed);
126 }
127 
LogMessage(LogSeverity::Code severity,uint16_t verbosity,const char * file_name,int line_number)128 LogMessage::LogMessage(LogSeverity::Code severity, uint16_t verbosity,
129                        const char *file_name, int line_number)
130     : severity_(severity),
131       verbosity_(verbosity),
132       should_log_(ShouldLog(severity_, verbosity_)),
133       force_debug_logs_(GetForceDebugLogging()),
134       stream_(should_log_) {
135   if (should_log_) {
136     stream_ << JumpToBasename(file_name) << ":" << line_number << ": ";
137   }
138 }
139 
~LogMessage()140 LogMessage::~LogMessage() {
141   if (should_log_) {
142     LowLevelLogging(severity_, kIcingLoggingTag, stream_.message,
143                     force_debug_logs_);
144   }
145   if (severity_ == LogSeverity::FATAL) {
146     std::terminate();  // Will print a stacktrace (stdout or logcat).
147   }
148 }
149 }  // namespace lib
150 }  // namespace icing
151