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