• 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 }  // namespace
68 
69 // Whether we should log according to the current logging level.
ShouldLog(LogSeverity::Code severity,int16_t verbosity)70 bool ShouldLog(LogSeverity::Code severity, int16_t verbosity) {
71   if (verbosity < 0) {
72     return false;
73   }
74   // Using the relaxed order for better performance because we only need to
75   // guarantee the atomicity for this specific statement, without the need to
76   // worry about reordering.
77   uint32_t curr_logging_level =
78       global_logging_level.load(std::memory_order_relaxed);
79   // If severity is less than the the threshold set.
80   if (static_cast<uint16_t>(severity) < (curr_logging_level >> 16)) {
81     return false;
82   }
83   if (severity == LogSeverity::VERBOSE) {
84     // return whether the verbosity is within the current verbose level set.
85     return verbosity <= (curr_logging_level & 0xffff);
86   }
87   return true;
88 }
89 
SetLoggingLevel(LogSeverity::Code severity,int16_t verbosity)90 bool SetLoggingLevel(LogSeverity::Code severity, int16_t verbosity) {
91   if (verbosity < 0) {
92     return false;
93   }
94   if (severity > LogSeverity::VERBOSE && verbosity > 0) {
95     return false;
96   }
97   // Using the relaxed order for better performance because we only need to
98   // guarantee the atomicity for this specific statement, without the need to
99   // worry about reordering.
100   global_logging_level.store(CalculateLoggingLevel(severity, verbosity),
101                              std::memory_order_relaxed);
102   return true;
103 }
104 
LogMessage(LogSeverity::Code severity,uint16_t verbosity,const char * file_name,int line_number)105 LogMessage::LogMessage(LogSeverity::Code severity, uint16_t verbosity,
106                        const char *file_name, int line_number)
107     : severity_(severity),
108       verbosity_(verbosity),
109       should_log_(ShouldLog(severity_, verbosity_)),
110       stream_(should_log_) {
111   if (should_log_) {
112     stream_ << JumpToBasename(file_name) << ":" << line_number << ": ";
113   }
114 }
115 
~LogMessage()116 LogMessage::~LogMessage() {
117   if (should_log_) {
118     LowLevelLogging(severity_, kIcingLoggingTag, stream_.message);
119   }
120   if (severity_ == LogSeverity::FATAL) {
121     std::terminate();  // Will print a stacktrace (stdout or logcat).
122   }
123 }
124 }  // namespace lib
125 }  // namespace icing
126